----------------------------------- 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 #