Question

I'm playing around with Ruby and I have written the following code:

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

  module ClassMethods
    def use_id_and_name_from_module(use_attribute)
      class_eval <<CODE
        def id_and_name
          "\#{id}-\#{#{use_attribute}.downcase}"
        end
CODE
    end
  end
end


class Model
  include IdAndNameRedefine

  attr_reader :id, :name1, :name2

  def initialize(id, name1, name2)
    @id = id
    @name1 = name1
    @name2 = name2
  end

  def id_and_name
    "#{id}-#{name1}"
  end

  use_id_and_name_from_module :name2
end

model = Model.new(1, "TesT", "Test number TWO")
puts model.id_and_name

When I'm trying to do here is to override the class method id_and_name in class Model with a method dynamicly inserted by the IdAndNameRedefine-module. When that module is included, it creates a "static" method (really, a class method of the Model.class as I understands it) and when use_id_and_name_from_module is called, it creates a class method in Model which redefines the id_and_name to use whatever attribute of Model asked for.

My question is.. Are there any better way of doing this, or is this the "correct" way of doing it? I'm not really sure if I like the class_eval with takes a string where I need to escape values etc. to make this work.

Was it helpful?

Solution

You don't have to pass a string to class_eval. It can take a block instead. In fact, I can't think of a single occasion where I've had to pass a string to class_eval. So we can rewrite the ClassMethods module like so:

module ClassMethods
  def use_id_and_name_from_module(use_attribute)
    class_eval do 
      define_method(:id_and_name) {"#{id}-#{send(use_attribute).downcase}"}
    end
  end
end

But in this particular case, we're just telling self to class_eval, meaning we're already in that class's context. So it can actually be shortened to:

module ClassMethods
  def use_id_and_name_from_module(use_attribute)
    define_method(:id_and_name) {"#{id}-#{send(use_attribute).downcase}"}
  end
end

(I just wanted to show how class_eval really works, since you seemed most interested in that part.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top