Ruby Meta-Programming

Sang Shin, sang.shin@sun.com, www.javapassion.com/rubyonrails



Meta-programming feature of Ruby language is what makes Rails a killer application. For example, the Rails declarations such as "find_by_name", "belongs_to" are possible because of the Meta-programming feature of Ruby language.  Now you may want to write your own code that worked in a similar way. 

In this lab, you are going to learn various meta-programming features of Ruby language, starting with introspection.  The dynamic typing, specifically duck typing, is then introduced.  Then one of the most unique features of Ruby, missing_method, is addressed.  Finally define_method is covered.


Expected duration: 120 minutes (excluding homework)



Software Needed

Before you begin, you need to install the JDK and NetBeans IDE software on your computer as described in  here.


OS platforms you can use


Change Log


Things to be done (By Sang Shin)


Lab Exercises


Exercise 1: Introspection


Learning points

Tasks to be performed
  1. Open, build, and run "RubyMeta_Introspection_respond_to" sample application
  2. Open, build, and run "RubyMeta_Introspection_respond_to2" sample application
  3. Open, build, and run "RubyMeta_Introspection_instance_of" sample application
  4. Open, build, and run "RubyMeta_Introspection_methods" sample application

(1.1) Open, build, and run "RubyMeta_Introspection_respond_to" sample application


1. Open "RubyMeta_Introspection_respond_to" sample application.


2. Study the code in main.rb.

# Introspection example

puts "----Display all the methods of Object class"
puts Object.methods.sort

puts "----Check if Object class has name method"
puts Object.respond_to?(:name)             #=> true

puts "----Check if Object class has send method"
puts Object.respond_to?(:send)             #=> true

puts "----Check if Object class has does_not_exist method"
puts Object.respond_to?(:does_not_exist)   #=> false


3. Build and run the application.



4. Spend some time understanding the result.

----Display all the methods of Object
Display all the methods of Object
<
<=
<=>
==
===
=~
>
>=
__id__
__send__
allocate
ancestors
autoload
autoload?
class
class_eval
class_variable_defined?
class_variables
clone
const_defined?
const_get
const_missing
const_set
constants
display
dup
eql?
equal?
extend
extended
freeze
frozen?
hash
id
include?
included
included_modules
inherited
initialize_copy
inspect
instance_eval
instance_exec
instance_method
instance_methods
instance_of?
instance_variable_defined?
instance_variable_get
instance_variable_set
instance_variables
is_a?
kind_of?
method
method_defined?
methods
module_eval
name
new
nil?
object_id
private_class_method
private_instance_methods
private_method_defined?
private_methods
protected_instance_methods
protected_method_defined?
protected_methods
public_class_method
public_instance_methods
public_method_defined?
public_methods
respond_to?
send
singleton_methods
superclass
taint
tainted?
to_a
to_s
type
untaint
----Check if Object class has name method
true
----Check if Object class has send method
true
----Check if Object class has does_not_exist method
false

                                                                                                                                                 return to top of exercise

(1.2) Open, build, and run "RubyMeta_Introspection_respond_to2" sample application


1. Open "RubyMeta_Introspection_respond_to2" sample application.
2. Study the code in main.rb.

# Introspection example

puts "----Define Hello class"
class Hello
 
  def myhellomethod(name)
  end
 
end

puts "----Check if Hello object has a method called myhellomethod"
hello_instance = Hello.new
puts hello_instance.respond_to?(:myhellomethod)

puts "----Check if Hello object has a method called xyz"
puts hello_instance.respond_to?(:xyz)

3. Run the project.
4. Study the result.

----Define Hello class
----Check if Hello object has a method called myhellomethod
true
----Check if Hello object has a method called xyz
false

                                                                                                                                                 return to top of exercise


(1.3) Open, build, and run "RubyMeta_Introspection_instance_of" sample application


1. Open "RubyMeta_Introspection_instance_of" sample application.
2. Study the code in main.rb.

class A
end

