in ruby I can bind a method to a receiver (instance):
class TEST
def meth
end
end
bound_method = TEST.new.method(:meth)
Question: How I can get the reveiver from a bound method back?
possible solution, found in docs:
/*
* call-seq:
* binding.receiver -> object
*
* Returns the bound receiver of the binding object.
*/
static VALUE
bind_receiver(VALUE bindval)
{
const rb_binding_t *bind;
GetBindingPtr(bindval, bind);
return vm_block_self(&bind->block);
}
How I can get the reveiver from a bound method back?
If you take a look at the documentation of Method, you will find the method Method#receiver, which returns the bound receiver of the Method object:
receiver → object
Returns the bound receiver of the method object.
(1..3).method(:map).receiver # => 1..3
Related
Given a class like:
class Thing
CONSTANT = 10
# other code
end
And another like:
class Other
def initialize
#thing = Thing.new
end
def method
puts CONSTANT
end
end
Is it possible to extend Forwardable to have Other's CONSTANT delegate to Thing's constant?
I have tried extendingSingleForwardable (see docs here ) like so:
class Other
extend SingleForwardable
def initialize
#thing = Thing.new
end
def method
puts CONSTANT
end
def_single_delegator :#thing, :CONSTANT
end
and:
def_single_delegator :#thing, :constant
but neither worked, am I getting the syntax wrong? If not, is there another way?
This one is answered by the documentation (bold emphasis mine):
def_single_delegator(accessor, method, new_name=method)
Defines a method method which delegates to accessor (i.e. it calls the method of the same name in accessor). If new_name is provided, it is used as the name for the delegate method.
So, no, you can only delegate message sends, not constant lookup.
Forwardable (and SingleForwardable) let you add class functions to your current class via a module. When you write a delegator you're specifying which methods are being passed on to the receiving object from the original module.
In your example, def_single_delegator :#thing, :CONSTANT is being interpreted as the following: Defines a method :CONSTANT which delegates to accessor :#thing (i.e. it calls the method of the same name in accessor).
As you can see, this is not passing on the value of the constant, instead it's passing on a method with the same name as the constant. If you want to pass on the same value as the constant you can provide an accessor method that returns to you the value of the original constant so that you can assign it in this class.
Given the following code below:
class Animal
end
dog = Animal.new # --> return value of Animal.new
What are the specific methods to retrieve the return value for Animal.new? I understand that a new instance is created from the class Animal and assigned to the variable dog. But what are the methods to retrieve the return value of Animal.new?
According to docs here:
new(args, ...) → obj
Calls allocate to create a new object of class’s class, then invokes
that object’s initialize method, passing it args. This is the method
that ends up getting called whenever an object is constructed using
.new.
You can test this yourself in irb. It returns an instance of that object.
# Instantiating a new instance of a class
irb(main):001:0> Class.new
=> #<Class:0x007fe24193c918>
# Assigning a new instance of a class to a variable
irb(main):005:0> some_var = Class.new
=> #<Class:0x007fe2410e68b8>
irb(main):006:0> some_var
=> #<Class:0x007fe2410e68b8>
class A
end
Calling a = A.new return the new object of class A, the string appear as eg #<A:0x00000002d8eb98> is the string containing human readable representation of the object from the default implementation of inspect method which is called each time new object is created.
The default inspect shows the object’s class name, an encoding of the object id and a list of the instance variables and their values User custom classes eg A should/adviced to override this method to provide better representation of their objects eg
class A
def inspect
"I am what i am"
end
end
b = A.new
prints -> I am what i amnot the hexadecimal value
really confused about what this RubyMonk examples does. class Not is supposed to return an object capable of inverting calls to Object#not.
class Object
def not
Not.new(self)
end
class Not
def initialize(original)
#original = original
end
def method_missing(sym, *args, &blk)
!#original.send(sym, *args, &blk)
end
end
end
class Person
def initialize(name)
#name = name
end
def smith?
#name == "Smith"
end
end
and this is how the test goes
puts Person.new("Smith").not.smith?
puts Person.new("Ziggy").not.smith?
what I don't understand is
in what ways does this change the built-in definition of method not?
when passing arguments to not, how does it "travel"? it goes to not method, after which a new instance of class Not is created and it gets passed to that instance?
what is need for the method_missing? what method could there possibly be missing in this scenario? and what does it do when there is a method missing? it's just being told to not send the arguments to #original and that's it?
Answering your question #1:
in what ways does this change the built-in definition of method not?
a) It doesn't, because b) not isn't a method, it's a keyword, and as such its definition is baked into the language specification.
More precisely: the not keyword is translated to a call to the method !, just like the ! operator, so all three of the following are equivalent:
not foo
!foo
foo.!
method_missing in Not class is the real magic. These is the scenario:
Person.new("Smith") # you create new person
Person.new("Smith").not # calls method #not on the person object instance
# the method #not will create new instance of the class Not and passing self as argument
# passing the person on which you have called the method
# then the initialize method of the Not class gets called
# because you want to create new object of the Not class and
# #original is the person on which you have called the method #not
Person.new("Smith").not.smith? # will call method #smith? on the Not object instance
what happened till now
person = Person.new("Smith")
not_class_object = person.not
not_class_object.smith? # there is no method named #smith? in the Not class
If no method exists it check all hierarchy and see if anything in the inheritance chain has implemented the smith? method. If none has implemented the smith? method then Ruby will call method_missing the same way, and you have changed the behavior of the method_missing for the Not class.
Now it will get the #original which is the person object and call the method on the person object, this Person instance object has implemented the method, and when the result comes we will just negate the outcome. So if the smith? method returns true for the person calling not.smith? will return false, because smith? method returns true we negate the value and get false, and if it returns false, when we negate you get true.
Edit:
Person is extension of Object, but there is no connection between Not and Person, Person is not extending Not and Not is not extending Person.
Not is class inside Object and it has no method named smith?, instance object of Person got smith? method. That is why it does not find smith? method on the Not instance object, and then it calls method_missing from the inheritance chain, and you have implemented method_missing for the Not class that it takes the object on which you have called not method of Object class and created instance object from Not class with parameter as Person instance object.
Edit2:
class NotPerson
...
# some code
...
end
p1 = Person.new("Smith")
p2 = Person.new("Ziggy")
p3 = NotPerson.new("something")
p1.smith? # -> true
p2.smith? # -> false
p3.smith? # Error there is no method named #smith? in NotPerson class
not_p1 = p1.not
not_p2 = p2.not
not_p3 = p3.not
not_p1.smith? # -> false
# Because there is no method #smith? on #not class, and #method_missing is called
not_p1.smith? # is eqivavlent to
!(p1.smith?)
not_p2.smith? # -> true
not_p3.smith? # Error there is no method #smith? definedin NotPerson class
Edit3:
check also some references how method_missing is working
method_missing
second_example
I'm working through the "Pickaxe Book" and the author gives the following example as a technique for giving a module/mixin state without using an instance variable:
...the module could use a module-level hash, indexed by the current
object ID, to store instance-specific data...
module Test
State = {}
def state=(value)
State[object_id] = value
end
def state
State[object_id]
end
end
class Client
include Test
end
c1 = Client.new
c2 = Client.new
c1.state = 'cat'
c2.state = 'dog'
c1.state # => "cat"
c2.state # => "dog"
I am unclear on how this works exactly. In particular, object_id. How is the object_id method able to access the Client instance in this manner? I tried using length to see if it would index according to that, but I got:
NameError: undefined local variable or method `length' for #<Client:0x00000000ecc570>
I'd like to make sure I understand the principles of what's going on here.
How is the object_id method able to access the Client instance in this
manner?
The state=() method is inherited from the Test module when it is included. Included modules create an anonymous class that is inserted right above the including class in the inheritance chain.
This line:
c1.state = 'cat'
is equivalent to:
c1.state=('cat')
And when c1 calls state=(), inside the state=() method self will be equal to c1. Inside a def, self is equal to the object that called the method.
When you call a method with no receiver, then self is the implicit receiver. Inside state=():
def state=(value)
State[object_id] = value
end
the object_id() method is called with no receiver, so self becomes the receiver. As a result, the line:
State[object_id] = value
is equivalent to:
State[self.object_id] = value
which is equivalent to:
State[c1.object_id] = value
If Client includes Test, and c1 is a Client, then object_id is c1.object_id, inherited from Object. Each Ruby object is guaranteed a unique object_id. Not all objects are guaranteed to have length (and furthermore, many objects will have non-unique length, e.g. "f" and [8] share the length 1).
The return value of a method is the value of its last statement. This means that Myclass.new following the definition below of the initialize method with super inside:
class Myclass < String
def initialize(arg)
super(arg.to_s)
"something"
end
end
should return "something". But it returns "test" instead:
Myclass.new("test") # => "test"
Why?
The class method new
creates a new instance, then
calls the instance method initialize on the instance created, which may return whatever, as in your example, then
returns the instance created.
The return value from initialize to new has no effect on the return value from new.
You're not calling initialize, you're calling new. The initialize method is essentially a hook that is executed when you create a new object, but it is typically never called directly.
If you want to get the return value of your initialize method, you need to call your initialize method. If you call a completely different method, it is only normal that you would get a completely different return value.