introduction to ruby’s reflection api

17
Introduction to Ruby’s Reflection API - Niranjan Sarade

Upload: niranjan-sarade

Post on 15-Jan-2015

4.221 views

Category:

Technology


3 download

DESCRIPTION

This ppt is an introduction to Ruby's reflection API with examples. (Reference :- 'Ruby Cookbook' book.)

TRANSCRIPT

Page 1: Introduction to Ruby’s Reflection API

Introduction to Ruby’s Reflection API- Niranjan Sarade

Page 2: Introduction to Ruby’s Reflection API

Reflection

a.k.a. Introspection

A program can examine its state and structure

A program can alter its state and structure

Ruby’s reflection API is rich and most of the methods are defined by Kernel, Object and Module

Page 3: Introduction to Ruby’s Reflection API

Determine type of an object

o.class #=> Returns the class of an object c

c.superclass #=> Returns the superclass of a class c

o.instance_of? c #=> Determines whether the object o.class == c

o.is_a? c or o.kind_of? c#=> determines o is an instance of c or any of its subclasses. If c is a module, then this

method tests whether o.class (or any of its ancestors) includes this module.

c === o#=> For any class or module c, determines if o.is_a?(c)

o.respond_to? Name#=> Determines whether the object has public or protected method with the specified

name. Pass true as 2nd parameter to check private methods as well

Page 4: Introduction to Ruby’s Reflection API

module Cend

class A include Cend

class B < Aend

a = A.newa.instance_of?(A) #=> true

b = B.newb.instance_of?(B) #=> trueb.instance_of?(A) #=> false #=> instance_of? does not check inheritence

b.is_a?(A) #=> trueb.is_a?(B) #=> trueb.is_a?(C) #=> true

B.is_a?(A) #=> falseA.is_a?(A) #=> false

Page 5: Introduction to Ruby’s Reflection API

o = “niranjan”

o.class #=> String

o.class.superclass #=> Object

o.class.superclass.superclass #=> nil : Object has no superclass

# Ruby 1.9 only

Object.superclass #=> BasicObject

BasicObject.superclass #=> nil

Page 6: Introduction to Ruby’s Reflection API

Ancestors of class or modulemodule A; endmodule B; include A; endclass C; include B; end

C < B #=> true : C includes BB < A #=> trueC < A #=> trueString < Numeric #=> nil: strings are not numbers

A.ancestors #=> [A]B.ancestors #=> [B, A]C.ancestors #=> [C, B, A, Object, Kernel]String.ancestors #=> [String, Comparable, Object, Kernel]

C.include?(B) #=> true (public instance method defined by the Module class)C.include?(A) #=> trueB.include?(A) #=> trueA.include?(A) #=> falseA.include?(B) #=> false

A.included_modules #=> [ ]B.included_modules #=> [A]C.included_modules #=> [B, A, Kernel]

Page 7: Introduction to Ruby’s Reflection API

Module.nesting

module Mclass C

Module.nesting #=> [M::C, M]end

end

The class method Module.nesting returns nesting of modules at the current location.

Module.nesting[0] => current class or module

Module.nesting[1] => containing class or module

Page 8: Introduction to Ruby’s Reflection API

Variables and Constants

- global_variables

- local_variables

- instance_variables

- class_variables

- constants

These methods except local_variables return array of strings in Ruby 1.8 and array of symbols in Ruby 1.9.

The local_variables method returns an array of strings in both versions of Ruby.

Page 9: Introduction to Ruby’s Reflection API

Querying, setting, removing and testing variables

Local variables :-x = 1eval(“x”) #=> 1eval(“x = 2”)eval(“x”)

Instance variables :-o = Object.newo.instance_variable_set(:@x, 10)o.instance_variable_get(:@x) #=> 10o.instance_variable_defined?(:@x) #=> true

Class variables :-Object.class_variable_set(:@@x, 5) #=> Private in Ruby 1.8Object.class_variable_get(:@@x) #=> 5 ; Private in Ruby 1.8Object.class_variable_defined?(:@@x) #=> true; Ruby 1.9 and later

Page 10: Introduction to Ruby’s Reflection API

Continued…

Constants :-Math.const_set(:EPI, Math::E*Math::PI)Math.const_get(:EPI) #=> 8.539…Math.const_defined? :EPI #=> true

