ruby .extend help needed - ruby

given
module Foo
def bar
puts "foobar"
end
end
I can do
String.extend(Foo)
and as a consequence do
String.bar # => "foobar"
Why doesnt this work?:
a = String.new
a.bar # => NoMethodError: undefined method `bar' for "":String
Is it because 'a' is now and instance and .extend only works against class methods? Why does it lose the 'new' functionality I have given String via .extend?

Ruby allows you to add methods from a Module to a Class in two ways: extend and include.
Using the module you gave:
module Foo
def bar
puts "foobar"
end
end
With extend the methods are added as class methods, and can be called directly on the class object itself:
class Bar
extend Foo
end
Bar.bar # => "foobar"
Alternatively, you can call it outside of the class scope:
class Bar
end
Bar.extend Foo
Bar.bar # => "foobar"
include is slightly different. It will add the methods as instance methods. They are only callable on an instance of the class:
class Bar
include Foo
end
Bar.bar # NoMethodError
a = Bar.new
a.bar # => "foobar"
The key difference was that we first had to make an instance a, before we could call the instance method.
As sepp2k noted, extend is can be called on any Object, not just Class objects. For example, you can go:
class Bar
end
a = Bar.new
a.extend Foo
a.bar # => "foobar"
However, bar will only be added to the single instance a. If we create a new instance, it you will not be able to call it.
b = Bar.new
b.bar # => MethodNotFoundError

In Ruby, class String is an object, and by doing String.extend(Foo), you create a singleton class for the String class object and include the module Foo in it (that means that you are adding class methods to the String class object, and so can call String.bar). Full stop.
a.bar doesn't work because there's no instance method bar.
No, you haven't given new to String via extend.

The Object#extend method adds to the receiver the methods defined by the argument module.
You have to remember that the String class is itself an object (of type Class) and so when you call "extend" with it as the receiver, that class object (String) itself gets the new method.
So in your first example, String.extend(Foo), adds to the String class instance the function "bar". That is, "bar" is now an instance method of the shadow class (aka Singleton class), so the object String (which is a class) now has the method "bar". This has roughly the same effect as adding a class method to the String class (e.g. def String.bar; puts 'foobar'; end), so it has no effect on instances of type String.

Related

To which object are top-level methods assigned in Ruby? [duplicate]

