tags:

views:

126

answers:

2

I'm trying to understand this function.

What I can see is an attribute and type are passed to the opal() method.

Then type_name takes its value from type as long as type is a Symbol or String. Otherwise, the name method is called on type. I imagine the name method is similar to the class method to get the class of the type argument.

After self.class_eval I'm kind of lost but my guess is this is defining maybe a block of code to be added to the class referenced by self.

How this works I'm not sure though.

Would appreciate if someone could explain what's going on after self.class_eval << DEF.

    def opal(attr, type)
      self.ds "#{attr}_id"
      type_name = (type.is_a?(Symbol) || type.is_a?(String)) ? type : type.name
      self.class_eval <<DEF
  def #{attr}
    if defined?(@#{attr})
      @#{attr}
    else 
      @#{attr} = if self.#{attr}_id
          #{type_name}.get(self.#{attr}_id)
        else
          nil
        end
    end
  end

  def #{attr}=(value)
    self.#{attr}_id = value.key
    @#{attr} = value
  end
DEF
    end
+5  A: 

Everything between <<DEF and DEF is just a string and the #{ ... }s work on that string like any other.

class_eval will cause the interpreter to run on the string in the context of the module.

So, if you know what attr and type are then you can work out what code is being run to add methods to the class.

Lets say attr is "foo" and type is "Bazzle". The code being run would be:

def foo
  if defined?(@foo)
    @foo
  else 
    @foo = if self.foo_id
      Bazzle.get(self.foo_id)
    else
      nil
    end
  end
end

def foo=(value)
  self.foo_id = value.key
  @foo = value
end
toholio
You say "class_eval will cause the interpreter to run on the string in the context of the module". So if I say self.class_eval "def bar end", the interpreter will add a "bar" method to the class?
franz
Yes. If you did that and there was already a `bar` method in the class it would be overridden.
toholio
Got it. Thanks .
franz
+3  A: 

To make it easy to understand, let's suppose the value of 'attr' is 'foo', here's what it looks like now:

self.class_eval <<DEF
  def foo
    if defined?(@foo) # Return the value of attr if it's defined
      @foo
    else 
      @foo = if self.foo_id
          #{type_name}.get(self.foo_id)
        else
          nil
        end
    end
  end

  def foo=(value) # Define setter
    self.foo_id = value.key
    @foo = value
  end
DEF

So it's just defining some getter and setter methods for @foo, and evaluating it at the class level.

cloudhead