diff options
Diffstat (limited to 'ruby.html.markdown')
-rw-r--r-- | ruby.html.markdown | 366 |
1 files changed, 300 insertions, 66 deletions
diff --git a/ruby.html.markdown b/ruby.html.markdown index 38d060a3..8f23b2e6 100644 --- a/ruby.html.markdown +++ b/ruby.html.markdown @@ -4,6 +4,15 @@ filename: learnruby.rb contributors: - ["David Underwood", "http://theflyingdeveloper.com"] - ["Joel Walden", "http://joelwalden.net"] + - ["Luke Holder", "http://twitter.com/lukeholder"] + - ["Tristan Hume", "http://thume.ca/"] + - ["Nick LaMuro", "https://github.com/NickLaMuro"] + - ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"] + - ["Ariel Krakowski", "http://www.learneroo.com"] + - ["Dzianis Dashkevich", "https://github.com/dskecse"] + - ["Levi Bostian", "https://github.com/levibostian"] + - ["Rahil Momin", "https://github.com/iamrahil"] + --- ```ruby @@ -29,6 +38,12 @@ You shouldn't either 8 - 1 #=> 7 10 * 2 #=> 20 35 / 5 #=> 7 +2**5 #=> 32 + +# Arithmetic is just syntactic sugar +# for calling a method on an object +1.+(3) #=> 4 +10.* 5 #=> 50 # Special values are objects nil # Nothing to see here @@ -46,8 +61,6 @@ false.class #=> FalseClass # Inequality 1 != 1 #=> false 2 != 1 #=> true -!true #=> false -!false #=> true # apart from false itself, nil is the only other 'falsey' value @@ -61,15 +74,37 @@ false.class #=> FalseClass 2 <= 2 #=> true 2 >= 2 #=> true +# Logical operators +true && false #=> false +true || false #=> true +!true #=> false + +# There are alternate versions of the logical operators with much lower +# precedence. These are meant to be used as flow-control constructs to chain +# statements together until one of them returns true or false. + +# `do_something_else` only called if `do_something` succeeds. +do_something() and do_something_else() +# `log_error` only called if `do_something` fails. +do_something() or log_error() + + # Strings are objects 'I am a string'.class #=> String "I am a string too".class #=> String -placeholder = "use string interpolation" +placeholder = 'use string interpolation' "I can #{placeholder} when using double quoted strings" #=> "I can use string interpolation when using double quoted strings" +# Prefer single quoted strings to double quoted ones where possible +# Double quoted strings perform additional inner calculations + +# Combine strings, but not with numbers +'hello ' + 'world' #=> "hello world" +'hello ' + 3 #=> TypeError: can't convert Fixnum into String +'hello ' + 3.to_s #=> "hello 3" # print to the output puts "I'm printing!" @@ -110,32 +145,47 @@ status == :approved #=> false # Arrays # This is an array -[1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] +array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] # Arrays can contain different types of items -array = [1, "hello", false] #=> => [1, "hello", false] +[1, 'hello', false] #=> [1, "hello", false] # Arrays can be indexed # From the front array[0] #=> 1 array[12] #=> nil +# Like arithmetic, [var] access +# is just syntactic sugar +# for calling a method [] on an object +array.[] 0 #=> 1 +array.[] 12 #=> nil + # From the end array[-1] #=> 5 -# With a start and end index -array[2, 4] #=> [3, 4, 5] +# With a start index and length +array[2, 3] #=> [3, 4, 5] + +# Reverse an Array +a=[1,2,3] +a.reverse! #=> [3,2,1] # Or with a range array[1..3] #=> [2, 3, 4] # Add to an array like this array << 6 #=> [1, 2, 3, 4, 5, 6] +# Or like this +array.push(6) #=> [1, 2, 3, 4, 5, 6] + +# Check if an item exists in an array +array.include?(1) #=> true # Hashes are Ruby's primary dictionary with keys/value pairs. # Hashes are denoted with curly braces: -hash = {'color' => 'green', 'number' => 5} +hash = { 'color' => 'green', 'number' => 5 } hash.keys #=> ['color', 'number'] @@ -146,28 +196,27 @@ hash['number'] #=> 5 # Asking a hash for a key that doesn't exist returns nil: hash['nothing here'] #=> nil -# Iterate over hashes with the #each method: -hash.each do |k, v| - puts "#{k} is #{v}" -end - # Since Ruby 1.9, there's a special syntax when using symbols as keys: -new_hash = { defcon: 3, action: true} +new_hash = { defcon: 3, action: true } new_hash.keys #=> [:defcon, :action] +# Check existence of keys and values in hash +new_hash.has_key?(:defcon) #=> true +new_hash.has_value?(3) #=> true + # Tip: Both Arrays and Hashes are Enumerable # They share a lot of useful methods such as each, map, count, and more # Control structures if true - "if statement" + 'if statement' elsif false - "else if, optional" + 'else if, optional' else - "else, also optional" + 'else, also optional' end for counter in 1..5 @@ -179,9 +228,15 @@ end #=> iteration 4 #=> iteration 5 -# HOWEVER -# No-one uses for loops -# Use `each` instead, like this: +# HOWEVER, No-one uses for loops. +# Instead you should use the "each" method and pass it a block. +# A block is a bunch of code that you can pass to a method like "each". +# It is analogous to lambdas, anonymous functions or closures in other +# programming languages. +# +# The "each" method of a range runs the block once for each element of the range. +# The block is passed a counter as a parameter. +# Calling the "each" method with a block looks like this: (1..5).each do |counter| puts "iteration #{counter}" @@ -192,6 +247,17 @@ end #=> iteration 4 #=> iteration 5 +# You can also surround blocks in curly brackets: +(1..5).each { |counter| puts "iteration #{counter}" } + +# The contents of data structures can also be iterated using each. +array.each do |element| + puts "#{element} is part of the array" +end +hash.each do |key, value| + puts "#{key} is #{value}" +end + counter = 1 while counter <= 5 do puts "iteration #{counter}" @@ -207,17 +273,44 @@ grade = 'B' case grade when 'A' - puts "Way to go kiddo" + puts 'Way to go kiddo' when 'B' - puts "Better luck next time" + puts 'Better luck next time' when 'C' - puts "You can do better" + puts 'You can do better' when 'D' - puts "Scraping through" + puts 'Scraping through' when 'F' - puts "You failed!" -else - puts "Alternative grading system, eh?" + puts 'You failed!' +else + puts 'Alternative grading system, eh?' +end +#=> "Better luck next time" + +# cases can also use ranges +grade = 82 +case grade +when 90..100 + puts 'Hooray!' +when 80...90 + puts 'OK job' +else + puts 'You failed!' +end +#=> "OK job" + +# exception handling: +begin + # code here that might raise an exception + raise NoMemoryError, 'You ran out of memory.' +rescue NoMemoryError => exception_variable + puts 'NoMemoryError was raised', exception_variable +rescue RuntimeError => other_exception_variable + puts 'RuntimeError was raised now' +else + puts 'This runs if no exceptions were thrown at all' +ensure + puts 'This code always runs no matter what' end # Functions @@ -226,7 +319,7 @@ def double(x) x * 2 end -# Functions (and all blocks) implcitly return the value of the last statement +# Functions (and all blocks) implicitly return the value of the last statement double(2) #=> 4 # Parentheses are optional where the result is unambiguous @@ -234,23 +327,23 @@ double 3 #=> 6 double double 3 #=> 12 -def sum(x,y) +def sum(x, y) x + y end # Method arguments are separated by a comma sum 3, 4 #=> 7 -sum sum(3,4), 5 #=> 12 +sum sum(3, 4), 5 #=> 12 # yield # All methods have an implicit, optional block parameter # it can be called with the 'yield' keyword def surround - puts "{" + puts '{' yield - puts "}" + puts '}' end surround { puts 'hello world' } @@ -260,47 +353,65 @@ surround { puts 'hello world' } # } -# Define a class with the class keyword -class Human - - # A class variable. It is shared by all instances of this class. - @@species = "H. sapiens" - - # Basic initializer - def initialize(name, age=0) - # Assign the argument to the "name" instance variable for the instance - @name = name - # If no age given, we will fall back to the default in the arguments list. - @age = age - end - - # Basic setter method - def name=(name) - @name = name - end - - # Basic getter method - def name - @name - end +# You can pass a block to a function +# "&" marks a reference to a passed block +def guests(&block) + block.call 'some_argument' +end - # A class method uses self to distinguish from instance methods. - # It can only be called on the class, not an instance. - def self.say(msg) - puts "#{msg}" - end +# You can pass a list of arguments, which will be converted into an array +# That's what splat operator ("*") is for +def guests(*array) + array.each { |guest| puts guest } +end - def species - @@species - end +# Define a class with the class keyword +class Human + # A class variable. It is shared by all instances of this class. + @@species = 'H. sapiens' + + # Basic initializer + def initialize(name, age = 0) + # Assign the argument to the "name" instance variable for the instance + @name = name + # If no age given, we will fall back to the default in the arguments list. + @age = age + end + + # Basic setter method + def name=(name) + @name = name + end + + # Basic getter method + def name + @name + end + + # The above functionality can be encapsulated using the attr_accessor method as follows + attr_accessor :name + + # Getter/setter methods can also be created individually like this + attr_reader :name + attr_writer :name + + # A class method uses self to distinguish from instance methods. + # It can only be called on the class, not an instance. + def self.say(msg) + puts msg + end + + def species + @@species + end end # Instantiate a class -jim = Human.new("Jim Halpert") +jim = Human.new('Jim Halpert') -dwight = Human.new("Dwight K. Schrute") +dwight = Human.new('Dwight K. Schrute') # Let's call a couple of methods jim.species #=> "H. sapiens" @@ -311,5 +422,128 @@ dwight.species #=> "H. sapiens" dwight.name #=> "Dwight K. Schrute" # Call the class method -Human.say("Hi") #=> "Hi" +Human.say('Hi') #=> "Hi" + +# Variable's scopes are defined by the way we name them. +# Variables that start with $ have global scope +$var = "I'm a global var" +defined? $var #=> "global-variable" + +# Variables that start with @ have instance scope +@var = "I'm an instance var" +defined? @var #=> "instance-variable" + +# Variables that start with @@ have class scope +@@var = "I'm a class var" +defined? @@var #=> "class variable" + +# Variables that start with a capital letter are constants +Var = "I'm a constant" +defined? Var #=> "constant" + +# Class is also an object in ruby. So class can have instance variables. +# Class variable is shared among the class and all of its descendants. + +# base class +class Human + @@foo = 0 + + def self.foo + @@foo + end + + def self.foo=(value) + @@foo = value + end +end + +# derived class +class Worker < Human +end + +Human.foo # 0 +Worker.foo # 0 + +Human.foo = 2 # 2 +Worker.foo # 2 + +# Class instance variable is not shared by the class's descendants. + +class Human + @bar = 0 + + def self.bar + @bar + end + + def self.bar=(value) + @bar = value + end +end + +class Doctor < Human +end + +Human.bar # 0 +Doctor.bar # nil + +module ModuleExample + def foo + 'foo' + end +end + +# Including modules binds their methods to the class instances +# Extending modules binds their methods to the class itself + +class Person + include ModuleExample +end + +class Book + extend ModuleExample +end + +Person.foo # => NoMethodError: undefined method `foo' for Person:Class +Person.new.foo # => 'foo' +Book.foo # => 'foo' +Book.new.foo # => NoMethodError: undefined method `foo' + +# Callbacks are executed when including and extending a module + +module ConcernExample + def self.included(base) + base.extend(ClassMethods) + base.send(:include, InstanceMethods) + end + + module ClassMethods + def bar + 'bar' + end + end + + module InstanceMethods + def qux + 'qux' + end + end +end + +class Something + include ConcernExample +end + +Something.bar # => 'bar' +Something.qux # => NoMethodError: undefined method `qux' +Something.new.bar # => NoMethodError: undefined method `bar' +Something.new.qux # => 'qux' ``` + +## Additional resources + +- [Learn Ruby by Example with Challenges](http://www.learneroo.com/modules/61/nodes/338) - A variant of this reference with in-browser challenges. +- [Official Documentation](http://www.ruby-doc.org/core-2.1.1/) +- [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/) +- [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - An older [free edition](http://ruby-doc.com/docs/ProgrammingRuby/) is available online. +- [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) - A community-driven Ruby coding style guide. |