class B < A
end

a = A.new
b = B.new

puts "----Exercise instance_of? and kind_of? methods among object instances"
puts a.instance_of?(A)
puts b.instance_of?(A)
puts b.kind_of?(A)

puts "----Exercise instance_of? and kind_of? methods for a class"
puts A.instance_of?(Class)
puts A.kind_of?(Class)

puts "----Display class information"
puts a.class
puts a.class.class

3. Run the project.
4. Study the result.

----Exercise instance_of? and kind_of? methods among object instances
true
false
true
----Exercise instance_of? and kind_of? methods for a class
true
true
----Display class information
A
Class

                                                                                                                                                 return to top of exercise



(1.4) Open, build, and run "RubyMeta_Introspection_methods" sample application


1. Open "RubyMeta_Introspection_methods" sample application.
2. Study the code in main.rb.

some_string = 'http://google.com'

puts "----Print the object's class, methods, superclass and ancestors (mixins and superclasses)"
p some_string.class
p some_string.methods
p some_string.class.superclass
p some_string.class.ancestors

puts "----Print the methods of the String class"
p String.private_instance_methods(false)
p String.public_instance_methods(false)

puts "----Pass true to recurse into parent classes"
p String.public_instance_methods(true)

puts "----Call instance methods with send()"
"Random text".send(:length) # 11
-23.send(:succ) # 22

puts "----Use Method objects and call()"
length_method = "Random text".method(:length)
length_method.call # 11

puts "----Another way, using eval()"
length_method = %q{"Random text".length}
eval length_method

3. Run the project.
4. Study the result.

