添加单例方法和访问实例变量 - 未定义

时间:2012-12-29 00:52:36

标签: ruby metaprogramming

好的,所以我试图solve step 2 in this puzzle,我遇到了麻烦。我的问题是在尝试访问实例变量(@name)或甚至调用类(name getter)上的方法时,ruby告诉我未定义的局部变量。对我来说,这似乎是一个范围问题。当动作名称和块作为参数给出时,问题就出现了。单例成功添加到实例变量我相信但是调用它,ruby告诉我“name”是一个未定义的局部变量。有任何想法吗?知道如何更有效地以其他方式模拟功能吗?

这是我的 Dog.rb 类:

class Dog
  MSGS = {:dance => 'is dancing', :poo => 'is a smelly doggy!', :laugh => 'finds this hilarious!'}
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def can(*actions)
    actions.each do |action|
      self.instance_eval do
        if block_given?
          define_singleton_method action do
            yield
          end
        else
          define_singleton_method(action) do
            name + ' ' + MSGS[action]
          end
        end
      end
    end
  end

  def method_missing(method_name,*args)
    name + " can't " + method_name.to_s
  end
end

这是拼图中的Dog_Game.rb:

require './dog'

lassie, fido, stimpy = %w[Lassie Fido Stimpy].collect{|name| Dog.new(name)}
lassie.can :dance, :poo, :laugh
fido.can(:poo){"#{name} is just wayyyy too smelly."} #name here is the source of the problem
stimpy.can :dance
stimpy.can(:cry){"#{name} cried AHHHH"}

p lassie.dance
p lassie.poo
p lassie.laugh
puts
p fido.dance
p fido.poo
p fido.laugh
puts
p stimpy.dance
p stimpy.poo
p stimpy.laugh
p stimpy.cry

2 个答案:

答案 0 :(得分:1)

将块传递给define_singleton_method,如果它是你想要的方法:

def can(*actions, &block)
  actions.each do |action|
    if block_given?
      define_singleton_method(action, block)
    else
      define_singleton_method(action) { "#{name} #{MSGS[action]}" }
    end
  end
end

这会输出您的期望。

(Delta首先将stimpy用于证明cry不在其他实例上,并在每个实例上调用cry。) < / p>

Stimpy is dancing
Stimpy can't poo
Stimpy can't laugh
Stimpy cried AHHHH

Lassie is dancing
Lassie is a smelly doggy!
Lassie finds this hilarious!
Lassie can't cry

Fido can't dance
Fido is just wayyyy too smelly.
Fido can't laugh
Fido can't cry

答案 1 :(得分:1)

1:   你创造了一个丑陋的方法:

self.instance_eval {} == define_singleton_method(callback,&amp; block)

你应该使用一个而不是两个!

2: 因为使用

时范围已更改
self.instance_eval do 
   #coding
end

你不能使用varible:name,所以只需使用define_singleton_method!

抱歉,我的英语很差!