Do I need to put it in context or can someone give me a general overview? I've tried to do my own googling but am not coming up with enough info.
The part that confuses me is the "class" part. I understand self.class_method_name but not
self.class_method_name.
self refers to the current instance of the class, self.class refers to the class of the instance.
For example:
class Person
def initialize
p self
p self.class
end
end
Person.new
This code would show:
#<Person:0x0000558351934020>
Person the class
The first line is the instance of Person, the second is the class per se.
Normally, when you define a method in class, it's instance of class, it mean you can only call it by object, ex:
class a
define method_x
end
end
, if you want to call method_x, you can only call by:
obj = a.new
obj.method_x
and you can not call : a.method_x
but when you define self.method_x, you can call it by class
class a
define self.method_x
end
end
a.method_x
, you can try as above and see result
Related
I anticipate that I am not trying to do anything practical here, just trying to understand some deeper Ruby concepts.
Supppose I have the following code
class Bookshelf
#book_qty = 100 # class instance var
class << self
attr_accessor :books_qty
end
def initialize
#book = "This book is in every object as an object instance variable"
end
# so far so good, but what happens with...
def self.initialize # what would be this called on ?
puts " and at what step would this be printed, if ever?"
# I thought it would be printed when the class code is parsed first time,
# but no
end
# or also
class << self
def initialize
puts "same here"
end
end
end
I know it might not make sense or might be too intricately related on how Ruby internals work, but, if by chance anyone has been puzzled too by this and knows the answer... please share it :)
There is no purpose to defining initialize for the singleton class (whether you use def self. or class << self). initialize is only called by Class#new and...
Bookshelf.singleton_class.new
# TypeError: can't create instance of singleton class
that's not allowed.
If you want code to be executed the first time a class is parsed, just put it in the class
class Bookshelf
puts "class defined!"
end
In some cases, it does make sense to define a custom constructor, but I wouldn't call the method initialize, since the instance method you override to customise initialisation is also called initialize. That would be a little confusing.
def self.initialize # what would be this called on ?
If you define a method like this, you can invoke it by sending the method directly to the class:
Bookshelf.initialize
Same thing applies for methods defined inside class << self.
As mentioned, it does make sense to define custom constructors for a class. Sometimes just for readability's sake:
class Bookshelf
attr_accessor :book_qty
def self.with_quantity(quantity)
new(quantity)
end
def initialize(quantity)
self.book_qty = quantity
end
end
Now you could instantiate a Bookshelf like this:
bs = Bookshelf.with_quantity 100
bs.quantity # => 100
You actually call .new on the singleton class of Bookshelf. And #initialize is basically just a hook for the instance to tweak its initialisation.
How you could access class instance variables
class Bookshelf
#book_qty = 1000
class << self
attr_accessor :book_qty
end
end
Bookshelf.book_qty # => 1000
Bookshelf.book_qty = 2000
Bookshelf.book_qty # => 2000
I want a class to return its own name, pluralized, using e.g. "active_support/inflector":
describe "self.resource" do
it "should be databases" do
Database.resource.should equal "databases"
end
end
class Database
def self.resource
self.class.to_s.tableize
end
end
This fails with:
expected #<String:84017460> => "databases"
got #<String:84018030> => "classes"
How can I access the name of the class a singleton method is being called on?
This should work:
class Database
def self.resource
to_s.tableize
end
end
The problem is you call to_s on the class Database belongs to, and it's Class class. You should call to_s on local self instead, which is Database itself. Since self is default receiver of the message, it's okay to leave simply to_s.tableize.
You shouldn't call class method on self. Singleton class already belongs to the class, not the instance.
In your case:
self.to_s.tableize
should work as intended.
I'm trying to create a singleton class that requires some sophisticated initialization. I've boiled my problem down to this test case:
class Dumb
attr_accessor :mything
#my_thing = 1 # this works
self.init_some_stuff # this gives undefined method
class << self
def init_some_stuff
#my_thing = 2
end
def spill_it
puts "My Thing: #{#my_thing}"
end
end
end
I can initialize simple variables, but want to call class methods to do it, and I get "undefined method". Since I intend it to be used as a singleton, a constructor would not get called. What am I missing?
A method is executed whenever it is met.
self.init_some_stuff
is placed before the definition of it. That is the problem. Place it after the definition.
I know self is the receiver of the method calling.
But I do not know if there is not self in method definition.
code example:
class One
def kk
"kk"
end
def self.kkk
"kkk"
end
end
puts One.new.kk
puts One.kkk
Why do I need to use new method for One used like One.new.kk ?
self.kkk here defines a class method of One. As you know, self is the receiver. In the context here it is the One class.
And One.new returns an instance of class One. kk is an instance method that only called by an instance.
class Demo2
def self.method1(a)
p a.is_a? Demo2
end
def method2(b)
p b.to_s
end
end
a=Demo2.new
# here, if you type a.... wait for hint, you just can only get method2()
# just because it class self.
a.method2('123')
Demo2.method1(a)
p Demo2 # this is a class
p a # this a class instance
>'123'
>true
>Demo2
>#<Demo2:0x290d768>
I think this simple code can make you clear, I don't talk OOP with you, that's so boring!^_^
the ruby book I'm reading has confused me a bit. If I do the following, I understand completely why the code throws an error;
class Person
def show_name
puts #name
end
end
person = Person.new
person.show_name
Person.show_name #(note the capital P) this line falls over
It throws an error stating that the Person class does not have a method called show_name, because it is an instance method. I understand this completely. The book then throws in this example;
class Class
def add_accessor(accessor_name)
self.class_eval %Q{attr_accessor :#{accessor_name}}
end
end
class Person
end
person = Person.new
Person.add_accessor :name #note the capital P
Person.add_accessor :age #capital P here too
person.name = "Mikey"
person.age = 30
puts person.name
and goes on to state how cool it is that you can add methods to classes dynamically. What I don't understand is why I am suddenly allowed to call the "add_accessor" method as a class method (with a capital P) when the method itself isn't defined as such? I thought all class methods had to be declared like this?
class Math
def self.PI
3.141
end
end
puts Math.PI
Is anyone able to enlighten me?
Ruby classes are objects like everything else to. Your Person class is really an object of class Class, which in turn inherits from class Module. When you add a method to class Class as an instance method, you are providing a new method for all classes.
If you had declared it with a def in Person, it would not be callable without an object. To add class methods for one class, but not all, you must prepend the method name with self or the name of the class:
class Person
def instance_method
end
def self.class_method
end
def Person.other_class_method
end
end
When you declare the method as self.class_method you are declaring your method to be a singleton method on the class object. self in a class or module declaration refers to the class object, which is why self. and Person. are the same.
When dealing with Ruby, just remember everything is an object, everything has methods. There are no functions in Ruby either, despite appearances to the contrary. Methods and objects, always.
Look at this:
person.instance_of?(Person) #=> true
Person.instance_of?(Class) #=> true
You have defined an instance method add_accessor for all the instances of the class Class, so Person class can use that method because it is an instance of Class.
I recommend yout to take a look at metaprogramming and Ruby Object Model.
Hoep this helps
You're extending the Class class, and all of your classes, like Person, are instances of Class (Yes, classes are instances of the Class class. They're ordinary objects).
So when you call Person.add_accessor, you're calling the instance method Class#add_accessor.
because Person (with capital P ) is an instance of the class Class.