1

I'm trying to implement a code that automatically creates a method if it fits a certain keyword, with the help of method_missing.

This works so far:

class Add
    def initialize()
        @result = ""
    end


    def output()
        puts @result
     end

    def method_missing(name, *args)
        if name.to_s.include? "add"
            code = "def #{name}(*args)"\
            "@result << args.to_s;"\
            "end"
            instance_eval(code)
        end
    end
end

 a = Add.new

 a.add_1("1") #created but not called
 a.add_2("2") #created but not called
 a.add_2("2") #called
 a.output #I want it to return 122, but it returns only 2 once.

I want the method to run once it is created. This does not happen, as the method has to be called again before the code in it is executed.

How would I implement this?

sawa
  • 165,429
  • 45
  • 277
  • 381
mre
  • 137
  • 11

3 Answers3

2

As a starting point, perhaps something like this.

class Add
  def initialize
    @result = ""
  end

  def output
    @result
  end

  def method_missing(name,arg)
    if name.to_s.include? 'add'
      @result << arg
      arg
    else
      super
    end
  end
end

a = Add.new

p a.add '1'  # "1"
p a.add '2'  # "2"
p a.add '2'  # "2"
p a.output   # "122"

p a.minus '1' #NoMethodError
Sagar Pandya
  • 9,323
  • 2
  • 24
  • 35
  • Thanks for your answer, but I simplified the code to make it easier to read. My actual code needs arguments. – mre Jan 27 '18 at 23:09
  • @maRei Write `arg` if it's one argument and use that instead of `n` i.e. `@result << arg`. Or use array notation on `arg` if you have more than one argument. – Sagar Pandya Jan 27 '18 at 23:12
  • @maRei updated answer. Also see [super](https://stackoverflow.com/q/4632224/5101493) – Sagar Pandya Jan 27 '18 at 23:18
1

The below code should achieve what you want:

class Add
  def initialize
    @result = ""
  end

  def output
    @result
  end

  def method_missing(name, *args, &block)
    if name.to_s.include?("add")
      self.class.send(:define_method, name) do |args|
        @result << args.to_s
      end

      self.send(name, *args)
    end
  end
end

However, within method_missing, you can simply just do

def method_missing(name, *args, &block)
  if name.include? "add"
    @result << args.join(" ")
  end
end

This should still work

Adim
  • 1,716
  • 12
  • 13
1
class Add

    def initialize
        @result = ''
    end

    def output
      puts @result
    end

    def method_missing(name, *args)
        if name =~ /add/
          Add.instance_eval do
            define_method(name) do |args|
              @result << args[0]
            end
          end
          send(name, args)
        else
          super
        end
    end
end
Sachin Singh
  • 7,107
  • 6
  • 40
  • 80