2013-06-28 23:57:57 +04:00
---
language: ruby
2013-07-04 09:59:13 +04:00
filename: learnruby.rb
2013-07-03 23:39:43 +04:00
contributors:
- ["David Underwood", "http://theflyingdeveloper.com"]
2013-07-04 09:53:12 +04:00
- ["Joel Walden", "http://joelwalden.net"]
2013-07-30 11:26:51 +04:00
- ["Luke Holder", "http://twitter.com/lukeholder"]
2013-08-12 22:53:00 +04:00
- ["Tristan Hume", "http://thume.ca/"]
2013-08-14 02:47:52 +04:00
- ["Nick LaMuro", "https://github.com/NickLaMuro"]
2013-08-31 04:58:23 +04:00
- ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"]
2014-03-11 01:05:49 +04:00
- ["Ariel Krakowski", "http://www.learneroo.com"]
2014-08-19 13:06:52 +04:00
- ["Dzianis Dashkevich", "https://github.com/dskecse"]
2014-11-11 04:45:17 +03:00
- ["Levi Bostian", "https://github.com/levibostian"]
2015-03-19 13:08:27 +03:00
- ["Rahil Momin", "https://github.com/iamrahil"]
2015-10-17 18:25:05 +03:00
- ["Gabriel Halley", "https://github.com/ghalley"]
- ["Persa Zula", "http://persazula.com"]
2015-11-02 18:06:01 +03:00
- ["Jake Faris", "https://github.com/farisj"]
2018-03-23 18:28:30 +03:00
- ["Corey Ward", "https://github.com/coreyward"]
2018-08-10 14:45:11 +03:00
- ["Jannik Siebert", "https://github.com/janniks"]
2018-10-04 03:19:01 +03:00
- ["Keith Miyake", "https://github.com/kaymmm"]
2013-06-28 23:57:57 +04:00
---
```ruby
# This is a comment
2019-10-01 23:45:47 +03:00
=begin
This is a multi-line comment.
The beginning line must start with "=begin"
and the ending line must start with "=end".
You can do this, or start each line in
a multi-line comment with the # character.
=end
2018-03-23 18:28:30 +03:00
# In Ruby, (almost) everything is an object.
2018-08-10 14:45:11 +03:00
# This includes numbers...
2018-03-23 18:28:30 +03:00
3.class #=> Integer
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# ...and strings...
2018-03-23 18:28:30 +03:00
"Hello".class #=> String
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# ...and even methods!
2018-03-23 18:28:30 +03:00
"Hello".method(:class).class #=> Method
2013-06-28 23:57:57 +04:00
# Some basic arithmetic
1 + 1 #=> 2
8 - 1 #=> 7
10 * 2 #=> 20
35 / 5 #=> 7
2018-03-23 18:28:30 +03:00
2 ** 5 #=> 32
2015-10-07 22:25:50 +03:00
5 % 3 #=> 2
2015-10-30 17:22:23 +03:00
# Bitwise operators
3 & 5 #=> 1
3 | 5 #=> 7
3 ^ 5 #=> 6
2013-06-28 23:57:57 +04:00
2013-07-30 11:28:40 +04:00
# Arithmetic is just syntactic sugar
# for calling a method on an object
2013-07-30 11:26:51 +04:00
1.+(3) #=> 4
2013-08-14 21:11:13 +04:00
10.* 5 #=> 50
2018-03-23 18:28:30 +03:00
100.methods.include?(:/) #=> true
2013-07-30 11:26:51 +04:00
2013-07-02 21:46:58 +04:00
# Special values are objects
2015-10-26 10:56:28 +03:00
nil # equivalent to null in other languages
2013-07-02 21:46:58 +04:00
true # truth
false # falsehood
nil.class #=> NilClass
true.class #=> TrueClass
false.class #=> FalseClass
2013-06-28 23:57:57 +04:00
# Equality
1 == 1 #=> true
2 == 1 #=> false
# Inequality
1 != 1 #=> false
2 != 1 #=> true
2018-08-10 14:45:11 +03:00
# Apart from false itself, nil is the only other 'falsey' value
2013-07-05 23:18:54 +04:00
2018-03-23 18:28:30 +03:00
!!nil #=> false
!!false #=> false
!!0 #=> true
!!"" #=> true
2013-07-05 23:18:54 +04:00
2013-06-28 23:57:57 +04:00
# More comparisons
2013-06-30 02:04:37 +04:00
1 < 10 # = > true
1 > 10 #=> false
2 < = 2 #=> true
2 >= 2 #=> true
2013-06-28 23:57:57 +04:00
2018-03-23 18:28:30 +03:00
# Combined comparison operator (returns `1` when the first argument is greater,
# `-1` when the second argument is greater, and `0` otherwise)
2018-10-04 03:19:01 +03:00
1 < => 10 #=> -1 (1 < 10 )
10 < => 1 #=> 1 (10 > 1)
1 < => 1 #=> 0 (1 == 1)
2015-10-30 17:17:15 +03:00
2015-03-05 02:56:23 +03:00
# Logical operators
true & & false #=> false
true || false #=> true
2015-06-16 21:54:54 +03:00
# 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()
2015-03-05 02:56:23 +03:00
2018-03-23 18:28:30 +03:00
# String interpolation
2013-06-28 23:57:57 +04:00
2014-08-19 13:06:52 +04:00
placeholder = 'use string interpolation'
2013-06-28 23:57:57 +04:00
"I can #{placeholder} when using double quoted strings"
2013-07-02 21:24:50 +04:00
#=> "I can use string interpolation when using double quoted strings"
2013-06-28 23:57:57 +04:00
2018-03-23 18:28:30 +03:00
# You can combine strings using `+`, but not with other types
2014-08-19 13:06:52 +04:00
'hello ' + 'world' #=> "hello world"
'hello ' + 3 #=> TypeError: can't convert Fixnum into String
'hello ' + 3.to_s #=> "hello 3"
2018-03-23 18:28:30 +03:00
"hello #{3}" #=> "hello 3"
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# ...or combine strings and operators
2015-10-17 19:16:14 +03:00
'hello ' * 3 #=> "hello hello hello "
2015-10-17 18:25:05 +03:00
2018-08-10 14:45:11 +03:00
# ...or append to string
2015-10-17 18:25:05 +03:00
'hello' < < ' world' #=> "hello world"
2018-08-10 14:45:11 +03:00
# You can print to the output with a newline at the end
2013-06-28 23:57:57 +04:00
puts "I'm printing!"
2015-10-07 03:55:51 +03:00
#=> I'm printing!
#=> nil
2018-08-10 14:45:11 +03:00
# ...or print to the output without a newline
2015-10-07 03:55:51 +03:00
print "I'm printing!"
2018-08-10 14:45:11 +03:00
#=> "I'm printing!" => nil
2013-06-28 23:57:57 +04:00
# Variables
x = 25 #=> 25
2013-07-02 21:46:58 +04:00
x #=> 25
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# Note that assignment returns the value assigned.
# This means you can do multiple assignment.
2013-06-28 23:57:57 +04:00
x = y = 10 #=> 10
x #=> 10
y #=> 10
2018-08-10 14:45:11 +03:00
# By convention, use snake_case for variable names.
2013-06-28 23:57:57 +04:00
snake_case = true
# Use descriptive variable names
path_to_project_root = '/good/name/'
2018-03-23 18:28:30 +03:00
m = '/bad/name/'
2013-06-28 23:57:57 +04:00
2013-07-04 10:03:25 +04:00
# Symbols are immutable, reusable constants represented internally by an
# integer value. They're often used instead of strings to efficiently convey
2018-08-10 14:45:11 +03:00
# specific, meaningful values.
2013-07-01 20:27:15 +04:00
2013-07-02 21:46:58 +04:00
:pending.class #=> Symbol
2013-07-01 20:27:15 +04:00
status = :pending
status == :pending #=> true
status == 'pending' #=> false
2013-07-02 21:46:58 +04:00
status == :approved #=> false
2013-07-01 20:27:15 +04:00
2018-08-10 14:45:11 +03:00
# Strings can be converted into symbols and vice versa.
2018-03-23 18:28:30 +03:00
status.to_s #=> "pending"
"argon".to_sym #=> :argon
2013-06-28 23:57:57 +04:00
# Arrays
2018-08-10 14:45:11 +03:00
# This is an array.
2013-08-14 02:42:03 +04:00
array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# Arrays can contain different types of items.
2014-08-19 13:06:52 +04:00
[1, 'hello', false] #=> [1, "hello", false]
2013-06-28 23:57:57 +04:00
2020-05-02 19:03:36 +03:00
# You might prefer %w instead of quotes
%w[foo bar baz] #=> ["foo", "bar", "baz"]
2018-08-10 14:45:11 +03:00
# Arrays can be indexed.
# From the front...
2013-06-28 23:57:57 +04:00
array[0] #=> 1
2015-10-07 22:26:10 +03:00
array.first #=> 1
2013-06-28 23:57:57 +04:00
array[12] #=> nil
2018-08-10 14:45:11 +03:00
# ...or from the back...
2013-06-28 23:57:57 +04:00
array[-1] #=> 5
2015-10-07 22:26:10 +03:00
array.last #=> 5
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# ...or with a start index and length...
2013-11-20 14:38:46 +04:00
array[2, 3] #=> [3, 4, 5]
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# ...or with a range...
array[1..3] #=> [2, 3, 4]
# You can reverse an Array.
2018-10-04 03:19:01 +03:00
# 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
2018-03-23 18:28:30 +03:00
a = [1,2,3]
2018-10-04 03:19:01 +03:00
a.reverse! #=> a==[3,2,1] because of the bang ('!') call to reverse
2015-10-05 15:21:23 +03:00
2018-08-10 14:45:11 +03:00
# Like arithmetic, [var] access is just syntactic sugar
# for calling a method '[]' on an object.
array.[] 0 #=> 1
array.[] 12 #=> nil
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# You can add to an array...
2013-06-28 23:57:57 +04:00
array < < 6 # = > [1, 2, 3, 4, 5, 6]
2015-08-26 09:15:36 +03:00
# Or like this
array.push(6) #=> [1, 2, 3, 4, 5, 6]
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# ...and check if an item exists in an array
2015-03-19 13:07:42 +03:00
array.include?(1) #=> true
2016-07-12 11:07:38 +03:00
# Hashes are Ruby's primary dictionary with key/value pairs.
2018-08-10 14:45:11 +03:00
# Hashes are denoted with curly braces.
2014-08-19 13:06:52 +04:00
hash = { 'color' => 'green', 'number' => 5 }
2013-07-01 20:27:15 +04:00
hash.keys #=> ['color', 'number']
2018-08-10 14:45:11 +03:00
# Hashes can be quickly looked up by key.
hash['color'] #=> "green"
2013-07-01 20:27:15 +04:00
hash['number'] #=> 5
2018-08-10 14:45:11 +03:00
# Asking a hash for a key that doesn't exist returns nil.
2013-07-01 20:27:15 +04:00
hash['nothing here'] #=> nil
2018-08-10 14:45:11 +03:00
# When using symbols for keys in a hash, you can use an alternate syntax.
2013-07-01 20:27:15 +04:00
2018-08-10 14:45:11 +03:00
hash = { :defcon => 3, :action => true }
hash.keys #=> [:defcon, :action]
2013-07-01 20:27:15 +04:00
2018-08-10 14:45:11 +03:00
hash = { defcon: 3, action: true }
hash.keys #=> [:defcon, :action]
2013-07-01 20:27:15 +04:00
2015-03-19 13:08:16 +03:00
# Check existence of keys and values in hash
2018-08-10 14:45:11 +03:00
hash.key?(:defcon) #=> true
hash.value?(3) #=> true
2015-03-19 13:08:16 +03:00
2018-08-10 14:45:11 +03:00
# Tip: Both Arrays and Hashes are Enumerable!
# They share a lot of useful methods such as each, map, count, and more.
2013-07-01 20:27:15 +04:00
2013-06-28 23:57:57 +04:00
# Control structures
2018-08-10 14:45:11 +03:00
# Conditionals
2013-06-28 23:57:57 +04:00
if true
2014-08-19 13:06:52 +04:00
'if statement'
2013-06-28 23:57:57 +04:00
elsif false
2014-08-19 13:06:52 +04:00
'else if, optional'
2013-06-28 23:57:57 +04:00
else
2014-08-19 13:06:52 +04:00
'else, also optional'
2013-06-28 23:57:57 +04:00
end
2020-01-31 22:04:15 +03:00
# If a condition controls invocation of a single statement rather than a block of code
2019-09-05 11:06:51 +03:00
# 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?
2018-08-10 14:45:11 +03:00
# Loops
2018-03-23 18:28:30 +03:00
# In Ruby, traditional `for` loops aren't very common. Instead, these
2018-08-10 14:45:11 +03:00
# basic loops are implemented using enumerable, which hinges on `each`.
2018-03-23 18:28:30 +03:00
(1..5).each do |counter|
puts "iteration #{counter}"
end
2018-08-10 14:45:11 +03:00
# Which is roughly equivalent to the following, which is unusual to see in Ruby.
2013-06-28 23:57:57 +04:00
for counter in 1..5
puts "iteration #{counter}"
end
2018-08-10 14:45:11 +03:00
# The `do |variable| ... end` construct above is called a 'block'. Blocks are similar
2018-03-23 18:28:30 +03:00
# to lambdas, anonymous functions or closures in other programming languages. They can
2018-08-10 14:45:11 +03:00
# be passed around as objects, called, or attached as methods.
2013-08-12 23:05:00 +04:00
#
2018-08-10 14:45:11 +03:00
# The 'each' method of a range runs the block once for each element of the range.
2013-08-12 23:05:00 +04:00
# The block is passed a counter as a parameter.
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
# You can also surround blocks in curly brackets.
2014-08-19 13:06:52 +04:00
(1..5).each { |counter| puts "iteration #{counter}" }
2013-08-12 22:53:00 +04:00
2013-08-12 23:05:00 +04:00
# The contents of data structures can also be iterated using each.
2013-08-12 22:53:00 +04:00
array.each do |element|
puts "#{element} is part of the array"
end
hash.each do |key, value|
puts "#{key} is #{value}"
end
2018-08-10 14:45:11 +03:00
# If you still need an index you can use 'each_with_index' and define an index
# variable.
2015-10-07 22:26:25 +03:00
array.each_with_index do |element, index|
2015-10-09 18:47:13 +03:00
puts "#{element} is number #{index} in the array"
2015-10-07 22:26:25 +03:00
end
2013-06-28 23:57:57 +04:00
counter = 1
while counter < = 5 do
puts "iteration #{counter}"
2013-07-06 04:56:02 +04:00
counter += 1
2013-06-28 23:57:57 +04:00
end
#=> iteration 1
#=> iteration 2
#=> iteration 3
#=> iteration 4
#=> iteration 5
2018-08-10 14:45:11 +03:00
# 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
2015-10-07 04:06:44 +03:00
# to it as defined in your block, and returns an entirely new array.
array = [1,2,3,4,5]
doubled = array.map do |element|
element * 2
end
puts doubled
#=> [2,4,6,8,10]
puts array
#=> [1,2,3,4,5]
2020-07-08 02:27:34 +03:00
# another useful syntax is .map(&:method)
2020-05-02 22:09:41 +03:00
a = ["FOO", "BAR", "BAZ"]
a.map { |s| s.downcase } #=> ["foo", "bar", "baz"]
a.map(& :downcase) #=> ["foo", "bar", "baz"]
2018-08-10 14:45:11 +03:00
# Case construct
2013-06-28 23:57:57 +04:00
grade = 'B'
2013-07-02 21:46:58 +04:00
2013-06-28 23:57:57 +04:00
case grade
when 'A'
2014-08-19 13:06:52 +04:00
puts 'Way to go kiddo'
2013-06-28 23:57:57 +04:00
when 'B'
2014-08-19 13:06:52 +04:00
puts 'Better luck next time'
2013-06-28 23:57:57 +04:00
when 'C'
2014-08-19 13:06:52 +04:00
puts 'You can do better'
2013-06-28 23:57:57 +04:00
when 'D'
2014-08-19 13:06:52 +04:00
puts 'Scraping through'
2013-06-28 23:57:57 +04:00
when 'F'
2014-08-19 13:06:52 +04:00
puts 'You failed!'
2013-08-14 21:11:13 +04:00
else
2014-08-19 13:06:52 +04:00
puts 'Alternative grading system, eh?'
2013-07-08 02:50:18 +04:00
end
2014-03-11 01:05:49 +04:00
#=> "Better luck next time"
2018-08-10 14:45:11 +03:00
# Cases can also use ranges
2014-03-11 01:05:49 +04:00
grade = 82
case grade
2014-08-19 13:06:52 +04:00
when 90..100
puts 'Hooray!'
when 80...90
puts 'OK job'
else
puts 'You failed!'
2014-03-11 01:05:49 +04:00
end
#=> "OK job"
2018-08-10 14:45:11 +03:00
# Exception handling
2014-11-11 04:45:17 +03:00
begin
2018-08-10 14:45:11 +03:00
# Code here that might raise an exception
2014-11-11 04:45:17 +03:00
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'
2015-03-05 02:56:23 +03:00
else
2014-11-11 04:45:17 +03:00
puts 'This runs if no exceptions were thrown at all'
2015-03-05 02:56:23 +03:00
ensure
2014-11-11 04:45:17 +03:00
puts 'This code always runs no matter what'
end
2014-03-11 01:05:49 +04:00
2017-08-30 01:39:42 +03:00
# Methods
2013-06-28 23:57:57 +04:00
def double(x)
x * 2
end
2018-08-10 14:45:11 +03:00
# Methods (and blocks) implicitly return the value of the last statement.
2013-06-28 23:57:57 +04:00
double(2) #=> 4
2018-08-10 14:45:11 +03:00
# Parentheses are optional where the interpretation is unambiguous.
2013-06-28 23:57:57 +04:00
double 3 #=> 6
double double 3 #=> 12
2014-08-19 13:06:52 +04:00
def sum(x, y)
2013-06-28 23:57:57 +04:00
x + y
end
2018-08-10 14:45:11 +03:00
# Method arguments are separated by a comma.
2013-06-28 23:57:57 +04:00
sum 3, 4 #=> 7
2014-08-19 13:06:52 +04:00
sum sum(3, 4), 5 #=> 12
2013-06-28 23:57:57 +04:00
# yield
2018-08-10 14:45:11 +03:00
# All methods have an implicit, optional block parameter.
2018-10-16 17:58:55 +03:00
# It can be called with the 'yield' keyword.
2013-07-01 20:27:15 +04:00
def surround
2014-08-19 13:06:52 +04:00
puts '{'
2013-07-01 20:27:15 +04:00
yield
2014-08-19 13:06:52 +04:00
puts '}'
2013-07-01 20:27:15 +04:00
end
surround { puts 'hello world' }
2013-06-28 23:57:57 +04:00
2018-08-10 14:45:11 +03:00
#=> {
#=> hello world
#=> }
2013-07-03 23:21:29 +04:00
2018-08-10 14:45:11 +03:00
# Blocks can be converted into a 'proc' object, which wraps the block
2018-03-23 18:28:30 +03:00
# 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,
2018-08-10 14:45:11 +03:00
# 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'.
2013-09-29 21:15:16 +04:00
def guests(& block)
2018-03-23 18:28:30 +03:00
block.class #=> Proc
block.call(4)
2013-09-29 21:15:16 +04:00
end
2014-08-19 13:06:52 +04:00
2018-08-10 14:45:11 +03:00
# The 'call' method on the Proc is similar to calling 'yield' when a block is
2019-12-09 20:19:36 +03:00
# present. The arguments passed to 'call' will be forwarded to the block as arguments.
2018-03-23 18:28:30 +03:00
guests { |n| "You have #{n} guests." }
# => "You have 4 guests."
2018-08-10 14:45:11 +03:00
# You can pass a list of arguments, which will be converted into an array.
# That's what splat operator ("*") is for.
2013-09-29 21:15:16 +04:00
def guests(*array)
2014-08-19 13:06:52 +04:00
array.each { |guest| puts guest }
2013-09-29 21:15:16 +04:00
end
2020-04-21 15:33:51 +03:00
# 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
2018-03-23 18:28:30 +03:00
# Destructuring
2018-08-10 14:45:11 +03:00
# Ruby will automatically destructure arrays on assignment to multiple variables.
2018-03-23 18:28:30 +03:00
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
2018-08-10 14:45:11 +03:00
# of an array into a list.
2018-03-23 18:28:30 +03:00
ranked_competitors = ["John", "Sally", "Dingus", "Moe", "Marcy"]
def best(first, second, third)
puts "Winners are #{first}, #{second}, and #{third}."
2016-01-26 03:52:06 +03:00
end
2018-03-23 18:28:30 +03:00
best *ranked_competitors.first(3) #=> Winners are John, Sally, and Dingus.
2018-08-10 14:45:11 +03:00
# The splat operator can also be used in parameters.
2018-03-23 18:28:30 +03:00
def best(first, second, third, *others)
puts "Winners are #{first}, #{second}, and #{third}."
puts "There were #{others.count} other participants."
end
best *ranked_competitors
#=> Winners are John, Sally, and Dingus.
#=> There were 2 other participants.
2016-01-26 03:52:06 +03:00
2018-08-10 14:45:11 +03:00
# By convention, all methods that return booleans end with a question mark.
5.even? #=> false
5.odd? #=> true
2016-01-26 03:58:46 +03:00
2018-08-10 14:45:11 +03:00
# By convention, if a method name ends with an exclamation mark, it does something destructive
2016-01-26 03:58:46 +03:00
# like mutate the receiver. Many methods have a ! version to make a change, and
2018-08-10 14:45:11 +03:00
# a non-! version to just return a new changed version.
2016-01-26 03:58:46 +03:00
company_name = "Dunder Mifflin"
company_name.upcase #=> "DUNDER MIFFLIN"
company_name #=> "Dunder Mifflin"
2018-08-10 14:45:11 +03:00
# We're mutating company_name this time.
company_name.upcase! #=> "DUNDER MIFFLIN"
2016-01-26 03:58:46 +03:00
company_name #=> "DUNDER MIFFLIN"
2018-08-10 14:45:11 +03:00
# Classes
2016-01-26 03:52:06 +03:00
2018-08-10 14:45:11 +03:00
# You can define a class with the 'class' keyword.
2013-07-03 23:21:29 +04:00
class Human
2013-08-08 14:17:10 +04:00
# A class variable. It is shared by all instances of this class.
2014-08-19 13:06:52 +04:00
@@species = 'H. sapiens'
2013-08-08 14:17:10 +04:00
# Basic initializer
2014-08-19 13:06:52 +04:00
def initialize(name, age = 0)
2018-08-10 14:45:11 +03:00
# Assign the argument to the 'name' instance variable for the instance.
2013-08-08 14:17:10 +04:00
@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
2018-08-10 14:45:11 +03:00
# The above functionality can be encapsulated using the attr_accessor method as follows.
2013-12-02 06:42:51 +04:00
attr_accessor :name
2018-08-10 14:45:11 +03:00
# Getter/setter methods can also be created individually like this.
2013-12-02 06:42:51 +04:00
attr_reader :name
attr_writer :name
2013-08-08 14:17:10 +04:00
# 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)
2014-08-19 13:06:52 +04:00
puts msg
2013-08-08 14:17:10 +04:00
end
def species
@@species
end
2013-07-03 23:21:29 +04:00
end
2018-08-10 14:45:11 +03:00
# Instantiating of a class
2014-08-19 13:06:52 +04:00
jim = Human.new('Jim Halpert')
dwight = Human.new('Dwight K. Schrute')
2013-07-03 23:21:29 +04:00
2018-08-10 14:45:11 +03:00
# You can call the methods of the generated object.
2013-07-03 23:21:29 +04:00
jim.species #=> "H. sapiens"
jim.name #=> "Jim Halpert"
2013-07-17 05:22:32 +04:00
jim.name = "Jim Halpert II" #=> "Jim Halpert II"
jim.name #=> "Jim Halpert II"
2013-07-03 23:21:29 +04:00
dwight.species #=> "H. sapiens"
dwight.name #=> "Dwight K. Schrute"
2018-08-10 14:45:11 +03:00
# Calling of a class method
2014-08-19 13:06:52 +04:00
Human.say('Hi') #=> "Hi"
2013-07-29 12:30:51 +04:00
2013-08-31 04:58:23 +04:00
# Variable's scopes are defined by the way we name them.
2018-08-10 14:45:11 +03:00
# Variables that start with $ have global scope.
2013-08-31 04:58:23 +04:00
$var = "I'm a global var"
defined? $var #=> "global-variable"
2018-08-10 14:45:11 +03:00
# Variables that start with @ have instance scope.
2013-08-31 04:58:23 +04:00
@var = "I'm an instance var"
defined? @var #=> "instance-variable"
2018-08-10 14:45:11 +03:00
# Variables that start with @@ have class scope.
2013-08-31 04:58:23 +04:00
@@var = "I'm a class var"
defined? @@var #=> "class variable"
2018-08-10 14:45:11 +03:00
# Variables that start with a capital letter are constants.
2013-08-31 04:58:23 +04:00
Var = "I'm a constant"
defined? Var #=> "constant"
2018-08-10 14:45:11 +03:00
# 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.
2013-08-07 11:20:20 +04:00
2018-08-10 14:45:11 +03:00
# Base class
2013-08-07 11:20:20 +04:00
class Human
@@foo = 0
def self.foo
@@foo
end
def self.foo=(value)
@@foo = value
end
end
2018-08-10 14:45:11 +03:00
# Derived class
2013-08-07 11:20:20 +04:00
class Worker < Human
end
2018-08-10 14:45:11 +03:00
Human.foo #=> 0
Worker.foo #=> 0
2013-08-07 11:20:20 +04:00
2018-08-10 14:45:11 +03:00
Human.foo = 2
Worker.foo #=> 2
2013-08-07 11:20:20 +04:00
2018-08-10 14:45:11 +03:00
# A class instance variable is not shared by the class's descendants.
2013-08-07 11:20:20 +04:00
class Human
@bar = 0
def self.bar
@bar
end
def self.bar=(value)
@bar = value
end
end
class Doctor < Human
end
2018-08-10 14:45:11 +03:00
Human.bar #=> 0
Doctor.bar #=> nil
2013-08-07 11:20:20 +04:00
2013-09-08 20:46:08 +04:00
module ModuleExample
def foo
'foo'
end
end
2018-08-10 14:45:11 +03:00
# Including modules binds their methods to the class instances.
# Extending modules binds their methods to the class itself.
2013-09-08 20:46:08 +04:00
class Person
include ModuleExample
end
class Book
extend ModuleExample
end
2018-08-10 14:45:11 +03:00
Person.foo #=> NoMethodError: undefined method `foo' for Person:Class
Person.new.foo #=> "foo"
Book.foo #=> "foo"
Book.new.foo #=> NoMethodError: undefined method `foo'
2013-09-08 20:46:08 +04:00
2014-08-19 13:06:52 +04:00
# Callbacks are executed when including and extending a module
2013-09-08 20:46:08 +04:00
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
2018-08-10 14:45:11 +03:00
Something.bar #=> "bar"
Something.qux #=> NoMethodError: undefined method `qux'
Something.new.bar #=> NoMethodError: undefined method `bar'
Something.new.qux #=> "qux"
2013-07-04 09:53:12 +04:00
```
2014-03-11 01:05:49 +04:00
## Additional resources
2014-08-19 13:06:52 +04:00
- [Learn Ruby by Example with Challenges ](http://www.learneroo.com/modules/61/nodes/338 ) - A variant of this reference with in-browser challenges.
2015-11-01 02:55:25 +03:00
- [An Interactive Tutorial for Ruby ](https://rubymonk.com/ ) - Learn Ruby through a series of interactive tutorials.
2016-07-12 11:07:38 +03:00
- [Official Documentation ](http://ruby-doc.org/core )
2014-03-11 01:05:49 +04:00
- [Ruby from other languages ](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/ )
2014-11-20 19:26:56 +03:00
- [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.
2014-08-19 13:06:52 +04:00
- [Ruby Style Guide ](https://github.com/bbatsov/ruby-style-guide ) - A community-driven Ruby coding style guide.
2021-08-22 00:08:42 +03:00
- [Try Ruby ](https://try.ruby-lang.org/ ) - Learn the basic of Ruby programming language, interactive in the browser.