Learn Ruby and rails from rails guru
Posts tagged learn ruby
Quick Start Ruby -5, Inheritance
May 22nd
This is a continuation of the following series of posts
Quick Ruby Tutorials-1
Quick Ruby Tutorials-2
Quick Ruby Tutorials-3
Quick Ruby Tutorials-4, Decision Making
def self.x
puts “I m a class method defined in class A”
end
def y
puts “I m an instance method defined in class A”
end
end
class B
end
b = B.new
B.x # no method error
b.y # no method error
The errors are obvious as we the methods x and y do not exist in class B.
end
b = B.new
B.x # “I m a class method defined in class A”
b.y # “I m an instance method defined in class A”
In the defination of class B, the part “< A" tells ruby that class B is inheriting from class A.
When class B inherits from class A, all the properties(methods, instance and class variables) in class A are available to class B
Syntax is as follows
end
Let us take another example
attr_accessor :sound
def initialize(s)
puts "in initialize of Animal class"
self.sound = s
end
def make_sound
puts self.sound + “ “ + self.sound
end
end
Let us define a class dog which inherits from animal
end
d = Dog.new(“bhow”) #in initialize of Animal class
d.make_sound # “bhow bhow”
Here we need to pass the sound of dog, every time a new dog is born.
But dog will always make the sound “bhow”. We need not pass the value for sound every time we create an instance of the Dog. For this we would need to override the initialize method in the Dog class as shown.
def initialize
puts "in initialize of Dog class"
self.sound = “bhow”
end
end
d = Dog.new #in initialize of Dog class
d.make_sound # “bhow bhow”
Note that in the above Dog class we have overridden the initialize method of the animal class(base class).
This overrides the initialize method of the base class(irrespective of the number of arguments).
So when the dog object is created, the initialize method of the Animal class is not executed.
There will be many occurrences when we only want to slightly modify the behaviour of the base class method, like
- add some more processing to the output of the method.
- call the method with some specific parameters to the method.
For this we need to access the base class(Animal) method in the derived class(Dog) method.
We can do this with the keyword “super”.
def initialize
puts "in initialize of Dog class"
super(“bhow”)
end
end
d = Dog.new
#in initialize of Dog class
#in initialize of Animal class
d.make_sound # bhow bhow
As we see first the initialize method in the Dog is called, which calls the initialize method in the Animal class with parameter “bhow”
Let us consider another use of “super”. We want the dog to bark 4 times when the make sound is called, unlike the make_sound method of the animal class which makes sound 2 times.
def initialize
puts "in initialize of Dog class"
super(“bhow”)
end
def make_sound
super
super
end
end
d = Dog.new
#in initialize of Dog class
#in initialize of Animal class
d.make_sound # bhow bhwo bhow bhow
Above we called super 2 times in the make_sound function. Due to this the sound is printed 4 times.
Let us take another example for overriding.
def to_s
"the string version of this array is: " + super
end
end
x = MyArray.new(['a','b','c'])
x.to_s # the string version of this array is: abc
In the above example we saw how we processed the output of the base class method, in the child class method.
Share
Quick Ruby Tutorials-4, Decision Making
Apr 17th
This is a continuation of the following series of posts
Quick Ruby Tutorials-1
Quick Ruby Tutorials-2
Quick Ruby Tutorials-3
Currently our Dog eats, anything and everything given to it. Lets give our dog some choice.
if you give the dog chocolate, it should ask for some more, otherwise it should behave normally.
def eat(food="bone")
puts "I am eating #{food}"
if (food == "chocoloate") # parnthesis are optional
puts "Give me some more"
end
end
end
d = Dog.new
d.eat("bread") # I am eating bread
d.eat("chocolate")
#I am eating chocolate
#Give me some more.
In the above code, we are using the If statement to make decisions ie to execute a certain part of code only if a particular condition is satisfied.
Syntax of if statement is as follows
# code1 which executes when expression1 is true
elsif (<expression2>)
# code2 which executes when expression2 is true and expression1 is false
elsif (<expression3>)
# code3 which executes when expression3 is true and expression 1 & 2 are false
else
#code 4 which executes when expression 1&2&3 are false.
end
The expression can be any ruby statement. If the output of the expression is true/not nil then the corresponding code is executed other wise it moves to the next elsif/else
So above
if expression1 one evaluates to true then code 1 is executed
if expression1 is false and expression2 is true then code2 is executed
…
if no expression is evaluated to true then the code in the else block is executed.
The elsif and the else block are optional.
There can be multiple elsif blocks but only one else block.
Else block does not accept any argument.
The else block is the last block in the if statment. After that there can be no further elsif/else
The if statement ends with a “end” irrespective of then number of elsif.
There can be different forms of if statements given below
#code which is executed if expression is true
end
A short form for this is this is
This is called a one liner if statement
Example:
puts "Drive Slow" if speed > 60 # Drive Slow
time = "afternoon"
puts "Good Morning" if time == "morning" #
The one liner if statements are very useful when there is no elsif/else part and the body of the if is just a single line of ruby code.
#code1
else
#code2
end
Here one of the parts code1 or code2 is always executed.
#code1
elsif expression2
#code2
end
Here if expression1 is true then code1 is executed, if expression1 is false but expression2 is true then code2 is executed. If both are false then nothing is executed.
More about expressions.
Again: The body of the if statement is executed if the expression evaluates to true or a non nil value which is not false.
Or
The body of the if statement is not executed if the expression evaluates to false or nil.
We will demonstrated this using one liner if statement.
In the body of the one liner if, we will keep a puts statement.
So if there is any output on screen, then we know that the expression has been satisfied.
puts "this will not print" if 2 > 3 #
puts "2 is less than 3" if 2 < 3 # 2 is less than 3
puts "this will not print" if 3 < 2 #
puts "3 which is a non nil object evaluates to true" if 3 #3 which is a non nil object evaluates to true
puts "true" if true # true
puts "this will not print" if false #
puts "this will not print" if nil
puts "3 is equal to 3" if 3 == 3 # 3 is equal to 3
puts "x is equal to 3" if x = 3 # x is equal to 3
puts "3 is not equal to 2" if 3 != 2 #3 is not equal to 2
Above we have used constants in the expression. This was to keep things simple.
We can use variables, method calls, and their combination in an expression.
Every expression can be a combination of objects, methods calls, operators.
2 important things to note from the above example are:
we can check whether an variable/object x exists by doing
The if statement is only executed when the object x exists ie when its value is not nil.
Second thing is, in case of an assignment operation, the output of the expression is the value which is assigned.
So if we do
x = y
then the output of this expression is y.
Coming back to the dog example:
Lets modify our Dog class so that,
if you give it “banana” to eat, the dog should not eat. It should ask for something else.
def eat(food="bone")
if food == "banana"
puts "I do not eat banana, give me something else"
else
puts "I am eating #{food}"
end
if food == "chocolate"
puts "Give me some more"
end
end
end
d = Dog.new
d.eat("banana") #I do not eat banana, give me something else
d.eat("bread") # I am eating bread
d.eat("chocolate")
#I am eating chocolate
#Give me some more.
Note that the condition if food == chocolate is being tested for even if the food is banana. We should move that loop into the body of if. This is called nested if ie an if inside if.
def eat(food="bone")
if food == "banana"
puts "I do not eat banana, give me something else"
else
puts "I am eating #{food}"
if food == "chocolate"
puts "Give me some more"
end
end
end
end
d = Dog.new
d.eat("banana") #I do not eat banana, give me something else
d.eat("bread") # I am eating bread
d.eat("chocolate")
#I am eating chocolate
#Give me some more.
It would much cleaner if we add a one liner if condition here, that makes it much more readable
def eat(food="bone")
if food == "banana"
puts "I do not eat banana, give me something else"
else
puts "I am eating #{food}"
puts "Give me some more" if food == "chocolate"
end
end
end
Lets add some more conditions, If you give it bone then it should say “great, u made my day”.
if you give it “sandwich” then it should say “mmmmmmmmmmmm, I have never eaten like this one before”
if you give it milk, then it should tell “Thankyou, I will become a strong dog after drinking milk”
Previous conditions also apply. It should not say “I am eating xyz” along with other statements as above.
def eat(food="bone")
if food == "banana"
puts "I do not eat banana, give me something else"
elsif food == "chocoloate"
puts "Give me some more"
elsif food == "bone"
puts "Great, you made my day"
elsif food == "sandwich"
puts "mmmmmmmmm I have never eaten like this one before"
elsif food == "milk"
puts "Thank you, I will become a strong dog after drinking milk"
else
puts "I am eating #{food}"
end
end
end
We replace this by a case statement.
Case statement is an alternative for a if statement.
If the output of a calculation depends on a value of an object, and the number of cases are high then it can become very cumbersome if you use if statement. It is much easier doing the same using a case statement.
Syntax for the case statement is :
when match_1 then result_1
when match_2 then result_2
when match_3 then result_3
when match_4 then result_4
else result_5
end
</end>
<code lang="ruby">
class Dog
def eat(food="bone")
message = case food
when "banana" then "I do not eat banana, give me something"
when "chocolate" then "Give me some more"
when "bone" then "Great, you made my day"
when "sandwich" then "mmmmmmmmm I have never eaten like this one before"
when "milk" then "Thank you, I will become a strong dog after drinking milk"
else "I am eating #{food}"
end
puts message
end
end
So this looks much cleaner the the code with if statement.
Note how we collected the output of the case statement in the variable message, and then printed the variable. We could have instead printed the value in the case statement it self as done in the if statement.
But this one is better, as if later, instead of printing the message on screen, I just want to return the message, or store it in a file then I would need to just change one line. Instead if we had embedded the puts in the case itself, then we would need to change many lines.
The code which adapts to a change, with lesser lines of changes, in lesser number of files, is a better code.
Let us take a different scenario:
A dog will reject the following items: banana, mango
It will accept the following : biscuit, bread, milk
def eat(food="bone")
if food == "banana" || food == "mango"
puts "I do not eat #{food}, give me something else"
elsif food == "milk" || food == "bread" || food == "biscuit"
puts "thank you for giving me #{food}"
else
puts "Can this be eaten?"
end
end
end
d = Dog.new
d.eat("banana") #I do not eat banana, give me something else.
d.eat("bread") # thank you for giving me bread.
d.eat("ball") # can this be eaten?
Now,if this list of eatables gets very long( the food which dog can eat and once which it cannot), then the program would become very cumbersome.
Let us use some magic of arrays to this.
@@good_food = ["milk", "bread", "biscuit","bone"]
@@bad_food = ["banana", "mango"]
def eat(food="bone")
if @@bad_food.include? food
puts "I do not eat #{food}, give me something else"
elsif @@good_food.include? food
puts "thank you for giving me #{food}"
else
puts "Can this be eaten?"
end
end
end
Here we are defining 2 class variables: @@good_food and @@bad_food. We initialize each of these to an array holding the respective food types.
In the if statement we use a method include?(x) on the array object.
This method returns true if x is present in the array else it returns false.
For a complete list of methods present in the array classs go to: http://ruby-doc.org/core/classes/Array.html
One fine day our dogs realize that global warming is increasing a high rate.
All the scientist dogs get together and do a research on this. They come to a conclusion that the major cause of the global warming is non vegetarianism(http://www.goveg.com/environment.asp).
So they all decide to go veg
Now if you gave our veg dogs a bone or meat to eat, should reject it, telling that stop non veg,stop global warming!.
Let us modify our code to do the same.
@@non_veg_food = ["bone","meat"]
@@good_food = ["milk", "bread", "biscuit"]
@@bad_food = ["banana", "mango"]
def eat(food="bone")
if @@bad_food.include? food
puts "I do not eat #{food}, give me something else"
elsif @@good_food.include? food
puts "thank you for giving me #{food}"
elsif @@non_veg_food.include? food
puts "Go Veg, Stop Global Warming!"
else
puts "Can this be eaten?"
end
end
end
dog = Dog.new
dog.eat("bone") #Go Veg, Stop Global Warming!
So, by now our dogs have become very choosy. You can go ahead and do the following extensions:
- Add methods to the class to modify(add/remove) the food choices of the dog
- Currently all our dogs have the same choices, add functionality so that each dog can have their own choices, they may have some default choices when the are born.
- Let the food habits of a dog develop automatically: When a dog is given a food to eat when it is hungry, add the foo to the good food list, when a dog is given food to eat when it is not well, or when it is not hungry then add the food to bad food list.
These are just ideas, you can try whatever comes to your mind, be creative
.
Share
Quick Ruby Tutorials-3, class and instance methods
Apr 6th
This is a continuation of the following series of posts
Quick Ruby Tutorials-1
Quick Ruby Tutorials-2
In the last post our Dog class had the abilities to eat, sleep, bark, shit etc.
The class definition for Dog class looked like
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
Let us extend it.
Besides other activities like sleeping, barking etc, our dog can now eat food.
On eating the food digestion should start. We make one more method for the same and call it in
the “eat” method.
def eat(food="bone")
puts "I am eating #{food}"
digest_food
end
def digest_food
puts "digesting food"
end
end
d = dog.new
d.eat
# I am eating bone
#digesting food
We could have written the code to digest food in the method “eat”, but we create a separate method called “digest” and call this method in “eat”. This is known as Single Responsibility Principle(SRP), ie each method should have only one responsibility. This helps to maintain the code.In future if the code changes, it is easier to change and test a small method which does only one thing. If we have a method which is big and performs many tasks at the same time then it is difficult to change and maintain the code.
Here we can directly call the digest_food method as shown.
This is not correct, digestion should only start after eating food. If we call digest_food directly then it can start even if the dog has not eaten the food.
Digesting food is an internal function of the dog which is triggered due to some other external event( here eating food).We should not be able to access digest_food method from outside the class.
For this we will make the digest_food method as private.
Private??
What are Private and Public Methods?
Private methods are ones which cannot be accessed/called from outside the class.
The methods which we were defining till now were public methods. By default all the methods of the class are public ie they can be accessed inside/outside the class. To make a method as private we need to add a keyword private as shown below.
private
def digest_food
end
def another_method
end
end
d = Dog.new
d.digest_food #error: private method digest food called
d.another_method #error: private method another_method called
As seen above, all the methods defined after the keyword private are private methods.
So our class definition looks like.
def eat(food="bone")
puts "I am eating #{food}"
digest_food
end
private
def digest_food
puts "digesting food"
end
end
d = dog.new
d.digest_method #error: private method another_method called
What are Class methods and Instance Methods?
Whatever methods we were defining till now were instance methods. Like bark, eat, digest_food etc.
We called these methods with respect to the instance/object like.
dog.bark
As these methods are related to an instance of the class they are called instance methods.
We cannot call instance method with respect to the class.
dog.weight #works
Dog.weight #error: NoMethod error
Class methods are ones which are called with respect to the class.
We have already come across a class method “new”. We don’t need to define “new” as Ruby gives this method for free with every class
.
We do Dog.new, we cannot do dog.new.
Class variables and instance variables
Instance variables are variables which are linked to the instance/object of the class
Instance variables as we have seen start with @ sign. There is a separate copy of the instance variable for each instance. They are accessible within a class in all the instance methods. They are not accessible outside a class. They are the ones responsible to store the data for an instance/object.
Class variables are once which store the data at class level.
Only one copy of the class variable is created for a class.
Class variables can be accessed in class as well as instance method.
There is a separate copy of instance variable for for every instance, but there is only one copy class variable.
Let us use a class variable to keep the count of number of dogs born.
@@population
end
#NameError: uninitialized class variable @@population in Dog
Above we defined a class variable population. Class variables are defined by adding a “@@”" before the variable name. But we need to initialize a class variable when it is being defined.
@@population = 0
end
We will increment the count of population after each dog is born. We can do this in the initialize method. We will also add a class method to access the value of the class variable.
@@population = 0
def initialize
@@population += 1
end
def self.population
return @@population
end
end
puts Dog.population # 0
d1 = Dog.new
puts Dog.population # 1
d1 = Dog.new
puts Dog.population # 1
d2 = Dog.new
puts Dog.population # 2
d3 = Dog.new
puts Dog.population # 3
Note how the class method is defined. A extra “self.” is added in front of the method name.
Let us try accessing the object_id(it is unique for every object) of the variable @@population in a class method and instance method.
@@population = 0
def initialize
@@population ++
end
def self.population
return @@population
end
def population
return @@population
end
def self.class_population_id
return @@population.object_id
end
def instance_population_id
return @@population.object_id
end
end
puts Dog.population # 0
d1 = Dog.new
d2 = Dog.new
d3 = Dog.new
d4 = Dog.new
puts Dog.population # 4
puts d1.instance_population_id # 233323
puts d2.instance_population_id # 233323
puts d3.instance_population_id # 233323
puts d4.instance_population_id # 233323
puts Dog.class_population_id #233323
Above we have done the following
- defined a class and instance method “population” to access the population count.
- defined a class and instance method “class_population_id” and “instance_population_id” to access the object_id of the class variable @@population.
The value of the population count from class and different instances is the same.
The object_id of class_variable @@population is also same from class and instance methods.
This implies that there is only one copy of the class variable.
More examples of a class method could be
- a find method to find the dogs with a particular name
- a count method which will return the total number of dogs
- an average age method which returns the average age of all the dogs which are alive.
Note the above all methods are performing some operation on a set of dogs, not on an individual dog, so they have to be defined as a class method.
We can use instance methods in place of class method, and call it with reference to a particular instance, but it is not the correct way.
def average_weight
puts "This should have been defined as a class method"
end
end
dog = Dog.new
dog.average_weight # This should have been defined as a class method
end
class Dog
def self.average_weight
puts "perfect"
end
end
Dog.average_weight #perfect
We can also use class methods in place of instance methods by passing the instance as a parameter to the method but again that is not the correct way.
def self.weight(dog)
puts "this should have been as instance method as it is related only to a particular dog."
end
end
dog = Dog.new
Dog.weight(dog) #this should have been as instance method as it is related only to a particular dog.
class Dog
def weight
puts "perfect"
end
end
dog = Dog.new
dog.weight #perfect
So In this post we have seen the following
Public And Private methods
Class methods and Instance methods
Class variable and instance variable.
More in the next post.
Share
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 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