Динамические методы в модуле? - PullRequest
1 голос
/ 02 августа 2010

У меня есть модуль под названием AB. Прямо сейчас это выглядит примерно так:

module AB
    extend self

    def some_method(hash)
        ....
    end

    ....
end

Мы используем это так: AB.some_method (: thing =>: что угодно,: etc => «Вы поняли идею»). Есть около полдюжины строк, которые пользователь должен передать, и я бы хотел превратить их в динамические методы, чтобы вместо AB.some_method (: thing =>: что угодно ...) они просто вызывали AB. что угодно (...) или AB :: что угодно (...). Я думал, что мог бы сделать это с method_missing, но я думаю, я не понимаю. Я сделал что-то вроде этого:

module AB
    def method_missing(name,*args)
        super unless THINGS.include?(name.to_s)
        ...
    end
end

Но я никогда не вхожу в этот метод, когда пытаюсь вызвать AB :: как угодно. Я думал о цикле по THINGS и использовании define_method, но я не был уверен, как определить методы, которые принимают аргументы.

Любая помощь приветствуется.

Ответы [ 2 ]

4 голосов
/ 03 августа 2010

Проблема в вашем втором примере кода заключается в том, что method_missing должен быть объявлен как self.method_missing. Следующие работы, как и ожидалось:

module AB
  THINGS = %w(whatever)

  def self.method_missing(name, *args)
    super unless THINGS.include?(name.to_s)
    "responding to #{name}"
  end
end

p AB.whatever    #=> "responding to whatever"
p AB.something   #=> NoMethodError
0 голосов
/ 02 августа 2010

Я думаю, что у вас есть два разных подхода, которые вы можете использовать, один - динамическое определение методов, другой - method_missing.Вот примеры обоих:

# first approach, define methods
class MyClassDefine
  def some_method args
    p args
  end

  [:foo,:bar].each do |name|
    define_method name do |args|
      # assume args is a hash, fix me
      some_method args.merge({:thing => name})
    end
  end
end

# second approach, use method_missing
class MyClassMissing
    def some_method args
    p args
  end

  def method_missing name, args
    super unless [:foo, :bar].include? name
    # again, assuming argument is a hash
    some_method args.merge(:thing => name)
  end
end

mcd = MyClassDefine.new
mcd.foo :etc => 'you get idea'
#=> {:etc=>"you get idea", :thing=>:foo}

mcm = MyClassMissing.new
mcm.foo :etc => 'you get idea'
#=> {:etc=>"you get idea", :thing=>:foo}

Здесь осталось лишь рассмотреть случаи, когда в качестве аргумента передаются методы, отличные от хэша.

...