0

I'm currently doing second week assignment 1 from this metaprogramming tutorial and have some problems with sending block for using it with define_method. The program simply doesn't see the block, returning false when I call block_given? even though I provide a block.

Here's the file that sends the block:

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

And the file that receives:

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
3
  • If the block is given, why are you defining a method? And if that's what you're supposed to do, what would be the result of calling to_sym on a splatted array? Commented Oct 15, 2015 at 17:15
  • @DaveNewton I can't even receive the block, so I couldn't edit that part of program. I send the only argument when passing a block and it's the method name Commented Oct 15, 2015 at 17:21
  • This has nothing to do with Rails, so you should remove the Rails tag. Commented Oct 15, 2015 at 19:34

2 Answers 2

1

I believe (but haven't checked) block_given? refers to a block being passed to the method defined by the closest lexically enclosing method definition, i.e. def, and does not work inside methods defined with define_method.

I know for a fact that yield only yields to a block being passed to the method defined by the closest lexically enclosing method definition, i.e. def, and does not yield from a block (which, after all, define_method is, it's just a method like any other method which takes a block, and just like any other taking a block, yield yields to the block of the method, not some other block).

It's kind of strange to combine yield and block_given? with explicitly named block-Procs anyway. If you have the name, there is no need for anonymity, you can just say

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

Or did you mean to pass the block to define_method to be used as the implementation of the method? Then it would be

if block
  define_method(args.to_sym, &block)
end
Sign up to request clarification or add additional context in comments.

Comments

0

Not sure if you can pass arguments and block to something that just gets defined. read this

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

Instead of define_method :can do |*args, &block| try the explicit def can(*args, &block)

It's weird to do it like that anyway..

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.