
-----------------------------------
Cervantes
Mon Mar 20, 2006 8:24 pm

Dynamic Classes
-----------------------------------
Classes in Ruby are dynamic. I say this for two reasons. 

Re-opening Classes
First, we can declare a class, do something else, then reopen the class later. The most common example of this is reopening one of the standard library classes to add a method.
class Array
    def each_group(n)
        (length / n).times do |i|
            yield self

The Creation of a Class
The second reason classes are dynamic is because the interpreter goes through the class much as it would your main program.
class Test
    puts "Hello from the Test Class!"
end
Hello from the Test Class!
The Test Class is defined and the code within it executed. Notice that we did not have to create a new Test object to get the "Hello..." message. That happened upon defining the object - no more. We could write an entire program within a class, and it would run fine.

Wrap Your Program in a Class
We can wrap a standard program -- one that contains methods and input and output, for example -- inside a Class, and it will run fine. Our "standard program" can even involve Classes of its own. This means we would have a class within a class.
class MyProgram
    class Foo
        attr_reader :bar
        def initialize (bar)
            @bar = bar
        end
    end
    puts "Hello, from the MyProgram Class, where we have"
    puts "just defined the Foo class. Prepare yourselves,"
    puts "for we are just about to create a Foo object"
    puts "within the MyProgram class!\n"
    
    inside_foo = Foo.new(42)
    puts "The value of 'bar' within the 'inside_foo' object is: #{inside_foo.bar}"
    
    puts "\nSuccess! We have created a Foo object and accessed"
    puts "it, all as we would normally do, but from within"
    puts "the MyProgram Class."
end

puts "\nThat was some journey; but we've made it to the"
puts "outside world alive! Now that we're out here,"
puts "let's do a little testing.\n"
puts "First, let's try to create a Foo object from the outside"

outside_foo = MyProgram::Foo.new(4)
puts "The value of 'bar' within the 'outside_foo' object is: #{outside_foo.bar}"

puts "\nSuccess! Once again, we have created and"
puts "accessed a Foo object."
The output to this program is all detailed by the program itself. It works as expected. 42 is output as the value of bar for the inside_foo object, and 4 is output as the value of bar for the outside_foo object.

Living within "Object"
In the first few minutes of learning Ruby, you don't see any object orientation.
puts "Hello World"
But there's OOP just below the surface.
irb(main):001:0> self
=> main
irb(main):002:0> self.class
=> Object
We're actually living within the Object class. It's as if we've got:
class Object
    puts "Hello World"
end
This brings new meaning to the phrase, "Everything in Ruby is an Object".

Eval
We can get more dynamic, though. We can use the power of eval and its many forms to do some awesome things. eval takes a string or block of code and interprets it. We can use instance_eval, class_eval, and module_eval, to evaluate code at different levels.
class Person
    def initialize(name_str)
        @names = name_str.split
        
        if @names.length == 2
            instance_eval {
                def first
                    @names.first
                end
                def last
                    @names.last
                end
            }
        end
    end
end

clapton = Person.new("Eric Clapton")
puts clapton.first
puts clapton.last

elvis = Person.new("Elvis")
puts elvis.first
puts elvis.last
Eric
Clapton
test2.rb:27: undefined method `first' for #