Learn Ruby and rails from rails guru
Archive for March, 2010
Quick Ruby Tutorials–2
Mar 24th
This is a continuation of the post Quick Ruby Tutorials -1
In the last post we created a Dog class with the ability to eat and bark. Lets continue to add more features to our class.
Each dog has a name, weight, height, color etc.
Let us add the property “weight” to the Dog class.
For this we need to
1) Store the weight of the dog. For this purpose we use an instance variable. Instance variables are explained later.
2) Add a method to access the weight
3) Add a method to set the weight.
def get_weight
@weight
end
def set_weight(w)
@weight = w
end
end
dog1 = Dog.new
dog1.set_weight(4)
dog1.get_weight #4
dog2 = Dog.new
dog2.get_weight # nil
dog2.set_weight(10)
dog2.get_weight # 10
dog1.get_weight # 4 , weight of dog1 still remains the same
@weight is an instance variable.
Instance variable start with @ sign.
Instance variable can be defined in any instance method. In this case it is defined in set_weight. In get weight it is being accessed, so if get_weight is called before set_weight then it returns a nil.
Note that, changing the weight of dog2 does not effect the weight of dog1.
So there is different copy of instance variable(@weight) for every instance(object). That is why we call it a instance variable.
Let us try accessing our instance variable directly from the object.
dog.@weight #error : syntax error
dog.weight #error: undefined method weight.
So we see that the instance variables are not accessible outside the object. That is the reason we needed to define the the instance methods get_weight and set_weight.
Let us change the names of the methods get_weight and set_weight
def weight
return @weight
end
def weight= new_weight
puts "in method weight="
# @weight is an instance variable. Instance variables start with @ sign.
@weight = weight
end
end
Now we can do
dog.weight #nil
dog.weight= 10 #in method weight=
dog.weight # 10
dog.weight = 20 #in method weight=
dog.weight # 20
Supper!!!
Note the special type of name we have given to method “weight=”.
This method is called when we do weight= or weight =(note the space between “weight” and “=”)
All these are same
dog.weight= 10
dog.weight = 10
Due to these type of methods and the possibility of eliminating parenthesis,
it does not look like we are accessing a method. It is as if we are accessing a variable “weight” inside the dog object.
When the name of the method is of the format method_name=, then ruby expects the method to accept only a single parameter. If you define a method with this format which accepts no parameters or accepts more than one parameters, then there would be a run time error. Try doing this
Hold to your seats tight, you may fly away after reading the next example
attr_accessor :weight
end
dog = Dog.new
dog.weight #nil
dog.weight = 10
dog.weight # 10
How did this happen, with just one line of code in the Dog class??
attr_accessor is a method which generates the getter method(to get the value of the instance variable),
and setter method(to set the value of the instance variable)
:weight: this is a data type symbol in ruby. attr_accessor creates instance variable @weight when it is passed the symbol :weight
More about symbols
Symbol. A symbol is an instance of the class Symbol and is defined by prefixing a colon with an identifier eg :name, :weight, :height etc. .
symbols are data types in ruby which are identified by a unique value property ie you cannot create 2 separate objects with same values.
y = :test
x.object_id # 79858
y.object_id# 79858
a = "test"
b = "test"
a.object_id # 22528570
b.object_id # 22520730
object id for both x and y are same. Object id is an internal id unique to the variable.(the values may be different for you)
object id for the strings are different. ie 2 different objects are created
Symbols are lighter version of their string counter parts
Symbols are much lighter on memory than strings
Most operations which can be performed on strings cannot be done on symbols.
Operations like read a part of the string, append something, delete some part of string etc
symbols with space are defined like :”ruby on rails”
symbols comparison is faster than string comparison as symbol comparison is just one comparison of hash value, but string comparison involves multiple comparison character by character(till there is no match)
When to use a symbol/ when to use a string
Whenever you want to name some thing: some property, key/value of a hash, but no string operations are required , use a symbol.
Getting back to our example,
Here attr_accessor generates for us the 2 mehtods weight and weight=.
We can pass multiple parameters to the attr_accessor method
attr_accessor :weight, :height, :name, :color
end
This creates the setter and getter methods for instance variables @weight, @height, @name and @color. ie it will create weigh,weight=, height and height= etc methods.
So now we can do
d.weight = 10
d.weight #10
d.height = 1
d.height #1
d.name = "Tim"
d.name #"Tim"
d.color = "brown"
d.name # "brown"
Similar to attr_accessor there attr_reader and attr_writer methods.
attr_reader only generate the reader(weight/height).
attr_writer only generates the writer(weight=/height=).
The properties of dog such as height/weight/color etc cannot me modified externally. ie they can only be read, not written. They may get modified due some internal processes. Like the weight and height of the dog grows due to metabolic activities internally.
The instance methods we define should only expose things which are possible.
So modification of weight, height, color should not be possible directly .
Of course we should be able to feed the dog more to increase its weight
attr_reader :weight, :height, :color
attr_accessor :name
end
d = Dog.new
d.weight = 1 # error undefined method weight= for the instance
d.height = 2 # error undefined method height= for the instance
d.color = "brown" # error undefined method color= for the instance
puts d.weight #nil
puts d.height #nil
puts d.color #nil
Not that you would need to comment out the line with errors for the program execution to complete
So it is clear from the above example that only setter/writer methods are not defined, only getter/reader methods are defined
Now our dog is born with no values set for weight, height, color. This is not correct.
Whenever a dog is born(a new object is created), the dog should have some weight, height, color etc.
Lets say when a dog is born it has a weight of 1 kg, height 0.5 feet and color “brown”.
We can use constructors for this purpose, similar to those in C++.
A constructor is a method which is called immediately after a new object is created.
In ruby the constructor method is named “initialize”.
So if you define a method with name “initialize” in your class, it will be called after a object of that class is created.
attr_reader :weight, :height, :color
attr_accessor: name
def initialize
puts "in initialize" #This is used to demonstrate the flow of control
@weight =1
@height = 0.5
@color = "brown"
end
end
dog = Dog.new #in initialize
puts dog.weight # 1
puts dog.height #0.5
dog.color # brown
Let us give our dog a name
puts dog.name # Tim
Note that a dog when born does not have a name. It is given to it later.
That is the reason we did not assign the name in the initialize method.
As per the above code, all the dogs born will have a weight of 1kg, height of 0.5 feet and white color.
If god would have written such a program, then there would be no diversity on this planet. That would be very boring, right?
We should have a option of selecting the weight, height and color. If we can pass these parameters to the new method that would be perfect.
That can be done making our initialize method accept some parameters.
attr_reader :weight, :height, :color
attr_accessor: name
def initialize(weight, height, color)
puts "in initialize"
@weight, @height, @color = weight, height, color #note the parallel assignment of variables
end
end
dog1 = Dog.new(2,1,"white") # in initialize
puts dog1.weight # 2
puts dog1.height # 1
puts dog1.color # white
dog2 = Dog.new # error: wrong number of arguments 0 for 3
It would be great if there are some defaults for the weight, color and heigth.
ie, if the value is not passed then use a default value
attr_reader :weight, :height, :color
attr_accessor: name
def initialize(weight = 1,height = 0.5, color = "brown")
puts "in initialize"
@weight, @height, @color = weight, height, color
end
end
d = Dog.new #in initialize
puts d.weight # 1
puts d.height # 0.5
puts d.color # white
d2 = Dog.new(4,2) #in initialize
puts d2.weight # 4
puts d.height # 2
puts d.color # brown
d3 = Dog.new
puts d2.weight # 1
puts d.height # .5
puts d.color # brown
So now God has lot more flexibility in creating new dogs
Add other abilities to our Dog :sleep, eat, run
attr_reader :weight, :height, :color
attr_accessor: name
def initialize(weight = 1,height = 0.5, color = "white")
puts "in initialize"
@weight, @height, @color = weight, height, color
end
def bark
puts "bhow bhow!!!"
end
def eat(food="bone")
puts "I am eating #{food}"
end
def sleep
puts "bbye, I am going to sleep"
end
def shit
puts "aah! now I am hungry again"
end
end
dog = Dog.new
dog.bark # bhow bhow!!!
dog.eat # I am eating bone
dog.sleep # bbye, I am going to sleep
dog.shit #aah! now I am hungry again
Now our dog can eat, bark, sleep and shit.
Good enough, we will enhance our dog in the next post.
Share
Learn Ruby – Procs, Blocks, Lambda
Mar 12th
Procs and Blocs is the part of Ruby which is not clear to many. This post should help you clear your doubts about Procs and Blocks.
Procs
Like variables hold data, procs hold the code itself.
Procs are first class objects of ruby with class Proc
We define a Proc as follows:
#or
my_proc = Proc.new do
puts “I am a Proc”
end
The first syntax is generally used for one liner Procs and the second one for multiline procs. Though there will be no errors if you do the other way, it is a good convention to follow.
Executing a Proc
To execute the Proc we do
Procs can accept parameters:
#single parameter, single line proc
print_name = Proc.new{|name| puts “my name is #{name}”}
print_name.call(“pankaj”) # “my name is pankaj”
#multiple parameters, single line proc
print_full_name = Proc.new{|first_name,last_name| puts "My name is #{first_name} #{last_name}"}
print_full_name.call("Pankaj","Bhageria") # My name is Pankaj Bhageria
#single parameter, multiple line proc
display_mult_table = Proc.new do |number|
for i in 1..5
puts "#{number} * #{i} = #{number*i}"
end
end
display_mult_table.call(2)
# 2 * 1 = 2
# 2 * 2 = 4
# 2 * 3 = 6
# 2 * 4 = 8
# 2 * 5 = 10
#multiple parameter, multiple line proc
for i in 1..limit
puts "#{number} * #{limit} = #{number*i}"
end
end
display_mult_table.call(2,3)
# 2 * 1 = 2
# 2 * 2 = 4
# 2 * 3 = 6
Note how the parameters are passed to the Proc definition in between the two vertical bars.
Passing a Proc to a method
As a proc is just another object, it can be passed around in methods, returned by methods etc. Suppose we want a block of code to be executed a certain number of times.
for i in 1..times # note the use of range here
code.call(i)
end
end
my_proc = Proc.new{|x| puts “I have been called #{x} times”}
run_code(5,my_proc)
#output:
# I have been called 1 times
# I have been called 2 times
# I have been called 3 times
# I have been called 4 times
# I have been called 5 times
Blocks
Blocks like procs are used to pass code to methods, but they are like undefined procs. ie they are not assigned to any variable, they are just passed to the methods. It will be more clearer when you see the examples.
They can be passed to any method, the method may or may not use them.
Then how does the method execute the block, as there is no parameter to reference it. The method can call the block, by giving the command “yield” which executes the code in the block.
# body of the method
end
some_method(){puts "I am passing a block"}
some_method{puts "I am passing a block"}
#Let us define a method which uses a block
def run_my_code
yield
end
run_my_code{puts "I am passing a block"}
# I am passing a block
#passing multiline blocks
run_my_code do
puts "I am passing a multiline block"
puts "This is the second line of the block"
end
#I am passing a multiline block
#This is the second line of the block
Blocks can be passed along with the other parameters of the method.
for i in 1..times
yield
end
end
run_my_code(2) { puts "passing a block along with params"}
#passing a block along with params
#passing a block along with params
run_my_code(2) do
puts "line1: passing a multi-line block along with params"
puts "line2: passing a multi-line block along with params"
end
#line1: passing a multi-line block along with params
#line2: passing a multi-line block along with params
#line1: passing a multi-line block along with params
#line2: passing a multi-line block along with params
Blocks can accept parameters like methods
for user in users
name = user[:first_name] + " " + user[:last_name]
yield(name)
end
end
#Name is Pankaj Bhageria
#Name is David Jones
Note that in the above example you can change the format of printing anytime by just changing the call to the method. You donot need to modify the method.
So this seperates the 2 things -
Working on the data: Here we are simply calculating the full name of the user, in real life it could have been more complex -
Using the result: Here we are passing the result to the output stream. We can store it to a database/file system or something.
If we need to store the result in a database/file we just need to modify the block passing along with the method.
Use of Ampersand(&)
Ampersand is used to convert a proc to a block and a block to a proc.
If a method want to accept a block but wants to use it as a proc, then add an & in front of the last parameter(the parameter which will receive the block.
my_code.call
end
run_my_code { puts "passing a block, accepting a proc"}
#passing a block, accepting a proc
Note above that we are using “my_code.call” and not yield.
If you have a proc and you want to pass it to a method which accepts block, then when passing use a ampersand before the proc parameter.
yield
end
my_proc = Proc.new { puts "passing a proc instead of block"}
run_my_code my_proc #error, wrong number of arguments
run_my_code &my_proc # passing a proc instead of block
So we have successfully passed a proc to a method which accepts a block
Important points
Only one block can be accepted by a method.
A block can be passed to any method, no need to define it.
To pass a proc instead of a block append an “&” in front of the Proc.
Lambda
my_lambda.call("Ruby")
#Ruby
Lambda is exactly same as a Proc with some minor difference, which we will take up in another post.
Share
Quick tips for learning Rails
Mar 11th
Know you basics well:
Without knowing your basics(programming, object oriented concepts, design patterns, database concepts),
you would face many difficulties in the path of becoming an expert.
Learn Ruby
It is a myth that knowing Ruby is not required to learn rails. But beware, without Ruby your path on Rails would be very bumpy and short.
Learn SQL:
Knowledge of sql is a must to write complex queries in active record and debugging problems related to database.
Write Code, Write Code, Write Code
This the best thing you can do.
Type out the code you write, do not copy paste from an ebook or any training material you are reffering.
This point is not about copy pasting chunks of code from the internet. When you are learning rails from some ebook or some e material, then when you try out examples, you tend to copy paste from the material. This way you never learn/remember the syntax and the method names.
Believe me, follow this one and you will remember the syntax, names of the methods only after 2-3 times you type it out. If you copy paste code, then even after 2 yrs of working on rails, you would be stuck without api.rubyonrails.org or google to refer for syntax.
Ask why
Ask why, understand why you are writing this and not something else. At first there will be many questions. Move ahead, and keep asking the questions, slowly all the pieces of the puzzle will join, and your questions will be answered.
Do not get stuck at some point, if you are not understanding some thing. Assume and move ahead, and come back to it later. Don’t be very fanatic about understanding everything in the first go. This way you may get frustrated and stop.
Read others good code.
This will help you prevent making mistakes and write better code faster.
Share
The darker side of the frameworks
Mar 4th
Frameworks and libraries make our life easier. But they also have their darker side.
They take away the basic power of the programmer, the power to think.
Yes frameworks make us lazy, and when difficult problems arise then we feel lost.
This is most true for people who directly start programming with some high level languages.
When difficult situations come, we are not ready to face it.
People who have worked with C (and assembly), had to write code for operations link sorting an array, for searching in an array and many such operations.
This builds their programming ability and prepares them to face tough business logic programs. I agree a lot of time was wasted in writing duplicate code due to this.
Today there are frameworks and libraries,for all the basic tasks which we come across during coding there are methods available. This saves lots of time and prevents duplication of efforts. But it also makes the programmers lazy.
A bit of complexity creates a turbulence in the mind of the programmer.
I am absolutely not telling you do not use the ready made methods available.
My point is keep aside a portion of your learning time to write some complex programs, so that you get a hang of them. That’s it.
These programs may be simple ruby programs. Let them have no relation with Rails. But they will help build your programming skills and your thought process.
Examples of some of such programs are
Sort an array of numbers by using different techniques
Print an array of numbers in all possible combination of order.
Loop through a 2 dimensional array and print all the pairs of elements.
Search in an array of numbers for a particular number, and return the first instance found
Write a program to find factorial of 2 numbers
Share


Quick Ruby Tutorials-1
Mar 19th
Posted by Pankaj Bhageria in Ruby
13 comments
So let us start learning Ruby.
To write ruby code you can use IRB ie interactive ruby for very short programs.
For larger programs you can use any other editor like Emacs or TextMate or SciTE(which ships with Ruby on windows).
Religiously we will make our first program ie “Hello World”
#OR
puts "Hello World" #Output: Hello World
puts is a method(function) which prints the string passed to it on the screen.
The string written after the # is the comment ie it is not executed by Ruby.
Comments are used to explain the code( like to show the output in our case).
These start with a # and the rest of the line after
The output for the above program is given at the end of the corresponding line as a comment. From now onwards we will not specify the word “Output” in the comments.
2+ 2 #this is a comment with other ruby code
As Ruby is fully object oriented language(Basically everything in ruby is an object.) we will start with classes and objects.
Let us create a class to represent a Dog.
end
Note how the classes are defined
end
To create an instance of Dog
d is the instance/object of the class dog.
So we have confirmed that the object d is of class Dog
As every thing in ruby is an object, let us check out the class of different datatypes.
puts "this is a string".class #String
puts 2.2.class #Float
We can create as many instances of dog we want
scooby = Dog.new
pummy = Dog.new
Here we have created 3 dogs: timmy, scooby, pummy
Now let us add to the dog capibilty to bark. For this we need to pass a command to the dog to bark
With the help of methods we can give the ability to ruby objects to receive messages
Methods are like functions in c/c++/java.
def bark
puts "bhow bhow!!"
end
end
d = Dog.new
d.bark() #bhow bhow !!
Ruby allows us to eliminate the parenthesis for method calls, it looks more cleaner without the parenthesis.
Note how the methods are defined
#method body
end
Above we used methods “new” and ‘class’. But we never defined these?
Ruby gives several methods for free to a class and object, so there is no need to define them.
When you pass message to an object, the object should reply back.
So every method in ruby returns some value.
Infact every statement in ruby has a return value.
the the class for nil is NilClass
Let us see the return values for different statements
go to irb and type the following without comments(comments are the output)
"test" # test
1 + 2 # 3
x = 1 # 1
x = 'Ruby' # Ruby
puts "Hello World"
#Hello World
# nil
Above we see the output of the various kinds of statements. The output is specified by the comments.
nil is the output of the puts satement. “Hello World” is due the puts statement, which prints on the screen.
nil in ruby mean, nothing, it is used to represent something which doesnot exist. It is similar to the null in sql.
#As we had told everything in ruby is an object, so nil also an object of Class NilClass
go to irb
NilClass
So a method when called also returns a specific value. Like the puts has a return value of nil.
return value of the method can be explicitly stated by return value or it is the output of the last statement executed in the method
The return value of the method bark is nil, because the last statement executed is puts “bhow bhow”, and puts method returns nil
Note the return value is not the string “bhow bhow”. This string is just printed be the puts statement.
puts value # nil
What is use of the return value.
The return value is useful when the method call is a part of another exression.
We can redefine our bark method as follows
def bark
return "bhow bhow!!"
end
end
d = Dog.new
puts d.bark # "bhow bhow !!"
Now the bark method returns the value “bark”, and this value is used in the put statement.
The return value could be used in any other way lik to store the value in a file/database.
We could have also defined our bark method as
def bark
"bhow bhow !!"
end
end
d = Dog.new
puts d.bark # "bhow bhow !!"
This works because, the as the rule, (as there is no explicit return) the return value is the output of the last statement executed. which is ”bhow bhow !!”
so return value of this is “bhow bhow!!”
Lets enable our dog to eat
We need to create a eat method for that
def eat
puts "I am eating"
end
end
d = Dog.new
d.eat # I am eating
We should be able to give specific food to our dog to eat.
The error tells that the method eat can accept 0 arguments and we are passing 1.(the paramter passed to a method is also called as arguments)
We should make the method “eat” accept 1 parameter/argument.
def eat(food)
puts "I am eating "
puts food
end
end
d = Dog.new
d.eat("bone")
# I am eating
# bone
From the above example we see that to define a method to accept parameters the syntax is as follows
end
To invoke the method with parameter you have to call the method with all the paramter values in the same order.
method_name(x,y,z) #x maps to param1, y maps to param2 z maps to param3
We also see that the method eat prints 2 lines. We didnot specify a new line(“/n”). This is because method puts prints a “/n” at the end by default.
We need to modify puts so that u can print the output in the same line.
def eat(food)
puts "I am eating #{food}"
end
end
d = Dog.new
d.eat("bone") # I am eating bone
d.eat "biscuit" # I am eating biscuit
Learnings from above example:
To replace a value of the value of a variable in a string do
Note that this will work only on the double quoted string
Try on irb
puts "value of x is #{x}" #value of x is 10
puts 'value of x is #{x}' #value of x is #{x}
In first case the value of x is printed, in the second case the string is printed as it is.
We could have also done
The above works if food is a string. If food is a Fixnum(integer) then
"I am eating " + 10.to_s
Learnings from above example:
to_s is a method of Fixnum class to convert it to string
To get a complete list of methods available in any class go to ruby-doc.org and see the list of methods in that class
Now every time we tell our dog to eat, we have to tell it, what is there to eat.
But most of the time we would be giving our dog, bone to eat. So when we do not tell what is there to eat, the dog should understand that we have given it bone.
If you have a background of C/C++/Java, you would probably think of using function overloading here, ie create another mehtod fodd which accepts no parameters.
If we do that in Ruby then the method which is defined first will be overridden and not overloaded ie that method will be replaced by the second method.
Let us see how
def eat(food)
puts "I am eating #{food}"
end
def eat
puts "I am eating bone"
end
end
d = Dog.new
d.eat # I am eating bone
d.eat("bone") #ArgumentError: wrong number of arguments(1 for 0)
Learnings from above example:
In Ruby there is no concept of method overloading.
In Ruby, you can re define a method any time, even after closing the class, you can reopen the class and then add/modify the exisiting methods.
define a class A
end
#reopen class a and add method m1 to it.
def m1
puts "in m1"
end
end
a = A.new
a.m1 #in m1
Reopen the class and add method m2
def m2
puts "in m2"
end
end
x = A.new
x.m1 # in m1
x.m2 # in m2
Reopen the class and modify method m2
def m2
puts "in modified m2"
end
end
a = A.new
a.m2 "in modified m2"
Let us add an eat method to a Fixnum class so that we can do 2.eat
we need to reopen the Fixnum class.
def eat
puts "I am not dog, a number cannot eat"
end
end
2.eat #I am not dog, a number cannot eat
Getting back to the world of Dogs.
We were solving to problem of allowing to call eat with and without passsing food.
We need to use default parameters for this.
The default parameter need not be passed to the method. When it is not passed it takes a default value which is defined during method defination.
So we make the parameter food as default ie the value of the food will be “bone” if no parameter is passed to the eat mehtod.
Let us see how.
def eat(food="bone")
puts "I am eating #{food}"
end
end
d = Dog.new
d.eat #I am eating bone
d.eat("chocolate") #I am eating chocolate
So now our dog understands that we have given it bone when we do not specify anything.
We have added methods for the dogs to bark, eat.
Now our dog can bark and eat.
We will add more features to our dog in later posts.
Let us summarize what we learnt
Print a string on output screen
Comments in Ruby
Define a class
Create a new object
Find the class of an object
Pass messages to an object by defining methods
Return value of methods and statements
Methods accepting parameters
Embedding values of variables in a string
Converting a number(Fixnum to a string)
Extending a class
Methods with default parameters
Share