----Print the object's class, methods, superclass and ancestors (mixins and superclasses)
String
["upcase!", "to_str", "lstrip", "upto", "sum", "crypt", "scan", "reverse!", "==", "each_byte", "=~", "tr!", "squeeze!", "inspect", "chop", "next!", "rstrip", "casecmp", "split", "succ!", "to_f", "<", "[]=", "~", "center", "slice!", "slice", "reverse", "sub", "insert", "upcase", "tr_s!", ">", "next", "strip!", "squeeze", "dump", "count", "sub!", "hash", "lstrip!", "to_sym", "replace", "<=", "hex", "strip", "capitalize!", "length", "chop!", "each_line", "swapcase", "[]", "include?", "chomp!", "<<", "gsub", "intern", "succ", "capitalize", "oct", "+", "delete!", "initialize_copy", "rindex", "chomp", "<=>", "to_i", "eql?", "tr_s", "match", "unpack", "index", "rstrip!", "*", "delete", "gsub!", "to_s", "rjust", "%", ">=", "empty?", "size", "swapcase!", "concat", "tr", "ljust", "each", "downcase!", "downcase", "zip", "sort", "reject", "to_a", "find", "entries", "map", "max", "min", "each_with_index", "member?", "inject", "sort_by", "collect", "partition", "detect", "all?", "select", "grep", "find_all", "any?", "between?", "methods", "freeze", "extend", "object_id", "nil?", "method", "tainted?", "is_a?", "instance_variable_get", "instance_variable_defined?", "instance_variable_set", "display", "send", "private_methods", "equal?", "type", "instance_of?", "id", "taint", "class", "instance_variables", "__send__", "protected_methods", "__id__", "frozen?", "respond_to?", "instance_eval", "===", "untaint", "clone", "singleton_methods", "instance_exec", "dup", "kind_of?", "public_methods"]
Object
[String, Enumerable, Comparable, Object, Kernel]
----Print the methods of the String class
["initialize"]
["upcase!", "to_str", "lstrip", "upto", "sum", "crypt", "scan", "reverse!", "==", "each_byte", "=~", "tr!", "squeeze!", "inspect", "chop", "next!", "rstrip", "casecmp", "split", "succ!", "to_f", "<", "[]=", "~", "center", "slice!", "slice", "reverse", "sub", "insert", "upcase", "tr_s!", ">", "next", "strip!", "squeeze", "dump", "count", "sub!", "hash", "lstrip!", "to_sym", "replace", "<=", "hex", "strip", "capitalize!", "length", "chop!", "each_line", "swapcase", "[]", "include?", "chomp!", "<<", "gsub", "intern", "succ", "capitalize", "oct", "+", "delete!", "initialize_copy", "rindex", "chomp", "<=>", "to_i", "eql?", "tr_s", "match", "unpack", "index", "rstrip!", "*", "delete", "gsub!", "to_s", "rjust", "%", ">=", "empty?", "size", "swapcase!", "concat", "tr", "ljust", "each", "downcase!", "downcase"]
----Pass true to recurse into parent classes
["upcase!", "to_str", "lstrip", "upto", "sum", "crypt", "scan", "reverse!", "==", "each_byte", "=~", "tr!", "squeeze!", "inspect", "chop", "next!", "rstrip", "casecmp", "split", "succ!", "to_f", "<", "[]=", "~", "center", "slice!", "slice", "reverse", "sub", "insert", "upcase", "tr_s!", ">", "next", "strip!", "squeeze", "dump", "count", "sub!", "hash", "lstrip!", "to_sym", "replace", "<=", "hex", "strip", "capitalize!", "length", "chop!", "each_line", "swapcase", "[]", "include?", "chomp!", "<<", "gsub", "intern", "succ", "capitalize", "oct", "+", "delete!", "initialize_copy", "rindex", "chomp", "<=>", "to_i", "eql?", "tr_s", "match", "unpack", "index", "rstrip!", "*", "delete", "gsub!", "to_s", "rjust", "%", ">=", "empty?", "size", "swapcase!", "concat", "tr", "ljust", "each", "downcase!", "downcase", "zip", "sort", "reject", "to_a", "find", "entries", "map", "max", "min", "each_with_index", "member?", "inject", "sort_by", "collect", "partition", "detect", "all?", "select", "grep", "find_all", "any?", "between?", "methods", "freeze", "extend", "object_id", "nil?", "method", "tainted?", "is_a?", "instance_variable_get", "instance_variable_defined?", "instance_variable_set", "display", "send", "private_methods", "equal?", "type", "instance_of?", "id", "taint", "class", "instance_variables", "__send__", "protected_methods", "__id__", "frozen?", "respond_to?", "instance_eval", "===", "untaint", "clone", "singleton_methods", "instance_exec", "dup", "kind_of?", "public_methods"]
----Call instance methods with send()
----Use Method objects and call()
----Another way, using eval()

                    
                                                                                                                            return to top of exercise


Exercise 2: Object#send


In many situations, it is highly desirable to be able to call a method that you won't know the name of until runtime.  The send allows you to call any method on any object based on the name of the method.  To use send, call send with the first argument as the name of the method to the call, and the rest of the arguments in the same way as a regular method call.
 
  1. Open, build, and run "RubyMeta_Object_send_hello" sample application
  2. Open, build, and run "RubyMeta_Object_send_plus" sample application
  3. Open, build, and run "RubyMeta_Object_send_hello2" sample application
  4. Open, build, and run "RubyMeta_Object_send_hello3" sample application

(2.1) Open, build, and run "RubyMeta_Object_send_hello" sample application


1. Open "RubyMeta_Object_send_hello" sample application.
2. Study the code in main.rb.

class Klass
  def hello(*args)
    "Hello " + args.join(' ')
  end
end

k = Klass.new

# The following four statements are equivalent
puts k.hello("gentle", "readers")             #=> "Hello gentle readers"
puts k.hello "gentle", "readers"          #=> "Hello gentle readers"
puts k.send(:hello, "gentle", "readers")  #=> "Hello gentle readers"
puts k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"

3. Run the project.
4. Study the result.

Hello gentle readers
Hello gentle readers
Hello gentle readers
Hello gentle readers


                                                                                                                                                         return to top of exercise

(2.2) Open, build, and run "RubyMeta_Object_send_plus" sample application


