I have two sets of code
#movies = ["Zoolander", "Sandlot"]
def good_movies
#movies.each do |movie|
puts "I love #{movie}!"
end
end
good_movies
#I love Zoolander!
#I love Sandlot!
I understand of the scope of local variables, so there has to be instance variables for the code to run otherwise I would get a NameError
But when it comes to this bit
class Example
#scope = "This is the scope of the class itself"
def hello
p #scope
end
end
ex = Example.new
ex.hello
# nil
Looks like the predefined instance variable cannot be accessed but I didn't get an error. It should be to do with the instantiation, but I don't know the exact reason why.
Can anyone give me some pointers on this?
Looks like the predefined instance variable cannot be accessed but I didn't get an error.
Accessing an undefined instance variable doesn't raise an exception, it just returns nil.
Since you define the instance variable on the class object itself, you need a method in the same scope to access it, i.e. a class method:
class Example
#scope = "This is the scope of the class itself"
def self.hello
p #scope
end
end
Example.hello
#=> "This is the scope of the class itself"
To define a variable for your instances, use initialize: (so each instance has its own #scope)
class Example
def initialize
#scope = "This is the scope of an instance"
end
def hello
p #scope
end
end
ex = Example.new
ex.hello
#=> "This is the scope of an instance"
You could also access the instance's class via Object#class and its instance variable via instance_variable_get:
class Example
#scope = "This is the scope of the class itself"
def hello
p self.class.instance_variable_get(:#scope)
end
end
ex = Example.new
ex.hello
#=> "This is the scope of the class itself"
Apparently this violates any encapsulation efforts. If you really wanted to do this, you should define a getter:
class Example
#scope = "This is the scope of the class itself"
class << self
attr_reader(:scope)
end
def hello
p self.class.scope
end
end
ex = Example.new
ex.hello
#=> "This is the scope of the class itself"
Example.scope
#=> "This is the scope of the class itself"
Related
I'd like to understand this code. Why is it returning Hello instead of Howdy! ?
class Speaker
#message = "Hello!"
class << self
#message = "Howdy!"
def speak
#message
end
end
end
puts Speaker.speak
First off, your message #message is not an instance variable, or rather not the type of instance variable you may be thinking about: it's a class-level instance var, so an instance variable of Speaker itself, which as an object is an instance of class Class.
Here's a version of the code that does what you're trying to do with a local variable and a closure:
class Speaker
#message = "Hello!"
class << self
message = "Howdy!"
define_method(:speak) { message }
end
end
Speaker.speak
#=> "Howdy!"
And here's some code that illustrates the difference between the class-level instance variable and a "normal" instance variable:
class Speaker
#message = 'Howdy!' # class-level instance variable
def initialize
#message = 'Hello!' # instance variable of Speaker's instances
end
def speak
#message
end
class << self
def speak
#message
end
end
end
Speaker.speak
#=> "Howdy!"
Speaker.new.speak
#=> "Hello!"
Here is your code, except I've defined the class method in the usual way (def self.speak...). As a class method is nothing more than an instance method defined on the class' singleton class, this change is merely a different way of creating the same class method. (If you doubt that, run the code below both ways.) I made that change because I thought it would make my explanation of what is happening clearer. I also added a puts statement.
class Speaker
#message = "Hello!"
def self.speak
puts "self=#{self}"
#message
end
class << self
#message = "Howdy!"
end
end
The first line of the class definition creates a class instance variable #message:
Speaker.instance_variables
#=> [:#message]
Speaker.instance_variable_get(:#message)
#=> "Hello!"
By constrast,
#message = "Howdy!"
creates an instance variable on Speaker's singleton class:
Speaker.singleton_class.instance_variables
#=> [:#message]
Speaker.singleton_class.instance_variable_get(:#message)
#=> "Howdy!"
Now invoke speak on Speaker:
Speaker.speak
# self=Speaker
#=> "Hello!"
As self #=> Speaker, speak is obviously returning the value of the class instance variable.
For speak to return the value of the instance variable defined on Speaker's singleton class we can write the following:
class Speaker
#message = "Hello!"
def self.speak
puts "self=#{self}"
puts "singleton_class = #{singleton_class}"
singleton_class.instance_variable_get :#message
end
class << self
#message = "Howdy!"
end
end
puts Speaker.speak
# self=Speaker
# singleton_class = #<Class:Speaker>
# Howdy!
In the last expression, because self equals Speaker and self is the implied receiver when there is no explicit receiver, "singleton_class is equivalent to Speaker.singleton_class.
The reason this code returns 'Hello' is that it is attempting to change an instance variable in a class << self block.
Class methods are for anything that does not deal with an individual instance of that class - instance variables are tied to individual instances of a class, and we can't change instance variables at a class level.
Instead of using an instance variable in the speak method, we should use a class variable (denoted by ##).
As an example, the following code will return 'Howdy!' -
class Speaker
##message = "Hello!"
class << self
##message = "Howdy!"
def speak
##message
end
end
end
puts Speaker.speak
I found this neat delegator based 'tee' implementation on SO:
https://stackoverflow.com/a/6410202/2379703
And I'm curious what is means for #targets (instance variable) means in the context of a class method:
require 'logger'
class MultiDelegator
def initialize(*targets)
#targets = targets
end
def self.delegate(*methods)
methods.each do |m|
define_method(m) do |*args|
#targets.map { |t| t.send(m, *args) }
end
end
self
end
class <<self
alias to new
end
end
log_file = File.open("debug.log", "a")
log = Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)
I get that it defining the methods write/close but #targets isn't even defined at this point since .to (aliased to new) has yet to be called so I'd assume #targets is nil.
Can anyone give an explanation as to the logistics of how this code works? Does ruby not even attempt to access/resolve #targets until the method in question is attempted to be called, which would be by the logger after it was instantiated?
The define_method method is called on a class to create an instance method. Inside that method, the self (and the instance variable) are instances of the class.
For example:
class Foo
#bar = "CLASS"
def initialize
#bar = "INSTANCE"
end
def self.make_method
define_method :whee do
p #bar
end
end
end
begin
Foo.new.whee
rescue NoMethodError=>e
puts e
end
#=> undefined method `whee' for #<Foo:0x007fc0719794b8 #bar="INSTANCE">
Foo.make_method
Foo.new.whee
#=> "INSTANCE"
It is correct that you can ask about instance variables that have never been created, at any time:
class Bar
def who_dat
puts "#dat is #{#dat.inspect}"
end
end
Bar.new.who_dat
#=> dat is nil
The same is true of other aspects of the language. As long as the code in the method is syntactically valid, it may be defined, even if invoking it causes a runtime error:
class Jim
def say_stuff
stuff!
end
end
puts "Good so far!"
#=> Good so far!
j = Jim.new
begin
j.say_stuff
rescue Exception=>e
puts e
end
#=> undefined method `stuff!' for #<Jim:0x007f9c498852d8>
# Let's add the method now, by re-opening the class
class Jim # this is not a new class
def stuff!
puts "Hello, World!"
end
end
j.say_stuff
#=> "Hello, World!"
In the above I define a say_stuff method that is syntactically valid, but that calls a method that does not exist. This is find. The method is created, but not invoked.
Then I try to invoke the method, and it causes an error (which we catch and handle cleanly).
Then I add the stuff! method to the class. Now I can run the say_stuff method (on the same instance as before!) and it works just fine.
This last example shows how defining a method does not run it, or require that it would even work when it is run. It is dynamically evaluated each time it is invoked (and only at that time).
I have a class A, which I would like to anonymously extend and add a class method to the child class. E.g.:
class A
end
Class.new A do
def self.new_class_method
puts 'I am a class method'
end
end.new_class_method
=> I am a class method
The above example works well, unless you want to access some variables outside of the def self.new_class_method block. E,g,
greeting = 'hello'
Class.new A do
def self.new_class_method
puts greeting + ' I am a class method'
end
end.new_class_method
=> NameError: undefined local variable or method `greeting'
I am using Ruby 1.8.7, which is sad because I believe Ruby 1.9+ contains an analog to define_method which adds a class method. Does anyone have a work around for 1.8.7?
I have tested the below in Ruby 1.8.7 :-
greeting = 'hello'
class A
end
Class.new A do
meta_klass = class << self; self ;end
meta_klass.send(:define_method, :new_class_method) do
puts greeting + ' I am a class method'
end
end.new_class_method
# >> hello I am a class method
As Ruby 1.8.7 doesn't support Object#singleton_class, I used meta_klass = class << self; self ;end. This method is available since 1.9.2, I think.
You can also use extend() to pry open an object's singleton class. Calling extend(module) adds the methods in the module to the calling object's(i.e. the receiver's) singleton class. So if you call extend(module) when self=A, i.e. inside class A, then the module's methods will be inserted into A's singleton class, and the methods in A's singleton class are also known as class methods of A:
class A
end
greeting = "hello"
Class.new(A) do
extend(
Module.new do
define_method(:greet) do
puts greeting
end
end
)
end.greet
--output:--
hello
And you can rewrite that like this (although then it's not as tricky):
class A
end
greeting = "hello"
Class.new(A) do
m = Module.new do
define_method(:greet) do
puts greeting
end
end
extend(m)
end.greet
...which isn't much different than:
class A
end
greeting = "hello"
m = Module.new do
define_method(:greet) do
puts greeting
end
end
Class.new(A) do
extend(m)
end.greet
...which moves the closure out of the class, and doesn't seem very tricky at all because it only opens up two scope gates instead of three.
Also note, extend() is a public method, so it doesn't require the trickery of a private method, i.e. where you can't specify an explicit receiver, so you have to create a context in which self is the object you want to call the private method on. In other words, you can specify an explicit receiver for extend(). How about the class that is returned by Class.new(A)?
class A
end
greeting = "hello"
Class.new(A).extend(
Module.new do
define_method(:greet) do
puts greeting
end
end
).greet
--output:--
hello
Hey, tacking on ".greet" there works! Uh oh, that has the makings of a one liner:
class A
end
greeting = "hello"
Class.new(A).extend(Module.new {define_method(:greet) {puts greeting} }).greet
--output:--
hello
Yeech!
More generally,
class A
end
class Object
def meta_def name, &blk
(class << self; self; end).instance_eval { define_method name, &blk }
end
end
greeting = 'hello'
Class.new A do
meta_def :new_class_method do
puts greeting + ' I am a class method'
end
end.new_class_method
#=> hello I am a class method
If you find this useful, don't thank me, thank some lucky stiff (which I saw mentioned by Jay Fields).
Not sure if this will solve your problem, but changing Greeting to uppercase (making it a constant) would work...
class A
end
Greeting = 'hello'
Class.new A do
def self.new_class_method
puts Greeting + ' I am a class method'
end
end.new_class_method
The following code prints nothing, I was expecting welcomeBack. Please explain.
class Hello
#instanceHello = "welcomeBack"
def printHello
print(#instanceHello)
end
Hello.new().printHello();
end
I just started to lean ruby, so please forgive if the question looks dumb.
If you could memorize only one thing about defining methods and setting variables, it's this: always ask yourself, what is self at this point?
class Hello
# This ivar belongs to Hello class object, not instance of Hello.
# `self` is Hello class object.
#instanceHello = "welcomeBack"
def printHello
# Hello##instanceHello hasn't been assigned a value. It's nil at this point.
# `self` is an instance of Hello class
print #instanceHello
end
def self.printSelfHello
# Now this is Hello.#instanceHello. This is the var that you assigned value to.
# `self` is Hello class object
print #instanceHello
end
end
Hello.new.printHello # >>
Hello.printSelfHello # >> welcomeBack
If you want to set a default value for an ivar, do it in the constructor:
class Hello
def initialize
#instanceHello = "welcomeBack"
end
def printHello
print #instanceHello
end
end
Hello.new.printHello # >> welcomeBack
In Ruby, instance variables are defined and used in instance methods. So you need to put your assignment in the initialize method:
class Hello
def initialize
#instanceHello = "welcomeBack"
end
def printHello
print(#instanceHello)
end
end
Hello.new.printHello();
Also, note that I moved the printHello call outside of the class definition. This is because the class isn't actually defined until after it is closed the first time; that is, after the last end.
class Hello
#instanceHello = "welcomeBack"
def printHello
puts self.class.instance_variable_get(:#instanceHello)
end
Hello.new.printHello; #=> welcomeBack
end
This is not good programming, but just to illustrate that a class (which is an instance of the class Class) can also have instance variables, like any other instance. They are called "class instance variables" and are preferred to class variables. The following example illustrates how a counter could be defined at the class level :
class Hello
#counter = 0
class << self # access methods for class instance variables must be
# defined in the singleton class
attr_accessor :counter
end
def printHello
self.class.counter += 1
puts "Hello #{self.class.counter}"
end
end
Hello.new.printHello; #=> Hello 1
Hello.new.printHello; #=> Hello 2
p Hello.singleton_methods #=> ["counter=", "counter"]
change #instanceHello to self.class.instance_variable_get(:#instanceHello)
#instanceHello is a class instance variant
the code is this:
class Hello
#instanceHello = "welcomeBack"
##classHello = "greeting!"
def printHello
print(self.class.instance_variable_get(:#instanceHello))
print(self.class.class_variable_get(:##classHello))
end
end
Hello.new().printHello();
I am writing a class method to create another class method. There seems to be some strangeness around how class_eval and instance_eval operate within the context of a class method. To illustrate:
class Test1
def self.add_foo
self.class_eval do # does what it says on the tin
define_method :foo do
puts "bar"
end
end
end
end
Test1.add_foo # creates new instance method, like I'd expect
Test1.new.foo # => "bar"
class Test2
def self.add_foo
self.instance_eval do # seems to do the same as "class_eval"
define_method :foo do
puts "bar"
end
end
end
end
Test2.add_foo # what is happening here?!
Test2.foo # => NoMethodError
Test2.new.foo # => "bar"
class Test3
def self.add_foo
(class << self; self; end).instance_eval do # call explicitly on metaclass
define_method :foo do
puts "bar"
end
end
end
end
Test3.add_foo # => creates new class method, as I'd expect
Test3.foo # => "bar"
My understanding is that class methods are instance methods defined on the metaclass of the class in question (Test2 in this case). Based on that logic, I would expect the receiver for the class method call add_foo to be the metaclass.
What is self referring to inside the Test2.add_foo method?
Why does calling instance_eval on this receiver object create an instance method?
The main difference between instance_eval and class_eval is that instance_eval works within the context of an instance, while class_eval works within the context of a class. I am not sure how familiar you are with Rails, but let's look at this for an example:
class Test3 < ActiveRecord::Base
end
t = Test3.first
t.class_eval { belongs_to :test_25 } #=> Defines a relationship to test_25 for this instance
t.test_25 #=> Method is defined (but fails because of how belongs_to works)
t2 = Test3.find(2)
t2.test_25 #=> NoMethodError
t.class.class_eval { belongs_to :another_test }
t.another_test #=> returns an instance of another_test (assuming relationship exists)
t2.another_test #=> same as t.another_test
t.class_eval { id } #=> NameError
t.instance_eval { id } #=> returns the id of the instance
t.instance_eval { belongs_to :your_mom } #=> NoMethodError
This happens because belongs_to is actually a method call that happens within the context of the class body, which you cannot call from an instance. When you try to call id with class_eval, it fails because id is a method defined on an instance, not in a class.
Defining methods with both class_eval and instance_eval work essentially the same when called against an instance. They will define a method only on the instance of the object it is called against.
t.class_eval do
def some_method
puts "Hi!"
end
end
t.instance_eval do
def another_method
puts "Hello!"
end
end
t.some_method #=> "Hi!"
t.another_method #=> "Hello!"
t2.some_method #=> NoMethodError
t2.another_method #=> NoMethodError
They differ, however, when dealing with the class.
t.class.class_eval do
def meow
puts "meow!"
end
end
t.class.instance_eval do
def bark
puts "woof!"
end
end
t.meow #=> meow!
t2.meow #=> meow!
t.bark #=> NoMethodError
t2.bark #=> NoMethodError
So where did bark go? It got defined on the instance of the class' singleton class. I'll explain more below. But for now:
t.class.bark #=> woof!
Test3.bark #=> woof!
So to answer your question about what self is referring to within the class body, you can construct a little test:
a = class Test4
def bar
puts "Now, I'm a #{self.inspect}"
end
def self.baz
puts "I'm a #{self.inspect}"
end
class << self
def foo
puts "I'm a #{self.inspect}"
end
def self.huh?
puts "Hmmm? indeed"
end
instance_eval do
define_method :razors do
puts "Sounds painful"
end
end
"But check this out, I'm a #{self.inspect}"
end
end
puts Test4.foo #=> "I'm a Test4"
puts Test4.baz #=> "I'm a Test4"
puts Test4.new.bar #=> Now I'm a #<Test4:0x007fa473358cd8>
puts a #=> But check this out, I'm a #<Class:Test4>
So what is happening here is that in the first puts statement above, we see that inspect is telling us that self within the context of a class method body is referring to the class Test4. In the second puts, we see the same thing, it's just defined differently (using the self.method_name notation for defining class methods). In the third, we see that self refers to an instance of Test4. The last one is a bit interesting because what we see is that self is referring to an instance of Class called Test4. That is because when you define a class, you're creating an object. Everything in Ruby is an object. This instance of object is called the metaclass or the eigenclass or singleton class.
You can access the eigenclass with the class << self idiom. While you're in there, you actually have access to the internals of the eigenclass. You can define instance methods inside of the eigenclass, which is congruent with calling self.method_name. But since you are within the context of the eigenclass, you can attach methods to the eigenclass' eigenclass.
Test4.huh? #=> NoMethodError
Test4.singleton_class.huh? #=> Hmmm? indeed
When you call instance_eval in the context of a method, you're really calling instance_eval on the class itself, which means that you are creating instance methods on Test4. What about where I called instance_eval inside of the eigenclass? It creates a method on the instance of Test4's eigenclass:
Test4.razors #=> Sounds painful
Hopefully, this clears up a few of your questions. I know that I have learned a few things typing out this answer!