90 likes | 355 Views
Dynamic Programming in Ruby. An Introduction. Dynamic Programming, a.k.a. Metaprogramming. Generally speaking, a language can be considered dynamic if a program written in the language can modify itself at runtime. Dynamic programming is not the same as dynamic typing. A simple case.
E N D
Dynamic ProgramminginRuby An Introduction
Dynamic Programming, a.k.a. Metaprogramming • Generally speaking, a language can be considered dynamic if a program written in the language can modify itself at runtime. • Dynamic programming is not the same as dynamic typing.
A simple case In Ruby, the delimiters #{ and } perform embedded evaluation. A value embedded in in these delimiters is evaluated as an expression. For example, the line puts(“#{3*3}”) will output 9, and puts(“#{‘somestring’.length}”) will output 10, which is the length of “somestring”.
A (more complex) simple case Although in practice it may not be very useful, the following is also allowed: “#{ class MyClass def myMethod puts("myMethod was called") end end }” myInstance = MyClass.new myInstance.myMethod This snippet, in a simple way, demonstrates the ability of a Ruby program to change itself at runtime. A program could gather Ruby code from some external input, embed that code in the #{} delimiters, and modify itself. Notice that MyClass can be used outside of the embedded evaluation because it has become part of the program.
The eval method eval is similar to #{} and can evaluate strings which span multiple lines: eval(‘ class MyClass def myMethod puts("myMethod was called") end end ’) myInstance = MyClass.new myInstance.myMethod
Really modifying Ruby Built-in Ruby classes can be changed at runtime. The following code adds the isValid method to the existing String class: class String def isValid? self.length > 0 && self.length <= 10 # A valid string is 1-10 characters long. end end puts('helloworld'.isValid?) # returns true puts('helloworldagain'.isValid?) # returns false The String class was modified, and the isValid? method became part of the String class which already existed.
Another example—numeric units class Numeric def ounces # add the ounces method to the existing Numeric class self end def quarts self * 32.ounces # A quart is 32 ounces end def gallons self * 4.quarts # A gallon is 4 quarts end end puts 2.gallons # Output the number of ounces in 2 gallons Puts 1.quarts # Output the number of ounces in 1 quart
method_missing Ruby provides a method called method_missing which is used in debugging. This is important in dynamic programming because a program could call a method which should have been previously created dynamically but was not. This condition must be handled, and can be handled gracefully, with method_missing. Adding the following method to the previous code for the Numeric class def method_missing(methodname) puts("#{methodname} does not exist") end will allow graceful handling of a missing method call. puts 1.pints # Outputs “pints does not exist”
Real-World Applications of Metaprogramming in Ruby Metaprogramming in Ruby can be used to create Domain Specific Languages (DSLs) • Sinatra is a DSL which is used to build web applications. ActiveRecord “connects business objects and database tables to create a persistable [sic] domain model where logic and data are presented in one wrapping.”