diff options
Diffstat (limited to 'ruby.html.markdown')
-rw-r--r-- | ruby.html.markdown | 361 |
1 files changed, 194 insertions, 167 deletions
diff --git a/ruby.html.markdown b/ruby.html.markdown index e0a6bb6e..d77672ab 100644 --- a/ruby.html.markdown +++ b/ruby.html.markdown @@ -15,32 +15,30 @@ contributors: - ["Gabriel Halley", "https://github.com/ghalley"] - ["Persa Zula", "http://persazula.com"] - ["Jake Faris", "https://github.com/farisj"] + - ["Corey Ward", "https://github.com/coreyward"] + - ["Jannik Siebert", "https://github.com/janniks"] + - ["Keith Miyake", "https://github.com/kaymmm"] --- ```ruby # This is a comment -=begin -This is a multiline comment -No-one uses them -You shouldn't either -=end +# In Ruby, (almost) everything is an object. +# This includes numbers... +3.class #=> Integer -# First and foremost: Everything is an object. - -# Numbers are objects - -3.class #=> Fixnum - -3.to_s #=> "3" +# ...and strings... +"Hello".class #=> String +# ...and even methods! +"Hello".method(:class).class #=> Method # Some basic arithmetic 1 + 1 #=> 2 8 - 1 #=> 7 10 * 2 #=> 20 35 / 5 #=> 7 -2**5 #=> 32 +2 ** 5 #=> 32 5 % 3 #=> 2 # Bitwise operators @@ -52,6 +50,7 @@ You shouldn't either # for calling a method on an object 1.+(3) #=> 4 10.* 5 #=> 50 +100.methods.include?(:/) #=> true # Special values are objects nil # equivalent to null in other languages @@ -70,11 +69,12 @@ false.class #=> FalseClass 1 != 1 #=> false 2 != 1 #=> true -# apart from false itself, nil is the only other 'falsey' value +# Apart from false itself, nil is the only other 'falsey' value -!nil #=> true -!false #=> true -!0 #=> false +!!nil #=> false +!!false #=> false +!!0 #=> true +!!"" #=> true # More comparisons 1 < 10 #=> true @@ -82,15 +82,15 @@ false.class #=> FalseClass 2 <= 2 #=> true 2 >= 2 #=> true -# Combined comparison operator -1 <=> 10 #=> -1 -10 <=> 1 #=> 1 -1 <=> 1 #=> 0 +# Combined comparison operator (returns `1` when the first argument is greater, +# `-1` when the second argument is greater, and `0` otherwise) +1 <=> 10 #=> -1 (1 < 10) +10 <=> 1 #=> 1 (10 > 1) +1 <=> 1 #=> 0 (1 == 1) # 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 @@ -101,61 +101,54 @@ 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 +# 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 +# You can combine strings using `+`, but not with other types 'hello ' + 'world' #=> "hello world" 'hello ' + 3 #=> TypeError: can't convert Fixnum into String 'hello ' + 3.to_s #=> "hello 3" +"hello #{3}" #=> "hello 3" -# Combine strings and operators +# ...or combine strings and operators 'hello ' * 3 #=> "hello hello hello " -# Append to string +# ...or append to string 'hello' << ' world' #=> "hello world" -# print to the output with a newline at the end +# You can print to the output with a newline at the end puts "I'm printing!" #=> I'm printing! #=> nil -# print to the output without a newline +# ...or print to the output without a newline print "I'm printing!" -#=> I'm printing! => nil +#=> "I'm printing!" => nil # Variables x = 25 #=> 25 x #=> 25 -# Note that assignment returns the value assigned -# This means you can do multiple assignment: +# Note that assignment returns the value assigned. +# This means you can do multiple assignment. x = y = 10 #=> 10 x #=> 10 y #=> 10 -# By convention, use snake_case for variable names +# By convention, use snake_case for variable names. snake_case = true # Use descriptive variable names path_to_project_root = '/good/name/' -path = '/bad/name/' +m = '/bad/name/' -# Symbols (are objects) # Symbols are immutable, reusable constants represented internally by an # integer value. They're often used instead of strings to efficiently convey -# specific, meaningful values +# specific, meaningful values. :pending.class #=> Symbol @@ -167,77 +160,85 @@ status == 'pending' #=> false status == :approved #=> false +# Strings can be converted into symbols and vice versa. +status.to_s #=> "pending" +"argon".to_sym #=> :argon + # Arrays -# This is an array +# This is an array. array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] -# Arrays can contain different types of items - +# Arrays can contain different types of items. [1, 'hello', false] #=> [1, "hello", false] -# Arrays can be indexed -# From the front +# Arrays can be indexed. +# From the front... array[0] #=> 1 array.first #=> 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 +# ...or from the back... array[-1] #=> 5 array.last #=> 5 -# With a start index and length +# ...or 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 +# ...or with a range... array[1..3] #=> [2, 3, 4] -# Add to an array like this +# You can reverse an Array. +# Return a new array with reversed values +[1,2,3].reverse #=> [3,2,1] +# Reverse an array in place to update variable with reversed values +a = [1,2,3] +a.reverse! #=> a==[3,2,1] because of the bang ('!') call to reverse + +# Like arithmetic, [var] access is just syntactic sugar +# for calling a method '[]' on an object. +array.[] 0 #=> 1 +array.[] 12 #=> nil + +# You can add to an array... 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 +# ...and check if an item exists in an array array.include?(1) #=> true # Hashes are Ruby's primary dictionary with key/value pairs. -# Hashes are denoted with curly braces: +# Hashes are denoted with curly braces. hash = { 'color' => 'green', 'number' => 5 } hash.keys #=> ['color', 'number'] -# Hashes can be quickly looked up by key: -hash['color'] #=> 'green' +# Hashes can be quickly looked up by key. +hash['color'] #=> "green" hash['number'] #=> 5 -# Asking a hash for a key that doesn't exist returns nil: +# Asking a hash for a key that doesn't exist returns nil. hash['nothing here'] #=> nil -# Since Ruby 1.9, there's a special syntax when using symbols as keys: +# When using symbols for keys in a hash, you can use an alternate syntax. -new_hash = { defcon: 3, action: true } +hash = { :defcon => 3, :action => true } +hash.keys #=> [:defcon, :action] -new_hash.keys #=> [:defcon, :action] +hash = { defcon: 3, action: true } +hash.keys #=> [:defcon, :action] # Check existence of keys and values in hash -new_hash.key?(:defcon) #=> true -new_hash.value?(3) #=> true +hash.key?(:defcon) #=> true +hash.value?(3) #=> true -# Tip: Both Arrays and Hashes are Enumerable -# They share a lot of useful methods such as each, map, count, and more +# Tip: Both Arrays and Hashes are Enumerable! +# They share a lot of useful methods such as each, map, count, and more. # Control structures +# Conditionals if true 'if statement' elsif false @@ -246,35 +247,34 @@ else 'else, also optional' end +# If a condition controls invokation of a single statement rather than a block of code +# you can use postfix-if notation +warnings = ['Patronimic is missing', 'Address too short'] +puts("Some warnings occurred:\n" + warnings.join("\n")) if !warnings.empty? + +# Rephrase condition if `unless` sounds better than `if` +puts("Some warnings occurred:\n" + warnings.join("\n")) unless warnings.empty? + +# Loops +# In Ruby, traditional `for` loops aren't very common. Instead, these +# basic loops are implemented using enumerable, which hinges on `each`. +(1..5).each do |counter| + puts "iteration #{counter}" +end + +# Which is roughly equivalent to the following, which is unusual to see in Ruby. for counter in 1..5 puts "iteration #{counter}" end -#=> iteration 1 -#=> iteration 2 -#=> iteration 3 -#=> iteration 4 -#=> iteration 5 -# 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 `do |variable| ... end` construct above is called a 'block'. Blocks are similar +# to lambdas, anonymous functions or closures in other programming languages. They can +# be passed around as objects, called, or attached as methods. # -# The "each" method of a range runs the block once for each element of the range. +# 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}" -end -#=> iteration 1 -#=> iteration 2 -#=> iteration 3 -#=> iteration 4 -#=> iteration 5 - -# You can also surround blocks in curly brackets: +# 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. @@ -285,8 +285,8 @@ hash.each do |key, value| puts "#{key} is #{value}" end -# If you still need an index you can use "each_with_index" and define an index -# variable +# If you still need an index you can use 'each_with_index' and define an index +# variable. array.each_with_index do |element, index| puts "#{element} is number #{index} in the array" end @@ -302,9 +302,9 @@ end #=> iteration 4 #=> iteration 5 -# There are a bunch of other helpful looping functions in Ruby, -# for example "map", "reduce", "inject", the list goes on. Map, -# for instance, takes the array it's looping over, does something +# There are a bunch of other helpful looping functions in Ruby. +# For example: 'map', 'reduce', 'inject', the list goes on. +# Map, for instance, takes the array it's looping over, does something # to it as defined in your block, and returns an entirely new array. array = [1,2,3,4,5] doubled = array.map do |element| @@ -315,6 +315,7 @@ puts doubled puts array #=> [1,2,3,4,5] +# Case construct grade = 'B' case grade @@ -333,7 +334,7 @@ else end #=> "Better luck next time" -# cases can also use ranges +# Cases can also use ranges grade = 82 case grade when 90..100 @@ -345,9 +346,9 @@ else end #=> "OK job" -# exception handling: +# Exception handling begin - # code here that might raise an exception + # Code here that might raise an exception raise NoMemoryError, 'You ran out of memory.' rescue NoMemoryError => exception_variable puts 'NoMemoryError was raised', exception_variable @@ -365,10 +366,10 @@ def double(x) x * 2 end -# Methods (and all blocks) implicitly return the value of the last statement +# Methods (and blocks) implicitly return the value of the last statement. double(2) #=> 4 -# Parentheses are optional where the result is unambiguous +# Parentheses are optional where the interpretation is unambiguous. double 3 #=> 6 double double 3 #=> 12 @@ -377,15 +378,14 @@ def sum(x, y) x + y end -# Method arguments are separated by a comma +# Method arguments are separated by a comma. sum 3, 4 #=> 7 sum sum(3, 4), 5 #=> 12 # yield -# All methods have an implicit, optional block parameter -# it can be called with the 'yield' keyword - +# All methods have an implicit, optional block parameter. +# It can be called with the 'yield' keyword. def surround puts '{' yield @@ -394,46 +394,78 @@ end surround { puts 'hello world' } -# { -# hello world -# } - +#=> { +#=> hello world +#=> } -# You can pass a block to a method -# "&" marks a reference to a passed block +# Blocks can be converted into a 'proc' object, which wraps the block +# and allows it to be passed to another method, bound to a different scope, +# or manipulated otherwise. This is most common in method parameter lists, +# where you frequently see a trailing '&block' parameter that will accept +# the block, if one is given, and convert it to a 'Proc'. The naming here is +# convention; it would work just as well with '&pineapple'. def guests(&block) - block.call 'some_argument' + block.class #=> Proc + block.call(4) end -# You can pass a list of arguments, which will be converted into an array -# That's what splat operator ("*") is for +# The 'call' method on the Proc is similar to calling 'yield' when a block is +# present. The arguments passed to 'call' will be forwarded to the block as arugments. + +guests { |n| "You have #{n} guests." } +# => "You have 4 guests." + +# 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 -# If a method returns an array, you can use destructuring assignment -def foods - ['pancake', 'sandwich', 'quesadilla'] +# Destructuring + +# Ruby will automatically destructure arrays on assignment to multiple variables. +a, b, c = [1, 2, 3] +a #=> 1 +b #=> 2 +c #=> 3 + +# In some cases, you will want to use the splat operator: `*` to prompt destructuring +# of an array into a list. +ranked_competitors = ["John", "Sally", "Dingus", "Moe", "Marcy"] + +def best(first, second, third) + puts "Winners are #{first}, #{second}, and #{third}." +end + +best *ranked_competitors.first(3) #=> Winners are John, Sally, and Dingus. + +# The splat operator can also be used in parameters. +def best(first, second, third, *others) + puts "Winners are #{first}, #{second}, and #{third}." + puts "There were #{others.count} other participants." end -breakfast, lunch, dinner = foods -breakfast #=> 'pancake' -dinner #=> 'quesadilla' -# By convention, all methods that return booleans end with a question mark -5.even? # false -5.odd? # true +best *ranked_competitors +#=> Winners are John, Sally, and Dingus. +#=> There were 2 other participants. -# And if a method ends with an exclamation mark, it does something destructive +# By convention, all methods that return booleans end with a question mark. +5.even? #=> false +5.odd? #=> true + +# By convention, if a method name ends with an exclamation mark, it does something destructive # like mutate the receiver. Many methods have a ! version to make a change, and -# a non-! version to just return a new changed version +# a non-! version to just return a new changed version. company_name = "Dunder Mifflin" company_name.upcase #=> "DUNDER MIFFLIN" company_name #=> "Dunder Mifflin" -company_name.upcase! # we're mutating company_name this time! +# We're mutating company_name this time. +company_name.upcase! #=> "DUNDER MIFFLIN" company_name #=> "DUNDER MIFFLIN" +# Classes -# Define a class with the class keyword +# You can define a class with the 'class' keyword. class Human # A class variable. It is shared by all instances of this class. @@ -441,7 +473,7 @@ class Human # Basic initializer def initialize(name, age = 0) - # Assign the argument to the "name" instance variable for the instance + # 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 @@ -457,10 +489,10 @@ class Human @name end - # The above functionality can be encapsulated using the attr_accessor method as follows + # 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 + # Getter/setter methods can also be created individually like this. attr_reader :name attr_writer :name @@ -475,13 +507,11 @@ class Human end end - -# Instantiate a class +# Instantiating of a class jim = Human.new('Jim Halpert') - dwight = Human.new('Dwight K. Schrute') -# Let's call a couple of methods +# You can call the methods of the generated object. jim.species #=> "H. sapiens" jim.name #=> "Jim Halpert" jim.name = "Jim Halpert II" #=> "Jim Halpert II" @@ -489,30 +519,30 @@ jim.name #=> "Jim Halpert II" dwight.species #=> "H. sapiens" dwight.name #=> "Dwight K. Schrute" -# Call the class method +# Calling of a class method Human.say('Hi') #=> "Hi" # Variable's scopes are defined by the way we name them. -# Variables that start with $ have global scope +# Variables that start with $ have global scope. $var = "I'm a global var" defined? $var #=> "global-variable" -# Variables that start with @ have instance scope +# Variables that start with @ have instance scope. @var = "I'm an instance var" defined? @var #=> "instance-variable" -# Variables that start with @@ have class scope +# 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 +# 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. +# Class is also an object in ruby. So a class can have instance variables. +# A class variable is shared among the class and all of its descendants. -# base class +# Base class class Human @@foo = 0 @@ -525,18 +555,17 @@ class Human end end -# derived class +# Derived class class Worker < Human end -Human.foo # 0 -Worker.foo # 0 +Human.foo #=> 0 +Worker.foo #=> 0 -Human.foo = 2 # 2 -Worker.foo # 2 - -# Class instance variable is not shared by the class's descendants. +Human.foo = 2 +Worker.foo #=> 2 +# A class instance variable is not shared by the class's descendants. class Human @bar = 0 @@ -552,8 +581,8 @@ end class Doctor < Human end -Human.bar # 0 -Doctor.bar # nil +Human.bar #=> 0 +Doctor.bar #=> nil module ModuleExample def foo @@ -561,9 +590,8 @@ module ModuleExample end end -# Including modules binds their methods to the class instances -# Extending modules binds their methods to the class itself - +# Including modules binds their methods to the class instances. +# Extending modules binds their methods to the class itself. class Person include ModuleExample end @@ -572,13 +600,12 @@ 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' +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) @@ -602,10 +629,10 @@ 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' +Something.bar #=> "bar" +Something.qux #=> NoMethodError: undefined method `qux' +Something.new.bar #=> NoMethodError: undefined method `bar' +Something.new.qux #=> "qux" ``` ## Additional resources |