Created
December 27, 2010 12:20
-
-
Save Sujimichi/756096 to your computer and use it in GitHub Desktop.
also available here http://pastie.org/pastes/1408409
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
##Ruby Tutorial | |
#This tutorial is to help you get started with using Ruby. | |
#I Assume you have Ruby installed with a copy of 'irb'. If not then install RubyVersionManager and ruby 1.9.2 (instructs to follow) | |
#Starting with the most basic, this is a comment. Marked with the # symbol | |
#I will use #=> to mean the output of a command | |
#The Basics | |
1 #This is a number, more specifically a Fixnum. An Integer value without decimal. | |
#You can do Maths with Fixnums as expected; | |
1 + 3 * 3 - 1 #=> 9 | |
(1 + 3) * (3 - 1) #=> 8 | |
5 / 2 #=> 2 !!! Wait thats not right should be 2.5. | |
#Calculations involving just Fixnums will return a Fixnum. Fixnum / Fixnum => Fixnum. | |
#When you need a decimal answer use a decimal in the calculation | |
5.0 / 2 #=> 2.5 #which is a Float | |
#5 / 2.0 would have the same effect (also see type casting later) | |
#A Fixnum in a calculation with a Float will return a Float. | |
#paste this into your irb window; | |
puts "hello World!!" | |
#That HAS to be the easiest implementation of that age old intro to programming | |
"hello World!!" #Is a String | |
#puts is a ruby method which outputs strings to the command line | |
"anything inside double quotes" | |
'or single quotes is a string object' | |
"you can put 'single quotes' inside double without breaking the string" #Double quotes are more "powerful" | |
"you can echo values/variables/method calls into a string like this #{5 + 2}" #The contents of the #{} is called at the time is parsed | |
#Ruby also has a short string class called Symbol | |
:a_symbol #will be treated like the string "a_symbol" (but it is not a string) | |
#Symbols can not have spaces and are prefixed with : | |
#Defining and Calling Variables | |
#Variables do not have to be pre defined | |
my_variable = 4.2 #you just assign a variable a value with the = operator (see naming conventions later) | |
my_variable #=> 4.2 #And call it | |
#A variable takes on the properties of the object Class you placed in it, therefore; | |
my_variable.round #=> 4 because it is now a FLoat and you can call .round on a Float | |
#the Class of variables is dynamically reassigned | |
var1 = 42 #var1 is now a Fixnum | |
var1 = "a string" #var1 is now a String | |
#There is no problem reusing a already defined variable for a different Class | |
a = 8039849 | |
b = 119.5 | |
c = 2893638431 #Assign some values to some variables | |
((a * b * 2) + c).round #Do Some maths | |
#=> 4815162342 #Return answer (which happens to be the number from Lost!) | |
#Float, Fixnum Symbol and String are all different types of Class. | |
#An instance of a Class e.g; 5 is an object. More on this later, just note that; | |
#Everything in Ruby is an object, so everything has a Class. | |
#Type Casting - Changing one class into another | |
2.to_f #=> 2.0 It has cast the Fixnum into a float | |
#So you can write 5.0/2 as | |
5.to_f / 2 #=> 2.5 | |
#You can cast a Float to a Fixnum | |
2.8.to_i #=> 2 It has cast the Float into a Fixnum, note it is rounded down | |
:ruby.to_s #=> "ruby" The symbol has been cast to a string | |
#There are limits to what can be cast into what. For example an Array [] cannot be cast into an Integer, but a string can; | |
"this string is not a number".to_i #=> 0 | |
"5 might get converted thou".to_i #=> 5 #A number at the beginning of a string is parsed, the rest is ignored. | |
#Rounding | |
2.8.round #=> 3 Will also return a Fixnum this time rounded according to decimal value | |
2.8.floor #=> 2 #round up | |
2.4.ceil #=> 3 #round down | |
##Equality and Comparison | |
true #Ruby's yin and yang | |
false #true and false are the boolean operators in Ruby, both are objects so yep they have a Class too. | |
5 == 5 #=> true | |
5 == 4 #=> false #Basic equality test | |
# == can also be written with .eql? which is a method on the object 5 | |
5.eql?(4) #=> false | |
true != false #=> true #The ! is the not operator in Ruby; true does not equal false returns true :) | |
not true == false #=> true #not is synonymous with ! | |
#greater than less than | |
5 > 4 #=> true | |
5 > 5 #=> false | |
5 < 5 #=> false | |
5 >= 5 #=> true | |
5 <= 5 #=> true | |
##Arrays and Hashes | |
#Arrays are indicated with square brackets [] | |
a = [] #A new empty array object (of the class Array) | |
a = Array.new #Would have the same effect | |
#Arrays are linear stores for arbitrary objects. Arrays retain their order | |
an_array = [1, 2.5, 3, "some str", true] | |
an_array.first #=> 1 | |
an_array.last #=> true #first and last, methods on the array object | |
an_array[1] #=> 2.5 #Accessing by index using [] | |
#NOTE Array indexes start at 0 !!! | |
an_array_of_arrays = [ [1,2,3], ["a", "b", "c"] ] #two arrays inside another array | |
an_array_of_arrays[0][1] #=> 2 #the 2nd value of the 1st inner array | |
an_array_of_arrays[1][2] #=> "c" #the 3rd value of the 2nd inner array | |
#Hashes are indicated with curly brackets {} | |
h = {} #a new empty hash object (do I need to say, class == Hash) {} == Hash.new | |
#hashes are indexable stores for arbitrary objects. Hashes do not retain order, they store a key, value pair | |
h = {:a_key => "a string", :true => true, :some_data => [1,2,3]} | |
#values in hashes are addressed like arrays, only the keys is used rather than numerical index | |
h[:some_data] #=> [1,2,3] | |
#Both Arrays and Hashes can be written over several lines to improve readability | |
an_array_of_arrays = [ | |
[1,2,3], | |
["a", "b", "c"], | |
"foo" | |
] | |
hash = { | |
:a_key => "a string", | |
:true => true, | |
:some_data => [1,2,3] | |
} | |
##Logic | |
#The Good ol' If block | |
a = (rand * 10).round #rand returns a Float between 0 and 1 | |
if a.eql?(1) | |
puts "the value a is 1" | |
elsif a.eql?(2) | |
puts "the value a is 2" | |
else | |
puts "Im a really stupid program that can only identify 1 and 2" | |
end# puts "the value of a is #{a}" #Would be a better! | |
#Ruby's unless block | |
#Ruby syntax has a nicer way of writing if not true or if !true | |
unless a.eql?(0) #Same as if !a.eql?(0) OR if not a.eql?(0) OR if a != 0 | |
puts "the value of a is #{a}" | |
else | |
puts "a was zero" | |
end | |
#Ruby allows 'if / unless' to be written inline without an 'end'. If there was no need to report "a was zero" then; | |
puts "the value of a is #{a}" unless a.eql?(0) | |
#AND OR && || | |
puts "the value of a is #{a}" unless a.eql?(0) || a.is_a?(String) # || is the OR operator | |
#This will now only run if a is not a String or if a is not == to 0 | |
#is_a? is an equality test for class same as value.class == String | |
puts "the value of a is #{a}" if a.is_a?(Fixnum) && a >= 1 # && is the AND operator | |
#&& is a "fast failing" AND. If the first assertion fails it returns without evaluating the others. | |
#If b && a; And b is more computationally intensive it would be better to write if a && b. Thus if a is false it does not need to call b | |
#In this case, if a is not a Fixnum then a >= 1 will not be evaluated. | |
##Loops | |
#Loops in Ruby come in various different forms. | |
#To call some code n number of times. The code in between the do..end is called a block. | |
5.times do |i| | |
puts i | |
end | |
#will loop 5 times. In each loop the variable i will be available; starting with i = 0 and ending on i=4 | |
#It will however return 5 at the end (explanation later) | |
#loop through an array | |
values = [1,2,3] | |
for value in values #Now I've shown you this loop, I want you to forget it an never use it!! | |
puts value | |
end | |
values.each do |value| #This how you 'should' write a loop to iterate through an array. | |
puts value | |
end | |
#The variable defined within the | | pipes is in the scope of the loop only. Once the loop as finished you could not call value | |
#They are both valid syntax but the first one is just a wrapper for the later. | |
#The first one makes a nice sentence 'for thing in things' but is not interchangeable with any other Ruby loop syntax. | |
#The latter is more akin to other aspects of Ruby (see methods and blocks later) | |
#That same loop could also be written | |
values.each {|value| puts value } #the do..end are replaced with {..} | |
#Variable scopes and Loops | |
#Certain variables are available both inside and outside a loop, others are limited to just withitn the loop. | |
s = 0 | |
values.each{|v| | |
s = s + v #The variable s is in scope both inside and outside the loop, v is just inside the loop. | |
} #note the { } notation is not limited to one line usage. | |
s #=> 6 #After the loop, 's', defined before the loop is in scope. | |
#v is not in scope anymore (see more about scope later) | |
v #=> NameError: undefined local variable or method `v' for main:Object | |
#At the end of an each loop you will be returned the object which was iterated over. After array.each{|i| #somecode } you are returned array. | |
#This allows you to chain method calls. So in a contrived example where you want to do two loops over the same object one after the other you could say; | |
values.each{|value| | |
puts "the first pass outputs this string with the value: #{value}" #block for the first loop | |
}.each{|value| | |
puts "the 2nd pass outputs this string with the value: #{value + 50}" #block for the 2nd loop | |
} | |
#IT would also work just fine to write it like this | |
values.each do |value| | |
#some code | |
end.each do |value| | |
#some more code | |
end | |
#But *I think* thats Ugly, buts that's a code style / readability question. | |
#Ruby offers different ways to do comparable things so you can use the best one for the given job. | |
#Ruby has a number of variations on the lowly loop. | |
values.each_with_index do |value, i| #Two values are passed into the block, the element and its index (starting with 0) | |
puts "the value in the #{i}th position is: #{value}" | |
end | |
values = [1,2,3] | |
s = values.inject{|val, next_val| val + next_val } #.inject is also a loop like each but with a twist. | |
#On the first pass val will contain the 1st element and next_val the 2nd. | |
#However on subsequent passes val will contain the result of the previous pass, next_val will have the next element. | |
#In this case (over [1,2,3]) on the first pass val and next val are 1 and 2. the blocks' result is their addition so on the next pass val is 3 and next_val is 3. | |
#On the final pass val is 6 and next_val is nil as no further elements exist so the loop ends returning 6 | |
s #=> 6 | |
#Perhaps two of the most useful forms of loop in Ruby are .map and .select | |
changed_values = values.map{|v| v + 1 } | |
changed_values #=> [2,3,4] #the result of each pass is returned as a element of the resulting array (of same size) | |
vals = ["foo", 7, 1, 23, "bar", 3, 5, 9] | |
vals.map{|v| v.is_a?(Fixnum) } #=> [false, true, true, true, false, true, true, true] | |
vals.map{|v| v if v.is_a?(Fixnum) } #=> [nil, 7, 1, 23, nil, 3, 5, 9] | |
vals.select{|v| v.is_a?(Fixnum) } #=> [7, 1, 23, 3, 5, 9] | |
#select is like the previous map only the 'v if' is implicit AND it removes the nil values. | |
#select selects elements for which the block evaluates true | |
#Don't forget with all these examples using {} notation for the blocks that the 'do...end' notation would work just as well. | |
##Methods or Functions | |
#A method is a named block of code encased in a def..end | |
def a_simple_method | |
#This method can be called but will return 'nil' | |
end | |
def add_values a, b | |
a + b | |
end | |
#The above method takes two arguments and sums them. It must have both arguments satisfied. | |
#Ruby will implicitly return result of the last line in a method. | |
#Methods are called like this | |
result = add_values(2, 8) #calls with args and assigns result to variable | |
results = add_values 3, 5 #method calls can be written without the parenthesis, but some consider that sloppy. Depends on usage realy. | |
#Now lets change the method to make the last arg optional. if b is not supplied then it is set to be nil | |
def add_values a, b = nil | |
if b.nil? #Any object can have .nil? called on it. It is inherent to all classes. In fact it is inherited (see Class inheritance later) | |
return a #return halts the method or a loop block it is within and returns the value at that line. | |
end | |
a + b | |
end | |
#This method will return a is b is not given, or if both given will add them | |
#Rubys inline 'if' would allow this to be written like this; | |
def add_values a, b = nil | |
return a if b.nil? | |
a + b | |
end | |
#NOTE nil is not the lack of an object, nil is an object itself. It can not be used to test if something exists | |
foo.nil? #=> NameError: undefined local variable or method `foo' for main:Object | |
foo = nil | |
foo.nil? #=> true | |
#While nil is not the same as false, it is considered false in an if context. | |
#The previous method could be written 'return a if !b' or 'return a if not b' or better still use 'unless' | |
def add_values a, b = nil | |
return a unless b | |
a + b | |
end | |
#This would perhaps be the best way to write this, assuming the most of the time you do supply both arguments | |
def add_values a, b = nil | |
return a + b if b | |
a | |
end | |
#Now for a different method | |
def sum_values values = Array.new #Takes one argument or sets it to [] if values not supplied | |
return nil unless values.is_a?(Array) #don't do anything and return nil unless values is an Array | |
values.inject{|i,j| i + j } #use inject to sum the elements in values and return implicitly | |
end | |
#method calls, map, inject select etc all return objects which can be treated as usual. | |
#So you can call methods one after the other sequentially | |
values = [1,2,3] | |
values.map{|v| v + 2}.inject{|i,j| i + j}.floor.to_f #=> 12.0 | |
sum_values(values) * 2 #=> 12 | |
#So now you have the basics of Ruby variables, methods, logic, loops and some primitive Classes | |
#You can define a method | |
def sum_values values = Array.new | |
values.inject{|i,j| i + j } if values.is_a?(Array) #same effect as above sum_values, just more compact | |
end | |
#and assign data to a variable | |
vals = [34, 53.87, 12.2, rand*10, 34.4] | |
#And pass the variable into the method to get a result | |
answer = sum_values(vals) | |
#But this all seems rather functional. Isn't Ruby meant to be Object Oriented? Yes, but you can write in both an OO and functional style. | |
##Rubys Naming Conventions | |
#Ruby comes from japan where they are sick of tryingToRead horribleCammelCased varaiableNames likeTheses | |
#Instead in_ruby we_use_underscored variable_and_method_names | |
#This is the convention; | |
Array #Capitalization is used for Classes and Constants | |
Array.new #All methods are lowercase and underscored | |
an_array = Array.new #An instance of a class (an object) is lowercase_underscored | |
##Object Oriented - Classes | |
#In Ruby every thing is an object and every object has a class. Also classes in Ruby are hierarchically arranged. | |
#So far you have seen some of the basic classes like String and Array. On every class you can instantiate a new instance of that class | |
a = Array.new | |
s = String.new | |
#on any object you can inquire about its class. | |
a.class #=> Array | |
s.class #=> String | |
5.class #=> Fixnum | |
a.class.class #=> Class | |
#The Class of a class is Class!! wtf. | |
#This is where you can see that everything in Ruby is a Class, and also that every class is a decedent of Class. | |
#Well great, what does that all mean? | |
#The inheritance of classes means that all classes have the methods which are defined in Class. | |
#for example you can call .nil? on any object because .nil? is defined on Class. | |
#So if Class is itself a class, can I do this? | |
Class.new | |
#Answer yes, but all you get back is a Class so its not much use. | |
#To define a new class is like defining a method only the keyword is class not def and the name Must be CapitalisedCammelCased | |
class Vegetable | |
end | |
#And there you have it, Vegetable is now defined. | |
vegetable = Vegetable.new | |
vegetable.class #=> Vegetable | |
#But still not a very useful class. We want to have vegetables which do things. | |
class Vegetable | |
def initialize weight # initialize is called when .new is called on a Class. Vegetable.new will call this method | |
@weight = weight.to_f # @variables!! A variable with @ is in the scope of the class, not just the method. @weight can be accessed anywhere inside a vegetable | |
end | |
def weighs | |
puts @weight | |
end | |
end | |
#Now we could create some vegetables with weight values and get the values back | |
veg_1 = Vegetable.new(5) | |
veg_2 = Vegetable.new(8) | |
veg_1.weighs #=> 5 | |
veg_2.weighs #=> 8 | |
#OK now we want some different types of vegetable and this is where we use class inheritance | |
class Tomato < Vegetable | |
def good_for_throwing? | |
@weight >= 8 # returns the boolean response from >= | |
end | |
end | |
class Potato < Vegetable | |
def poisonous? | |
rand < 0.1 | |
end | |
end | |
tomato = Tomato.new(9) | |
potato = Potato.new(5) | |
[tomato, potato].map{|veg| veg.weighs} #=> [9,5] #map the weights from each veg | |
tomato.good_for_throwing? #=> true | |
potato.poisonous? #=> rand dependent output | |
#We now have two classes which share some common methods but which behave differently. | |
#You can now create groups of objects of these classes. | |
#Ruby allows classes to be redefined at runtime. This means you can use an existing class, but modify it during execution. | |
#Assuming that you pasted the above code defining Vegetable and its sub classes into your irb window, paste this in. | |
class Vegetable | |
def eat_a_bit bit = rand | |
return "none left" if @weight <= 0 | |
@weight -= bit | |
end | |
end | |
#The Existing Vegetable class has now been patched with a new method. You can now call .eat_a_bit on any vegetable. | |
potato.eat_a_bit | |
#Going back to the earlier example of using a method to sum values in an array, we can now put that method into Array itself | |
vals = [34, 53.87, 12.2, rand*10, 34.4] | |
#Currently calling vals.sum will not work. There is no .sum method. So we need to define one. | |
class Array | |
def sum | |
self.inject{|i,j| i + j } #self is a references to the instance of that class. It has replaced the call to values from sum_values before. | |
end | |
end | |
#And now there is!! | |
#The code you add will replace existing methods of the same name but leaves the rest unchanged. | |
vals.sum #=> 6 | |
#Now you have the basics of creating a class and extending existing classes. With the definition of methods is all there really is to it. | |
##Advanced Stuff | |
#When you define a method it is a block of code which has a name. When you use a loop the block of code inside the loop is nameless. | |
#There is another nameless block which is simple called a 'block' and uses &blk to represent it. | |
#You can define a method with takes &blk as an argument. It can only take one &blk and it must be the last arg. | |
def test r = rand, &blk | |
yield(r) | |
end | |
#This method takes some code passed into it as &blk and 'yields' that code inside the method | |
#it also passes r into the block with it is called (r is rand is not given) | |
test { puts "I don't take an arg" } | |
test {|f| puts "I take an arg and show it #{f} inside this string" } | |
ans = test {|f| 5 * 3 + f } | |
#When passing args as well as a block the syntax to call is like this; method(variables){block} | |
ans = test(6){|f| 5 * 3 + f } | |
#This is not just useful. This is fundamental to how Ruby works. | |
#When you call values.each{|f| #some_code} you are calling the method .each and passing it a &blk. | |
#In all cases where a {} or do end encases some code, that is a &blk which will be yield at some point. | |
#.each on an array will call yield on the block you passed for each element in the array and will pass the element in as the arg. | |
#This is why the array.each{|element| #code} syntax is more regarded than the for element in array syntax. | |
#Another form of nameless method is a Proc. These are like blocks but they can be assigned to variables. | |
some_code = Proc.new{|arg| | |
if arg.is_a?(String) | |
puts "arg is a string" | |
else | |
arg * 5 | |
end | |
} | |
#some_code now holds a bit of code which can be called. In this case because there is an arg it must be supplied. | |
some_code.call("slkjflksdjf") #=> arg is a string | |
some_code.call(5) #=> 25 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment