Blocks and Collections in Ruby
for (year = 1950, year < Date.current.year, year.advance(1.year))
if year > 1974
mocking_for_year[year].mock_about_overly_imperative_code!
end
endAlternatives
- map
- each
- filter
- detect
- inject
- for_each_object
Example
tag_conditions = tag_list.map do |tag|
sanitize_sql(["tags.name like ?", tag])
end.join(" OR ")What does do do?
Blocks
They let you pass code
into another context
and they are lexically scoped
They are not a λ
twice = lambda do |x|
x * 2
end
twice.call(5) #=> 10twice = -> (x) { x * 2 }
twice.call(5) #=> 10Stabby Syntax
Block usefulness
Opening files (naive)
file = File.open("/etc/hosts")
data = file.read
...File Descriptor just hanging out
file.closeBlock usefulness
Better
data = File.open("/etc/hosts") do |file|
file.read
endDifferences
| Blocks | Lambdas | Procs | |
|---|---|---|---|
| Is an object | No | Yes | Yes |
| Multiple can be passed into function | No | Yes | Yes |
| Check number of arguments | Yes | Yes | No |
Examples
Each
[34, 52, 88].each do |id|
suspend_account(id)
endfor id in [34, 52, 88] do
suspend_account(id)
endeach_with_index
[34, 52, 88].each_with_index do |i, index|
Account.find(i).delete if index.odd?
endMap
balances = []
[34, 52, 88].each do |id|
balances << account_balance(id)
endbalances = [34, 52, 88].map do |id|
account_balance(id)
endFilter
active_accounts = [34, 52, 88].select do |id|
Account.find(id).active?
endactive_accounts = []
[34, 52, 88].each do |id|
active_accounts << id if Account.find(id).active?
endDetect
big_number = [34, 52, 88].detect do |id|
id > 50
endbig_number = nil
[34, 52, 88].each do |id|
if id > 50
big_number = id
break
end
endeach_with_object
by_currency = Account.all.each_with_object(Hash.new(0)) do |account, acc|
acc[account.currency] += 1
endby_currency = Account.all.group_by(&:currency)group_by
index_by
by_currency = Account.all.index_by(&:id)inject
sum = [34,52,88].inject(0) do |acc, n|
acc + n
endsum = [34,52,88].inject(0, &:+)inject
sum
sum = [34,52,88].suminject
sum = [34,52,88].inject(0) do |acc, id|
account = Account.find(id)
acc + account.balance
endsum = [34,52,88].map do |id|
Account.find(id).balance
end.summap + inject
select
[34,52,88, 33].select(&:even?)sum = [34,52,88].map do |id|
Account.find(id)
end.reject do |account|
account.active?
end.map(&:balance).sumbalance of inactive accts
any? many? all?
[34,52,88,33].any? do |i|
i.even?
end[34,52,88].all?(&:even?)all?
deck
By kircxo
deck
- 357