Using a mixin method inside an instance method - ruby

Why does this not work:
class Myclass
include HTTParty
def dosomething
base_uri("some_url")
end
end
The base_uri method is a class method of HTTParty. It works fine if I call it from my class, outside of any instance methods, or from a class method, but when try to call it from an instance method I get "NoMethodError: undefined method `base_uri' for #"
Why? Shouldn't there be some way to refer to the HTTParty class from within my instance method so I can call that HTTParty class method?
I could change it to a class method, but then every instance of my class would have the same value for base_uri.

Why doesn't it work? Because that's not how Ruby works. Similarly, this doesn't work:
class Foo
def self.utility_method; ...; end
def inst_method
utility_method # Error! This instance has no method named "utility_method"
end
end
You could work around this by just doing:
class MyClass
include HTTParty
def dosomething
HTTParty.base_uri("some_url")
end
end
Let's look deeper at how method lookup works with modules. First, some code:
module M
def self.m1; end
def m2; end
end
class Foo
include M
end
p Foo.methods - Object.methods #=> []
p Foo.new.methods - Object.methods #=> [:m2]
class Bar
extend M
end
p Bar.methods - Object.methods #=> [:m2]
p Bar.new.methods - Object.methods #=> []
class Jim; end
j = Jim.new
j.extend M
p j.methods - Object.methods #=> [:m2]
As we see, you can use extend to cause an object (a class or instance) to use the 'instance' methods of a module for the object itself (instead of instances), but you cannot cause 'class methods' of the module to be inherited by anything. The closest you can get is this idiom:
module M2
module ClassMethods
def m1; end # Define as an instance method of this sub-module!
end
extend ClassMethods # Make all methods on the submodule also my own
def self.included(k)
k.extend(ClassMethods) # When included in a class, extend that class with
end # my special class methods
def m2; end
end
class Foo
include M2
end
p Foo.methods - Object.methods #=> [:m1]
p Foo.new.methods - Object.methods #=> [:m2]
If the HTTParty module used the above pattern, and so made the base_uri method available on your MyClass, then you could do this:
class MyClass
include HTTParty
def dosomething
self.class.base_uri("some_url")
end
end
...but that's more work than just directly referencing the module owning the method.
Finally, because this might help you, here's a diagram I made some years ago. (It's missing some core objects from Ruby 1.9, like BasicObject, but is otherwise still applicable. Click for a PDF version. Note #3 from the diagram is particularly applicable.)
(source: phrogz.net)

class Myclass
include HTTParty
def dosomething
Myclass.base_uri("some_url")
end
end

Related

Behaviour of instance_eval

My understanding of instance_eval was that if I have module M then the following were equivalent:
module M
def foo
:foo
end
end
class C
class << self
include M
end
end
puts C.foo
equivalent to:
module M
def foo
:foo
end
end
class C
end
C.instance_eval do
include M
end
puts C.foo
However, the first example prints :foo and the second throws a NoMethodError? (Ruby 2.3.0)
In both cases above, if I had replaced:
include M
with:
def foo
:foo
end
ie directly defining the method rather than including a module then both cases would have resulted in a C.foo method being defined. Should I be surprised at this difference between include and defining the method directly?
Or does it ever even make sense to call include within the context of instance_eval? Should it only ever be called within a class_eval?
In each of these cases, what object are you calling include on? In your first example, you're calling include on C's singleton class:
class C
class << self
p self == C.singleton_class
include M
end
end
# => true
p C.foo
# => :foo
...so your include line is equivalent to C.singleton_class.include(M).
In your second example, however, you're calling include on C itself:
class C
end
C.instance_eval do
p self == C
include M
end
# => true
p C.foo
# => NoMethodError: undefined method `foo' for C:Class
p C.new.foo
# => :foo
...so you're doing the equivalent of C.include(M), which is the same as:
class C
p self == C
include M
end
# => true
p C.new.foo
# => :foo
What would work like you want would be to call instance_eval on C's singleton class:
class D
end
D.singleton_class.instance_eval do
p self == D.singleton_class
include M
end
# => true
p D.foo
# => :foo
Module#class_eval() is very different from Object#instance_eval(). The instance_eval() only changes self, while class_eval() changes both self and the current class.
Unlike in your example, you can alter class_instance vars using instance_eval though, because they are in the object scope as MyClass is a singleton instance of class Class.
class MyClass
#class_instance_var = 100
##class_var = 100
def self.disp
#class_instance_var
end
def self.class_var
##class_var
end
def some_inst_method
12
end
end
MyClass.instance_eval do
#class_instance_var = 500
def self.cls_method
##class_var = 200
'Class method added'
end
def inst_method
:inst
end
end
MyClass.disp
#=> 500
MyClass.cls_method
#=> 'Class method added'
MyClass.class_var
#=> 100
MyClass.new.inst_method
# undefined method `inst_method' for #<MyClass:0x0055d8e4baf320>
In simple language.
If you have a look in the upper class defn code as an interpreter, you notice that there are two scopes class scope and object scope. class vars and instance methods are accessible from object scope and does not fall under jurisdiction of instance_eval() so it skips such codes.
Why? because, as the name suggests, its supposed to alter the Class's instance(MyClass)'s properties not other object's properties like MyClass's any object's properties. Also, class variables don’t really belong to classes—they belong to class hierarchies.
If you want to open an object that is not a class, then you can
safely use instance_eval(). But, if you want to open a class definition and define methods with def or include some module, then class_eval() should be your pick.
By changing the current class, class_eval() effectively reopens the class, just like the class keyword does. And, this is what you are trying to achieve in this question.
MyClass.class_eval do
def inst_method
:inst
end
end
MyClass.new.inst_method
#=> :inst