1. Open "RubyMeta_Object_send_plus" sample application.
2. Study the code in main.rb.

# The following statements are equivalent
puts 2+3
puts 2+(3)
puts 2.send(:+, 3)
puts 2.send :+, 3

# The following statements are equivalent
puts 2*3
puts 2*(3)
puts 2.send(:*, 3)
puts 2.send :*, 3

3. Run the project.
4. Study the result.

5
5
5
5
6
6
6
6

                                                                                                                                                 return to top of exercise



(2.3) Open, build, and run "RubyMeta_Object_send_hello2" sample application


1. Open "RubyMeta_Object_send_hello2" sample application.
2. Study the code in main.rb.

class Hello

  # Constructor - invoked by Hello.new
  def initialize(greeting)
    # Instance variables start with @
    @greeting = greeting
  end
 
  def my_hello(name)
    @completegreeting = "#{@greeting} #{name}"
  end
 
end

hello_instance = Hello.new("Hello")

# The following statements are equivalent
puts hello_instance.my_hello("Boston!")
puts hello_instance.my_hello "Boston!"
puts hello_instance.send(:my_hello, "Boston")
puts hello_instance.send :my_hello, "Boston"

3. Run the project.
4. Study the result.

Hello Boston!
Hello Boston!
Hello Boston!
Hello Boston!

                                                                                                                                                 return to top of exercise

(2.4) Open, build, and run "RubyMeta_Object_send_hello3" sample application


1. Open "RubyMeta_Object_send_hello3" sample application.
2. Study the code in main.rb.

puts "----Define Hello class"
class Hello

  # Constructor - invoked by Hello.new
  def initialize(greeting)
    # Instance variables start with @
    @greeting = greeting
  end
 
  def my_hello_method1(name)
    @completegreeting = "#{@greeting}1 #{name}"
  end
 
  def my_hello_method2(name)
    @completegreeting = "#{@greeting}2 #{name}"
  end
 
  def my_hello_method3(name)
    @completegreeting = "#{@greeting}3 #{name}"
  end
 
end

puts "----Create an object instance of Hello class and call a method of it"
hello_instance = Hello.new("Hello")

# Simulate the set of methods you want to call during runtime
methods_array = ["my_hello_method1", "my_hello_method2", "my_hello_method3"]

puts "----Call a method using send passing name of a method as a parameter"
methods_array.each do |x|
  puts hello_instance.send(x, "Boston")
end

3. Run the project.
4. Study the result.

----Define Hello class
----Create an object instance of Hello class and call a method of it
----Call a method using send passing name of a method as a parameter
Hello1 Boston
Hello2 Boston
Hello3 Boston

                                                                                                                                                 return to top of exercise


Exercise 3: Dynamic Typing (Duck Typing)


In this exercise,  you are going to exercise the dynamic typing (Duck typing) feature of Ruby language.  Duck typing is a fundamental part of Ruby coding. The idea behind "Duck Typing", which has recently be made popular again by Ruby and other script languages, is to make the concept of types less restrictive. For more information on Duck typing, please see The Perils of Duck Typing.
  1. Open, build, and run "RubyMeta_DynamicTyping" sample application

(3.1) Open, build, and run "RubyMeta_DynamicTyping" sample application


1. Open "RubyMeta_DynamicTyping" sample application.
2. Study the code in main.rb.

# The Duck class
class Duck
  def quack
    puts "Duck is quacking!"
  end
end

# The Mallard class
class Mallard
  def quack
    puts "Mallard is quacking!"
  end
end

# If it quacks like a duck, it must be duck
def quack_em(ducks)
  ducks.each do |duck|
    if duck.respond_to? :quack
       duck.quack
    end
  end
end

birds = [Duck.new, Mallard.new, Object.new]

puts "----Call quack method for each item of the birds array. Only Duck and Mallard should be quacking."
quack_em(birds)

3. Run the project.
4. Study the result.