In Ruby 1.9, we can pass ‘false’ as 2nd argument to const_get and const_defined? to specify that these methods should only look at the current class or module and should not consider inherited constants.

Object and Module define private methods for undefining instance variables, class variables and constants. (Use eval or send to invoke these methods)

They return the value of the removed variable or constant.

o.instance_eval {remove_instance_variable(:@x)}String.class_eval {remove_class_variable (:@@x)}Math.send :remove_const, :EPI

Page 11: Introduction to Ruby’s Reflection API

Listing and testing methods

o = “test”o.methods #=> [ names of all public methods ]o.public_methods #=> same as aboveo.public_methods(false) #=> Exclude inherited methodso.protected_methods #=> [ ]o.private_methods #=> array of all private methodso.private_methods(false) #=> Exclude inherited private methodsdef o.single; 1; end # define a singleton methodo.singleton_methods #=> [“single”]

String.instance_methods == “s”.public_methods #=> trueString.instance_methods(false) == “s”.public_methods(false) #=> trueString.public_instance_methods == String.instance_methods #=> trueString.protected_instance_methods #=> []String.private_instance_methods(false) #=> [“initialize_copy”, “initialize”]

The class methods of a class or module are singleton methods of the Class or Module object. So to list the class methods, use Object.singleton_methods:

Math.singleton_methods #=> [“acos”, “log10”, …]

Page 12: Introduction to Ruby’s Reflection API

Define, undefine and alias methods

define_method –> private instance method of Module class

# add an instance method names m to class c with body b

def add_method(c,m,&b) c.class_eval {

define_method(m,&b)}

end

add_method(String, :greet) {‘Hello’ + self}

‘world’.greet #=> ‘Hello world’

To create a synonym or an alias for an existing method :-

alias plus + # make plus a synonym for the + operator (2 identifiers to be hardcoded)

Or

alias_method # private instance method of Module class (dynamic programming)

Page 13: Introduction to Ruby’s Reflection API

Continued…

undef method_name

remove_method or undef _method => private methods of Module class

remove_method removes the definition of the method from the current classIf there is a version defined by a superclass, that version now will be inherited.

undef_method prevents any invocation of the specified method through an instance of the class, even if there is an inherited version of that method.

Page 14: Introduction to Ruby’s Reflection API

Aliasing

A more practical reason for aliasing methods is to insert new functionality into amethod – augmenting existing methods

def hellop ‘hello’

end

alias original_hello hello

def hellop ‘some stuff’original_hellop ‘some more stuff’

end

Page 15: Introduction to Ruby’s Reflection API

Method lookup or method name resolution algorithm

For method invocation expression o.m, Ruby performs name resolution with the followingsteps :-

1. First, it checks the eigenclass of o for singleton methods named m2. If no method m is found in the eigenclass, ruby searches the class of o for an instance method

named m3. If not found, ruby searches the instance methods of any modules included by the class of o. If that

class includes more than one module, then they are searched in the reverse of the order in which they were included. i.e. the most recently included module is searched first.

4. If not found, then the search moves up the inheritance hierarchy to the superclass. Steps 2 and 3 are repeated for each class in the inheritance hierarchy until each ancestor class and its included modules have been searched.

5. If not found, then method_missing is invoked instead. In order to find an appropriate definition of this method, the name resolution algorithm starts over at step 1. The Kernel module provides a default implementation of method_missing, so this second pass of name resolution is guaranteed to succeed.

6. This may seem like it requires ruby to perform an exhaustive search every time it invokes a method.7. However, successful method lookups will be cached so that subsequent lookups of the same name

will be very quick.

Page 16: Introduction to Ruby’s Reflection API

e.g. “hello”.world

1. Check the eigenclass for singleton methods.

2. Check the String class. There is no instance method named ‘world’.

3. Check the Comparable and Enumerable modules of the String class for an instance method named ‘world’.

4. Check the superclass of String, which is Object.

5. Look for method_missing in each of the spots above. The first definition of method_missing we find id in the Kernel module, so this method gets invoked.

6. It raises an exception NoMethodError : undefined method ‘world’ for “hello”:String.

7. However, successful method lookups will be cached so that subsequent lookups of the same name will be very quick.

Page 17: Introduction to Ruby’s Reflection API

Thank you !