Is it possible to have methods inside methods?

I have a method inside a method. The internal method depends on the variable loop that is being executed. It is a bad idea?

+69
methods ruby
01 Feb '11 at 15:07
source share
6 answers

UPDATE. Since this answer seems to have gained some interest recently, I would like to point out that there is a discussion on the tracker issue with the Ruby problem in order to remove the function being discussed here, namely, to prohibit the definition of methods inside the method body .




No, Ruby has no nested methods.

You can do something like this:

class Test1 def meth1 def meth2 puts "Yay" end meth2 end end Test1.new.meth1 

But this is not a nested method. I repeat: Ruby has no nested methods.

What it is is the definition of a dynamic method. When you start meth1 , the body of meth1 will be executed. The body simply defines a method called meth2 , so after running meth1 once, you can call meth2 .

But where is meth2 defined? Well, this is not explicitly defined as a nested method, since there are no nested methods in Ruby. It is defined as an instance method of Test1 :

 Test1.new.meth2 # Yay 

In addition, it will be redefined each time meth1 started:

 Test1.new.meth1 # Yay Test1.new.meth1. # test1.rb:3: warning: method redefined; discarding old meth2 # test1.rb:3: warning: previous definition of meth2 was here # Yay 

In short: no, Ruby does not support nested methods.

Also note that in Ruby, method bodies cannot be private, only blocking bodies can. This pretty much eliminates the basic use of nested methods, because even if Ruby supports nested methods, you cannot use external method variables in a nested method.




UPDATE CONTINUED: at a later stage, this syntax could be reused to add nested methods in Ruby that will behave as I described: they will be bound to their containing method, i.e. invisible and inaccessible outside their containing method body. And, perhaps, they will have access to their substantive lexical sphere. However, if you read the discussion I linked above, you may notice that matz is highly dependent on nested methods (but still to remove nested method definitions).

+134
Feb 01 '11 at 16:27
source share

This is actually possible. You can use procs / lambda for this.

 def test(value) inner = ->() { value * value } inner.call() end 
+8
Mar 02 '16 at 20:41
source share

No, no, Ruby has nested methods. Check this:

 def outer_method(arg) outer_variable = "y" inner_method = lambda { puts arg puts outer_variable } inner_method[] end outer_method "x" # prints "x", "y" 
+4
Jan 05 '13 at 19:55
source share

You can do something like this

 module Methods define_method :outer do outer_var = 1 define_method :inner do puts "defining inner" inner_var = outer_var +1 end outer_var end extend self end Methods.outer #=> defining inner #=> 1 Methods.inner #=> 2 

This is useful when you are doing things like DSL recording that require sharing the area between methods. But otherwise, it’s much better for you to do something else, because, as the other answers say, inner redefined whenever outer is called. If you want this behavior, and sometimes you can, this is a good way to get it.

+1
Jun 15 '14 at 21:13
source share

Ruby's way is to fake it with intricate hacks that will make some users wonder: β€œHow does it even work in fuck?”, While the less curious just remembers the syntax needed to use this thing. If you've ever used Rake or Rails, you've seen such things.

Here's a hack:

 def mlet(name,func) my_class = (Class.new do def initialize(name,func) @name=name @func=func end def method_missing(methname, *args) puts "method_missing called on #{methname}" if methname == @name puts "Calling function #{@func}" @func.call(*args) else raise NoMethodError.new "Undefined method `#{methname}' in mlet" end end end) yield my_class.new(name,func) end 

What this means is to define a top-level method that creates the class and passes it to the block. The class uses method_missing to pretend that it has a method with the name you selected. It "implements" the method by invoking the lambda you must provide. By naming the object with a single-letter name, you can minimize the amount of additional input required (which is the same as what Rails does in schema.rb ). mlet is named after the general form of Lisp flet , except when f means "function", m means "method".

You use it as follows:

 def outer mlet :inner, ->(x) { x*2 } do |c| c.inner 12 end end 

You can create a similar device that allows you to define many internal functions without additional nesting, but this requires an even more ugly hack of the kind that you can find in the implementation of Rake or Rspec. Finding out how rspec let! will give you a long way to creating such a terrible abomination.

0
May 13 '17 at 7:21
source share

: - D

Ruby has nested methods, only they don’t do what you expect from them

 1.9.3p484 :001 > def kme; 'kme'; def foo; 'foo'; end; end => nil 1.9.3p484 :003 > self.methods.include? :kme => true 1.9.3p484 :004 > self.methods.include? :foo => false 1.9.3p484 :005 > kme => nil 1.9.3p484 :006 > self.methods.include? :foo => true 1.9.3p484 :007 > foo => "foo" 
-one
Jan 31 '14 at 14:29
source share



All Articles