This question already has answers here:
Ruby what class gets a method when there is no explicit receiver?
(2 answers)
Closed 7 months ago.
In Ruby every method is assigned to an object (right?). Ruby provides a lot of "built in" methods and gives the ability to the user to create "user defined" methods.
Built in methods are all defined in a class like String, Integer, Array and so on. Built in methods are all invoked placing a dot after an object followed by the method call.
string = "example"
string = string.reverse
However, when I define a method with the syntax
def method_name (args)
#body
end
to which object is this method assigned? And why when I have to call a method that I have defined I don't use the "dot syntax" but I just write its name and pass it some arguments without applying it to an object, like this:
method_name args
In Ruby every method is assigned to an object (right?)
Incorrect. In Ruby, methods are assigned to modules (including classes). When you call a method on an object, Ruby runtime searches for the method along the object's class's ancestor chain (the object's singleton class -> the object's class ->
the superclass -> superclass's superclass -> ... -> BasicObject). If the method is found, it is bound to the object and gets called, otherwise the Ruby runtime searches for a special method called method_missing and bind it to the current object and calls it.
to which object is this method assigned?
It's assigned to the class Object, as a private instance method.
def foo
:foo
end
Object.private_instance_methods.grep(/foo/)
#=> [:foo]
I guess Ruby does this in order to make top-level "functions" look global.
class A
def self.a
foo
end
def a
foo
end
end
A.a #=> :foo
A.new.a #=> :foo
There is top-level object in Ruby -- main
def method_name(args)
# body
end
self
# => main
self.methods.grep(/method_name/)
# => [:method_name]
main is an instance of Object. Any methods defined in main become instance methods of Object
Object.private_instance_methods.grep(/method_name/)
# => [:method_name]
This makes them available everywhere (because all classes are descendants of Object), meaning that we can call the method without a receiver inside classes
For example
def foo
puts "foo"
end
class X
def y
foo
end
end
# will print foo
X.new.y
# will raise private method `foo' called for #<X:0x000055e406a0f060> (NoMethodError)
# to reproduce don't use irb, just usual file
X.new.foo
Read more

Do methods have to be always inside classes in Ruby?

Hey guys I am new to Ruby. I have a question: Do methods have to be always inside classes?
Technically they are aways defined inside a class, but this doesn't mean you always need to open a class to define a method.
Here is what might look like a top-level function in other languages:
def foo
puts self
puts self.class
end
If we simply call foo, we'll get:
main
Object
This actually defined a private instance method in the Object class. We see that self in the top-level scope is a special object called main.
On the other hand, we can try to call this method on other stuff:
'bar'.foo #!> private method `foo' called for "bar":String (NoMethodError)
This errorred out as foo is private. We can use a special method called send to invoke private methods:
'bar'.send :foo
Gets us:
bar
String
We can also define methods in the so-called singleton classes. You can think of them as classes with only a single instance. For example:
foo = 'foo'
def foo.bar
puts 'baz'
end
foo.bar # => baz
'quix'.bar # !> undefined method `bar' for "quix":String
'foo'.bar # !> undefined method `bar' for "foo":String
puts (foo.singleton_class.instance_methods - Object.instance_methods).first
# => bar
Here the bar method was defined on the singleton class of foo. Note that even another string with the same contents is still a difference instance, hence it doesn't have the bar method.
Hey guys I am new to Ruby. I have a question: Do methods have to be always inside classes?
No.
Methods have to be always inside modules. (Class are modules, too.)
Example:
module Foo
def bar; end
end
There is no class here.

Methods defined in class Object are instance and class one at the same time

How can be described that a method boo defined in Object class becomes instance and class one at the same time in class Foo?
class Foo; end
class Object
def boo
'boo method'
end
end
p Foo.boo # => boo method
p Foo.new.boo # => boo method
Every object is an instance of Object. Thus, every object will respond to boo.
Foo is an object (classes are objects, too), ergo, Foo is an instance of Object (it is an instance of Class, which is a subclass of Module, which is a subclass of Object).
Foo.new is an object (it is an instance of Foo, which is a subclass of Object).
Since both Foo and Foo.new are instances of Object, both respond to boo.
[Note: I am ignoring the existence of BasicObject.]
If you really want to do this, keep in mind that the class context and the instance context are entirely different so instance variables are not equivalent.
module FooMethods
def boo
'boo'
end
end
class Foo
extend FooMethods
include FooMethods
end
This deliberately imports the mixin at both the class level via extend and instance level via include.
Perhaps forwarding the method to self is an option?
require 'forwardable'
class Foo
extend Forwardable
def self.boo
'boo method'
end
def_delegator self, :boo
end
Foo.boo
#=> "boo method"
Foo.new.boo
#=> "boo method"

Confusing behaviour between class and object

Since we know that class is also an object of class Class. I have a doubt here.
I have a class defined here Foo and a method which prints the object.
class Foo
def bar
puts self
end
puts self
end
When I do Foo.new.bar o/p will be # <Foo:0x935c740>
which represents an object of class Foo.
Why not the self outside the method prints #<Class: 0x..> as its an object of class Class?
Sorry if my question is wrong but please clarify it.
Here is a little different way to define a classes/objects:
klass = Class.new {
puts self
def bar
puts self
end
}
# #<Class:0x3fbdbb8>
As you can see, it outputs #<Class:0x3fbdbb8>. So its class is Class. You can check it via class method:
klass.class
# => Class
When you name your class with uppercase letter (for example Example) for the first time, it use it as output instead of cryptic name like: #<Class:0x3fbdbb8>.
Foo = Class.new {
puts self
def bar
puts self
end
}
Still outputs cryptic name because Foo ='s part hasn't been evaluated yet.
puts Foo
Outputs correct name - Foo
What if I name it again?
Qux = Foo
# => Foo
Nothing. Foo will be Foo forever.
Names of classes and modules are constant in ruby. So when you are defining a class you are creating an object of class Class and providing it with a constant name and hence when you do a puts self in a class context, it gives a class name instead of something like #<Class: 0x..>

What's the difference between self.generate and Invoice.generate?

class Invoice
def Invoice.generate(order_id, charge_amount, credited_amount = 0.0)
Invoice.new(:order_id => order_id, :amount => charge_amount, :invoice_type => PURCHASE, :credited_amount => credited_amount)
end
end
Why would you create Invoice.generate inside Invoice class rather than self.generate?
self.generate is easier to work with, whereas Invoice.generate is arguably more explicit. Other than that, there's no difference between the two.
Explanation
You can define a method on any instance using this form
def receiver.method(args)
end
Check this out
class Foo
end
def Foo.bar
"bar"
end
Foo.bar # => "bar"
And yes, I mean any instance. It's absolutely possible that one instance has some method while another doesn't
f = Foo.new
def f.quux
'quux'
end
f2 = Foo.new
f.quux # => "quux"
f2.quux # => # ~> -:20:in `<main>': undefined method `quux' for #<Foo:0x007fe4e904a6c0> (NoMethodError)
A reminder: inside of class definition (but outside of method definitions) self points to that class.
class Foo
# self is Foo
end
So, armed with this knowledge, the difference between self.generate and Invoice.generate should be obvious.
Under normal circumstances, it would practically have no difference from def self.generate.
The only edge case I can think of is if you have a nested class with the same name, then the explicit version would apply only to the nested class.
class A
def self.x
name
end
def A.y
name
end
class A
# nested class A::A
end
def self.p
name
end
def A.q
name
end
end
> A.x # => "A"
> A.y # => "A"
> A.p # => "A"
> A.q # => NoMethodError: undefined method `q' for A:Class
> A::A.q # => "A::A"
As you see, after a nested class with the same name is defined, subsequent explicit class method definitions made with the class name refer to the nested class, but explicit definitions made beforehand refer to the original.
Implicit definitions made with self always refer to the base class.
You have 2 ways for defining a class method.
1) You can use the name of the class directly
class Test #Test is now an instance of a built-in class named Class
def Test.class_method
"I'm a class method."
end
end
2) You can use the self variable, which is always pointing to the current object
class Test
def self.class_method
"I'm a class method."
end
end
Once you understand that classes are objects, this use of the self variable to define a class method finally makes sense.
The value of self
Not too surprinsingly, when you are inside a class method, the value of self refers to the object that holds the class structure (the instance of class Class). This means that :
class Test
def self.class_method
self.x
end
end
is equivalent to :
class Test
def self.class_method
Test.x
end
end
When you are inside an instance method, the value of self still refers to the current object. This time however, the current object is an instance of class Test, not an instance of class Class.
More info. : http://www.jimmycuadra.com/posts/self-in-ruby

Resources