why is the instance variable #my_instance return nil even thought it's been set to 0 in the my_method ?
attr_accessor should let me write and read the instance, right ?
what would be the right way to do something like this ?
thank You.
class Myclass
attr_accessor :my_instance
def initialize
#my_instance
end
def called_method
puts "this is my instance value #{my_instance} "
end
def my_method
my_instance = 0
puts "i set my instance to be #{my_instance}"
called_method
end
end
a = Myclass.new
a.my_method
called_method return nil when i expect 0
what would be the right way to do something like this ?
my_instance = 0
This creates a local variable instead of calling your setter. Give ruby a hint that you want to call the method:
self.my_instance = 0
Or you can set the instance variable directly:
#my_instance = 0
Related
This short code is working when I'm using class variable ##points instead of #points. I wonder why it's happening like this? Someone can explain me? It looks like #points is always nil.
class Game
#points = 0
def start
until #points == 10
puts "Guess number between 0 and 10:"
num = gets.chomp.to_i
break if #points == 0
guess_number(num)
puts "Your score is: #{#points}"
end
end
def guess_number(num)
#points += 1 if num == rand(0..10)
end
end
game = Game.new
game.start
Because #points is a class instance variable, and to access it from within the instance method's scope you'd have to either do
self.class.instance_variable_get(:#points)
or define an attr_accessor in Game's singleton_class
class Game; class << self; attr_accessor :points; end; end
and then you'd be able to do
self.class.points
But neither of these is what you really want.
code is working when I'm using class variable ##points instead of
#points
It is working, because you do have access to class variable from within a scope of an instance methods.
It looks like #points is always nil
It is always nil, because you never defined an instance variable #points, but, as said, class instance variable.
So these three things are different (you could read up something about Ruby scoping - do not mix with AR scopes):
class variable
class instance variable
instance variable
To solve it there are many ways, but if you want to keep it on the instance level, wrap #points into a method:
def points
#points ||= 0
end
And then use it as points - now it'll work as you are expecting.
Thanks to answer by Andrey Deineko. I came up with such solution to use instance variable here.
class Game
def initialize
#points = 0
end
def start
until points == 10
puts "Guess number between 0 and 10:"
num = gets.chomp.to_i
break if points == 10
guess_number(num)
puts "Your score is: #{points}"
end
end
private
def guess_number(num)
if num == rand(0..10)
increment_points
end
end
def points
#points
end
def increment_points
#points += 1
end
end
game = Game.new
game.start
I want to create a special settings class Settings. The class should be able to handle cases when a user types something like Settings.new.method_1.method_2.method_3 and it's translated to something like:
result = nil
if ConfigurationSettings['method_1'].present?
result = ConfigurationSettings['method_1']
if result['method_2'].present?
result = result['method_2']
...
end
return result
Of course, I'll make it more flexible later so it can have more than 2/3 "methods".
I guess this is the issue you are facing:
class Settings
def abc
puts "abc"
end
def xyz
puts "xyz"
end
end
s = Settings.new
s.abc
#abc
# => nil
s.xyz
#xyz
# => nil
s.abc.xyz
#abc
#NoMethodError: undefined method `xyz' for nil:NilClass
The issue here is s.abc is returning nil and xyz is called over nil. What you are trying to achieve is called Method Chaining. Now, xyz needs an Settings object. Simplest thing to do here is:
class Settings2
def abc
puts "abc"
self
end
def xyz
puts "xyz"
self
end
end
s2 = Settings2.new
s2.abc.xyz
#abc
#xyz
method_missing is available for your use and can be used to help you solve this problem. Coupling this with method chaining and you're good to go. For example:
class Settings
def method_missing(meth)
puts "Missing #{meth}"
self
end
def test
puts "Test"
self
end
end
a = Settings.new
a.test
a.test.b
a.b.test
The trouble with the other answers is all the methods return "self" so if you want to access a nested value...
final_value = Settings.new.method_1.method_2.method_3
You're just going to get the whole settings hash instead.
Try this instead...
class Settings
class SubSettings
def initialize(sub_setting)
#sub_setting = sub_setting
end
def method_missing(method, *arguments, &block)
if #sub_setting[method].is_a?(Hash)
SubSettings.new #sub_setting[method]
else
#sub_setting[method]
end
end
def answer
#sub_setting
end
end
def initialize
#settings = ConfigurationSettings
end
def method_missing(method, *arguments, &block)
SubSettings.new #settings[method]
end
end
ConfigurationSettings = {level1a: {level2a: {level3a: "hello", level3b: "goodbye"}, level2b: {level3b: "howdy"}}}
result = Settings.new.level1a.level2a.level3b
p result
=> "goodbye"
What this does is take the initial method and takes the associated sub-hash of the ConfigurationSettings hash and stored it into a new object of class SubSettings. It applies the next method and if the result is another sub-hash it iterates to create another SubSettings, etc. It only returns the actual result when it no longer sees hashes.
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();
How can a class method (inside a module) update an instance variable? Consider the code bellow:
module Test
def self.included(klass)
klass.extend ClassMethods
end
module ClassMethods
def update_instance_variable
#temp = "It won't work, bc we are calling this on the class, not on the instance."
puts "How can I update the instance variable from here??"
end
end
end
class MyClass
include Test
attr_accessor :temp
update_instance_variable
end
m = MyClass.new # => How can I update the instance variable from here??
puts m.temp # => nil
You'd have to pass your object instance to the class method as a parameter, and then return the updated object from the method.
That does nto quite make sense.
You use the initialize method to set default values.
class MyClass
attr_accessor :temp
def initialize
#temp = "initial value"
end
end
The initialize method is automatically run for you when you create a new object.
When your class declaration is run, there are no, and cannot be any, instances of the class yet.
If you want to be able to change the default values later you can do something like this:
class MyClass
attr_accessor :temp
##default_temp = "initial value"
def initialize
#temp = ##default_temp
end
def self.update_temp_default value
##default_temp = value
end
end
a = MyClass.new
puts a.temp
MyClass.update_temp_default "hej"
b = MyClass.new
puts b.temp
prints
initial value
hej
If you also want that to change already created instances' variables you need additional magic. Please explain exactly what you wish to accomplish. You are probably doing it wrong :)
I'm trying to understand this function.
What I can see is an attribute and type are passed to the opal() method.
Then type_name takes its value from type as long as type is a Symbol or String. Otherwise, the name method is called on type. I imagine the name method is similar to the class method to get the class of the type argument.
After self.class_eval I'm kind of lost but my guess is this is defining maybe a block of code to be added to the class referenced by self.
How this works I'm not sure though.
Would appreciate if someone could explain what's going on after self.class_eval << DEF.
def opal(attr, type)
self.ds "#{attr}_id"
type_name = (type.is_a?(Symbol) || type.is_a?(String)) ? type : type.name
self.class_eval <<DEF
def #{attr}
if defined?(##{attr})
##{attr}
else
##{attr} = if self.#{attr}_id
#{type_name}.get(self.#{attr}_id)
else
nil
end
end
end
def #{attr}=(value)
self.#{attr}_id = value.key
##{attr} = value
end
DEF
end
Everything between <<DEF and DEF is just a string and the #{ ... }s work on that string like any other.
class_eval will cause the interpreter to run on the string in the context of the module.
So, if you know what attr and type are then you can work out what code is being run to add methods to the class.
Lets say attr is "foo" and type is "Bazzle". The code being run would be:
def foo
if defined?(#foo)
#foo
else
#foo = if self.foo_id
Bazzle.get(self.foo_id)
else
nil
end
end
end
def foo=(value)
self.foo_id = value.key
#foo = value
end
To make it easy to understand, let's suppose the value of 'attr' is 'foo', here's what it looks like now:
self.class_eval <<DEF
def foo
if defined?(#foo) # Return the value of attr if it's defined
#foo
else
#foo = if self.foo_id
#{type_name}.get(self.foo_id)
else
nil
end
end
end
def foo=(value) # Define setter
self.foo_id = value.key
#foo = value
end
DEF
So it's just defining some getter and setter methods for #foo, and evaluating it at the class level.