Skip to content

Instantly share code, notes, and snippets.

@francisco-rojas
Last active August 29, 2015 14:03
Show Gist options
  • Save francisco-rojas/5bcbea8d1ad52a4ff451 to your computer and use it in GitHub Desktop.
Save francisco-rojas/5bcbea8d1ad52a4ff451 to your computer and use it in GitHub Desktop.
Metaprogramming Ruby 2: Book Notes

Open Classes (also known as Monkey Patching)

Instead of creating a class that performs common operations on strings like this:

class StringUtils
  def self.to_alphanumeric(s)
    s.gsub(/[^\w\s]/, '')
  end
end

reopen the String class and add the method there to make it available on all strings:

class String
  def to_alphanumeric
    gsub(/[^\w\s]/, '')
  end
end

Then you would call:

'#3, the *Magic, Number*?'.to_alphanumeric # => '3 the Magic Number'

instead of:

StringUtils.to_alphanumeric('3 the Magic Number') # => '3 the Magic Number'

You can confirm this method now belongs to the String class by running:

String.instance_methods.grep /^to/  # => [:to_i, :to_f, :to_s, :to_str, :to_sym, :to_r, :to_c, :to_enum, :to_alphanumeric]

WARNING!: Be careful not to override existing functionality by mistake.

Constants

In Ruby any reference that begins with an uppercase letter, including the names of classes and modules, is a constant. The scope of constants follows its own special rules:

module MyModule
  MyConstant = 'Outer constant'
  class MyClass
    MyConstant = 'Inner constant'
  end
end

The previous code generates the following tree of constants:

  • MyModule
    • MyClass
      • MyConstant
    • MyConstant

All the constants in a program are arranged in a tree similar to a file system, where modules (and classes) are directories and regular constants are files. Like in a file system, you can have multiple files with the same name, as long as they live in different directories. You can even refer to a constant by its path, as you’d do with a file. Constants’ paths use a double colon as a separator:

W = 'root constant'
module R
  W = 'outer module constant'
  module M
    W = 'inner module constant'
    ::W # => "root constant"
    class C
      X = 'a class constant'
      ::W # => "root constant"
      R::W # => "outer module constant"
    end
    C::X # => "a class constant"
  end
  M::W # => "inner module constant"
end  
R::W # => "outer module constant"
R::M::W # => "inner module constant"
R::M::C::X # => "a class constant"

If you’re sitting deep inside the tree of constants, you can provide the absolute path to an outer constant by using a leading double colon as root:

Y = 'a root-level constant'
module M
  Y = 'a constant in M'
  Y # => "a constant in M"
  ::Y # => "a root-level constant"
end

The Module class also provides an instance method and a class method that, confusingly, are both called constants. Module#constants returns all constants in the current scope, like your file system’s ls command (or dir command, if you’re running Windows). Module.constants returns all the top-level constants in the current program, including class names:

module M
  Y = 'a constant in M'
  class C
    X = 'a constant'
  end
  C::X # => "a constant"
end

M.constants # => [:C, :Y]
Module.constants.include? :Object # => true
Module.constants.include? :Module # => true

Finally, if you need the current path, check out Module.nesting:

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

Private Methods

Private methods come from two rules working together:

  • first, you need an explicit receiver to call a method on an object that is not yourself
  • second, private methods can be called only with an implicit receiver.

Put these two rules together, and you’ll see that you can only call a private method on yourself. You can call this the “private rule.”

A WORD OF WARNING

The problems with Ghost Methods boil down to the fact that they are not really methods: instead, they’re just a way to intercept method calls. Because of this fact, they behave different than actual methods. For example, they don’t appear in the list of names returned by Object#methods. In contrast, Dynamic Methods are just regular methods that happened to be defined with define_method instead of def, and they behave the same as any other method. There are times when Ghost Methods are your only viable option. This usually happens when you have a large number of method calls, or when you don’t know what method calls you might need at runtime (Like the Builder example).

Ghost Methods can be dangerous. You can avoid most of their problems by following a few basic recommendations (always call super, always redefine respond_to_missing?)—but even then, Ghost Methods can sometimes cause puzzling bugs.

There is is a simple rule of thumb that you can follow when in doubt: use Dynamic Methods if you can, and Ghost Methods if you have to.

Dynamic Methods

When you call a method, you’re actually sending a message to an object:

obj.send(:my_method, 3)  # => 6

the first argument to send is the message that you’re sending to the object —that is, a symbol or a string representing the name of a method. Any remaining arguments (and the block, if one exists) are simply passed on to the method.

Why would you use send instead of the plain old dot notation? Because with send, the name of the method that you want to call becomes just a regular argument. You can wait literally until the very last moment to decide which method to call, while the code is running. This technique is called Dynamic Dispatch, and you’ll find it wildly useful.

###Defining Methods Dynamically

class MyClass
  define_method :my_method do |my_arg|
    my_arg * 3
  end
end

obj = MyClass.new
obj.my_method(2) # => 6

define_method is executed within MyClass, so my_method is defined as an instance method of MyClass. This technique of defining a method at runtime is called a Dynamic Method. There is one important reason to use define_method over the more familiar def keyword: define_method allows you to decide the name of the defined method at runtime.

The refactoring example of the chapter using Dynamic Methods:

class Computer
  def initialize(computer_id, data_source)
    @id = computer_id
    @data_source = data_source
		
    # Extracting the names of all components:
    # First, if you pass a block to Array#grep, the block is evaluated for each element
    # that matches the regular expression. Second, the string matching the
    # parenthesized part of the regular expression is stored in the global variable
    # $1. So, if data_source has methods named get_cpu_info and get_mouse_info, this code
    # ultimately calls Computer.define_component twice, with the strings "cpu" and "mouse".
    # Note that define_method works equally well with a string or a symbol.		
    # As a bonus, you don’t even have to write or maintain the list of components. If someone 
    # adds a new component to DS, the Computer class will support it automatically.
    data_source.methods.grep(/^get_(.*)_info$/) { Computer.define_component $1 }
  end
  def self.define_component(name)
    define_method(name) do
      info = @data_source.send "get_#{name}_info", @id
      price = @data_source.send "get_#{name}_price", @id
      result = "#{name.capitalize}: #{info} ($#{price})"
      return "* #{result}" if price >= 100
      result
    end
  end
