.. index:: 
	single: Reflection and Meta-programming; Introduction

===============================
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()
* globals()
* functions()
* cfunctions()
* islocal()
* isglobal()
* isfunction()
* iscfunction()
* packages()
* ispackage()
* classes()
* isclass()
* packageclasses()
* ispackageclass()
* classname()
* objectid()
* isobject() 
* attributes()
* methods()
* isattribute()
* isprivateattribute()
* ismethod()
* isprivatemethod()
* addattribute()
* addmethod()
* getattribute()
* setattribute()
* mergemethods()
* packagename()

.. index:: 
	pair: Reflection and Meta-programming; locals()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	test("hello")

	func test cMsg

		see cMsg + nl

		x = 10
		y = 20
		z = 30

		see locals()

Output:

.. code-block:: ring

	hello
	cmsg
	x
	y
	z

.. index:: 
	pair: Reflection and Meta-programming; globals()

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

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

Syntax:

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

Example:

.. code-block:: ring

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

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

Output:

.. code-block:: ring


	message from test()
	Global Variables:
	x
	y
	z

.. index:: 
	pair: Reflection and Meta-programming; functions()

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

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

Syntax:

.. code-block:: ring

	functions() --> a list contains functions names

Example:

.. code-block:: ring

	see functions()

	func f1
		see "f1" + nl

	func f2
		see "f2" + nl

	func f3 
		see "f3" + nl

Output:

.. code-block:: ring

	f1
	f2
	f3

.. index:: 
	pair: Reflection and Meta-programming; cfunctions()

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

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

Syntax:

.. code-block:: ring

	cfunctions() --> a list contains functions names

Example:

.. code-block:: ring

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

Output:

.. code-block:: ring

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

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

.. index:: 
	pair: Reflection and Meta-programming; islocal()

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

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

Syntax:

.. code-block:: ring

	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:: ring

	test()

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

Output:

.. code-block:: ring

	1
	1
	0


.. index:: 
	pair: Reflection and Meta-programming; isglobal()

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

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

Syntax:

.. code-block:: ring

	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:: ring

	x=10 y=20

	test()

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

Output:

.. code-block:: ring

	1
	1
	0

.. index:: 
	pair: Reflection and Meta-programming; isfunction()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	1
	1
	0

.. index:: 
	pair: Reflection and Meta-programming; iscfunction()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

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

Output:

.. code-block:: ring

	1
	1
	0

.. index:: 
	pair: Reflection and Meta-programming; packages()

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

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

Syntax:

.. code-block:: ring

	packages() --> a list contains packages names

Example:

.. code-block:: ring

	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:: ring

	package1
	package2
	package3
	package4

.. index:: 
	pair: Reflection and Meta-programming; ispackage()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	1
	1
	0
	1

.. index:: 
	pair: Reflection and Meta-programming; classes()

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

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

Syntax:

.. code-block:: ring

	classes() --> a list contains classes names

Example:

.. code-block:: ring

	See classes()

	Class class1
		Func f1

	Class class2
		Func f1

	Class class3
		Func f1

Output:

.. code-block:: ring

	class1
	class2
	class3

.. index:: 
	pair: Reflection and Meta-programming; isclass()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	0
	1
	1

.. index:: 
	pair: Reflection and Meta-programming; packagesclasses()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	classes in Package1
	class1
	classes in Package2
	class1
	class2
	class3

.. index:: 
	pair: Reflection and Meta-programming; ispackagesclass()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	1
	0
	1
	1

.. index:: 
	pair: Reflection and Meta-programming; classname()

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

Syntax:

.. code-block:: ring

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


Example:

.. code-block:: ring

	o1 = new point
	o2 = new rect

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

	class point
	class rect

.. index:: 
	pair: Reflection and Meta-programming; objectid()

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

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

Syntax:

.. code-block:: ring

	objectid(object) --> Returns the object id

Example:

.. code-block:: ring

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

	func test v
		see objectid(v) + nl

	Class point x y z

Output:

.. code-block:: ring

	021B5808
	021B5808
		
.. index:: 
	pair: Reflection and Meta-programming; isobject()