----Call quack method for each item of the birds array. Only Duck and Mallard should be quacking.
Duck is quacking!
Mallard is quacking!

                                                                                                                                                 return to top of exercise


Summary

In this exercise,  you have learned dynamic typing feature of Ruby language.

                                                                                                                                                           return to the top



Exercise 4: Missing Methods


In this exercise, you are going to exercise the basic concept of method_missing.  The method_missing os a callback hook that makes easy to change the behavior in case a method that is called on anobject that does not respond to that method.  This allows great flexibility and gives you the possibility to create message recording, delegators.
  1. Open, build, and run "RubyMeta_MethodMissing_Error" sample application
  2. Open, build, and run "RubyMeta_MethodMissing_Called" sample application
  3. Open, build, and run "RubyMeta_MethodMissing_Finder" sample application
  4. Open, build, and run "RubyMeta_MethodMissing_RomanToInteger" sample application
  5. Open, build, and run "RubyMeta_MethodMissing_ProxyPattern" sample application

(4.1) Open, build, and run "RubyMeta_MethodMissing_Error" sample application


Leaning point: If a method that is not existent in a class is invoked, NoMethodError exception will be generated.

1. Open "RubyMeta_MethodMissing_Error" sample application.
2. Study the code in main.rb.

# When you send a message to an object, the object executes the first method
# it finds on its method lookup path with the same name as the message. If it
# fails to find any such method, it raises a NoMethodError exception - unless
# you have provided the object with a method called method_missing. The
# method_missing method is passed the symbol of the nonexistent method, and
# any arguments that were passed in.

class Dummy
end 

puts "----Call a method that does not exist in the Dummy class and expect NoMethodError exception."
dummy = Dummy.new
dummy.call_a_method_that_does_not_exist

