You must use return when returning multiple results from a method, or just return the array
def m
return 1,2,3
end
print m [1, 2, 3]
def m
1,2,3
end
print m [1, 2, 3] syntax error, unexpected ',', expecting keyword_end
__send__ is an safer alternative to send if you are paranoid about somebody monkeypatching send.
Note: send can call an objects private methods.
If may be safer to use public_send for 'tainted' send parameters.
Object.new.send(:local_variables) [:_]
Object.new.public_send(:local_variables) NoMethodError: private method `local_variables' called
Beware that setter methods will return the set value, not what the method returns, for consistency
class My
def x=(x)
@x = x
'boooo'
end
def x
@x
end
end
o = My.new
p o.x = 1 1, not 'boooo'
The default superclass of a class is Object
class MyClass
end
class MyClass < Object
end
You can make a class like this:
my_class = Class.new do
def hello
puts :hello
end
end
my_class.new.hello hello
to_a is related to the splat operator
the splat operator uses .to_a()
class MyClass
def to_a
['hi', 'there']
end
end
p *MyClass.new
hi
there
splat related cool trick for being sure to create an array
seems to_a is not required for a variable to respond to *
a = 1
p [*a] [1]
a = 'asf'
p [*a] ['asdf']
a = [1,2,3]
p [*a] [1,2,3]
use Integer() to convert or validate an integer
i = Integer(1)
p i = Integer(1.623) 1
p i = Integer('number') invalid value for Integer(): "number" (ArgumentError)
to_s is used by puts, etc
to_str is used when a string is required, like + and <<
class MyClass
def to_str
'instance of MyClass'
end
end
puts 'this is an ' + MyClass.new this is an instance of MyClass
Danger of find()ing for nil
p [1,2,3,nil,4,5,6].find {|n| n.nil?} nil
p [1,2,3,4,5,6].find {|n| n.nil?} nil
p [1,2,3,nil,4,5,6].include? nil true
p [1,2,3,4,5,6].include? nil false
select! / reject! is a handy but brutal
a = [1,2,3,4,5,6,7,8]
a.select! {|x| x % 2 == 1}
p a [1,3,5,7]
a = [1,2,3,4,5,6,7,8]
a.reject! {|x| x % 2 == 1}
p a [2,4,6,8]
grep and ===
grep calls === on argument for each element
same as enumerable.select {|element| expression === element }
p [1,2,"3",4,"5",6].grep String ["3", "5"]
p ['red', 'white', 'blue'].grep /w/ ['white]
p [10, 20, 30, 40, 50].grep 20..40 [20, 30, 40]
p ['red', 'white', 'blue'].grep(/w/) {|x| x.upcase} ['WHITE]
p ['red', 'white', 'blue'].grep(/w/).map {|x| x.upcase} ['WHITE]
a = [1,2,3]
p a.take(2) [1,2]
p a [1,2,3] (unchanged)
p a.drop(2) [3]
p a [1,2,3] (unchanged)
take_while and drop_while are like first and select
p [12,32,54,100,445,35353,333333].take_while {|x| x < 500} [12, 32, 54, 100, 445]
p [12,32,54,100,445,35353,333333].drop_while {|x| x < 500} [35353, 333333]
min_by is less confusing than min and the spaceship operator if you aren't using numbers
p %w{red blue green purple yellow}.min blue
p %w{red blue green purple yellow}.min_by {|x| x.size } red
p %w{red blue green purple yellow}.min_by {|x| x[0].ord } blue
Three ways to sort an array of custom classes
things.sort
things.sort {|a,b| a.value <=> b.value }
things.sort_by {|a| a.value }
Include Comparable, define <=>, and get comparison abilities for your class
class ComparableClass
include Comparable
attr_accessor :value
def initialize(value)
self.value = value
end
def <=>(other)
value <=> other.value
end
def inspect
value
end
end
objs = 5.times.map {|x| ComparableClass.new(x) }
p objs[0] < objs[3] true
p objs[2] < objs[1] false
Enumerators can be implemented like below (enumerators depend on fibers ). I
wrote this in 5 minutes but it still hurts my head to think about.
class MyEnumerator
def initialize(&b)
@fiber = Fiber.new do
yielder = ->(x){ Fiber.yield x }
b.call(yielder)
end
end
def next
@fiber.resume
end
end
e = MyEnumerator.new do |y|
[1,2,3].each do |x|
y.yield x
end
end
p e.next 1
p e.next 2
p e.next 3
enum_for takes a method to enumerate on, and could be implemented like this
class Array
def my_enum_for(method = :each)
Enumerator.new do |y|
send(method) do |x|
y << x
end
end
end
end
e = [1,2,3].my_enum_for(:map)
p e.next 1
p e.next 2
p e.next 3
Protect an object with its enumerable (not sure how useful this is)
a = (0..9).to_a
e = a.enum_for
p e.map {|x| x} [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
e << 10 undefined method `<<' for Enumerator:
Making a class 'enumerable' without including Enumerable by hooking its each() up to enumerator
class MyClass
def initialize
@a = (0..9).to_a
end
def each
@a.each {|x| yield x}
end
end
obj = MyClass.new
obj.each {|x| print x } 0123456789
p obj.enum_for(:each).min 0
p obj.enum_for(:each).max 9
Three ways to test for regex match, ugh
re = /there/
string = 'here there everywhere'
puts "Match!" if re.match(string)
puts "Match!" if string =~ re
puts "Match!" if re =~ string
puts "Match!" if re === string
puts "Match!" if string === re doesn't work in reverse
extend() : "the mixing of a module into an object's singleton class"
From ruby-doc.org: "Adds to obj the instance methods from each module given as a parameter."
Common use: dump a modules instance methods into a class's singleton class
Difference from include(): which dumps modules instance methods into classes instance methods
module MyModule
def hello
puts :hello
end
end
obj = Object.new
obj.extend MyModule
obj.hello hello
String.extend MyModule
'asdf'.class.hello hello
class << obj
include MyModule
end
obj.hello hello
Some idioms used used proc objects
def mult(factor)
Proc.new do |x|
x * factor
end
end
mult3 = mult(3)
p mult3.call(3) 9
def mk_counter
count = 0
Proc.new { count = count + 1 }
end
counter = mk_counter
p counter.call 1
p counter.call 2
p counter.call 3
Weird way to run runable object
proc = Proc.new {|x| puts x }
proc.call('asdf') asdf
proc['asdf'] asdf
proc.('asdf') asdf
instance_eval for more friendly configuration
class Person
def initialize(&block)
instance_eval(&block)
end
def first(name=nil)
@first = @first || name
end
def last(name=nil)
@last = @last || name
end
end
person = Person.new do
first 'Bob'
last 'Smith'
end
p person.first Bob
p person.last Smith
method_missing can be used for delegation
class MyArray
def initialize
@array = []
end
def method_missing(method, *args, &b)
@array.send(method, *args, &b)
end
end
ma = MyArray.new
ma << 1
ma << 2
ma << 3
p ma.join(', ') "1, 2, 3"
use included to mixin a class method with include()
could use extend() but sometimes you want to mixin *both* class and instance methods
module MyModule
def a_instance_method
puts 'hello from a_instance_method'
end
def self.included(c)
def c.a_class_method
puts 'hello from a_class_method'
end
end
end
class MyClass
include MyModule
end
MyClass.a_class_method hello from a_class_method
MyClass.new.a_instance_method hello from a_instance_method
Note: Is it true there is no way to mixin module class methods?
Using include() we can include instance methods into a class.
Using extend() we can include instance methods into an objects singleton class.
There might be with unbind and bind, but its looking like a mess.