summaryrefslogtreecommitdiffhomepage
path: root/ruby.html.markdown
diff options
context:
space:
mode:
authorDmitrii Kuznetsov <torgeek@users.noreply.github.com>2021-02-22 18:36:35 +0300
committerGitHub <noreply@github.com>2021-02-22 18:36:35 +0300
commitbc8bd2646f068cfb402850f7c0f9b1dbfe81e5a0 (patch)
tree89213fd6afbf9cc9303c1c2fa08dafc840a9d99d /ruby.html.markdown
parent363d5281f1e3d5bee6339b5316405b0a4b592c49 (diff)
parent110511a10110f96b20f107c078f7d5ef4c01b109 (diff)
Merge pull request #1 from adambard/master
Merge from original adambard
Diffstat (limited to 'ruby.html.markdown')
-rw-r--r--ruby.html.markdown384
1 files changed, 219 insertions, 165 deletions
diff --git a/ruby.html.markdown b/ruby.html.markdown
index a1532855..4b96b71c 100644
--- a/ruby.html.markdown
+++ b/ruby.html.markdown
@@ -15,32 +15,39 @@ 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
-
-# First and foremost: Everything is an object.
+This is a multi-line comment.
+The beginning line must start with "=begin"
+and the ending line must start with "=end".
-# Numbers are objects
+You can do this, or start each line in
+a multi-line comment with the # character.
+=end
-3.class #=> Fixnum
+# In Ruby, (almost) everything is an object.
+# This includes numbers...
+3.class #=> Integer
-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 +59,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 +78,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 +91,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 +110,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 +169,88 @@ 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
+# You might prefer %w instead of quotes
+%w[foo bar baz] #=> ["foo", "bar", "baz"]
+
+# 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 +259,34 @@ else
'else, also optional'
end
+# If a condition controls invocation 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 +297,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 +314,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 +327,12 @@ puts doubled
puts array
#=> [1,2,3,4,5]
+# another useful syntax is .map(&:method)
+a = ["FOO", "BAR", "BAZ"]
+a.map { |s| s.downcase } #=> ["foo", "bar", "baz"]
+a.map(&:downcase) #=> ["foo", "bar", "baz"]
+
+# Case construct
grade = 'B'
case grade
@@ -333,7 +351,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 +363,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
@@ -359,16 +377,16 @@ ensure
puts 'This code always runs no matter what'
end
-# Functions
+# Methods
def double(x)
x * 2
end
-# Functions (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 +395,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 +411,88 @@ end
surround { puts 'hello world' }
-# {
-# hello world
-# }
+#=> {
+#=> hello world
+#=> }
-
-# You can pass a block to a function
-# "&" 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 arguments.
+
+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']
+# There is also the shorthand block syntax. It's most useful when you need
+# to call a simple method on all array items.
+upcased = ['Watch', 'these', 'words', 'get', 'upcased'].map(&:upcase)
+puts upcased
+#=> ["WATCH", "THESE", "WORDS", "GET", "UPCASED"]
+
+sum = [1, 2, 3, 4, 5].reduce(&:+)
+puts sum
+#=> 15
+
+# 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 +500,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 +516,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 +534,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 +546,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 +582,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 +608,8 @@ end
class Doctor < Human
end
-Human.bar # 0
-Doctor.bar # nil
+Human.bar #=> 0
+Doctor.bar #=> nil
module ModuleExample
def foo
@@ -561,9 +617,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 +627,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 +656,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