3. Run the project.
4. Study the result.
----Call a method that does not exist in the Dummy class and expect NoMethodError exception.
C:\handsonlabs\ruby_meta\samples\RubyMeta_MethodMissing_Error\lib\main.rb:13: undefined method `a_method_that_does_not_exist' for #<Dummy:0x19eda2c> (NoMethodError)



                                                                                                                                                 return to top of exercise


(4.2) Open, build, and run "RubyMeta_MethodMissing_Called" sample application


Leaning point: If method_missing(m, *args) method is defined in a class, it will be called (instead of NoMethodError exception being generated) when a method that does not exist is invoked.

1. Open "RubyMeta_MethodMissing_Called" sample application.
2. Study the code in main.rb.

class Dummy 
  def method_missing(m, *args) 
    puts "There's no method called #{m} here -- so method_missing method is called."
    puts "   with arguments #{args}"   
  end 
end 

puts "----Call a method that does not exist in the Dummy class and observe that the method_missing is called."
dummy = Dummy.new
dummy.a_method_that_does_not_exist
dummy.a_method_that_does_not_exist(3)
dummy.a_method_that_does_not_exist(3, " Sang Shin ", Time.now)

3. Run the project.
4. Study the result.

----Call a method that does not exist in the Dummy class and observe that the method_missing is called.
There's no method called a_method_that_does_not_exist here -- so method_missing method is called.
   with arguments
There's no method called a_method_that_does_not_exist here -- so method_missing method is called.
   with arguments 3
There's no method called a_method_that_does_not_exist here -- so method_missing method is called.
   with arguments 3 Sang Shin Thu Jul 03 12:44:18 -0400 2008

                                                                                                                                                 return to top of exercise


(4.3) Open, build, and run "RubyMeta_MethodMissing_Finder" sample application


Leaning point: How Rails' find_by_xxxx() finder method is implemented through method_missing.

1. Open "RubyMeta_MethodMissing_Finder" sample application.
2. Study the code in main.rb.

class Finder 
  def find(name) 
    puts "find(#{name}) is called"
  end 
 
  def method_missing(name, *args)
    if /^find_(.*)/ =~ name.to_s
      return find($1)
    end
    super
  end
end

puts "----Call a method that does not exist in the Finder class and observe that the method_missing is called."
f = Finder.new
f.find("Something")
f.find_by_last_name("Shin")
f.find_by_title("Technology Architect")

3. Run the project.
4. Study the result.

----Call a method that does not exist in the Finder class and observe that the method_missing is called.
find(Something) is called
find(by_last_name) is called
find(by_title) is called

                                                                                                                                                 return to top of exercise


(4.4) Open, build, and run "RubyMeta_MethodMissing_RomanToInteger" sample application


Leaning point: How Roman-to-Integer conveter is implemented through method_missing.

1. Open "RubyMeta_MethodMissing_RomanToInteger" sample application.
2. Study the code in main.rb.

class Roman      
 
  # Maps roman numeral digits to their integer values
  DIGITS = {
    'I' => 1,
    'V' => 5,
    'X' => 10,
    'L' => 50,
    'C' => 100,
    'D' => 500,
    'M' => 1000,
  }

  # ...

  def roman_to_integer(roman_string)
    last = nil
    roman_string.to_s.upcase.split(//).reverse.inject(0) do |memo, digit|
      if digit_value = DIGITS[digit]
        if last && last > digit_value
          memo -= digit_value
        else
          memo += digit_value
        end
        last = digit_value
      end
      memo
    end
  end

  def method_missing(method)       
    str = method.id2name
    roman_to_integer(str)     
  end   
end

r = Roman.new 

puts "----Convert Roman to Integer using method_missing"
puts r.IV      #=> 4   
puts r.XXIII   #=> 23   
puts r.MM     #=> 2000

3. Run the project.
4. Study the result.

----Convert Roman to Integer using method_missing
4
23
2000

                                                                                                                                                 return to top of exercise


(4.5) Open, build, and run "RubyMeta_MethodMissing_ProxyPattern" sample application


Learning point: How a Proxy object can be created through method_missing and used to invoke methods of existing classes.

1. Open "RubyMeta_MethodMissing_ProxyPattern" sample application.
2. Study the code in main.rb.

# Define Proxy class
class Proxy
  def initialize(object)
    @object = object
  end
 
  def method_missing(symbol, *args)
    # Call a method whose name is the value of symbol parameter
    @object.send(symbol, *args)
  end
end

puts "----Create an array object."
object = ["a", "b", "c"]

puts "----Create a Proxy object with instance variable @object is set with array object"
proxy = Proxy.new(object)

puts "----Call first method of the Proxy object, which has not been defined before. So the
          method_missing(..) method is called with the symbol set with first. Within the
          method_missing(..) method, the @object is set to the array object and the symbol
          is set to first.  So it is the same thing as calling first method of the array
          object.  So you will see a as a result."
puts proxy.first

puts "----Call last method, which has not been defined before"
puts proxy.last

puts "----Create a String object"
object2 = String.new("Ruby on Rails Programming with Passion!")

puts "----Create a Proxy object with instance variable @object is set with array object"
proxy2 = Proxy.new(object2)

puts "----Call upcase method of String class"
puts proxy2.upcase

puts "----Call swapcase method of String class"
puts proxy2.swapcase

3. Run the project.
4. Study the result.

----Create an array object.
----Create a Proxy object with instance variable @object is set with array object
----Call first method of the Proxy object, which has not been defined before. So the
          method_missing(..) method is called with the symbol set with first. Within the
          method_missing(..) method, the @object is set to the array object and the symbol
          is set to first.  So it is the same thing as calling first method of the array
          object.  So you will see a as a result.
a
----Call last method, which has not been defined before
c
----Create a String object
----Create a Proxy object with instance variable @object is set with array object
----Call upcase method of String class
RUBY ON RAILS PROGRAMMING WITH PASSION!
----Call swapcase method of String class
rUBY ON rAILS pROGRAMMING WITH pASSION!

                                                                                                                                                 return to top of exercise

Summary

In this exercise, you have learned basic features of method_missing.

                                                                                                                                                           return to the top


Exercise 5: Define Method


  Learning point: How define_method is used. 

     define_method(symbol, method)     => new_method
     define_method(symbol) { block }   => proc

The define_method defines an instance method in the receiver. The method parameter can be a Proc or Method object. If a block is specified, it is used as the method body.

Tasks to be performed:
  1. Open, build, and run "RubyMeta_DefineMethod" sample application
  2. Open, build, and run "RubyMeta_DefineMethod2" sample application
  3. Open, build, and run "RubyMeta_DefineMethod3" sample application

(5.1) Open, build, and run "RubyMeta_DefineMethod" sample application


1. Open "RubyMeta_DefineMethod" sample application.
2. Study the code in main.rb.

class Love
  define_method(:my_hello) do |arg1, arg2|
    puts "#{arg1} loves #{arg2}"
  end
end

love = Love.new
love.my_hello("Sang Shin", "Young Shin")

3. Run the project.
4. Study the result.

----Call a method that is defined via define_method
Sang Shin loves Young Shin

                                                                                                                                                 return to top of exercise

(5.2) Open, build, and run "RubyMeta_DefineMethod2" sample application


Leaning point: define_method can be used to create a new method during runtime.  In this example, the name of the to-be-created method is entered by a user.

1. Open "RubyMeta_DefineMethod2" sample application.
2. Study the code in main.rb.

puts "----Get a method name from a user.  Type something in the Output window and press Enter."
$my_method = gets

puts "----Define Love class which has define_method"
class Love
  define_method $my_method.intern do |arg1, arg2|
    puts "#{$my_method} method is being invoked"
    puts "#{arg1} loves #{arg2}"
  end
end

puts "----Create an instance of Love class"
love = Love.new

puts "----Invoke a method that was dynamically defined"
love.send($my_method, "Daniel", "Yina")

3. Run the project.




4. Study the result.

----Get a method name from a user.  Type something in the Output window and press Enter.
 whatever
----Define Love class which has define_method
----Create an instance of Love class
----Invoke a method that was dynamically defined
 whatever
 method is being invoked
Daniel loves Yina


                                                                                                                                                 return to top of exercise


(5.3) Open, build, and run "RubyMeta_DefineMethod3" sample application


1. Open "RubyMeta_DefineMethod3" sample application.
2. Study the code in main.rb.

class A     
  def fred       
    puts "In Fred"     
  end     
  def create_method(name, &block)       
    self.class.send(:define_method, name, &block)     
  end     
  define_method(:wilma) { puts "Charge it!" }   
end 

class B < A     
  define_method(:barney, instance_method(:fred))   
end   

a = B.new   

puts "----a.barney is equivalent to a.fred"
a.barney  

puts "----a.wilma is equivalent to a.wilma"
a.wilma   

puts "----a.create_method(:betty) { p self }"
a.create_method(:betty) { p self }   

puts "----a.betty"
a.betty

3. Run the project.
4. Study the result.

----a.barney is equivalent to a.fred
In Fred
----a.wilma is equivalent to a.wilma
Charge it!
----a.create_method(:betty) { p self }
----a.betty
C:\handsonlabs\ruby_meta\samples\RubyMeta_DefineMethod3\lib\main.rb:27: private method `betty' called for #<B:0x16d2702> (NoMethodError)

                                                                                                                                                 return to top of exercise

Summary

In this exercise,  you have learned how to use define_method.

                                                                                                                                                 return to the top




Homework Exercise (for people who are taking Sang Shin's "Ruby/JRuby/Rails Development online course")


1. The homework is to write your own Ruby application as described below.  The goal of this homework is to test your understanding on method_missing.
puts my_instance.method1
puts my_instance.whatever
puts my_instance.m545        

method1 method has 7 characters
whatever method has 8 characters
m545 has 4 characters
2. Send the following files to railshomeworks@sun.com with Subject as RailsHomework-ruby_meta.


                                                                                                                          return to the top