Calling an instance method from a class method - ruby

I have this class:
class MyClass
##variable = 9
def initialize
##variable -= 1
end
def self.tracker
puts ##variable
if ##variable <9
puts "#{action}"
end
end
def action
puts "The number is less than 9!"
end
end
And when I try to call the class method:
MyClass.tracker
I keep getting this error:
`tracker': undefined local variable or method `action' for MyClass:Class (NameError)
Is it not possible to call an instance method from a class method or vice versa? Am I doing something wrong?

In order to call an instance method you need to create an instance of the object. In ruby calling 'new' creates an instance of a class.
You can change this line
puts "#{action}"
To this:
puts "#{new.action}"
.new inside of the class will make a new instance of the class you are in. Which will also run your initialize and decrease ##variable by one. The way the class is written right now we never past if ##variable <9 unless you are making instances of the class outside of the code you shared.
Overall this is a pretty odd class. It isn't common to use class variables like this. It is much more common to create an instance of a class, use instance variables/methods to house your logic.

Related

Why can some classes and/or methods be called without instances of their parent class?

I'm near the finish of the Ruby track in Code Academy, and I'm curious about a peculiar thing: I was under the impression that a class is a repository of constants, methods, etc... and that in order to access most of them, you would first need to create an instance of that class or in some cases the methods of themselves can be invoked (as in they are all technically part of the global object). And then I saw something like this:
#Worked
Time.now
I understood as this as the method [now] of instance of class [Time] being invoked. I then tried to invoke the method on its own:
#Failed
now
and that failed, and I assumed that while a method can be created in the general scope [as part of the global object], if it relies on initialized variables of "parent" class, it cannot be called on its own, because it would not know which object to search for those initialized variables. Following that I created a test class:
class Clock
def initialize
#hours = 1
#minutes = 30
end
def showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
#this worked
watch = Clock.new
watch.showTime
#this failed
showTime
I then just created a basic method (assuming it's in the global level)
def mymethod
puts "The mighty METHOD!"
end
#Works
mymethod
and calling this method the way I did, without referencing the global object worked. So... the questions I have are as follows:
How can [Time.now] be called in this fashion? Shouldn't there be an instance of Time first created?
Why can't I call the method [now] on its own? Am I right that it relies on resources that it cannot find when called this way?
Why could I not call the method showTime on its own? But if I define any method on the "global" level I can access it without referencing the global object
First of all, your intuition is correct.
Every methods must be an instance method of some receiver.
Global methods are defined as private instance methods on Object class and hence seem to be globally available. Why? From any context Object is always in the class hierarchy of self and hence private methods on Object are always callable without receiver.
def fuuuuuuuuuuun
end
Object.private_methods.include?(:fuuuuuuuuuuun)
# => true
Class methods are defined as instance methods on the "singleton class" of their class instance. Every object in Ruby has two classes, a "singleton class" with instance methods just for that one single object and a "normal class" with method for all objects of that class. Classes are no different, they are objects of the Class class and may have singleton methods.
class A
class << self # the singleton class
def example
end
end
end
A.singleton_class.instance_methods.include?(:example)
# => true
Alternative ways of defining class methods are
class A
def self.example
end
end
# or
def A.example
end
Fun fact, you can define singleton methods on any object (not just on class objects) using the same syntax def (receiver).(method name) as follows
str = "hello"
def str.square_size
size * size
end
str.square_size
# => 25
"any other string".square_size
# => raises NoMethodError
Some programming language history — Singleton classes are taken from the Smalltalk language where they are called "metaclasses". Basically all object-oriented features in Ruby (as well as the functional-style enumerators on Enumerable) are taken from the Smalltalk language. Smalltalk was an early class-based object-oriented language created in the 70ies. It was also the language that invented graphical user interfaces like overlapping windows and menus et cetera. If you love Ruby maybe also take a look at Smalltalk, you might fall in love yet again.
This is known as a class method. If CodeAcademy didn't cover it, that's a shame. Here's some examples:
# basic way
class Foo
def self.bar; :ok; end
end
Foo.bar # => :ok
# alternate syntax
class Foo
class << self
def bar; :ok; end
end
end
# alternate syntax, if Foo class already exists
def Foo.bar; :ok; end
# alternate approach if Foo class already exists
Foo.class_exec do
def bar; :ok; end
end
# to define a class method on an anonymous 'class' for a single instance
# you won't need to use this often
Foo.new.singleton_class.class_exec do
def bar; :ok; end
end
# to define a class method on an instance's actual class
Foo.new.class.class_exec do
def bar; :ok; end
end
Another way to get class methods is to extend a module.
module FooMethods
def bar; :ok; end
end
module Foo
extend FooMethods
end
Foo.bar # => :ok
Note that with Modules, the methods are always defined as instance methods. This way they can be either extended into class scope or included into instance scope. Modules can also have class methods, using the exact same syntax / examples as shown above with classes. However there's not such as easy to load a module's class methods via include or extend.
How can [Time.now] be called in this fashion? Shouldn't there be an
instance of Time first created?
The Time.now method is a class method, not an instance method and therefore can be called directly on the Time class rather than an instance of it Time.new
Class methods are defined on the class themselves using the self keyword:
class Time
def self.now
# code
end
end
Time.now # works
Why can't I call the method [now] on its own? Am I right that it
relies on resources that it cannot find when called this way?
When you call a method "on its own" you're actually implicitly calling it on self:
self.now
The above is the same as just doing:
now
Why could I not call the method showTime on its own? But if I define
any method on the "global" level I can access it without referencing
the global object
You defined the showTime method on a specific class so you have to send that method to that class. When you define a method in the "global" scope you're implicitly defining it on self and the subsequent call to mymethod is actually self.mymethod so it will work.
Time.now is a class method.
To define a class method, you need to define the method with self. : def self.method_name
class Clock
#hours = 1
#minutes = 30
def self.showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
Clock.showTime
#=> The time is: 1:30
If you want to call now on its own, you can do so inside Time class :
class Time
puts now
#=> 2017-01-19 22:17:29 +0100
end

Does defining initialize for a singleton class make sense in Ruby?

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

When revoke a method in Class definition, what's the difference between custom defined class and the ruby reserved class such as `Class` or `Object`

I'm ruby newbie, I am learning some ruby's basic knowledge such as class inheritance.
I write some snippets to deepen my understanding, but the bellow 2 snippets make me very confused.
class Object
def hello_o
puts "Hello in Object"
end
hello_o
end
This one print "Hello in Object" while
class A
def hello_a
puts "Hello in A"
end
hello_a
end
this one throw me an error:
undefined local variable or method hello_a' for A:Class
Why? I think both A and Object is class.
With the first example, you defined an instance method hello_o on class Object, and called it from Object, which is an instance of Class class, which inherits Object class, so it worked.
With your second example, you defined an instance method hello_a of class A, and tried to call it from A, which is an instance of Class class, which does not inherit A class, so it failed.
You are dynamically adding a method to the Object class, which is the root of the object hierarchy. therefore, anything that subclasses Object (which is everything, implicitly) will have that method available to it. That's why you're allowed to call it in your class definition.
class Object
def hello_o
puts "Hello in Object"
end
hello_o
end
class A
end
A.hello_o # this will work

Call Class Methods to Initialize Static Class

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.

Mocking the initialize method on a ruby class?

How can I mock the initialize method on a ruby class?
I'm doing some testing and want to mock out the object that is created from a new call.
I tried to write a few things and none of them seemed to get the mock class to return from the new call. It just keeps returning the normal, expected object.
EDIT:
one attempt -
class MockReminderTimingInfoParser < ReminderTimingInfoParser
def new(blank)
ReminderTimingInfoParserForTest.new
end
end
describe ReminderParser do
parser = ReminderParser.new(MockReminderTimingInfoParser)
it "should parse line into a Reminder" do
parser.parse(" doesnt matter \"message\"").should == Reminder.new('message', ReminderTimingInfo.new([DaysOfWeek.new([:sundays])], [1]))
end
end
class ReminderTimingInfoParserForTest
include TimingInfoParser
def parse_section(section); [DaysOfWeek.new([:sundays]), 1] end
def reminder_times_converter(times); times end
end
class MockReminderTimingInfoParser < ReminderTimingInfoParser
def new(blank)
ReminderTimingInfoParserForTest.new
end
end
Here, you are defining a method called new for all instances of the class MockReminderTimingInfoParser. In your question, you mention that you want to hook into instance creation. However, in Ruby, instance creation is not done by instance methods. Obviously, this cannot work, since in order to call an instance method, you'd need to have an instance first!
Instead, instances are created by calling a factory method (commonly called new) on the class.
In other words, in order to create an instance of MockReminderTimingInfoParser, you would call MockReminderTimingInfoParser.new, but you have defined a method MockReminderTimingInfoParser#new. In order to call the method you have defined, you would have to call MockReminderTimingInfoParser.new.new.
You need to define a method on MockReminderTimingInfoParser's singleton class. There's several ways to do that. One way would be just mimicking the way you would call the method:
def MockReminderTimingInfoParser.new(blank)
ReminderTimingInfoParserForTest.new
end
Another would be opening up MockReminderTimingInfoParser's singleton class:
class << MockReminderTimingInfoParser
def new(blank)
ReminderTimingInfoParserForTest.new
end
end
However, in both of these cases, MockReminderTimingInfoParser obviously has to exist first. Given that you need to define the class anyway, here's the most idiomatic way of defining methods on a class's (or module's) singleton class:
class MockReminderTimingInfoParser < ReminderTimingInfoParser
def self.new(blank)
ReminderTimingInfoParserForTest.new
end
end
Could you inherit the class and then supply your own initialize?

Resources