===============================
Reflection and Meta-programming
===============================

Since the Ring programming language is a dynamic language, we can get answers about
the program code and we can modify our code during the runtime.

In this chapter we will learn about this and the available functions to use.

locals() Function
=================

We can get a list of variables names in the current scope using the locals() function.

Syntax:

.. code-block:: none

	locals() --> a list contains the variables names in the current scope

Example:

.. code-block:: none

	test("hello")

	func test cMsg

		see cMsg + nl

		x = 10
		y = 20
		z = 30

		see locals()

Output:

.. code-block:: none

	hello
	cmsg
	x
	y
	z

globals() Function
==================

We can get a list of variables names in the global scope using the globals() function.

Syntax:

.. code-block:: none
	
	globals() --> a list contains variables names in the global scope

Example:

.. code-block:: none

	x=10 y=20 z=30
	test()

	func test
		see "message from test()" + nl +
		    "Global Variables:" + nl
		see globals()

Output:

.. code-block:: none


	message from test()
	Global Variables:
	x
	y
	z

functions() Function
====================

We can get a list of functions names written in the Ring language using the functions() function.

Syntax:

.. code-block:: none

	functions() --> a list contains functions names

Example:

.. code-block:: none

	see functions()

	func f1
		see "f1" + nl

	func f2
		see "f2" + nl

	func f3 
		see "f3" + nl

Output:

.. code-block:: none

	f1
	f2
	f3

cfunctions() Function
=====================

We can get a list of functions names written in the C language using the cfunctions() function.

Syntax:

.. code-block:: none

	cfunctions() --> a list contains functions names

Example:

.. code-block:: none

	aList =  cfunctions()
	See "Count : " + len(aList) + nl
	for x in aList
		see x + "()" + nl
	next

Output:

.. code-block:: none

	Count : 186
	len() 
	add() 
	del() 
	get() 
	clock()
	...

.. note:: The complete list is removed from the previous output.

islocal() Function
==================

We can check if a variable is defined in the local scope or not using the islocal() function.

Syntax:

.. code-block:: none

	islocal(cVariableName) --> returns 1 if the variable is defined in the local scope
				   returns 0 if the variable is not defined in the local scope

Example:

.. code-block:: none

	test()

	func test
		x=10 y=20
		see islocal("x") + nl + 
		    islocal("y") + nl + 
		    islocal("z") + nl

Output:

.. code-block:: none

	1
	1
	0


isglobal() Function
===================

We can check if a variable is defined in the global scope or not using the isglobal() function.

Syntax:

.. code-block:: none

	isglobal(cVariableName) --> returns 1 if the variable is defined in the global scope
				    returns 0 if the variable is not defined in the global scope

Example:

.. code-block:: none

	x=10 y=20

	test()

	func test
		see isglobal("x") + nl + 
		    isglobal("y") + nl + 
		    isglobal("z") + nl

Output:

.. code-block:: none

	1
	1
	0

isfunction() Function
=====================

We can check if a Ring function is defined or not using the isfunction() function.

Syntax:

.. code-block:: none

	isfunction(cFunctionName) --> returns 1 if the Ring function is defined
				      returns 0 if the Ring function is not defined

Example:

.. code-block:: none

	see isfunction("f1") + nl + 
	    isfunction("f2") + nl + 
	    isfunction("f3") + nl

	func f1
		see "message from f1()" + nl

	func f2
		see "message from f2()" + nl

Output:

.. code-block:: none

	1
	1
	0

iscfunction() Function
======================

We can check if a C function is defined or not using the iscfunction() function.

Syntax:

.. code-block:: none

	iscfunction(cFunctionName) --> returns 1 if the C function is defined
				       returns 0 if the C function is not defined

Example:

.. code-block:: none

	see iscfunction("len") + nl + 
  	    iscfunction("add") + nl + 
  	    iscfunction("test") + nl

Output:

.. code-block:: none

	1
	1
	0


packages() Function
===================

We can get a list of packages names using the packages() function.

Syntax:

.. code-block:: none

	packages() --> a list contains packages names

Example:

.. code-block:: none

	See packages()

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1

	Package Package3
		Class class1
			Func f1

	Package Package4
		Class class1
			Func f1

Output:

.. code-block:: none

	package1
	package2
	package3
	package4


ispackage() Function
====================

We can check if a package is defined or not using the ispackage() function.

Syntax:

.. code-block:: none

	ispackage(cPackageName) --> returns 1 if the Package is defined
				    returns 0 if the Package is not defined

Example:

.. code-block:: none

	See ispackage("package1") + nl + 
	    ispackage("package4") + nl + 
	    ispackage("package5") + nl +
	    ispackage("package3") + nl

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1

	Package Package3
		Class class1
			Func f1

	Package Package4
		Class class1
			Func f1

Output:

.. code-block:: none

	1
	1
	0
	1


classes() Function
==================

We can get a list of classes names using the classes() function.

Syntax:

.. code-block:: none

	classes() --> a list contains classes names

Example:

.. code-block:: none

	See classes()

	Class class1
		Func f1

	Class class2
		Func f1

	Class class3
		Func f1

Output:

.. code-block:: none

	class1
	class2
	class3

isclass() Function
==================

We can check if a class is defined or not using the isclass() function.

Syntax:

.. code-block:: none

	isclass(cClassName) -->  returns 1 if the Class is defined
				 returns 0 if the Class is not defined

Example:

.. code-block:: none

	see isclass("class4") + nl + 
	    isclass("class3") + nl +
	    isclass("class2") + nl

	Class class1
		func f1

	class class2
		func f1

	class class3
		func f1

Output:

.. code-block:: none

	0
	1
	1

packageclasses() Function
=========================

We can get a list of classes names inside a package using the packageclasses() function.

Syntax:

.. code-block:: none

	packageclasses(cPackageName) --> a list contains classes names inside the package

Example:

.. code-block:: none

	see "classes in Package1" + nl
	see packageclasses("Package1")
	see "classes in Package2" + nl
	see packageclasses("Package2")

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1
		Class class2
			Func f1
		Class class3
			func f1


Output:

.. code-block:: none

	classes in Package1
	class1
	classes in Package2
	class1
	class2
	class3


ispackageclass() Function
=========================

We can check if a class is defined inside package or not using the ispackageclass() function.

Syntax:

.. code-block:: none

	ispackageclass(cPackageName,cClassName) -->  returns 1 if the Class is defined  
		  				     returns 0 if the Class is not defined 

Example:

.. code-block:: none

	see ispackageclass("package1","class1") + nl +
	    ispackageclass("package1","class2") + nl +
	    ispackageclass("package2","class1") + nl +
	    ispackageclass("package2","class2") + nl

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1
		Class class2
			Func f1
		Class class3
			func f1

Output:

.. code-block:: none

	1
	0
	1
	1

classname() Function
====================
		
We can know the class name of an object using the classname() function

Syntax:

.. code-block:: none

	classname(object) --> Returns the object class name


Example:

.. code-block:: none

	o1 = new point
	o2 = new rect

	see classname(o1) + nl		# print point
	see classname(o2) + nl		# print rect

	class point
	class rect

objectid() Function
===================

We can know the object id using the objectid() function

Syntax:

.. code-block:: none

	objectid(object) --> Returns the object id

Example:

.. code-block:: none

	o1 = new point
	see objectid(o1) + nl
	test(o1)

	func test v
		see objectid(v) + nl

	Class point x y z

Output:

.. code-block:: none

	021B5808
	021B5808
		
isobject() Function
===================

We can check the variable to know if it's an object or not using the isobject() function

Syntax:

.. code-block:: none

	isobject(variable) --> Returns True if it's an object, False if it's not

		
attributes() Function
=====================

We can get the object attributes using the attributes() function

Syntax:

.. code-block:: none

	attributes(object) --> Returns a list contains the object attributes

Example:

.. code-block:: none

	o1 = new point
	aList = attributes(o1)		# we can use see attributes(o1)
	for t in aList see t next	# print xyz 
	Class Point x y z
		
methods() Function
==================

We can get the object methods using the methods() function

Syntax:

.. code-block:: none

	methods(object) --> Returns a list contains the object methods


Example:

.. code-block:: none

	o1 = new test
	aList = methods(o1)

	for x in aList
		cCode = "o1."+x+"()"
		eval(cCode)
	next

	Class Test
		func f1
			see "hello from f1" + nl
		func f2
			see "hello from f2" + nl
		func f3
			see "hello from f3" + nl
		func f4
			see "hello from f4" + nl

Output:

.. code-block:: none

	hello from f1
	hello from f2
	hello from f3
	hello from f4


isattribute() Function
======================

We can test if the object contains an attribute or not using the isattribute() function

Syntax:

.. code-block:: none

	isattribute(object,cAttributeName) --> Returns True if the object contains the attribute

Example:

.. code-block:: none

	o1 = new point

	see isattribute(o1,"x") + nl	# print 1
	see isattribute(o1,"t") + nl	# print 0
	see isattribute(o1,"y") + nl	# print 1
	see isattribute(o1,"z") + nl	# print 1

	class point x y z

isprivateattribute() Function
=============================

We can test if the object contains a private attribute or not using the isprivateattribute() function

Syntax:

.. code-block:: none

	isprivateattribute(object,cAttributeName) --> Returns True if the object 
						      contains the private attribute

Example:

.. code-block:: none

	o1 = new person

	see isprivateattribute(o1,"name") + nl + 
	    isprivateattribute(o1,"address") + nl + 
	    isprivateattribute(o1,"phone") + nl + 
	    isprivateattribute(o1,"job") + nl + 
	    isprivateattribute(o1,"salary")

	Class Person
		name address phone
		private
			job salary

Output:

.. code-block:: none

	0
	0
	0
	1
	1

	
ismethod() Function
===================

We can test if the object class contains a method or not using the ismethod() function

Syntax:

.. code-block:: none

	ismethod(object,cMethodName) --> Returns True if the object class contains the method

Example:

.. code-block:: none

	o1 = new point

	see ismethod(o1,"print") + nl		# print 1

	mylist = []
	mylist + new point

	see ismethod(mylist[1],"print") + nl	# print 1

	class point x y z
		func print
			see x + nl + y + nl + z + nl


isprivatemethod() Function
==========================

We can test if the object class contains a private method or not using the isprivatemethod() function

Syntax:

.. code-block:: none

	isprivatemethod(object,cMethodName) --> Returns True if the object class contains 
						the private method

Example:

.. code-block:: none

	o1 = new Test

	see isprivatemethod(o1,"f1") + nl +
	    isprivatemethod(o1,"f2") 

	Class Test
		func  f1
			see "message from f1()" + nl
		private
			func f2
				see "message from f2()" + nl

Output:

.. code-block:: none

	0
	1

addattribute() Function
=======================

We can add an attribute (or a group of attributes) to the object state (not the class) using
the addattribute() function

Syntax:

.. code-block:: none

	AddAttribute(object,cAttributeName|aAttributesList)

Example(1):

.. code-block:: none

	see new point {x=10 y=20 z=30}
	Class Point 
		AddAttribute(self,["x","y","z"])

Example(2):

.. code-block:: none

	o1 = new point
	addattribute(o1,"x")
	addattribute(o1,"y")
	addattribute(o1,"z")
	see o1 {x=10 y=20 z=30}
	class point


Output:

.. code-block:: none

	x: 10.000000
	y: 20.000000
	z: 30.000000




addmethod() Function
====================

We can add a method to the object class using the addmethod() function
This method can be used with any object from the same class.

Syntax:

.. code-block:: none

	AddMethod(Object,cNewMethodName,cMethodName|AnonymousFunction)

Example:

.. code-block:: none

	o1 = new point { x=10 y=20 z=30 }

	addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )

	o1.print()

	Class point
		x y z
	
Output:

.. code-block:: none

	10
	20
	30

Instead of using anonymous function to add new method to the class, we can use the function name

Example:

.. code-block:: none

	o1 = new point { x=10 y=20 z=30 }

	myfunc = func { see x + nl + y + nl + z + nl }

	addmethod(o1,"print", myfunc )
	addmethod(o1,"display", myfunc )
	addmethod(o1,"show", myfunc )

	o1.print()
	o1.display()
	o1.show()

	Class point
		x y z


Output:

.. code-block:: none

	10
	20
	30
	10
	20
	30
	10
	20
	30

Since we add the method to the class, any object from that class can use this method

Example:

.. code-block:: none

	o1 = new point { x=10 y=20 z=30 }
	o2 = new point { x=100 y=200 z=300 }
	o3 = new point { x=50 y=150 z=250 }

	addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )

	o1.print()
	o2.print()
	o3.print()

	Class point
		x y z

Output:

.. code-block:: none

	10
	20
	30
	100
	200
	300
	50
	150
	250

getattribute() function
=======================

We can get the object attribute value using the getattribute() function

Syntax:

.. code-block:: none

	GetAttribute(oObject,cAttributeName) ---> Attribute Value

Example:

.. code-block:: none

	o1 = new point

	see getattribute(o1,"name") + nl +
	    getattribute(o1,"x") + nl +
	    getattribute(o1,"y") + nl + 
	    getattribute(o1,"z") + nl

	Class Point
		x=10 y=20 z=30
		name = "3D-Point"
	
Output:

.. code-block:: none

	3D-Point
	10
	20
	30

setattribute() function
=======================

We can set the object attribute value using the setattribute() function

Syntax:

.. code-block:: none

	SetAttribute(oObject,cAttributeName,Value)

Example:

.. code-block:: none

	o1 = new person
	setattribute(o1,"cName","Mahmoud")
	setattribute(o1,"nSalary",1000000)
	setattribute(o1,"aColors",["white","blue","yellow"])

	see o1
	see o1.aColors

	Class Person
		cName
		nSalary
		aColors

Output:

.. code-block:: none

	cname: Mahmoud
	nsalary: 1000000.000000
	acolors: List...
	white
	blue
	yellow


mergemethods() Function
=======================

We can share methods between classes without inheritance using the MergeMethods() function

This function merge class methods to another class.

Syntax:

.. code-block:: none

	MergeMethods(cClassNameDestination,cClassNameSource)

Example:

.. code-block:: none

	mergemethods("count","share")
	mergemethods("count2","share")

	o1 = new count  { test() }
	o1 = new count2 { test() }

	Class Share
		func one
			see "one" + nl
		func two
			see "two" + nl
		func three
			see "three" + nl

	Class Display
		Func printline
			see copy("*",20) + nl

	Class Count from Display
		Func test
			printline()
			one()
			two()
			three()
			printline()

	Class Count2 from Display
		Func test
			three()
			two()
			one()
			printline()	

Output:

.. code-block:: none

	********************
	one
	two
	three
	********************
	three
	two
	one
	********************