ruby private class method helper

Hi I am trying to create a helper for mass defining ruby methods as private class methods. In general one can define a method as a private class method by using private_class_method key work. But I would like to create a helper in the following style:
class Person
define_private_class_methods do
def method_one
end
def method_two
end
end
end
The way I planned to dynamically define this is in the following way, which is not at all working:
class Object
def self.define_private_class_methods &block
instance_eval do
private
&block
end
end
end
any ideas where I might be going wrong?
$ cat /tmp/a.rb
class Object
def self.define_private_class_methods &cb
existing = methods(false)
instance_eval &cb
(methods(false) - existing).each { |m| singleton_class.send :private, m }
end
end
class Person
define_private_class_methods do
def method_one
puts "¡Yay!"
end
end
end
Person.send(:method_one)
Person.public_send(:method_one)
$ ruby /tmp/a.rb
¡Yay!
/tmp/a.rb:18:in `public_send': private method `method_one'
called for Person:Class (NoMethodError)
Did you mean? method
from /tmp/a.rb:18:in `<main>'
Please note, that it’s hard to understand, what you are trying to achieve and possibly there is better, cleaner and more robust way to achieve this functionality.
Similar, yet different (and semantically more correct IMHO) to #mudasobwa's answer:
class Class
def define_private_class_methods(&definition)
class_methods_prior = methods
singleton_class.class_eval(&definition)
(methods - class_methods_prior).each do |method_name|
private_class_method method_name
end
end
end
class Person
define_private_class_methods do
def method_one
1
end
end
end
Person.method_one # !> NoMethodError: private method `method_one' called for Person:Class
Person.send :method_one # => 1
Note: It will not change the accessibility of a class method that you are currently overwriting.
You could define the methods in an anonymous module by passing the block to Module.new, make each instance method in the module private and extend your class with the module:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each { |m| mod.send(:private, m) }
extend(mod)
end
end
This has the desired result:
class Person
define_private_class_methods do
def method_one
123
end
end
end
Person.send(:method_one)
#=> 123
Person.method_one
#=> private method `method_one' called for Person:Class (NoMethodError)
... and as a bonus, it also gives you a super method: (probably of little use)
class Person
def self.method_one
super * 2
end
end
Person.method_one
#=> 456
Of course, you don't have to use extend, you could just as well define the methods manually:
class Class
def define_private_class_methods(&block)
mod = Module.new(&block)
mod.instance_methods.each do |m|
define_singleton_method(m, mod.instance_method(m))
private_class_method(m)
end
end
end
The essential component is the anonymous module, so you have a (temporary) container to define the methods in.

Ruby: DRY class methods calling Singleton instance methods [duplicate]

