Using symbols to access instance variables? - ruby

Apparently, Ruby can make a code block returning an instance variable's value with a symbol. Consider:
class Person
attr_accessor :fn
end
def give(n,&b)
i=0
while(i<n)
aa = Person.new
aa.fn = "name #{i}"
i=i+1
puts b.call(aa)
end
end
Now, both give(5, &:fn) and give(5) {|x| x.fn} give
name 0
name 1
name 2
name 3
name 4
=> nil
But what does &:fn really mean? I know the ampersand can convert a Proc to a block such as
bb = Proc.new {|x| x.fn}
give(5, &bb)
So what does the symbol :fn mean? Where can I see a documentation of its use like this? Can we use a symbol to access the instance variable, like say person:new or person[:new]?

Simple. The statment
attr_accessor :fn
Doesn't define some sort of special instance variable thing. It declares two methods of (approximately) this form:
def fn
#fn
end
def fn=(v)
#fn=v
end
The Ruby "syntax" &:fn is a symbol that the operator & tries to convert to a proc. And, guess what? Symbol implements to_proc. Guess that that looks like:
def to_proc
Proc.new {|obj| obj.__send__(self)}
end
That captures self, which is the symbol :fn, which, on invocation, tells obj to execute the method fn, which returns the value of the instance variable.
EDIT: Answering the second part of the question, no and yes. With the syntax you say, no. But you can call a method from a symbol with BasicObject#__send__ and you can do the same for not attr_accessor instance variables with Object#instance_variable_get.

Related

(Argument Error) thrown when trying to instantiate a custom object in Ruby

I want to instantiate an object from a class I wrote on a different file. What I got is wrong number of arguments (given 1, expected 0) (ArgumentError)
Here is the main code
# ./lib/parking_lot
require_relative './lot.rb'
class ParkingLotInterface
def initialize(input: $stdin, output: $stdout)
#input, #output = input, output
#lot = nil
end
def prompt_input
#lot = Lot.new(10)
end
end
parking_lot_interface = ParkingLotInterface.new(input: $stdin, output: $stdout)
parking_lot_interface.prompt_input
And here is the object class
# ./lib/lot
class Lot
attr_reader :slots,
def initialize(size)
#slots = Arrays.new(size)
end
end
The error was thrown at the line where I tried to instantiate a new Lot object. Looking at the internet, people who had the same problem got told that they didn't specify def initialize in the class, or they mistyped it. However, I did what they all said and I still faced wrong number of arguments (given 1, expected 0) (ArgumentError)
What did I do wrong?
In Ruby, method definitions are expressions as well (in fact, in Ruby, everything is an expression, there are no statements), so they evaluate to an object. Method definition expressions evaluate to a Symbol denoting the name of the method that was defined.
So,
def initialize(*) end
#=> :initialize
In your code, you have a comma after attr_reader :slots, which means that you pass two arguments to attr_reader, namely the symbol :slots and the expression def initialize(…) … end. Since Ruby is a strict language, the arguments to attr_reader will be evaluated first, before attr_reader itself is executed.
So, what happens first is that the method definition expression gets evaluated. This defines a (private) method named initialize. It also evaluates to the symbol :initialize.
Next, the expression attr_reader :slots, :initialize gets evaluated, which defines two methods named slots and initialize, thus overwriting the method you just defined. Note that this will print a warning:
lot.rb:3: warning: method redefined; discarding old initialize
lot.rb:5: warning: previous definition of initialize was here
You should always read the warnings, the Ruby developers don't spend the hard work putting them in just for the fun of it!
The solution is to remove the comma telling Ruby to look for a second argument.
There is a second error in your code, namely that you misspelt Array within Lot#initialize.
And, there are a couple of stylistic improvements that you could make:
There is no need to pass a path and a filename extension to require_relative. It should be require_relative 'lot'.
Un-initialized instance variables evaluate to nil, so there is no need to initialize #lot to nil.
$stdin and $stdout are the default argument values of the stdin: and stdout: keyword parameters, so there is no need to pass them explicitly.
It is seldom necessary to create an array of a specific size, since Ruby arrays are dynamic and can change their size at any time.
With all this taken in to account, your code would look something like this:
# ./lib/parking_lot
require_relative 'lot'
class ParkingLotInterface
def initialize(input: $stdin, output: $stdout)
#input, #output = input, output
end
def prompt_input
#lot = Lot.new(10)
end
end
parking_lot_interface = ParkingLotInterface.new
parking_lot_interface.prompt_input
# ./lib/lot
class Lot
attr_reader :slots
def initialize(size)
#slots = Array.new(size)
# could be #slots = []
# depending on how you use `#slots` later
end
end
Delete the comma after
attr_reader :slots,
it would be
attr_reader :slots
And take a look, you are trying to instance Arrays (and must not to be in plural) on lot.rb
def initialize(size)
#slots = Arrays.new(size)
end
it would be
def initialize(size)
#slots = Array.new(size)
end