end

Method Missing

Method_missing is a private instance method of BasicObject that every object inherits.

nick.send :method_missing, :my_method	# => NoMethodError: undefined method `my_method' for #<Lawyer:0x007f801b0f4978>

you can override it to intercept unknown messages. Each message landing on method_missing’s desk includes the name of the method that was called, plus any arguments and blocks associated with the call.

class Lawyer
  def method_missing(method, *args)
    puts "You called: #{method}(#{args.join(', ')})"
    puts "(You also passed it a block)" if block_given?
  end
end

bob = Lawyer.new
bob.talk_simple('a', 'b') do
  # a block
end
# => You called: talk_simple(a, b) \n (You also passed it a block)

Overriding method_missing allows you to call methods that don’t really exist.

###Ghost Methods When you need to define many similar methods, you can spare yourself the definitions and just respond to calls through method_missing. This is like saying to the object, “If they ask you something and you don’t understand, do this.” From the ```’s side, a message that’s processed by method_missing looks like a regular call—but on the receiver’s side, it has no corresponding method. This trick is called a Ghost Method.

#####The Hashie Gem Example

require 'hashie'
# A Mash is a more powerful version of Ruby’s standard OpenStruct class: a hash-like object
# whose attributes work like Ruby variables. If you want a new attribute, just
# assign a value to the attribute, and it will spring into existence.
# Hashie::Mash is a subclass of Ruby’s Hash, and its attributesare actually Ghost Methods.
icecream = Hashie::Mash.new 
icecream.flavor = "strawberry"
icecream.flavor# => "strawberry"

Looking at Hasie::Mash.method_missing:

module Hashie
  class Mash < Hashie::Hash
    def method_missing(method_name, *args, &blk)
      # If the name of the called method is the name of a key in the hash (such as
      # flavor), then Hashie::Mash#method_missing simply calls the [] method to return the
      # corresponding value.    
      return self.[](method_name, &blk) if key?(method_name)
      # If the name ends with a "=", then method_missing chops
      # off the "=" at the end to get the attribute name and then stores its value.
      match = method_name.to_s.match(/(.*?)([?=!]?)$/)
      case match[2]
      when "="
        self[match[1]] = args.first
        # ...
      else
        # if the name of the called method doesn’t match any of these cases, then
        # method_missing just returns a default value.
        default(method_name, *args, &blk)
      end
    end
    # ...
  end
end

###Dynamic Proxies Ghost Methods are often used in wrappers for something else (maybe another object, a web service, or code written in a different language). They collect method calls through method_missing and forward them to the wrapped object.

#####The Ghee Gem Example

class Ghee
  class ResourceProxy
    # ...
    # when you call a method that just reads from an attribute, such as
    # url or description, that call ends into Ghee::ResourceProxy#method_missing. In turn,
    # method_missing forwards the call to the object returned by Ghee::ResourceProxy#subject.
    def method_missing(message, *args, &block)
      subject.send(message, *args, &block)
    end
    # this method makes an HTTP call to the GitHub API, receives the GitHub object in JSON format 
    # and converts it to a hash-like object which is actually a Hashie::Mash
    def subject
      @subject ||= connection.get(path_prefix){|req| req.params.merge!params }.body
    end
  end
end

Here is how Ghee uses this class:

class Ghee
  module API
    module Gists
      # A proxy does two things. First, it implements methods
      # that require specific code, such as star. Second, it forwards methods that
      # just read data, such as url, to the wrapped hash.
      class Proxy < ::Ghee::ResourceProxy
        # When you call a method that changes the state of an object, such as
        # Ghee::API::Gists#star, Ghee places an HTTP call to the corresponding GitHub URL.
        def star
          connection.put("#{path_prefix}/star").status == 204
        end
        # ...
    end
  end
end

An object such as Ghee::ResourceProxy, that catches Ghost Methods and forwards them to another object, is called a Dynamic Proxy.

#####respond_to_missing? If you ask an object whether it responds to a Ghost Method the response wil be false:

cmp = Computer.new(0, DS.new)
cmp.respond_to?(:mouse) # => false

Ruby provides a clean mechanism to make respond_to? aware of Ghost Methods. respond_to? calls a method named respond_to_missing?, that is supposed to return true if a method is a Ghost Method, so you should override respond_to_missing? every time you override method_missing

class Computer
  # ...
  def respond_to_missing?(method, include_private = false)
    @data_source.respond_to?("get_#{method}_info") || super
  end
end

cmp.respond_to?(:mouse) # => true

The refactoring example of the chapter using Method Missing:

class Computer < BasicObject
  def initialize(computer_id, data_source)
    @id = computer_id
    @data_source = data_source
  end
  
  def method_missing(name, *args)
    super if !@data_source.respond_to?("get_#{name}_info")
    info = @data_source.send("get_#{name}_info", @id)
    price = @data_source.send("get_#{name}_price", @id)
    result = "#{name.capitalize}: #{info} ($#{price})"
    return "* #{result}" if price >= 100
    result
  end
end

#####const_missing Rake went through an upgrade path: for a few versions, you could use either the new class names or the old, non-namespaced names. Rake allowed you to do that by Monkepatching the Module#const_missing method

class Module
  def const_missing(const_name)
    case const_name
    when :Task
      Rake.application.const_warning(const_name)
      Rake::Task
    when :FileTask
      Rake.application.const_warning(const_name)
      Rake::FileTask
    when :FileCreationTask
    # ...
    end
  end
end

