NoMethodError in ruby module - ruby

module Add
def addition
sum=1+2
puts sum
end
a=Add.addition
Can anyone tell me what I'm missing and why I am getting this error->
undefined method `addition' for Add:Module (NoMethodError)

You are confusing class methods and instance methods. Your definition:
module Add
def addition
...
end
end
defines methods on instances of Add whereas you called a method on the module Add. If you want to define a class/module method, you need to define like:
module Add
def self.addition
...
end
end

If you want to be able to call it directly, define it as a directly accessible method:
def self.addition
# ...
end
Or you can always rework this using:
module Add
# ...(methods)...
extend self
end
Where that will automatically promote all mixin-type methods as being directly accessible.
You can also tag them more selectively like this:
module Add
def addition
# ...
end
module_method :addition
end
That method is then available either as Add.addition or if some other module or class calls include Add.

Related

Why can't Ruby find a method declared right above?

I have a simple file called helper.rb that looks like this:
module MyHelper
def initialize_helper
puts "Initialized"
end
initialize_helper()
end
And another simple file like this:
require_relative 'helper.rb'
include MyHelper
puts "Done"
But when I run this second file, it results in this error:
helper.rb:6:in `<module:MyHelper>': undefined method `initialize_helper' for MyHelper:Module (NoMethodError)
Why can't Ruby find this initializeHelper method defined directly above where I'm calling it???
Try
def self.initialize_helper
puts "Initialized"
end
Without the self., you're declaring an instance method intended to be called on objects, not the module itself. So, for instance, your original code is intended to be used like
module MyHelper
def initialize_helper
puts "Initialized"
end
end
class Foo
include MyHelper
end
Foo.new.initialize_helper
But if you want to call it on the module, you need to have self. in front of it to make it a method on the module itself.

calling module method into another module in Ruby

FIle module.rb
module CardExpiry
def check_expiry value
return true
end
end
file include.rb
#raise File.dirname(__FILE__).inspect
require "#{File.dirname(__FILE__)}/module.rb"
module Include
include CardExpiry
def self.function
raise (check_expiry 1203).inspect
end
end
calling
Include::function
is this possible ?
Error trigger when calling :
`function': undefined method `check_expiry' for Include:Module (NoMethodError)
You stumbled over the difference of include and extend.
include makes the method in the included module available to instances of your class
extend makes the methods in the included module available in the class
When defining a method with self.method_name and you access self within that method, self is bound to the current class.
check_expiry, however, is included and thus only available on the instance side.
To fix the problem either extend CardExpiry, or make check_expiry a class method.
I've looked at your problem in a bit more detail, and the issue is your module.rb file:
module CardExpiry
def self.check_expiry value
return true
end
end
First, there was an end missing from the file - both def and module need to be closed.
Second, the magical self. in the def line turns the method into a pseudo-global function - this answer explains it better than I can.
Furthermore, to call the method, you need to use:
raise (CardExpiry::check_expiry 1203).inspect

Using super with class_eval