isobject() Function
===================

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

Syntax:

.. code-block:: ring

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

		
.. index:: 
	pair: Reflection and Meta-programming; attributes()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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
		
.. index:: 
	pair: Reflection and Meta-programming; methods()

methods() Function
==================

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

Syntax:

.. code-block:: ring

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


Example:

.. code-block:: ring

	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:: ring

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


.. index:: 
	pair: Reflection and Meta-programming; isattribute()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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

.. index:: 
	pair: Reflection and Meta-programming; isprivateattribute()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	0
	0
	0
	1
	1

.. index:: 
	pair: Reflection and Meta-programming; ismethod()
	
ismethod() Function
===================

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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

.. index:: 
	pair: Reflection and Meta-programming; isprivatemethod()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	0
	1

.. index:: 
	pair: Reflection and Meta-programming; addattribute()

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:: ring

	AddAttribute(object,cAttributeName|aAttributesList)

Example(1):

.. code-block:: ring

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

Example(2):

.. code-block:: ring

	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:: ring

	x: 10.000000
	y: 20.000000
	z: 30.000000


.. index:: 
	pair: Reflection and Meta-programming; addmethod()


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:: ring

	AddMethod(Object,cNewMethodName,cMethodName|AnonymousFunction)

Example:

.. code-block:: ring

	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:: ring

	10
	20
	30

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

Example:

.. code-block:: ring

	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:: ring

	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:: ring

	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:: ring

	10
	20
	30
	100
	200
	300
	50
	150
	250

.. index:: 
	pair: Reflection and Meta-programming; getattribute()

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

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

Syntax:

.. code-block:: ring

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

Example:

.. code-block:: ring

	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:: ring

	3D-Point
	10
	20
	30
	

Example:

We can Find a Class List Member using GetAttribute() using a function findclass()
The Find uses the member name, rather than the column number

.. code-block:: ring

	myList =
	          [new Company {position=3 name="Mahmoud" symbol="MHD"},
	           new Company {position=2 name="Bert" symbol="BRT"},
	           new Company {position=1 name="Ring" symbol="RNG"}
	          ]
	
	see myList
	see nl +"=====================" + nl + nl
	
	for i = 1 to len(myList)
	     see  "Pos: "+ i +" | "+ myList[i].position +" | "+ myList[i].name +
		  " | "+  myList[i].symbol    +" | "+ nl
	next
	
	
	See findclass(myList, "MHD", "symbol") +nl   ### Specify Member class name
	
	###---------------------------------------
	
	func findclass classList, cValue, classMember
	
	       See nl + "FindClass: "  +" "+ cValue + nl + nl
	
	       for i = 1 to len(classList)
	            result = getattribute( classList[i], classMember )
	           
	           See "Result-Attr: " + i +" "+  result +nl
	           if result = cValue
	               j = i
	            ok      
	       next
	return j
	
	###--------------------------------------
	
	class company position name symbol

Output:

.. code-block:: ring

	Pos: 1 | 3 | Mahmoud | MHD |
	Pos: 2 | 2 | Bert | BRT |
	Pos: 3 | 1 | Ring | RNG |
	
	FindClass:  MHD
	
	Result-Attr: 1 MHD
	Result-Attr: 2 BRT
	Result-Attr: 3 RNG
	
	1

	
.. index:: 
	pair: Reflection and Meta-programming; setattribute()

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

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

Syntax:

.. code-block:: ring

	SetAttribute(oObject,cAttributeName,Value)

Example:

.. code-block:: ring

	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:: ring

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

.. index:: 
	pair: Reflection and Meta-programming; mergemethods()

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:: ring

	MergeMethods(cClassNameDestination,cClassNameSource)

Example:

.. code-block:: ring

	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:: ring

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

.. index:: 
	pair: Reflection and Meta-programming; packagename()

packagename() Function
====================
		
We can know the package name of the latest sucessful import command using the packagename() function

Syntax:

.. code-block:: ring

	packagename() --> Returns the package name of the latest sucessful import


Example:

.. code-block:: ring

	load "weblib.ring"
	import System.web
	see packagename()	# system.web