define_method 没有接收块作为参数 ruby

define_method doesn't receive block as a parameter ruby

我目前正在做 this metaprogramming tutorial 的第二周作业 1 并且在发送块以将其与 define_method 一起使用时遇到一些问题。程序根本看不到该块,当我调用 block_given 时返回 false?尽管我提供了一个块。

这是发送块的文件:

require_relative 'dog'

lassie, fido, stimpy = %w[Lassie Fido Stimpy].collect{|name| Dog.new(name)}
lassie.can :dance, :poo, :laugh
fido.can :poo
stimpy.can :dance

stimpy.can(:cry){"#{name} cried AHHHH"} # the block that I can't receive

puts lassie.name

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 # method call

以及接收到的文件:

Dog = Class.new do
    MESSAGES = { dance: "is dancing", poo: "is a smelly doggy!", laugh: "finds this hilarious" }

    define_method :initialize do |name|
    instance_variable_set(:@name, name)
    end

    define_method :name do
    instance_variable_get :@name
    end

    define_method :can do |*args, &block|
    puts block_given? # false 
    if block_given?
        define_method args.to_sym do
        yield
        end
    else
        args.each do |ability|
        self.class.instance_eval do
            define_method "#{ability}".to_sym do
            @name + " " + MESSAGES[ability]
            end
        end
        end
    end
    end

    define_method :method_missing do |arg|
    puts "#{@name} doesn't understand #{arg}"
    end
end

不确定您是否可以传递参数并阻止刚刚定义的内容。 read this

define_method(symbol, method) → symbol
define_method(symbol) { block } → symbol 

而不是 define_method :can do |*args, &block| 尝试显式 def can(*args, &block)

反正这样做很奇怪..

I believe (但还没有检查) block_given? 指的是一个块被传递给由最接近的词法封闭方法定义定义的方法,即 def,并且 不会 在使用 define_method 定义的方法中工作。

知道一个事实,即yield只产生一个块被传递给最接近词法封闭方法定义定义的方法,即def,并且 不会 从一个块中产生(毕竟, define_method 是,它只是一种方法,就像任何其他采用块的方法一样,就像任何其他方法一样采取一个块,yield 屈服于方法的块,而不是其他块)。

无论如何,将 yieldblock_given? 与显式命名的块 Proc 结合起来有点奇怪。有名字就不用匿名了,直接说

if block
  define_method(args.to_sym) do block.() end
end

或者您的意思是将块传递给 define_method 以用作方法的实现?那么就是

if block
  define_method(args.to_sym, &block)
end