When you reference a constant that doesn’t exist, Ruby passes the name of the constant to const_missing as a symbol. Class names are just constants, so a reference to an unknown Rake class such as Task was routed to Module#const_missing. In turn, const_missing warned you that you were using an obsolete class name.

require 'rake'
task_class = Task
# => WARNING: Deprecated reference to top-level constant 'Task' found [...]
# => Use --classic-namespace on rake command
# => or 'require "rake/classic_namespace"' in Rakefile

After the warning, you automatically got the new, namespaced class name in place of the old one:

task_class  # => Rake::Task

#####WARNING!: infinite loops when using method_missing

class Roulette
  def method_missing(name, *args)
    person = name.to_s.capitalize
    3.times do
      number = rand(10) + 1
      puts "#{number}..."
    end
    "#{person} got a #{number}"
  end
end

number_of = Roulette.new
puts number_of.bob  # => roulette_failure.rb:7:in `method_missing': stack level too deep (SystemStackError)

In the code above since the variable number is inside the block by the time it is called it doen't exists so the code will try to call a method called number on the object which doen't exist so the call ends up in method_missing again thus causing an infinite loop.

This is a common problem with Ghost Methods: since unknown calls become calls to method_missing, your object might accept a call that’s just plain wrong. Finding a bug like this one in a large program can be pretty painful.

REMEMBER TO FALL BACK ON BasicObject#method_missing when you get a call you don't know how to handle.

class Roulette
  def method_missing(name, *args)
    person = name.to_s.capitalize
    super unless %w[Bob Frank Bill].include? person
    number = 0
    3.times do
      number = rand(10) + 1
      puts "#{number}..."
    end
    "#{person} got a #{number}"
  end
end

#####WARNING!: existing methods in objects and Blank Slates When using method missing to redirect messages to other objects problems like the following might come up:

my_computer = Computer.new(42, DS.new)
my_computer.display # => nil

in the previous code you where expecting the call to _my_computer.display to be forwarded to the data_source object and return the information corresponding the display information of the device in question. However, it returns nil, which means the call is not getting to the data_source object. By executing the following

Object.instance_methods.grep /^d/
# => [:dup, :display, :define_singleton_method]

you realize that Object defines a method named display (a seldom-used method that prints an object on a port and always returns nil). Computer inherits from Object, so it gets the display method. The call to Computer#display finds a real method by that name, so it never lands on method_missing. You’re calling a real, live method instead of a Ghost Method.

This problem tends to crop up with Dynamic Proxies. Whenever the name of a Ghost Method clashes with the name of a real, inherited method, the latter wins. If you don’t need the inherited method, you can fix the problem by removing it.

A skinny class with a minimal number of methods is called a Blank Slate. As it turns out, Ruby has a ready-made Blank Slate for you to use called BasicObject. Inheriting from BasicObject is the quicker way to define a Blank Slate in Ruby.

#####Removing specific methods from a class You can remove a method from a class by using either Module#undef_method or Module#remove_method. The drastic undef_method removes any method, including the inherited ones. The kinder remove_method removes the method from the receiver, but it leaves inherited methods alone.

#####The Builder Example

class BlankSlate
  # Hide the method named +name+ in the BlankSlate class. Don't
  # hide +instance_eval+ or any method beginning with "__".
  def self.hide(name)
    # ...
    if instance_methods.include?(name._blankslate_as_name) && name !~ /^(__|instance_eval$)/
      undef_method name
    end
  end
  # ...
  instance_methods.each { |m| hide(m) }
end

Builder doesn’t go as far as removing each and every method from BlankSlate. It keeps instance_eval (a method that you’ll get to know in the next chapter) and all the “reserved methods”—methods that are used internally by Ruby, whose names conventionally begin with a double underscore.

The basics of blocks

def a_method(a, b)
  # yield takes care of providing the parameters to the block
  # if more args are passed to the block than the ones it receives
  # they will be ignored
  a + yield(a, b)
end

# if less args are passed to the block than the ones specified
# the remaining args will be nill
a_method(1, 2) {|x, y| (x + y) * 3 }  # => 10

Within a method, you can ask Ruby whether the current call includes a block. You can do that with the Kernel#block_given? method

Blocks are Closures

When you define the block, it simply grabs the bindings that are there at that moment, and then it carries those bindings along when you pass the block into a method:

def my_method
  x = "Goodbye"
  yield("cruel")
end

x = "Hello"
my_method {|y| "#{x}, #{y} world" } # => "Hello, cruel world"

Scope

v1 = 1
class MyClass
  v2 = 2
  local_variables # => [:v2]
  def my_method
    v3 = 3
    local_variables
  end
  local_variables # => [:v2]
end

obj = MyClass.new
obj.my_method # => [:v3]
obj.my_method # => [:v3]
local_variables # => [:v1, :obj]

as soon as you enter a new scope, the previous bindings are simply replaced by a new set of bindings.

“Whenever the program changes scope, some bindings are replaced by a new set of bindings.” Granted, this doesn’t happen to all the bindings each and every time. For example, if a method calls another method on the same object, instance variables stay in scope through the call. In general, though, bindings tend to fall out of scope when the scope changes.

There are exactly three places where a program leaves the previous scope behind and opens a new one:

  • Class definitions
  • Module definitions
  • Methods Scope changes whenever the program enters (or exits) a class or module def- inition or a method. These three borders are marked by the keywords class, module, and def, respectively. Each of these keywords acts like a Scope Gate.

There is a subtle difference between class and module on one side and def on the other. The code in a class or module definition is executed immediately. Conversely, the code in a method definition is executed later, when you eventually call the method.

Flattening Scopes

Class.new is a perfect replacement for class. You can also define instance methods in the class if you pass a block to Class.new

my_var = "Success"
MyClass = Class.new do 
  # Now we can print my_var here... 
  puts "#{my_var} in the class definition!"
  
  def my_method
    # ...but how can we print it here?
    # no because the def keyword is a scope gate
    # when the method gets called the variable
    # won't be available
  end
