rubymethodsclass-eval

class_eval issue Ruby


I am trying to use class_eval to create a method metaprogrammatically if the method that's called starts with "plus". However, I'm having trouble putting together the actual syntax of the class_eval

class Adder
  def initialize(my_num)
    @my_num = my_num
  end
  def my_num
    @my_num
  end
end
    def method_missing(meth, *args)
        my_meth = meth.to_s
        #puts my_meth[0, 4]
        if my_meth[0, 4] == "plus" then #/plus\d/ then
            num = my_meth.slice(/\d+/).to_i

            original_num = self.my_num.to_i
            my_sum = original_num + num
            class_eval{ eval{"def #{meth}; @my_int = #{my_sum} return @my_int end\n"}}
        end
        else
        super
    end


y = Adder.new(12)
puts y.plus10

When the plus10 (or whatever number) is called, the newly created method should add that number to the integer that's being called on, and produce the new sum.

Thanks


Solution

  • Try this:

    class Adder
      def initialize(my_num)
        @my_num = my_num
      end
      def my_num
        @my_num
      end
      def method_missing(meth, *args)
        my_meth = meth.to_s
          if my_meth[0, 4] == "plus" then
            num = my_meth.slice(/\d+/).to_i
            original_num = my_num
            my_sum = original_num + num
            self.class.class_eval do
              define_method "#{meth}" do
                my_int = my_sum
              end
            end
            send meth
          else
            super
          end
      end
    end
    y = Adder.new(12)
    puts y.plus10  # => 22
    

    UPDATE

    and this is slightly improved version:

    class Adder
      def initialize(num)
        @num = num
      end
    
      def method_missing(name, *args)
        name_string = name.to_s
        if /^plus(\d+)/ =~ name_string
          sum = Regexp.last_match(1).to_i + @num
          self.class.class_eval do
            define_method "#{name}" do
              sum
            end
          end
          send name
        else
         super
        end
      end
    end
    
    y = Adder.new(12)
    puts y.plus10  # => 22