Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ##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
Add Comment
Please, Sign In to add comment