Binding method to instance

Is there a way to bind an existing method to an existing instance of an object if both the method and the instance are passed as symbols into a method that does that if the instance is not a symbol?
For example:
def some_method
#do something
end
some_instance = Klass.new(something)
def method_that_binds(:some_method, to: :some_instance)
#how do I do that?
end
Your requirements are a little unusual, but it is possible to do this mostly as you say:
class Person; end
harry = Person.new
barry = Person.new
def test
puts 'It works!'
end
define_method :method_that_binds do |a_method, to|
eval(to[:to].to_s).singleton_class.send(:define_method, a_method, &Object.new.method(a_method))
end
method_that_binds :test, to: :harry
harry.test
# It works! will be sent to STDOUT
barry.test
# undefined method 'test'
This doesn't actually use a named parameter, but accepts a hash with a to key, but you can see you can call it in the way you want. It also assumes that the methods you are defining are defined globally on Object.
The API you want doesn't easily work, because you have to know from which scope you want to access the local variable. It's not quite clear to me why you want to pass the name of the local variable instead of passing the content of the local variable … after all, the local variable is present at the call site.
Anyway, if you pass in the scope in addition to the name, this can be accomplished rather easily:
def some_method(*args)
puts args
puts "I can access some_instance's ivar: ##private_instance_var"
end
class Foo; def initialize; #private_instance_var = :foo end end
some_instance = Foo.new
def method_that_binds(meth, to:, within:, with: [])
self.class.instance_method(meth).bind(within.local_variable_get(to)).(*with)
end
method_that_binds(:some_method, to: :some_instance, within: binding, with: ['arg1', 'arg2'])
# arg1
# arg2
# I can access some_instance's ivar: foo
As you can see, I also added a way to pass arguments to the method. Without that extension, it becomes even simpler:
def method_that_binds(meth, to:, within:)
self.class.instance_method(meth).bind(within.local_variable_get(to)).()
end
But you have to pass the scope (Binding) into the method.
If you'd like to add a method just to some_instance i.e. it's not available on other instances of Klass then this can be done using define_singleton_method (documentation here.)
some_instance.define_singleton_method(:some_method, method(:some_method))
Here the first use of the symbol :some_method is the name you'd like the method to have on some_instance and the second use as a parameter to method is creating a Method object from your existing method.
If you'd like to use the same name as the existing method you could wrap this in your own method like:
def add_method(obj, name)
obj.define_singleton_method(name, method(name))
end
Let's say we have a class A with a method a and a local variable c.
class A
def a; 10 end
end
c = '5'
And we want to add the method A#a to c.
This is how it can be done
c.singleton_class.send :define_method, :b, &A.new.method(:a)
p c.b # => 10
Explanations.
One way to add a method to an object instance and not to its class is to define it in its singleton class (which every ruby object has).
We can get the c's singleton class by calling the corresponding method c.signleton_class.
Next we need to dynamically define a method in its class and this can usually be accomplished by using the define_method which takes a method name as its first argument (in our case :b) and a block. Now, converting the method into a block might look a bit tricky but the idea is relatively simple: we first transform the method into a Method instance by calling the Object#method and then by putting the & before A.new.method(:a) we tell the interpreter to call the to_proc method on our object (as our returned object is an instance of the Method, the Method#to_proc will be called) and after that the returned proc will be translated into a block that the define_method expects as its second argument.

Why are symbols in Ruby not thought of as a type of variable?

New to programming and to Ruby, and I hope this question about symbols is in line. I understand that symbols in Ruby (e.g., :book, :price) are useful particularly as hash keys, and for all-around doing a lightweight, specific subset of the things that strings can do.
However, I am confused about symbols in one respect. Specifically, when they're used in the attr_accessor types of methods, it appears that they are behaving more like a variable. E.g., attr_reader :book, :price.
If true that they are variables in that usage, this is a bit puzzling because they are not typically listed among variable types (like the $global, #instance, local, ##class, and sometimes, CONSTANT, variable types) when variables types are described.
And if symbols are variables when used this way, what scope should be expected of them? Or are they still somehow lightweight strings in this context as well? (Or perhaps in some broader way, do symbols, strings, and variables all share a fundamental duck-like nature?) Thank you in advance for your insights and advice.
Symbols are not variables, but a type of literal value, like numerals and quoted strings. Significantly, symbols are used to represent variables and other named values in the Ruby runtime. So when the Ruby interpreter sees the name foo used as a variable or method name, what it looks up in the Hash of runtime values is the symbol :foo, not the string "foo". This was, in fact, the original use of the term "symbol" in programming language terminology; variables, functions, constants, methods, and so on are said to be stored in the compiler or interpreter's "symbol table".
Pretty much any time you're passing around the name of something in Ruby, you're going to use a symbol. If you use method_missing as a catch-all to implement arbitrary methods on your object class, a symbol is what it receives as an argument telling it the name of the method that was actually called. If you inspect an object with .methods or .instance_variables, what you get back is an array of symbols. And so on.
They aren't variables because they don't hold values, they are immutable. The thing is the value itself. It's similar to numbers. You can't set the value of 1. 1 = 2 doesn't work.
Symbols used in accessor methods are not variables. They are just representing the name of a variable. Variables hold some reference, so you cannot use a variable itself in defining accessor methods. For example, suppose you wanted to define an accessor method for the variable #foo in a context where its value is "bar". What would happen if Ruby's syntax were to be like this:
attr_accessor #foo
This would be no different from writing:
attr_accessor "bar"
where you have no access to the name #foo that you are interested in. Therefore, such constructions have to be designed to refer to variable names at a meta level. Symbol is used for this reason. They are not variables themselves. They represent the name of a variable.
And the variable relevant to accessor methods are instance variables.
attr_accessor and such are all methods that belong to the class, Class. They expect symbols as arguments. You could write your own version of attr_ that used strings, if you wanted. Its just a ruby idiom. Here's an example of attr_acessor that stores all the previous values of attr_accessor I made for a homework assignment.
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s # make sure it's a string
attr_reader attr_name # create the attribute's getter
attr_reader attr_name+"_history" # create bar_history getter
class_eval %Q"
def #{attr_name}=(value)
if !defined? ##{attr_name}_history
##{attr_name}_history = [nil]
end
##{attr_name} = value
##{attr_name}_history << value
end
"
end
end
Ruby's attr_accessor, attr_reader, and attr_writer are just shorthand ways of avoiding writing a bit of repetitive code. The following question expands on how these work: Why use Ruby's attr_accessor, attr_reader and attr_writer?
Instead of thinking of attr_reader :book as a variable, just think of it as a name of an attribute that is specified using a symbol.
To address your "If true that they are variables" and "scope" questions, it would have been simpler to answer that accessor symbols have nothing to do with instance variables, even if it sounds iconoclastic. They don't point to instance variables. Accessors only define getter and setter methods. Under Object#instance_variables, the Pickaxe(*) says : Note that simply defining an accessor does not create the corresponding instance variable.
In Ruby, a variable does not exist until you assign a value to it. The following code demonstrates this.
class MyClass
attr_accessor :name
attr_reader :book
end
obj = MyClass.new # line 6
print '1) obj.instance_variables : '; p obj.instance_variables
print '2) obj.name : '; p obj.name
obj.name = 'xyz'
print '3) obj.instance_variables : '; p obj.instance_variables
print '4) obj.name : '; p obj.name
print '5) obj.book : '; p obj.book
class MyClass
def initialize(p_book)
#book = p_book
end
end
obj = MyClass.new('The Pickaxe') # line 21
print '6) [new] obj.book : '; p obj.book
class MyClass
method_name = 'title'
attr_accessor method_name # line 26
end
obj.title = 'Programming Ruby'
print '7) obj.instance_variables : '; p obj.instance_variables
print '8) obj.title : '; p obj.title
Output :
$ ruby -w t.rb
1) obj.instance_variables : []
2) obj.name : nil
3) obj.instance_variables : ["#name"]
4) obj.name : "xyz"
5) obj.book : nil
6) [new] obj.book : "The Pickaxe"
7) obj.instance_variables : ["#title", "#book"]
8) obj.title : "Programming Ruby"
1) empty array : accessors have not defined instance variables
2) asking for instance variable #name answers nil : it does not exist
3) assigning a value has created the instance variable.
Note that name = is a syntactic sugar for using the setter as an ordinary method with a parameter : obj.name=('xyz')
4) the getter method name answers the value of #name
5) the getter method book answers nil because the instance variable #book does not exist. Defining an accessor attr_reader :book has not defined the corresponding instance variable
6) the getter method book answers the value assigned in initialize, called by new on line 21. The instance variable #book has been created by #book = p_book
line 26) I have always believed that accessors accept only symbols. I discover that a variable is possible, but of limited interest.
7) the setter method title= has created #title. This also shows that instance variables belong to a single object. We often believe that they belong to all instances of the class, as in other languages. In this case, #name belongs only to the object created on line 6.
8) the getter method title answers the value of #title
class MyClass
def title # line 34
#book + ' (cheating !)'
end
end
print '9) obj.title : '; p obj.title
Output :
t.rb:34: warning: method redefined; discarding old title
9) obj.title : "The Pickaxe (cheating !)"
9) of course there is a tight correlation between an accessor symbol and the corresponding instance variable, because, behind the scene, Ruby creates methods which reference an instance variable of the same name. You could define your own getter and cheat.
Note that besides class variables (##var, some dislike them as ugly as global variables), classes can also have instance variables. I call them class instance variables :).
class MyClass : Ruby allocates a new instance of class Class, defines a constant MyClass, and assigns the new instance to that constant. Thus MyClass is an ordinary object (instance of Class) and as such can have instance variables.
if RUBY_VERSION[0..2] == '1.8'
class Object
def singleton_class
class << self
self
end
end
end
end
class MyClass
singleton_class.instance_eval do
attr_accessor :counter
end
#counter = 0
def initialize(p_book)
#book = p_book
self.class.counter += 1
end
end
print '10) MyClass.singleton_methods : '; p MyClass.singleton_methods
print '11) MyClass.instance_variables : '; p MyClass.instance_variables
obj = MyClass.new('Ruby')
print '12) [new] obj.book ', MyClass.counter, ': '; p obj.book
obj = MyClass.new('Metaprogramming')
print '13) [new] obj.book ', MyClass.counter, ': '; p obj.book
Output :
t.rb:55: warning: method redefined; discarding old initialize
10) MyClass.singleton_methods : ["counter", "counter="]
11) MyClass.instance_variables : ["#counter"]
12) [new] obj.book 1: "Ruby"
13) [new] obj.book 2: "Metaprogramming"
More on singleton methods here : What does def `self.function` name mean?
(*) http://pragprog.com/book/ruby3/programming-ruby-1-9
(Answer to your comment)
dog = 'dog' or String.new("dog")
After dog = String.new, the field class of instance dog points to class String.
class << dog
puts "inside #{self}" #=> inside #<Class:#<String:0x007fb38a83a820>>
def bark
puts 'woof'
end
end
dog.bark #=> "woof"
p dog.singleton_methods #=> ["bark"]
With class << dog or def dog.bark, Ruby creates an anonymous class, the field class of instance dog now points to this anonymous class, and from there to String. Methods defined in this context with def or define_method go into the methods table of the anonymous class.
Ruby 1.9.2 has introduced Object#singleton_class. [The Pickaxe] Returns the singleton class of obj, creating one if necessary. (I add) It is equivalent to class << self; self end.
The Ruby Programming Language (O'Reiily) simply says : to open the eigenclass [singleton class] of the object o, use class << o.
So I don't know how to read it loud. I have read that some would prefer o >> class. It's only recently that I have found how to figure out what this strange expression means. I pronounce : go from o to it's anonymous class.
class << MyClass
def dog
puts 'dog as class method'
end
end
MyClass.dog #=> dog as class method
The same is true for a class. With class MyClass, MyClass, as instance of Class, is an object with a pointer to its class Class. With def MyClass.some_method or class << MyClass, Ruby creates an anonymous class which is inserted between MyClass and Class, and class methods go into it.
Maybe something like: "from class, instantiate singleton object self
Yes for "from class/object" to anonymous singleton class/eigenclass/metaclass.
But we don't instantiate self. Self (in Smaltalk, this in C++/Java) is kind of a reserved word which designate the receiver of the message. dog.bark : in OO language we say that the message bark in sent to object dog. Inside the method bark, self will be set to dog, so that we can reference dog. This is more obvious with
o1 = MyClass.new; o2 = MyClass.new
o1.some_method; o2.some_method
some_method must be able to reference the receiver in a generic way, is it o1 or o2, this is what self is for.
Cool, I guess you understand them by now.
However why are they so important?
Symbols in Ruby are immutable whereas strings are mutable.
You think ok cool, so what?
Let's assume you have an array of strings, like so:
[ "a", "b", "a", "b", "a", "b", "c" ]
For each new string you create ruby is going to create a string/object which holds the value of "a" and because strings are mutable things ruby assigns a different id to each of them.
If you were to use symbols instead:
[ :a, :b, :a, :b, :a, :b, :c ]
Ruby now will point to those symbols and it will only create them once.
Let's do some benchmarking:
require 'benchmark'
Benchmark.bm do |x|
x.report("Symbols") do
a = :a
1000_000.times do
b = :a
end
end
x.report("Strings") do
a = "a"
1000_000.times do
b = "a"
end
end
end
ruby -w symbols.rb
Symbols 0.220000 0.000000 0.220000 ( 0.215795)
Strings 0.460000 0.000000 0.460000 ( 0.452653)
If you'd like to see all the symbols you have already created you could do:
Symbol.all_symbols
You can also send a message to them asking about their id:
:a.object_id #=> 123
:a.object_id #=> 123
"a".id #=> 23323232
"a".id #=> some_blob_number
Again that's because Strings in Ruby are mutable and Symbols are not.
Ruby Symbols represent names inside the Ruby Interpreter.
This video really helped me:
Ruby's Symbols Explained
I hope it helps you all.

Dynamic constant assignment

class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
gives me the error:
SyntaxError: dynamic constant assignment error
Why is this considered a dynamic constant? I'm just assigning a string to it.
Your problem is that each time you run the method you are assigning a new value to the constant. This is not allowed, as it makes the constant non-constant; even though the contents of the string are the same (for the moment, anyhow), the actual string object itself is different each time the method is called. For example:
def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
Perhaps if you explained your use case—why you want to change the value of a constant in a method—we could help you with a better implementation.
Perhaps you'd rather have an instance variable on the class?
class MyClass
class << self
attr_accessor :my_constant
end
def my_method
self.class.my_constant = "blah"
end
end
p MyClass.my_constant #=> nil
MyClass.new.my_method
p MyClass.my_constant #=> "blah"
If you really want to change the value of a constant in a method, and your constant is a String or an Array, you can 'cheat' and use the #replace method to cause the object to take on a new value without actually changing the object:
class MyClass
BAR = "blah"
def cheat(new_bar)
BAR.replace new_bar
end
end
p MyClass::BAR #=> "blah"
MyClass.new.cheat "whee"
p MyClass::BAR #=> "whee"
Because constants in Ruby aren't meant to be changed, Ruby discourages you from assigning to them in parts of code which might get executed more than once, such as inside methods.
Under normal circumstances, you should define the constant inside the class itself:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
If for some reason though you really do need to define a constant inside a method (perhaps for some type of metaprogramming), you can use const_set:
class MyClass
def my_method
self.class.const_set(:MY_CONSTANT, "foo")
end
end
MyClass::MY_CONSTANT
#=> NameError: uninitialized constant MyClass::MY_CONSTANT
MyClass.new.my_method
MyClass::MY_CONSTANT #=> "foo"
Again though, const_set isn't something you should really have to resort to under normal circumstances. If you're not sure whether you really want to be assigning to constants this way, you may want to consider one of the following alternatives:
Class variables
Class variables behave like constants in many ways. They are properties on a class, and they are accessible in subclasses of the class they are defined on.
The difference is that class variables are meant to be modifiable, and can therefore be assigned to inside methods with no issue.
class MyClass
def self.my_class_variable
##my_class_variable
end
def my_method
##my_class_variable = "foo"
end
end
class SubClass < MyClass
end
MyClass.my_class_variable
#=> NameError: uninitialized class variable ##my_class_variable in MyClass
SubClass.my_class_variable
#=> NameError: uninitialized class variable ##my_class_variable in MyClass
MyClass.new.my_method
MyClass.my_class_variable #=> "foo"
SubClass.my_class_variable #=> "foo"
Class attributes
Class attributes are a sort of "instance variable on a class". They behave a bit like class variables, except that their values are not shared with subclasses.
class MyClass
class << self
attr_accessor :my_class_attribute
end
def my_method
self.class.my_class_attribute = "blah"
end
end
class SubClass < MyClass
end
MyClass.my_class_attribute #=> nil
SubClass.my_class_attribute #=> nil
MyClass.new.my_method
MyClass.my_class_attribute #=> "blah"
SubClass.my_class_attribute #=> nil
SubClass.new.my_method
SubClass.my_class_attribute #=> "blah"
Instance variables
And just for completeness I should probably mention: if you need to assign a value which can only be determined after your class has been instantiated, there's a good chance you might actually be looking for a plain old instance variable.
class MyClass
attr_accessor :instance_variable
def my_method
#instance_variable = "blah"
end
end
my_object = MyClass.new
my_object.instance_variable #=> nil
my_object.my_method
my_object.instance_variable #=> "blah"
MyClass.new.instance_variable #=> nil
In Ruby, any variable whose name starts with a capital letter is a constant and you can only assign to it once. Choose one of these alternatives:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
Constants in ruby cannot be defined inside methods. See the notes at the bottom of this page, for example
You can't name a variable with capital letters or Ruby will asume its a constant and will want it to keep it's value constant, in which case changing it's value would be an error an "dynamic constant assignment error". With lower case should be fine
class MyClass
def mymethod
myconstant = "blah"
end
end
Ruby doesn't like that you are assigning the constant inside of a method because it risks re-assignment. Several SO answers before me give the alternative of assigning it outside of a method--but in the class, which is a better place to assign it.
Many thanks to Dorian and Phrogz for reminding me about the array (and hash) method #replace, which can "replace the contents of an array or hash."
The notion that a CONSTANT's value can be changed, but with an annoying warning, is one of Ruby's few conceptual mis-steps -- these should either be fully immutable, or dump the constant idea altogether. From a coder's perspective, a constant is declarative and intentional, a signal to other that "this value is truly unchangeable once declared/assigned."
But sometimes an "obvious declaration" actually forecloses other, future useful opportunities. For example...
There are legitimate use cases where a "constant's" value might really need to be changed: for example, re-loading ARGV from a REPL-like prompt-loop, then rerunning ARGV thru more (subsequent) OptionParser.parse! calls -- voila! Gives "command line args" a whole new dynamic utility.
The practical problem is either with the presumptive assumption that "ARGV must be a constant", or in optparse's own initialize method, which hard-codes the assignment of ARGV to the instance var #default_argv for subsequent processing -- that array (ARGV) really should be a parameter, encouraging re-parse and re-use, where appropriate. Proper parameterization, with an appropriate default (say, ARGV) would avoid the need to ever change the "constant" ARGV. Just some 2¢-worth of thoughts...

Ruby newbie question: hashes

i have the following
class test
hash={}
def printHash
puts hash[1]
puts hash[2]
puts hash[3]
end
end
test.new.printHash
this prints:
1
0
1
Why does this happen? how can i test whether or not i have put something in that spot of the hash? or am i missing something
You're well off the mark, but it appears to be doing something because hash is a builtin function which returns a Fixnum hashcode for the object. When you use square brackets on a Fixnum, you get the value of the specific bit. What you want to do is to create an instance variable, which starts with the sigil #. Also, you have to create instance variables within a method, so we'll use the one that's called whenever an object of the class is created, initialize:
class Test
def initialize
#hash = {}
end
def printHash
puts #hash[1]
puts #hash[2]
puts #hash[3]
end
end
Now you'll find this prints nil for all three. To test whether a hash has a value for a specific key, you can use has_key?.
Basically 'hash' is out of scope, what you are referencing in your printHash function is a different object altogether, normally it would be nil (a new unassigned object) but as Pesto points out 'hash' is a built in function - somewhat confusing this explanation.
By putting an '#' sign in front of the your variable and assigning it in the initialize method (which is called after 'new') it becomes available in the entire instance of your object.

Resources