This question already has answers here:
Calling a method of a Ruby Singleton without the reference of 'instance'
(5 answers)
Closed 7 years ago.
I have the a Singleton class ExchangeRegistry which keeps all the Exchange objects.
Instead of needing to call:
ExchangeRegistry.instance.exchanges
I want to be able to use:
ExchangeRegistry.exchanges
This works, but I'm not happy with the repetition:
require 'singleton'
# Ensure an Exchange is only created once
class ExchangeRegistry
include Singleton
# Class Methods ###### Here be duplication and dragons
def self.exchanges
instance.exchanges
end
def self.get(exchange)
instance.get(exchange)
end
# Instance Methods
attr_reader :exchanges
def initialize
#exchanges = {} # Stores every Exchange created
end
def get(exchange)
#exchanges[Exchange.to_sym exchange] ||= Exchange.create(exchange)
end
end
I'm not happy with the duplication in the class methods.
I've tried using Forwardable and SimpleDelegator but can't seem to get this to DRY out. (Most examples out there are not for class methods but for instance methods)
The forwardable module will do this. Since you are forwarding class methods, you have to open up the eigenclass and define the forwarding there:
require 'forwardable'
require 'singleton'
class Foo
include Singleton
class << self
extend Forwardable
def_delegators :instance, :foo, :bar
end
def foo
'foo'
end
def bar
'bar'
end
end
p Foo.foo # => "foo"
p Foo.bar # => "bar"
The accepted answer is clever, but seems needlessly complex (not to mention to performance penalty of method_missing.
The usual way to solve this is to just assign the instance to a constant.
class ExchangeRegistrySingleton
include Singleton
# ...
end
ExchangeRegistry = ExchangeRegistrySingleton.instance
You can take advantage of method_missing hook and delegate the method calls to instance.
require 'singleton'
class ExchangeRegistry
include Singleton
# Missing methods will be delegated to `instance` if an implementation is available.
# Else `NoMethodError` will be raised via call to `super`
def self.method_missing method_name, *args
if instance.respond_to? method_name
puts "** Defining new method: '#{method_name}'"
(class << self; self; end).instance_eval do
define_method(method_name) do |*args|
instance.send(method_name, *args)
end
end
instance.send(method_name, *args)
else
super
end
end
attr_reader :exchanges
def initialize
#exchanges = {} # Stores every Exchange created
end
def get(exchange)
#exchanges[Exchange.to_sym exchange] ||= Exchange.create(exchange)
end
end
# By default, there is no class method - `exchanges`
p ExchangeRegistry.singleton_methods.grep(/exchanges/)
#=> []
p ExchangeRegistry.exchanges
#=> ** Defining new method: 'exchanges'
#=> {}
# After first call to `exchanges`, a new class method is now available
# Future calls will not hit `method_missing` again.
p ExchangeRegistry.singleton_methods.grep(/exchanges/)
#=> [:exchanges]
p ExchangeRegistry.exchanges
#=> {}
Another answer of this question indicates that there is performance penalty for handling method_missing. Hence, I have updated the answer to define the class method when first time a method_missing is reported. The update is based on article: Dynamically create class methods in Ruby

Inheriting class methods from modules / mixins in Ruby

It is known that in Ruby, class methods get inherited:
class P
def self.mm; puts 'abc' end
end
class Q < P; end
Q.mm # works
However, it comes as a surprise to me that it does not work with mixins:
module M
def self.mm; puts 'mixin' end
end
class N; include M end
M.mm # works
N.mm # does not work!
I know that #extend method can do this:
module X; def mm; puts 'extender' end end
Y = Class.new.extend X
X.mm # works
But I am writing a mixin (or, rather, would like to write) containing both instance methods and class methods:
module Common
def self.class_method; puts "class method here" end
def instance_method; puts "instance method here" end
end
Now what I would like to do is this:
class A; include Common
# custom part for A
end
class B; include Common
# custom part for B
end
I want A, B inherit both instance and class methods from Common module. But, of course, that does not work. So, isn't there a secret way of making this inheritance work from a single module?
It seems inelegant to me to split this into two different modules, one to include, the other to extend. Another possible solution would be to use a class Common instead of a module. But this is just a workaround. (What if there are two sets of common functionalities Common1 and Common2 and we really need to have mixins?) Is there any deep reason why class method inheritance does not work from mixins?
A common idiom is to use included hook and inject class methods from there.
module Foo
def self.included base
base.send :include, InstanceMethods
base.extend ClassMethods
end
module InstanceMethods
def bar1
'bar1'
end
end
module ClassMethods
def bar2
'bar2'
end
end
end
class Test
include Foo
end
Test.new.bar1 # => "bar1"
Test.bar2 # => "bar2"
Here is the full story, explaining the necessary metaprogramming concepts needed to understand why module inclusion works the way it does in Ruby.
What happens when a module is included?
Including a module into a class adds the module to the ancestors of the class. You can look at the ancestors of any class or module by calling its ancestors method:
module M
def foo; "foo"; end
end
class C
include M
def bar; "bar"; end
end
C.ancestors
#=> [C, M, Object, Kernel, BasicObject]
# ^ look, it's right here!
When you call a method on an instance of C, Ruby will look at every item of this ancestor list in order to find an instance method with the provided name. Since we included M into C, M is now an ancestor of C, so when we call foo on an instance of C, Ruby will find that method in M:
C.new.foo
#=> "foo"
Note that the inclusion does not copy any instance or class methods to the class – it merely adds a "note" to the class that it should also look for instance methods in the included module.
What about the "class" methods in our module?
Because inclusion only changes the way instance methods are dispatched, including a module into a class only makes its instance methods available on that class. The "class" methods and other declarations in the module are not automatically copied to the class:
module M
def instance_method
"foo"
end
def self.class_method
"bar"
end
end
class C
include M
end
M.class_method
#=> "bar"
C.new.instance_method
#=> "foo"
C.class_method
#=> NoMethodError: undefined method `class_method' for C:Class
How does Ruby implement class methods?
In Ruby, classes and modules are plain objects – they are instances of the class Class and Module. This means that you can dynamically create new classes, assign them to variables, etc.:
klass = Class.new do
def foo
"foo"
end
end
#=> #<Class:0x2b613d0>
klass.new.foo
#=> "foo"
Also in Ruby, you have the possibility of defining so-called singleton methods on objects. These methods get added as new instance methods to the special, hidden singleton class of the object:
obj = Object.new
# define singleton method
def obj.foo
"foo"
end
# here is our singleton method, on the singleton class of `obj`:
obj.singleton_class.instance_methods(false)
#=> [:foo]
But aren't classes and modules just plain objects as well? In fact they are! Does that mean that they can have singleton methods too? Yes, it does! And this is how class methods are born:
class Abc
end
# define singleton method
def Abc.foo
"foo"
end
Abc.singleton_class.instance_methods(false)
#=> [:foo]
Or, the more common way of defining a class method is to use self within the class definition block, which refers to the class object being created:
class Abc
def self.foo
"foo"
end
end
Abc.singleton_class.instance_methods(false)
#=> [:foo]
How do I include the class methods in a module?
As we just established, class methods are really just instance methods on the singleton class of the class object. Does this mean that we can just include a module into the singleton class to add a bunch of class methods? Yes, it does!
module M
def new_instance_method; "hi"; end
module ClassMethods
def new_class_method; "hello"; end
end
end
class HostKlass
include M
self.singleton_class.include M::ClassMethods
end
HostKlass.new_class_method
#=> "hello"
This self.singleton_class.include M::ClassMethods line does not look very nice, so Ruby added Object#extend, which does the same – i.e. includes a module into the singleton class of the object:
class HostKlass
include M
extend M::ClassMethods
end
HostKlass.singleton_class.included_modules
#=> [M::ClassMethods, Kernel]
# ^ there it is!
Moving the extend call into the module
This previous example is not well-structured code, for two reasons:
We now have to call both include and extend in the HostClass definition to get our module included properly. This can get very cumbersome if you have to include lots of similar modules.
HostClass directly references M::ClassMethods, which is an implementation detail of the module M that HostClass should not need to know or care about.
So how about this: when we call include on the first line, we somehow notify the module that it has been included, and also give it our class object, so that it can call extend itself. This way, it's the module's job to add the class methods if it wants to.
This is exactly what the special self.included method is for. Ruby automatically calls this method whenever the module is included into another class (or module), and passes in the host class object as the first argument:
module M
def new_instance_method; "hi"; end
def self.included(base) # `base` is `HostClass` in our case
base.extend ClassMethods
end
module ClassMethods
def new_class_method; "hello"; end
end
end
class HostKlass
include M
def self.existing_class_method; "cool"; end
end
HostKlass.singleton_class.included_modules
#=> [M::ClassMethods, Kernel]
# ^ still there!
Of course, adding class methods is not the only thing we can do in self.included. We have the class object, so we can call any other (class) method on it:
def self.included(base) # `base` is `HostClass` in our case
base.existing_class_method
#=> "cool"
end
As Sergio mentioned in comments, for guys who are already in Rails (or don’t mind depending on Active Support), Concern is helpful here:
require 'active_support/concern'
module Common
extend ActiveSupport::Concern
def instance_method
puts "instance method here"
end
class_methods do
def class_method
puts "class method here"
end
end
end
class A
include Common
end
You can have your cake and eat it too by doing this:
module M
def self.included(base)
base.class_eval do # do anything you would do at class level
def self.doit #class method
##fred = "Flintstone"
"class method doit called"
end # class method define
def doit(str) #instance method
##common_var = "all instances"
#instance_var = str
"instance method doit called"
end
def get_them
[##common_var,#instance_var,##fred]
end
end # class_eval
end # included
end # module
class F; end
F.include M
F.doit # >> "class method doit called"
a = F.new
b = F.new
a.doit("Yo") # "instance method doit called"
b.doit("Ho") # "instance method doit called"
a.get_them # >> ["all instances", "Yo", "Flintstone"]
b.get_them # >> ["all instances", "Ho", "Flintstone"]
If you intend to add instance, and class variables, you will end up pulling out your hair as you will run into a bunch of broken code unless you do it this way.

Remove/undef a class method

You can dynamically define a class method for a class like so:
class Foo
end
bar = %q{def bar() "bar!" end}
Foo.instance_eval(bar)
But how do you do the opposite: remove/undefine a class method? I suspect Module's remove_method and undef_method methods might be able to be used for this purpose, but all of the examples I've seen after Googling for hours have been for removing/undefining instance methods, not class methods. Or perhaps there's a syntax you can pass to instance_eval to do this as well.
Thanks in advance.
class Foo
def self.bar
puts "bar"
end
end
Foo.bar # => bar
class <<Foo
undef_method :bar
end
# or
class Foo
singleton_class.undef_method :bar
end
Foo.bar # => undefined method `bar' for Foo:Class (NoMethodError)
When you define a class method like Foo.bar, Ruby puts it Foo's singleton class. Ruby can't put it in Foo, because then it would be an instance method. Ruby creates Foo's singleton class, sets the superclass of the singleton class to Foo's superclass, and then sets Foo's superclass to the singleton class:
Foo -------------> Foo(singleton class) -------------> Object
super def bar super
There are a few ways to access the singleton class:
class <<Foo,
Foo.singleton_class,
class Foo; class << self which is commonly use to define class methods.
Note that we used undef_method, we could have used remove_method. The former prevents any call to the method, and the latter only removes the current method, having a fallback to the super method if existing. See Module#undef_method for more information.
This also works for me (not sure if there are differences between undef and remove_method):
class Foo
end
Foo.instance_eval do
def color
"green"
end
end
Foo.color # => "green"
Foo.instance_eval { undef :color }
Foo.color # => NoMethodError: undefined method `color' for Foo:Class
You can remove a method in two easy ways. The drastic
Module#undef_method( )
removes all methods, including the inherited ones. The kinder
Module#remove_method( )
removes the method from the receiver, but it
leaves inherited methods alone.
See below 2 simple example -
Example 1 using undef_method
class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
undef_method :x
end
obj = B.new
obj.x
result -
main.rb:15:in
': undefined methodx' for # (NoMethodError)
Example 2 using remove_method
class A
def x
puts "x from A class"
end
end
class B < A
def x
puts "x from B Class"
end
remove_method :x
end
obj = B.new
obj.x
Result -
$ruby main.rb
x from A class
I guess I can't comment on Adrian's answer because I don't have enough cred, but his answer helped me.
What I found: undef seems to completely remove the method from existence, while remove_method removes it from that class, but it will still be defined on superclasses or other modules that have been extened on this class, etc.
If you would like to remove method with name what calculate dinamically, you should use eigenclasses like:
class Foo
def self.bar
puts "bar"
end
end
name_of_method_to_remove = :bar
eigenclass = class << Foo; self; end
eigenclass.class_eval do
remove_method name_of_method_to_remove
end
this way is better than others answers, becouse here i used class_eval with block. As you now block see current namespace, so you could use your variables to remove methods dinamically
Object.send(:remove_const, :Foo)

Resources