end

to access the variable you can use define method method with a block instead of the def keyword to define the method.

my_var = "Success"
MyClass = Class.new do
  "#{my_var} in the class definition"
  define_method :my_method do
    "#{my_var} in the method"
  end
end

MyClass.new.my_method # => Success in the method

If you replace Scope Gates with method calls, you allow one scope to see variables from another scope. Technically, this trick should be called nested lexical scopes, but many Ruby coders refer to it simply as “flattening the scope”.

Sharing Scopes

def define_methods
  # this variable is protected 
  # by the def scope gate
  shared = 0
  Kernel.send :define_method, :counter do
    shared
  end
  Kernel.send :define_method, :inc do |x|
    shared += x
  end
end

define_methods
counter # => 0
inc(4)
counter # => 4
Spell: Shared Scope

BasicObject#instance_eval, which evaluates a block in the context of an object:

class MyClass
  def initialize
    @v = 1
  end
end

obj = MyClass.new
obj.instance_eval do
  self # => #<MyClass:0x3340dc @v=1>
  @v # => 1
end

so it can access the receiver’s private methods and instance variables, such as @v. Even if instance_eval changes self, the block that you pass to instance_eval can still see the bindings from the place where it’s defined

v = 2
obj.instance_eval { @v = v }
obj.instance_eval { @v } # => 2

Alternatively, check instance_exec().

Clean Rooms

Are objects used to execute blocks inside of them, just that. The ideal Clean Room doesn’t have many methods or instance variables, because the names of those methods and instance variables could clash with the names in the environment that the block comes from. For this reason, instances of BasicObject usually make for good Clean Rooms, because they’re Blank Slates.

Callable Objects

Although most things in Ruby are objects, blocks are not. But why would you care about that? Imagine that you want to store a block and execute it later. To do that, you need an object.

A Proc is a block that has been turned into an object. You can create a Proc by passing the block to Proc.new. Later, you can evaluate the block-turned-object with Proc#call:

inc = Proc.new {|x| x + 1 } 
inc.call(2) # => 3
# is the same as:
inc = proc {|x| x + 1 } 
inc.call(2) # => 3

This technique is called a Deferred Evaluation. Ruby provides two Kernel Methods that convert a block to a Proc: lambda and proc.

p = lambda {|x| x + 1 }
# is the same as:
p = ->(x) { x + 1 }

If You want to pass the block to another method (or block) or you want to convert the block to a Proc you can use the & operator. However, this argument must be the last in the list of arguments and prefixed by an & sign.

def math(a, b)
  yield(a, b)
end
def do_math(a, b, &operation)
  math(a, b, &operation)
end
do_math(2, 3) {|x, y| x * y} # => 6

The & operator converts a Proc to a block and viceversa.

