Play a game unless you're tired. If you're tired, go to bed.
unless tired
puts "Play games"
else
puts "Go to bed"
end
my_name = 'Cheng-Yu'
# must use double quotes around the string to be formatted,
# using single quotes will not cause an evaluation just like in php
puts "My name is #{my_name}."
For more details: http://rors.org/2008/10/26/dont-escape-in-strings
# this will return a boolean
some_string.include? "string to match"
# gsub(pattern, rep) => a string with `pattern` replaced by `rep`
sub_string = some_string.gsub(/\s+/, ' ')
or using gsub!
# gsub!(pattern, rep) => a string with `pattern` replaced by `rep` and set the new string back
some_string.gsub!(/\s+/, ' ')
Two different ways to define a range:
0..5 # [0, 1, 2, 3, 4, 5]
0...5 # [0, 1, 2, 3, 4]
You may either use ..
or ...
to enum some range of numbers
for num in 1...13
puts num
end
1
2
3
4
5
6
7
8
9
10
11
12
or
for num in 1..13
puts num
end
1
2
3
4
5
6
7
8
9
10
11
12
13
# Infinite loop that prints `YOLO` for days.
loop { puts "YOLO" }
# loop until i <= 0
i = 20
loop do
i -= 1
puts i
break if i <= 0
end
In Ruby, the continue
keyword in a loop is replaced by next
.
However, break
remains the same.
for i in 1..20
if i % 2 == 0
next
end
puts i
end
The above code will print out the odd numbers in [1, 20].
each
is a iterator that iterate through a iteratable.
array = [1,2,3,4,5]
# You may give arbitary name the element it iterate through
# in this case, x
array.each do |x|
x += 10
print "#{x}"
end
As seen in most for the languages, this iterator will not modify the original values.
(Review) forEach
seen in Javascript.
arr = [1, 2, 3];
arr.forEach(function(ele){
console.log(ele);
});
numbers = [1, 2, 3, 4, 5]
# one way to loop
numbers.each { |item| puts item }
# another way to loop
numbers.each do |item|
puts item
end
# do something for multiple times
3.times{
puts "Ruby Sparks"
}
my_map = Hash.new
my_another_map = {
"key" => "value"
}
# giving a default value to an undefined key
map2 = Hash.new("default_val")
colors = {"blue" => 3, "green" => 1, "red" => 2}
colors = colors.sort_by do |color, count|
count
end
colors.reverse!
or if you don't want to reverse
that
colors = {"blue" => 3, "green" => 1, "red" => 2}
colors = colors.sort_by do |color, count|
# use some simple math
-count
end
arr = [4, 5, 3]
arr.sort!
or with custom comparison rules:
arr = ["yolo", "yoy", "yay"]
arr.sort! { |first, second|
# sort by length, desc
second.length <=> first.length
}
Just something like public void someMethod(String... args)
in Java.
def func(*args)
args.each{ |arg|
puts arg
}
end
?
is legal for a name of a method.
def is_even? (num)
return num % 2 == 0
end
You can think of blocks as a way of creating methods that don't have a name. (These are similar to anonymous functions in JavaScript or lambdas in Python.)
3.times{
puts "Blocks!"
}
Can be thought as "Is the first operand greater than the second one?"
1 <=> 1 # Since 1 == 1, it should be 0
2 <=> 1 # Since 2 > 1, it should be 1
1 <=> 2 # Since 1 < 2, it should be -1
By default, Ruby will return last line of a method.
def add(a, b)
a + b
# or use explicit return
# return a + b
end
# c will be 4
c = add(1, 3)
Ruby symbol as a sort of name.
It's important to remember that symbols aren't strings:
"string" == :string # false
Also, only one symbol may exist in a give time.
Try to access the object_id
:
# different object_ids
puts "string".object_id
puts "string".object_id
# same object_ids
puts :symbol.object_id
puts :symbol.object_id
Use symbols are good for performance:
- They're immutable, meaning they can't be changed once they're created
- Only one copy of any symbol exists at a given time, so they save memory
my_hash = {
:first => "yep"
}
Converting symbols to strings (or strings to symbols)
:my_sym.to_s # "my_sym"
"my_sym".to_sym # :my_sym
"my_sym".intern # :my_sym
For Ruby 1.9+, you may use the symbols in a hash more like the way in Javascript.
my_hash = {
one: 2 # one is a symbol with : at the end
# which is equal to :one => 2
}
Creating Hash
from a 2D array.
Hash[[1, 2, 3].zip(["a", "b", "c"])]
=begin
{
1: "a",
2: "b",
3: "c"
}
=end
More about zip
: http://dfriedm.github.io/blog/2013/10/12/ruby-zip-method/
movie_ratings = {
memento: 1,
primer: 3.5,
the_matrix: 3
}
# good_movies = {:primer => 3.5}
good_movies = movie_ratings.select{ |k, v|
# return true if it is selected, false otherwise.
v > 3
}
Of course, you may filter an array using select
.
(1..10).to_a.select{ |num|
# return true if it is selected, false otherwise.
num % 3 == 0
}
# [3, 6, 9]
my_hash = {
one: 1,
two: 2
}
my_hash.each_key{ |k|
puts k
}
my_hash.each_value{ |v|
puts v
}
my_hash = {
kingsman: 4.5
}
# if a key exist, it will return the value of the key
# and delete it from the hash
pop_val = my_hash.delete(:kingsman)
# otherwise, it will return a nil
nil_val = my_hash.delete(:gone_girl)
Enumarate elements in an iterable and repeat it forever.
arr = [1, 2, 3]
arr.cycle #<Enumerator: [1, 2, 3]:cycle>
# infinite loop that prints "1 2 3 1 2 3 1 2 3 ..."
arr.cycle.each{ |element|
puts element
}
arr = [1, 2, 3]
arr.rotate!
arr.rotate!
arr.rotate!
[2, 3, 1]
[3, 1, 2]
[1, 2, 3]
Must followed by a then
after the when
if you don't want to add a newline.
case color
when "Red" then puts "Apple"
when "Green" then puts "Watermelon"
else puts "Whatever..."
end
Assign to a variable only if it is nil
.
my_book = nil
my_book ||= "What if"
my_book ||= "Zen"
puts my_book
"What if"
Iterate from a
to b
.
Works on numbers
# prints 3, 4, 5, 6, ..., 10
3.upto(10){ |num|
puts num
}
And alphabets
# prints E, D, ..., A
'E'.downto('A'){ |char|
puts char
}
Check if an object can respond to a certain method.
Same as [obj respondToSelector:@selector(someMethod:)];
in Objective-C
canPush = [1, 2, 3].respond_to?(:push)
canNotPush = {one: 1}.respond_to?(:push)
.next
will return the iterable.
# return 4
3.next
arr = [1, 2, 3]
ele = arr.to_enum
puts ele.next #=> 1
puts ele.next #=> 2
puts ele.next #=> 3
puts ele.next #raises StopIteration (an exception)
arr = [1, 2, 3]
arr << 4
# => [1, 2, 3, 4]
# which is equivalent to arr.push(4)
name = "Cheng-Yu "
name << "Hsu"
# => "Cheng-Yu Hsu"
# which is equivalent to name += "Hsu"
# can do it mutiple times
coffee = "Latte"
"I love " << coffee << "!"
isNil = my_obj.nil?
# In Ruby 1.9+
require 'prime'
puts Prime.instance.first 5
# In Ruby 1.8-
require 'prime'
prime_arr ||= []
prime = Prime.new
5.times{ prime_arr < prime.next}
puts prime_arr
In the previous example, if you try to run the second snippet on Ruby 1.9+ interpreter, you'll find that the interpreter complains about Prime.new
is a deprecated method.
To disable the warning, try to set the log level.
# make the interpreter less talkative
$VERBOSE = nil
For more details: http://devblog.avdi.org/2011/08/25/temporarily-disabling-warnings-in-ruby/
map
and collect
are the same method that produce another array by manipulating each element of an array (results are of the same size of the original ones).
arr = [1, 2, 3]
doubled_arr = arr.map{ |num|
num * 2
}
# prints out [2, 4, 6]
puts doubled_arr
or you can do it with collect
arr = [1, 2, 3]
doubled_arr = arr.collect{ |num|
num * 2
}
# prints out [2, 4, 6]
puts doubled_arr
map
, reduce
, and inject
: http://railspikes.com/2008/8/11/understanding-map-and-reduce
How to make your method accept a block? Actually, it's all about mixin (inject a code section into another code section).
To do this in a method, use the yield
keyword.
def block_test
puts "We're in the method!"
puts "Yielding to the block..."
yield
puts "We're back in the method!"
end
block_test { puts ">>> We're in the block!" }
Output
We're in the method!
Yielding to the block...
>>> We're in the block!
We're back in the method!
def show_my_name(name)
puts "In the method!"
puts "Begin to yield..."
yield(name)
puts "Yield ends, back to the method!"
end
show_my_name("Cheng-Yu"){ |name|
puts "My name is " << name << "."
}
Above is the example of yield
ing a implicit block.
You can do it by explicit calling a block as a Proc
def show_my_name(name, &block)
block.call(name)
end
show_my_name('cy') { |name| p name }
Be aware, block.call
is much more slower than yield
for ~2.0x, so use yield
.
DRY (Don't Repeat Yourself) is a design policy in Ruby.
To define a repeatable block, we need to assign it to a reference, otherwise, it will be anonymous and disappear after it's allocated.
Proc
serves as this purpose, you may understand it as a repeatable block.
even_numbers = Proc.new { |n|
n % 2 == 0
}
(1..100).to_a.select(&even_numbers)
Without parameters:
my_proc = Proc.new {
puts "My number is 100!"
}
my_proc.call
With parameters
my_proc = Proc.new { |num|
puts "My number is #{num}!"
}
my_proc.call(19)
You may call build-in methods as a Proc
.
strings = ["1", "2", "3"]
nums = strings.map(&:to_i)
# [1, 2, 3]
my_arr = [1, 2, 3]
sum = my_arr.reduce(:+)
# sum = 1 + 2 + 3 = 6
lambda
looks like to a proc
.
my_lambda = lambda {
puts "I'm the lambda!"
}
my_lambda.call
# I'm the lambda
Short syntax of lambda
triple = -> (x) { x * 3 }
[1, 2, 3].map(&triple)
However, there're some differences between them.
One is the way they handle the parameters:
Proc
does NOT check the number of parameters.lambda
does check the number of parameters
sum = proc{ |a, b|
a + b
}
puts sum.call(1, 3)
puts sum.call(1)
4
TypeError: nil can't be coerced into Fixnum
sum = lambda { |a, b|
a + b
}
puts sum.call(1, 3)
puts sum.call(1)
4
ArgumentError: wrong number of arguments (1 for 2)
Another difference is that Proc
and lambda
treat return
differently:
-
The
return
inProc
actually jumps out theProc
block, which will cause theProc
and the callerreturn
immediately (more like mixin, which injects some code into other codes).Note that if a
proc
(block) is passed as an argument, a explicitreturn
will casue an exception. http://ruby-doc.org/core-2.1.5/LocalJumpError.html -
And the return in
lambda
will return the value to the caller (also the control).
def test_return
my_proc = Proc.new { return "This is a string!" }
my_proc.call
# will not be called,
# since the proc returns the method
"This is a line of DEAD code!"
end
puts test_return
This is a string!
def test_return
my_lambda = lambda{
return "This is a string!"
}
my_lambda.call
# by default, Ruby will return the last line
# of code it executes, that is,
# the following one.
"This is a line of alive code!"
end
puts test_return
This is a line of alive code!
For more details: http://stackoverflow.com/questions/1740046/whats-the-difference-between-a-proc-and-a-lambda-in-ruby
-
Use
class
to define a class. -
Use
initialize
to override the constructor. -
Variables:
@name
: an instance variable namedname
@@objectType
: a class variable namedobjectType
$constant
: a global variable namedGLOB
, it's dangerous, be aware.
-
Use normal method definition to define instance methods:
def myMethod # do something end
-
Use
self.method_name
orClassName.method_name
to define class methods:class MyClass def self.classMethod # do something end def MyClass.classMethod2 # do something end end # calling it MyClass.classMethod MyClass.classMethod2
Reference: http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/
-
Subclass
# a subclass of Fixnum named MyCoolNum class MyCoolNum < Fixnum end
Raise an error.
def myFunc(num)
raise ArgumentError unless num.is_a? Integer
end
Inject a code snippet into another file (at instance level).
Use include
to do it!
# calc.rb
module Calc
def add(a, b)
a + b
end
def sub(a, b)
a - b
end
end
Inject into this
# my_num_set.rb
# include other files
require_relative './calc.rb'
class MyNumSet
include Calc
end
And others may call
my_num_set = MyNumSet.new
my_num_set.add(1, 2)
Inject a code snippet into another file (at class level).
Use extend
to do it!
module ThePresent
def now
puts "Now?"
end
end
class TheHereAnd
extend ThePresent
end
TheHereAnd.now
Output
Now?
To use the access control modifiers in Ruby OOP, put the keyword before the definition of the method.
class MyClass
public
def pubMethod
puts "This is a public method!"
end
private
def priMethod
puts "This is a private method!"
end
end
MyClass.new.priMethod
Output
NoMethodError: private method `priMethod' called for #<MyClass:0x007ff8518521f8>
More details: http://blog.eddie.com.tw/2011/07/26/public-protected-and-private-method-in-ruby/
class Person
# read only
attr_reader :name
# write only
attr_writer :name
def initialize(name)
@name = name
end
end
generates the following code
def name
@name
end
# This is an awesome setter,
# a function with name:
# obj.name=
def name=(value)
@name = value
end
And can be used like
me = Person.new("CY")
me.name = "Cheng-Yu"
puts me.name
Output
Cheng-Yu
class Person
# read/write
attr_accessor :name, :whatever
def initialize(name)
@name = name
end
end
Module can be understood as a library serves for certain purposes. (My contains methods, constants)
module Circle
M_PI = 3.14
def self.area(r)
r * r * M_PI
end
end
Double columns serves for namespace
, which is like fully qualified name in Java.
It's used to resolve conflict method names or variable names. Put the module/class name before double columns to specify the namespace.
puts Circle::M_PI
puts Math::PI
To import some module, use require
(just like the way we do in Node.js
).
require 'date'
puts Date.today
You may use mixin to achieve psuedo multiple inheritances.
module MartialArts
def swordsman
puts "I'm a swordsman."
end
end
# Both Ninja and Samurai are "sort of" SwordsMan now!
# Like an attribute, not actually inherit from SwordsMan
class Ninja
include MartialArts
def initialize(clan)
@clan = clan
end
end
class Samurai
include MartialArts
def initialize(shogun)
@shogun = shogun
end
end
Integer to binary / hex.
5.to_s(2) # 101
11.to_s(16) # b
String to binary / hex.
"5".ord # 53
"5".unpack("B*") # ["00110101"]
"5".unpack("H*") # ["35"]
More: http://ruby-doc.org/core-2.2.1/String.html#method-i-unpack
def print_args(*args)
print args
end
-
Invoke with argument
[1, 2, 3]
(an array):send(:print_args, [1, 2, 3]) # output: [[1, 2, 3]]
-
Invoke with 3 arguments:
send(:print_args, *[1, 2, 3]) # output: [1, 2, 3]
Note: *
can used for converting splat arguments to array and vice versa (just like &
for proc
).