I have an app that includes modules into core Classes for adding client customizations.
I'm finding that class_eval is a good way to override methods in the core Class, but sometimes I would like to avoid re-writing the entire method, and just defer to the original method.
For example, if I have a method called account_balance, it would be nice to do something like this in my module (i.e. the module that gets included into the Class):
module CustomClient
def self.included base
base.class_eval do
def account_balance
send_alert_email if balance < min
super # Then this would just defer the rest of the logic defined in the original class
end
end
end
end
But using class_eval seems to take the super method out of the lookup path.
Does anyone know how to work around this?
Thanks!
I think there are several ways to do what you're wanting to do. One is to open the class and alias the old implementation:
class MyClass
def method1
1
end
end
class MyClass
alias_method :old_method1, :method1
def method1
old_method1 + 1
end
end
MyClass.new.method1
=> 2
This is a form of monkey patching, so probably best to make use of the idiom in moderation. Also, sometimes what is wanted is a separate helper method that holds the common functionality.
EDIT: See Jörg W Mittag's answer for a more comprehensive set of options.
I'm finding that instance_eval is a good way to override methods in the core Class,
You are not overriding. You are overwriting aka monkeypatching.
but sometimes I would like to avoid re-writing the entire method, and just defer to the original method.
You can't defer to the original method. There is no original method. You overwrote it.
But using instance_eval seems to take the super method out of the lookup path.
There is no inheritance in your example. super doesn't even come into play.
See this answer for possible solutions and alternatives: When monkey patching a method, can you call the overridden method from the new implementation?
As you say, alias_method must be used carefully. Given this contrived example :
module CustomClient
...
host.class_eval do
alias :old_account_balance :account_balance
def account_balance ...
old_account_balance
end
...
class CoreClass
def old_account_balance ... defined here or in a superclass or
in another included module
def account_balance
# some new stuff ...
old_account_balance # some old stuff ...
end
include CustomClient
end
you end up with an infinite loop because, after alias, old_account_balance is a copy of account_balance, which now calls itself :
$ ruby -w t4.rb
t4.rb:21: warning: method redefined; discarding old old_account_balance
t4.rb:2: warning: previous definition of old_account_balance was here
[ output of puts removed ]
t4.rb:6: stack level too deep (SystemStackError)
[from the Pickaxe] The problem with this technique [alias_method] is that you’re relying on there not being an existing method called old_xxx. A better alternative is to make use of method objects, which are effectively anonymous.
Having said that, if you own the source code, a simple alias is good enough. But for a more general case, i'll use Jörg's Method Wrapping technique.
class CoreClass
def account_balance
puts 'CoreClass#account_balance, stuff deferred to the original method.'
end
end
module CustomClient
def self.included host
#is_defined_account_balance = host.new.respond_to? :account_balance
puts "is_defined_account_balance=#{#is_defined_account_balance}"
# pass this flag from CustomClient to host :
host.instance_variable_set(:#is_defined_account_balance,
#is_defined_account_balance)
host.class_eval do
old_account_balance = instance_method(:account_balance) if
#is_defined_account_balance
define_method(:account_balance) do |*args|
puts 'CustomClient#account_balance, additional stuff'
# like super :
old_account_balance.bind(self).call(*args) if
self.class.instance_variable_get(:#is_defined_account_balance)
end
end
end
end
class CoreClass
include CustomClient
end
print 'CoreClass.new.account_balance : '
CoreClass.new.account_balance
Output :
$ ruby -w t5.rb
is_defined_account_balance=true
CoreClass.new.account_balance : CustomClient#account_balance, additional stuff
CoreClass#account_balance, stuff deferred to the original method.
Why not a class variable ##is_defined_account_balance ? [from the Pickaxe] The module or class definition containing the include gains access to the constants, class variables, and instance methods of the module it includes.
It would avoid passing it from CustomClient to host and simplify the test :
old_account_balance if ##is_defined_account_balance # = super
But some dislike class variables as much as global variables.
[from the Pickaxe] The method Object#instance_eval lets you set self to be some arbitrary object, evaluates the code in a block with, and then resets self.
module CustomClient
def self.included base
base.instance_eval do
puts "about to def account_balance in #{self}"
def account_balance
super
end
end
end
end
class Client
include CustomClient #=> about to def account_balance in Client
end
As you can see, def account_balance is evaluated in the context of class Client, the host class which includes the module, hence account_balance becomes a singleton method (aka class method) of Client :
print 'Client.singleton_methods : '
p Client.singleton_methods #=> Client.singleton_methods : [:account_balance]
Client.new.account_balance won't work because it's not an instance method.
"I have an app that includes modules into core Classes"
As you don't give much details, I have imagined the following infrastructure :
class SuperClient
def account_balance
puts 'SuperClient#account_balance'
end
end
class Client < SuperClient
include CustomClient
end
Now replace instance_eval by class_eval. [from the Pickaxe] class_eval sets things up as if you were in the body of a class definition, so method definitions will define instance methods.
module CustomClient
...
base.class_eval do
...
print 'Client.new.account_balance : '
Client.new.account_balance
Output :
#=> from include CustomClient :
about to def account_balance in Client #=> as class Client, in the body of Client
Client.singleton_methods : []
Client.new.account_balance : SuperClient#account_balance #=> from super
"But using instance_eval seems to take the super method out of the lookup path."
super has worked. The problem was instance_eval.

Modules in Ruby

Please explain why self is used in def self.included (klass) below.
module A
def self.included(klass)
puts "A -> #{klass}"
puts A
puts self
end
end
class X
include A
end
By writing def self.included you are defining a method that is part of the singleton class of module A. In general, singleton methods can only be called by doing A.included() but this singleton method has a special name included that causes the Ruby interpreter to call when the module gets included in to a class.
A normal method in a module (defined with def foo) can only be called if the module gets included in to something else.
This is how you declare a module method that can be called directly. Normally methods defined within a module are only usable if another class or module includes them, like class X in this example.
module Example
def self.can_be_called
true
end
def must_be_included
true
end
end
In this case you will see these results:
Example.can_be_called
# => true
Example.must_be_included
# => NoMethodError: undefined method `must_be_included' for Example:Module
The self declared methods are not merged in to the classes or modules that include it, though. They are special-purpose that way.

How can I get around the lack of module inheritance in Ruby?

I'm trying to create a component system in Ruby using the observer pattern. Components must be defined as modules because they exist only to be mixed in to a ComponentContainer. But there are certain methods that Components have, which I'd ideally like to define in some kind of base class, but I can't do that since they're modules.
Here's what I'd like to do:
module Component
def self.on(event, &block)
#definition..
end
def self.fire(event)
#pass event to subscribers
end
end
module FooComponent < Component
on :foo_event do |param1, param2|
#...
end
end
The different types of Components use the on and fire methods, but they can't inherit them, because modules can't have parents. What should I do? Is this not ruby-like?
I could get this to work by making Component and FooComponent classes, but then I can't mix them into a ComponentContainer using extend or include.
A clean way to do this is to abstract away the use of extend using the Module#included hook method. This method is called on a module with a reference to the base that is including it. What this code does is creates a Component module that automatically extends the base with the desired methods:
module Component
def self.included(base)
base.extend Methods
end
module Methods
def on(event, &block)
# ...
end
def fire(event)
# ...
end
end
end
module FooComponent
include Component
on :foo_event do |param1, param2|
# ...
end
end
What if you created a separate module called BaseComponent that defined the basic methods all component modules should have, and then in your custom components, include that BaseComponent.
Then, you should still be able to mixin those custom components into your ComponentContainer class.
You can extend the Component's methods into your "child"-module:
module Component
extend self # (only if you also want to allow calling via Component.on like in the original example)
def on(event, &block)
#definition..
end
def fire(event)
#pass event to subscribers
end
end
module FooComponent
extend Component
on :foo_event do |param1, param2|
#...
end
end

Resources