Какво прави alias
?
class Something
def name() 'baba' end
alias relative name
def name() 'dyado' end
end
p Something.new.relative
Прави копие на метода
Каква е разликата между alias
и alias_method
?
alias_method
е метод, докато alias
е синтаксис
class Something
1.upto(5).each do |index|
alias_method "to_s_#{index}", :to_s
end
end
Кой (и как) може да вика private
методи?
class Something
private
def foo
end
end
self.foo
)На какво могат да завършваш методите в Ruby?
?
ако са предикати!
ако имат две версии=
ако са setter%
Какви са конвенциите за имена на методи, променливи, константи и имена на класове?
UpperCamelCase
- константи (включва имена на класове)normal_snake_case
- променвили, методиSCREAMING_SNAKE_CASE
- константи, които не са имена на класове или модулиObject#tap
извиква блока със себе си и връща обекта, на който е извикан.
array = [].tap do |items|
items # []
items.equal? array # false
items << 'foo'
'other thing'
end
array # ["foo"]
Имате следния код
(1..10).select { |x| x.odd? }.map { |x| x ** 2 }
Искате да видите какво остава след select
-а:
(1..10).select { |x| x.odd? }.tap { |x| p x }.map { |x| x ** 2 }
class Array
def occurences_count
Hash.new(0).tap do |result|
each { |item| result[item] += 1 }
end
end
end
Следните два реда са (почти) еквивалентни:
name = ->(object) { object.name }
name = :name.to_proc
Когато подавате блок на метод с &block
, Ruby извиква
#to_proc
, ако block
не е метод.
Съответно, следните два реда са еквивалентни
%w[foo plugh larodi].map { |s| s.length } # [3, 5, 6]
%w[foo plugh larodi].map(&:length) # [3, 5, 6]
Всъщност, малко по сложно е:
block = ->(obj, *args) { obj.method_name *args }
block = :method_name.to_proc
Това значи, че може да направите така:
[{a: 1}, {b: 2}, {c: 3}].inject { |a, b| a.merge b } # {:a=>1, :b=>2, :c=>3}
[{a: 1}, {b: 2}, {c: 3}].inject(&:merge) # {:a=>1, :b=>2, :c=>3}
Или дори:
[1, 2, 3, 4].inject { |a, b| a + b } # 10
[1, 2, 3, 4].inject(&:+) # 10
['Foo' :bar, 3].map(&:to_s).map(&:upcase)
class Symbol
def to_proc
# ...?
end
end
send
send
, за да викате произволни методи на този обектprivate
или protected
такиваpublic_send
, ако искате да не прекрачвате този праг3.send :+, 4 # 7
class Symbol
def to_proc
->(object, *args) { object.public_send self, *args }
end
end
Модулите в Ruby имат няколко предназначения:
Днес ще разгледаме последното.
Модулите в Ruby просто съдържат методи. Дефинират се подобно на класове:
module UselessStuff
def almost_pi
3.1415
end
def almost_e
2.71
end
end
Модулите могат да се "миксират" с клас. Тогава той получава всички методи на модула като instance методи.
module UselessStuff
def almost_pi
3.1415
end
end
class Something
include UselessStuff
end
Something.new.almost_pi # 3.1415
В метод на модула, self
е инстанцията, на която е извикан.
module Introducable
def introduction
"Hello, I am #{name}"
end
end
class Person
include Introducable
def name() 'The Doctor' end
end
doctor = Person.new
doctor.introduction # "Hello, I am The Doctor"
Методите на класа имат приоритет пред методите на модула.
module Includeable
def name() 'Module' end
end
class Something
def name() 'Class' end
include Includeable
end
Something.new.name # "Class"
Ако два модула дефинират един и същи метод, ползва се последния:
module Chunky
def name() 'chunky' end
end
module Bacon
def name() 'bacon' end
end
class Something
include Chunky
include Bacon
end
Something.new.name # "bacon"
Просто за информация: методите на mixin-ите имат приоритет пред тези на родителя.
Всичко това е свързано с нещо, наречено ancestor chain, за което ще си говорим следващия път.
Помните ли тези методи?
[1, 2, 3, 4, 5].select(&:odd?) # [1, 3, 5]
%w[foo plugh barney].map(&:length) # [3, 5, 6]
[1, 2, 3, 4, 5].inject(&:*) # 120
Те са имплементирани в Enumerable
, а не в Array.
Всяка колекция в Ruby ги има.
all? any? chunk collect collect_concat count cycle detect drop drop_while each_cons each_entry each_slice each_with_index each_with_object entries find find_all find_index first flat_map grep group_by include? inject map max max_by member? min min_by minmax minmax_by none? one? partition reduce reject reverse_each select slice_before sort sort_by take take_while to_a zip
После ще видите как генерирах тази таблица.
Хешовете също са Enumerable
:
hash = {2 => 3, 4 => 5}
hash.to_a # [[2, 3], [4, 5]]
hash.map { |p| p[0] + p[1] } # [5, 9]
hash.map { |k, v| k + v } # [5, 9]
hash.inject(0) { |s, p| s + p[0] * p[1] } # 26
Някои от Enumerable
методите в Hash
са предефинирани
hash = {2 => 3, 4 => 5, 6 => 7, 8 => 9}
hash.select { |k, v| v > 6 } # {6=>7, 8=>9}
hash.to_a.select { |k, v| v > 6 } # [[6, 7], [8, 9]]
Enumerable#select
връща списък, но Hash#select
връща Hash.
Hash
, Array
Range
от числа, дати, символи и прочееSet
и други...#all?
/#any?
връщат истина ако всички/един елемент(и) от
колекцията отговарят на някакво условие
[1, 2, 3, 4].all? { |x| x.even? } # false
[1, 2, 3, 4].any? { |x| x.even? } # true
[2, 4, 6, 8].all? { |x| x.even? } # true
[2, 4, 6, 8].any? { |x| x.odd? } # false
# И разбира се:
[1, 2, 3, 4].any?(&:even?) # true
#each_with_index
yield-ва всеки елемент с индекса му в масива
%w[foo bar baz].each_with_index do |word, index|
puts "#{index}. #{word}"
end
Извежда:
0. foo 1. bar 2. baz
Името казва всичко, което ви е нужно да знаете
hash = %w[foo bar plugh larodi]
groups = hash.group_by { |word| word.length }
groups # {3=>["foo", "bar"], 5=>["plugh"], 6=>["larodi"]}
#each_slice(n)
yield
-ва елементите на части по n
:
%w[a b c d e f g h].each_slice(3) do |slice|
p slice
end
Извежда
["a", "b", "c"] ["d", "e", "f"] ["g", "h"]
#each_cons(n)
yield
"подмасиви" с n
елемента
[1, 2, 3, 4, 5].each_cons(3) do |cons|
p cons
end
Извежда
[1, 2, 3] [2, 3, 4] [3, 4, 5]
Вече знаете какво прави
[1, 2, 3, 4].include? 3 # true
[1, 2, 3, 4].member? 5 # false
Двете са синоними
[1, 2, 3].zip([4, 5, 6]) # [[1, 4], [2, 5], [3, 6]]
[1, 2].zip([3, 4], [5, 6]) # [[1, 3, 5], [2, 4, 6]]
Като #all?
и #any?
, но в други случаи
%w[foo bar larodi].one? { |word| word.length == 6 } # true
%w[foo bar larodi].one? { |word| word.length == 3 } # false
[1, 5, 3].none? { |number| number.even? } # true
[1, 2, 3].none? { |number| number.even? } # false
[1, 2, 3, 4, 5].take(2) # [1, 2]
[1, 2, 3, 4, 5].drop(2) # [3, 4, 5]
[1, 3, 5, 6, 7, 9].take_while(&:odd?) # [1, 3, 5]
[1, 3, 5, 6, 7, 9].drop_while(&:odd?) # [6, 7, 9]
all? any? chunk collect collect_concat count cycle detect drop drop_while each_cons each_entry each_slice each_with_index each_with_object entries find find_all find_index first flat_map grep group_by include? inject map max max_by member? min min_by minmax minmax_by none? one? partition reduce reject reverse_each select slice_before sort sort_by take take_while to_a zip
Enumerable.instance_methods.
sort.
map { |name| name.to_s.rjust(16) }.
each_slice(5) { |row| puts row.join '' }
Disclaimer: Леко редактирах whitespace-а за да се събере в слайд
Трябва да дефинирате #each
.
Той ви дава всичко останало.
class FibonacciNumbers
include Enumerable
def initialize(limit)
@limit = limit
end
def each
current, previous = 1, 0
while current < @limit
yield current
current, previous = current + previous, current
end
end
end
FibonacciNumbers.new(100).to_a # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
class StepRange
include Enumerable
def initialize(first, last, step)
@first, @last, @step = first, last, step
end
def each
@first.step(@last, @step) { |n| yield n }
end
end
StepRange.new(1, 10, 2).select { |n| n > 5 } # [7, 9]