0

When is it good practice to have methods inside methods?

Here is a bad use example of methods in methods:

class SomeClass
  def self.fooify(a, b, c)
    def self.bar?(a)
      (a % 3) == 0
    end

    return a if self.bar?(a)
    return b + c
  end
end

Bonus points - how would you stub bar?

xxjjnn
  • 14,591
  • 19
  • 61
  • 94
  • 1
    Have you had a look at http://stackoverflow.com/questions/4864191/is-it-possible-to-have-methods-inside-methods – Bala Jul 03 '14 at 09:30
  • Aha, didn't see. Thanks – xxjjnn Jul 03 '14 at 10:46
  • In my opinion, lambdas and procs are created to be throw-away piece of code. `bar = ->(a){ (a%3)==0 }` and in the if: `return a if bar.(a)` (or `bar.call()`). Or you can just do: `return a if ->(a){ (a%3) == 0 }.(a)`. Taking into account that `a, b, c` are local in the `self.fooify`, you don't have to specify arguments for lambdas, so it may be like this: `return a if ->{(a%3) == 0)}.()` ps. This was for answer for stub bar, but I am not sure if I understood it correctly. – Darek Nędza Jul 03 '14 at 11:39

1 Answers1

2

You can use method definition within methods, so those inner methods are defined when parent method is called:

class A
  def self.define_foo
    def foo
      :foo
    end
  end
end

a = A.new
a.foo      #=> undefined method foo
A.define_foo
a.foo      #=> :foo

This however is rather rare, as methods defined that way has no access to params passed to the parent. Much more useful is to use define_method which carries binding the method has been created in:

class A
  def self.define_sth(sth)
    define_method sth do 
      sth
    end
  end
end

a = A.new
a.bar      #=> undefined method bar
A.define_sth(:bar)
a.bar      #=> :bar

This is being used for example by rails when defining associations. When you call Parent.has_one :child, method has_one calls define_method to create child, child=, build_child and create_child methods.

As for stubbing, methods created that way are no different from any other methods, you just stub them as usual.

BroiSatse
  • 44,031
  • 8
  • 61
  • 86
  • Thanks! There is a bug, define_method sth should be define_method bar I think. Editing failed =( – xxjjnn Jul 03 '14 at 11:00
  • 1
    @ClothSword - I've rejected this edit, as this would give you `undefined method bar`. `define_method` is just a regular method. The argument passed is the name of the new method, in this case the method name is passed as an argument to the parent method. – BroiSatse Jul 03 '14 at 11:07