Procs vs Lambdas Procs created with lambda actually differ in some respects from Procs created any other way (You can use the Proc#lambda? method to check whether the Proc is a lambda).

Procs, Lambdas, and return The first difference between lambdas and procs is that the return keyword means different things. In a lambda, return just returns from the lambda:

def double(callable_object)
  callable_object.call * 2
end

l = lambda { return 10 }
double(l) # => 20

In a proc, return behaves differently. Rather than return from the proc, it returns from the scope where the proc itself was defined:

def another_double
  p = Proc.new { return 10 }
  result = p.call
  return result * 2 # unreachable code!
end

another_double # => 10

Procs, Lambdas, and Arity A particular proc or lambda might have an arity of two, meaning that it accepts two arguments:

p = Proc.new {|a, b| [a, b]}
p.arity # => 2

lambdas tend to be less tolerant than procs (and regular blocks) when it comes to arguments. Call a lambda with the wrong arity, and it fails with an ArgumentError. On the other hand, a proc fits the argument list to its own expectations:

p = Proc.new {|a, b| [a, b]} # => [1, 2]
p.call(1, 2, 3)
p.call(1) # => [1, nil]

If there are too many arguments, a proc drops the excess arguments. If there are too few arguments, it assigns nil to the missing arguments.

Generally speaking, lambdas are more intuitive than procs because they’re more similar to methods. They’re pretty strict about arity, and they simply exit when you call return. For this reason, many Rubyists use lambdas as a first choice, unless they need the specific features of procs.

Methods, like lambdas, are just callable objects.

class MyClass
  def initialize(value)
    @x = value
  end
  
  def my_method
    @x
  end
end

object = MyClass.new(1)
m = object.method :my_method
m.call # => 1

A Method object is similar to a block or a lambda. Indeed, you can convert a Method to a Proc by calling Method#to_proc, and you can convert a block to a method with define_method. However, there is an important difference between lambdas and methods: a lambda is evaluated in the scope it’s defined in (it’s a closure), while a Method is evaluated in the scope of its object.

UnboundMethods are like Methods that have been detached from their original class or module. You can turn a Method into an UnboundMethod by calling Method#unbind. You can also get an UnboundMethod directly by calling Module#in- stance_method. You can’t call an UnboundMethod, but you can use it to generate a normal method that you can call.

Class Definitions

When you use the class keyword, you aren’t just dictating how objects will behave in the future. On the contrary, you’re actually running code.

Class definitions also return the value of the last statement, just like methods and blocks do:

result = class MyClass
  self
end
result # => MyClass

Although you can get a reference to the current object through self, there’s no equivalent keyword to get a reference to the current class. However, in most situations it’s easy to keep track of the current class just by looking at the code:

  • At the top level of your program, the current class is Object, the class of main. (That’s why, if you define a method at the top level, that method becomes an instance method of Object).
  • In a method, the current class is the class of the current object. (Try defining a method inside another method with def, and you’ll see that the new method is defined on the class of self. This information is probably going to win you some Ruby trivia contest).
  • When you open a class with the class keyword (or a module with the module keyword), that class becomes the current class.

As you know, wherever you are in a Ruby program, you always have a current object: self. Likewise, you always have a current class (or module). When you define a method, that method becomes an instance method of the current class.

How can you open the class if you don’t know its name? You need some way other than the class keyword to change the current class. Enter the class_eval method.

class_eval()

Module#class_eval (also known by its alternate name, module_eval) evaluates a block in the context of an existing class:

def add_method_to(a_class)
  a_class.class_eval do
    def m; 'Hello!'; end
  end
end
add_method_to String
"abc".m # => "Hello!"

Instance_eval only changes self, while class_eval changes both self and the current class. (This is not the whole truth: instance_eval does also change the current class, but you’ll have to wait for Singleton Classes and instance_eval(), on page 127 to learn how exactly.)

Module#class_eval is actually more flexible than class. You can use class_eval on any variable that references the class, while class requires a constant. Also, class opens a new scope, losing sight of the current bindings, while class_eval has a Flat Scope (83).This means you can reference variables from the outer scope in a class_eval block. Finally, just like instance_eval has a twin method called instance_exec, mod- ule_eval/class_eval also has an equivalent module_exec/class_exec method that can pass extra parameters to the block. Use instance_eval to open an object that is not a class, and class_eval to open a class definition and define methods with def. But what if you want to open an object that happens to be a class (or module) to do something else than using def? Should you use instance_eval or class_eval then? If all you want is to change self, then both instance_eval and class_eval will do the job nicely. However, you should pick the method that best communicates your intentions. If you’re thinking “I want to open this object, and I don’t particularly care it’s a class,” then instance_eval is fine. If you’re thinking “I want an Open Class (14) here,” then class_eval is almost certainly a better match.

#####Current Class Wrap-up

  • The Ruby interpreter always keeps a reference to the current class (or module). All methods defined with def become instance methods of the current class.
  • In a class definition, the current object self and the current class are the same—the class being defined.
  • If you have a reference to the class, you can open the class with class_eval (or module_eval).

#####Class Instance Variables The Ruby interpreter assumes that all instance variables belong to the current object self. This is also true in a class definition:

class MyClass
  @my_var = 1
end

In a class definition, the role of self belongs to the class itself, so the instance variable @my_var belongs to the class. Don’t get confused. Instance variables of the class are different from instance variables of that class’s objects as you can see in the following example:

class MyClass
  @my_var = 1
  def self.read; @my_var; end
  def write; @my_var = 2; end
  def read; @my_var; end
end
obj = MyClass.new
obj.read # => nil
obj.write 
obj.read # => 2
MyClass.read # => 1

The previous code defines two instance variables. Both happen to be named @my_var, but they’re defined in different scopes, and they belong to different objects. A Class Instance Variable can be accessed only by the class itself— not by an instance or by a subclass. Class variables are different from Class Instance Variables, because they can be accessed by subclasses and by regular instance methods.

Example:

class Loan
  def initialize(book)
    @book = book
    @time = Time.now
  end
  def to_s
    "#{@book.upcase} loaned on #{@time}"
  end
end

Loan stores the title of a book and the time when it was loaned—that is, the time when the object was created. You’d like to write a unit test for the to_s method, but to write that test, you’d have to know the exact time when the object was created. This is a common problem with code that relies on Time or Date: such code returns a different result every time it runs, so you don’t know what result to test for.

class Loan
  def initialize(book)
    @book = book
    @time = Loan.time_class.now
  end
  
  def self.time_class
    @time_class || Time
  end
  
  def to_s
  # ...

In production, Loan always uses the Time class, because @time_class is always nil. By contrast, the unit tests can rely on a fake time class that always returns the same value.

class FakeTime
  def self.now; 'Mon Apr 06 12:15:50'; end
end

require 'test/unit'
class TestLoan < Test::Unit::TestCase
  def test_conversion_to_string
    Loan.instance_eval { @time_class = FakeTime }
    loan = Loan.new('War and Peace')
    assert_equal 'WAR AND PEACE loaned on Mon Apr 06 12:15:50', loan.to_s
  end
end

Redefine the following class without using the class keyword:

class MyClass < Array
  def my_method
    'Hello!'
  end
end

# Solution:
c = Class.new(Array) do
  def my_method
    'Hello!'
  end
end

Now you have a variable that references a class, but the class is still anonymous. The name of a class is just a constant, so you can assign it yourself:

  MyClass = c

When you assign an anonymous class to a constant, Ruby understands that you’re trying to give a name to the class, and it does something special: it turns around to the class and says, “Here’s your new name.” Now the constant references the Class, and the Class also references the constant. If it weren’t for this trick, a class wouldn’t be able to know its own name, and you couldn’t write this:

c.name # => "MyClass"

Singleton Methods

Ruby allows you to add a method to a single object.

str = "just a regular string"
def str.title?
 self.upcase == self
end
str.title? # => false
str.methods.grep(/title?/) # => [:title?]
str.singleton_methods # => [:title?]

A method like this one, which is specific to a single object, is called a Singleton Method. You can define a Singleton Method with either the syntax above, or the Object#define_singleton_method method.

The Truth About Class Methods

Classes are just objects, and class names are just constants. If you remember this concept, then you’ll see that calling a method on a class is the same as calling a method on an object:

an_object.a_method
AClass.a_class_method

See? The first line calls a method on an object referenced by a variable, and the second line calls a method on an object (that also happens to be a class) referenced by a constant. It’s the same syntax. Class methods are Singleton Methods of a class. So, the syntax for defining a Singleton Methods with def is always the same:

def object.method
 # Method body here
end

def MyClass.method
 # Method body here
end

def self.method
 # Method body here
end

Class Macros

All the attr_* methods are defined on class Module, so you can use them when- ever self is a module or a class. A method such as attr_accessor is called a Class Macro. Class Macros look like keywords, but they’re just regular class methods that are meant to be used in a class definition.

#####Class Macros Applied The Book class in the Bookworm source code has methods named GetTitle, title2, and LEND_TO_USER. By Ruby’s conventions, these methods should be named title, subtitle, and lend_to, respectively. However, there are other projects that use the Book class, and you have no control over these projects. If you just rename the methods, you will break the callers.

You can rename the methods if you invent a Class Macro (117) that deprecates the old names:

class Book
 def title # ...
 def subtitle # ...
 def lend_to(user)
 puts "Lending to #{user}"
 # ...
 def self.deprecate(old_method, new_method)
  define_method(old_method) do |*args, &block|
   warn "Warning: #{old_method}() is deprecated. Use #{new_method}()."
   send(new_method, *args, &block)
  end
 end

 deprecate :GetTitle, :title
 deprecate :LEND_TO_USER, :lend_to
 deprecate :title2, :subtitle
end

The deprecate method takes the old name and the new name of a method and defines a Dynamic Method (52) that catches calls to the old name. The Dynamic Method forwards the calls to the renamed method—but first it prints a warning on the console to notify the callers that the old name has been deprecated:

 b = Book.new
 b.LEND_TO_USER("Bill") 
 # => Warning: LEND_TO_USER() is deprecated. Use lend_to().
      Lending to Bill

Singleton Classes

The Singleton Method can’t live in obj, because obj is not a class. It can’t live in MyClass, because if it did, all instances of MyClass would share it. And it cannot be an instance method of MyClass’s superclass, Object. So then, where do Sin- gleton Methods live? Class methods are a special kind of Singleton Method—and just as baffling:

def MyClass.my_class_method; end

When you ask an object for its class, Ruby doesn’t always tell you the whole truth. Instead of the class that you see, an object can have its own special, hidden class. That’s called the singleton class of the object. (You can also hear it called the metaclass, or the eigenclass.

Ruby has a special syntax, based on the class keyword, that places you in the scope of the singleton class:

class << an_object
 # your code here
end
singleton_class.class # => Class

you can also get a reference to the singleton class with the handy Object#singleton_class method:

"abc".singleton_class # => #<Class:#<String:0x331df0>>

The previous example also shows that a singleton class is a class—but a very special one. For starters, it’s invisible until you resort to either Object#single- ton_class, or the exotic class << syntax. Also, singleton classes have only a single instance (that’s where their name comes from), and they can’t be inherited. More important, a singleton class is where an object’s Singleton Methods live:

def obj.my_singleton_method; end
singleton_class.instance_methods.grep(/my_/) # => [:my_singleton_method]

#####Method Lookup Revisited f an object has a singleton class, Ruby starts looking for methods in the singleton class rather than the conventional class, and that’s why you can call Singleton Methods such as obj#a_singleton_method. If Ruby can’t find the method in the singleton class, then it goes up the ancestors chain, ending in the superclass of the singleton class—which is the object’s class. From there, everything is business as usual.

Like any other object, a singleton class must have its own singleton class:

class << "abc"
 class << self
  self # => #<Class:#<Class:#<String:0x33552c>>>
 end
end

The example program:

class C
 def a_method
  'C#a_method()'
 end
end

class D < C; end
obj = D.new
obj.a_method # => "C#a_method()"

obj = Object.new
obj.singleton_class # => #<Class:#<Object:0x007fd96909b588>>

class << obj
 def a_singleton_method
  'obj#a_singleton_method()'
 end
end

Adding a class method to the example program.

class C
 class << self
  def a_class_method
   'C.a_class_method()'
  end 
 end
end

C.singleton_class # => #<Class:C>
D.singleton_class # => #<Class:D>
D.singleton_class.superclass # => #<Class:C>
C.singleton_class.superclass # => #<Class:Object>

“The superclass of the singleton class is the singleton class of the superclass. It’s easy.” “There are classes, singleton classes, and modules. There are instance methods, class methods, and Singleton Methods.”

If you put singleton classes together with regular classes and modules, you end up with the seven rules of the Ruby object model:

  1. There is only one kind of object—be it a regular object or a module.
  2. There is only one kind of module—be it a regular module, a class, or a singleton class.
  3. There is only one kind of method, and it lives in a module—most often in a class.
  4. Every object, classes included, has its own “real class,” be it a regular class or a singleton class.
  5. Every class, with the exception of BasicObject, has exactly one ancestor— either a superclass, or a module. This means you have a single chain of ancestors from any class up to BasicObject.
  6. The superclass of the singleton class of an object is the object’s class. The superclass of the singleton class of a class is the singleton class of the class’s superclass.
  7. When you call a method, Ruby goes “right” in the receiver’s real class and then “up” the ancestors chain. That’s all there is to know about the way Ruby finds methods.

Since class methods are just Singleton Methods that live in the class’s singleton class, now you have three different ways to define a class method. Here they are:

def MyClass.a_class_method; end

class MyClass
 def self.another_class_method; end
end

# this method is the prefered one because
# it acknowledges the singleton class explicitly
class MyClass
 class << self
  def yet_another_class_method; end
 end
end

#####Singleton Classes and instance_eval()

  • class_eval changes both self and the current class.
  • instance_eval also changes the current class: it changes it to the singleton class of the receiver.
s1, s2 = "abc", "def"

s1.instance_eval do
 def swoosh!; reverse; end
end

s1.swoosh! # => "cba"
s2.respond_to?(:swoosh!) # => false

You’ll rarely, if ever, see instance_eval used purposefully to change the current class, as in the example above. The standard meaning of instance_eval is this: “I want to change self.”

If you want an attribute that’s specific to MyClass, you need a different technique. Define the attribute in the singleton class:

class MyClass
 class << self
  attr_accessor :c
 end
end
MyClass.c = 'It works!'
MyClass.c # => "It works!"

To understand how this works, remember that an attribute is actually a pair of methods. If you define those methods in the singleton class, they become class methods.

The superclass of #BasicObject is none other than good old Class.

BasicObject.singleton_class.superclass # => Class

“when a class includes a module, it gets the module’s instance methods—not the class methods. Class methods stay out of reach, in the module’s singleton class.”

module MyModule
 def self.my_method; 'hello'; end
end

class MyClass
 include MyModule
end
MyClass.my_method # NoMethodError!

To make it work define my_method as a regular instance method of MyModule. Then include the module in the singleton class of MyClass.

module MyModule
 def my_method; 'hello'; end
end

class MyClass
 class << self
  include MyModule
 end
end

This technique is called a Class Extension. But the same applies to objects "Object Extension".

module MyModule
 def my_method; 'hello'; end
end

obj = Object.new
class << obj
 include MyModule
end
obj.my_method # => "hello"
obj.singleton_methods # => [:my_method]

Class Extensions (131) and Object Extensions (131) are common enough that Ruby provides a method just for them, named Object#extend:

module MyModule
 def my_method; 'hello'; end
end

obj = Object.new
obj.extend MyModule 
obj.my_method # => "hello"

class MyClass
 extend MyModule
end
MyClass.my_method # => "hello"

Object#extend is simply a shortcut that includes a module in the receiver’s singleton class.

Method Wrappers

If you have a method that you don’t want to modify directly, because it’s in a library. You want to wrap additional functionality around this method so that all clients get the additional functionality automatically.

You can give an alternate name to a Ruby method by using Module#alias_method:

class MyClass
 def my_method; 'my_method()'; end
 alias_method :m, :my_method
end

obj = MyClass.new
obj.my_method # => "my_method()"
obj.m # => "my_method()"

class MyClass
 alias_method :m2, :m
end
obj.m2 # => "my_method()"

In alias_method, the new name for the method comes first, and the original name comes second. (Ruby also has an alias keyword which is an alternative to Module#alias_method. It can come useful if you want to alias a method at the top level, where Module#alias_method is not available).

You can alias a method and then redefine it:

class String
 alias_method :real_length, :length
 def length
  real_length > 5 ? 'long' : 'short'
 end
end

"War and Peace".length # => "long"
"War and Peace".real_length # => 13

The previous code redefines String#length, but the alias still refers to the original method. This gives you insight into how method redefinition works. When you redefine a method, you don’t really change the method. Instead, you define a new method and attach an existing name to that new method. You can still call the old version of the method as long as you have another name that’s still attached to it.

You can write an Around Alias in three simple steps:

  1. You alias a method.
  2. You redefine it.
  3. You call the old method from the new method.

In Ruby it’s the method’s name, not the method itself, that is either public or private.

One downside of Around Aliases is that they pollute your classes with one additional method name. You can fix this small problem somehow by making the old version of the method private after you alias it. (In Ruby it’s the method’s name, not the method itself, that is either public or private.) Another potential problem of Around Aliases has to do with loading. You should never load an Around Alias twice, unless you want to end up with an exception when you call the method. Can you see why? The main issue with Around Aliases, however, is that they are a form of Monkeypatching. Like all Monkeypatches, they can break existing code that wasn’t expecting the method to change.

#####More Method Wrappers Refinements have one additional features that enables you to use them in place of Around Aliases (135): if you call super from a refined method, you will call the original, unrefined method. Here comes an example:

module StringRefinement
 refine String do
  def length
   super > 5 ? 'long' : 'short'
  end
 end
end
using StringRefinement

War and Peace".length # => "long"

Like other Refinements, this Refinement Wrapper only applies until the end of the file (or, in Ruby 2.1, the module definition). This makes it generally safer than the equivalent Around Alias, which applies everywhere.

You have a third way of wrapping a method: you can use Module#prepend This means that a method in a prepended module can override a method in the includer, and call the nonoverridden version with super:

module ExplicitString
 def length
  super > 5 ? 'long' : 'short'
 end
end

String.class_eval do
 prepend ExplicitString
end

"War and Peace".length # => "long"

You can call this a Prepended Wrapper. It’s not local like a Refinement Wrapper, but it’s generally considered cleaner and more explicit than both a Refinement Wrapper and an Around Alias.

Chapter6

Kernel#eval

Kernel#eval takes a string that contains Ruby code. Kernel#eval executes the code in the string and returns the result.

array = [10, 20]
element = 30
eval("array << element") # => [10, 20, 30]

The power of eval becomes apparent when you compute your Strings of Code on the fly.

POSSIBLE_VERBS = ['get', 'put', 'post', 'delete']
POSSIBLE_VERBS.each do |m|
	eval <<-end_eval
		def #{m}(path, *args, &b)
			r[path].#{m}(*args, &b)
		end
	end_eval
end

Binding Objects

A Binding is a whole scope packaged as an object. The idea is that you can create a Binding to capture the local scope and carry it around. Later, you can execute code in that scope by using the Binding object in conjunction with eval. You can create a Binding with the Kernel#binding method:

class MyClass
	def my_method
		@x = 1
		binding
	end
end
b = MyClass.new.my_method
eval "@x", b # => 1

Ruby also provides a predefined constant named TOPLEVEL_BINDING, which is just a Binding of the top-level scope. You can use it to access the top-level scope from anywhere in your program:

class AnotherClass
	def my_method
		eval "self", TOPLEVEL_BINDING
	end
end
AnotherClass.new.my_method # => main

The first optional argument to eval is a Binding. The remaining two optional arguments are used to tweak the stack trace in case of exceptions.

eval(statements, @binding, file, line)

Strings of Code vs. Blocks

eval is a special case in the eval* family: it evaluates a String of Code instead of a block, like both class_eval and instance_eval do. However, instance_eval and class_eval can take either a String of Code or a block.

array = ['a', 'b', 'c']
x = 'd'
array.instance_eval "self[1] = x"
array # => ["a", "d", "c"]

Because a block and a String of Code are so similar, in many cases you have the option of using either one. Which one should you choose? The short answer is that you should probably avoid Strings of Code whenever you have an alternative for security reasons.

The Trouble with eval()

  • To start with, Strings of Code don’t always play well with your editor’s features, such as syntax coloring and autocompletion.
  • Strings of Code tend to be difficult to read and modify
  • Ruby won’t report a syntax error in a String of Code until that string is evaluated, potentially resulting in brittle programs that fail unexpectedly at runtime.
  • Code Injection

#####Defending Yourself from Code Injection When it comes to code injection, some strings are safer than others. Only strings that derive from an external source can contain malicious code, so you might simply limit your use of eval to those strings that you wrote yourself.

#####Tainted Objects and Safe Levels Ruby automatically marks potentially unsafe objects—in particular, objects that come from external sources—as tainted. Tainted objects include strings that your program reads from web forms, files, the command line, or even a system variable. Every time you create a new string by manipulating tainted strings, the result is itself tainted.

Ruby also provides the notion of safe levels, which complement tainted objects nicely. When you set a safe level (which you can do by assigning a value to the $SAFE global variable), you disallow certain potentially dangerous operations.

You can choose from four safe levels, from the default 0 (“hippie commune,” where you can hug trees and format hard disks) to 3 (“military dictatorship,” where every object you create is tainted by default).

By using safe levels carefully, you can write a controlled environment for eval. Such an environment is called a Sandbox.

#####The ERB example

class ERB
	def result(b=new_toplevel)
		if @safe_level
			proc {
			$SAFE = @safe_level
			eval(@src, b, (@filename || '(erb)'), 0)
		}.call
		else
			eval(@src, b, (@filename || '(erb)'), 0)
		end
	end
#...

new_toplevel is a method that returns a copy of TOPLEVEL_BINDING. The @src instance variable carries the content of a code tag, and the @safe_level instance variable contains the safe level required by the user. If no safe level is set, the content of the tag is simply evaluated. Otherwise, ERB builds a quick Sandbox: it makes sure that the global safe level is exactly what the user asked for and also uses a Proc as a Clean Room to execute the code in a separate scope. (Note that the new value of $SAFE applies only inside the Proc. Contrary to what happens with other global variables, the Ruby interpreter takes care to reset $SAFE to its former value after the call.)

Checked Attributes with Eval()

def add_checked_attribute(klass, attribute)
	eval "
		class #{klass}
			def #{attribute}=(value)
				raise 'Invalid attribute' unless value
				@#{attribute} = value
			end
			def #{attribute}()
				@#{attribute}
			end
		end
		"
end

Checked Attributes with Dynamic Methods

def add_checked_attribute(klass, attribute)
	klass.class_eval do
		define_method "#{attribute}=" do |value|
			raise 'Invalid attribute' unless value
			instance_variable_set("@#{attribute}", value)
		end

		define_method attribute do
			instance_variable_get "@#{attribute}"
		end
	end
end

Checked Attributes with Blocks

def add_checked_attribute(klass, attribute, &validation)
	klass.class_eval do
		define_method "#{attribute}=" do |value|
			raise 'Invalid attribute' unless validation.call(value)
			instance_variable_set("@#{attribute}", value)
		end

		define_method attribute do
			instance_variable_get "@#{attribute}"
		end
	end
end

Checked Attributes with Class Macro

class Class
	def attr_checked(attribute, &validation)
		define_method "#{attribute}=" do |value|
			raise 'Invalid attribute' unless validation.call(value)
			instance_variable_set("@#{attribute}", value)
		end

		define_method attribute do
			instance_variable_get "@#{attribute}"
		end
	end
end

Hook Methods

The object model is an eventful place. Lots of things happen there as your code runs: classes are inherited, modules are mixed into classes, and methods are defined, undefined, and removed. You can “catch” these events like you catch a mouse-click event on a graphical interface.

class String
	def self.inherited(subclass)
		puts "#{self} was inherited by #{subclass}"
	end
end

class MyString < String; end #=> String was inherited by MyString

The inherited method is an instance method of Class, and Ruby calls it when a class is inherited. By default, Class#inherited does nothing, but you can override it with your own code as in the earlier example. A method such as Class#inherited is called a Hook Method because you can use it to hook into a particular event. Just as you override Class#inherited to plug into the lifecycle of classes, you can plug into the lifecycle of modules by overriding Module#included and (in Ruby 2.0) Module#prepended:

module M1
	def self.included(othermod)
		puts "M1 was included into #{othermod}"
	end
end

module M2
	def self.prepended(othermod)
		puts "M2 was prepended to #{othermod}"
	end
end

class C
	include M1
	prepend M2
end
#=> M1 was included into C
    M2 was prepended to C

You can also execute code when a module extends an object by overriding Module#extended. Finally, you can execute method-related events by overriding Module#method_added, method_removed, or method_undefined.

module M
	def self.method_added(method)
		puts "New method: M##{method}"
	end

	def my_method; end
end
#=> New method: M#my_method

These hooks only work for regular instance methods, which live in the object’s class. They don’t work for Singleton Methods, which live in the object’s singleton class. To catch Singleton Method events, you can use BasicObject#singleton_method_added, singleton_method_removed, and singleton_method_undefined.

There is an important difference between overriding Module#included and overridingModule#include. Module#included exists solely to be used as a Hook Method, and its defaultimplementation is empty. But Module#include has some real work to do: it must actuallyinclude the module. That’s why our hook’s code also should call the base implementation of Module#include through super. If you forget super, you’ll still catch the event, but you won’t include the module anymore. As an alternative to overriding, you can turn a regular method into a Hook Method by using an Around Alias.

Checked Attributes with Class Macro and Hooks

module CheckedAttributes
	def self.included(base)
		base.extend ClassMethods
	end

	module ClassMethods
		def attr_checked(attribute, &validation)
			define_method "#{attribute}=" do |value|
				raise 'Invalid attribute' unless validation.call(value)
				instance_variable_set("@#{attribute}", value)
			end

			define_method attribute do
				instance_variable_get "@#{attribute}"
			end
		end
	end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment