Какво прави alias
?
class Something
def name() 'baba' end
alias relative name
def name() 'dyado' end
end
p Something.new.relative
Прави копие на метода
Кой (и как) може да вика private
методи?
class Something
private
def foo
end
end
self.foo
)На какво могат да завършваш методите в Ruby?
?
ако са предикати!
ако имат две версии=
ако са setterКакви са конвенциите за имена на методи, променливи, константи и имена на класове?
;
Следните хранилища може да са ви интересни
Някои от възможните интеракции:
Ще разгледаме:
class Array
def to_hash
Hash[*self.flatten]
end
end
[[1, [2, 3]], [4, [5, 6]]].to_hash # {1=>2, 3=>4, 5=>6}
Ако някой от елементите е масив, номера няма да мине
def to_hash
result = Hash.new
for i in 0...self.size
result[self[i][0]] = self[i][1]
end
result
end
Не ползвайте for
- остаряла форма е и вътрешно вика #each
.
Hash.new
е глупав начин да напишеше {}
self.each do |key, value|
щеше да е напълно достатъчен
class Array
def occurences_count
res = Hash.new(0)
self.map { |elem| res[elem] += 1 }
res
end
end
Някои от вас смесват табулации и интервали:
Накратко, научете се как да ползвате редакторите си.
class Array
def index_by
h=Hash.new
while not(self.empty?)
x=self.first
h[yield x]=x
self.shift
end
puts h
end
end
while
и until
се ползват много рядко в Ruby.def to_hash
res = {}
self.each do |v|
res[v[0]] = v[1]
end
res
end
res
? v
? wtf?def subarray_count(subarray)
raise ArgumentException if subarray.empty?
to_return = 0
victim = self.dup
while victim.length >= subarray.length do
to_return += 1 if victim.first(subarray.length) == subarray
victim.shift
end
to_return
end
victim
? Наистина?
def subarray_count(subarray)
result = 0
for i in 0...size
fail = 0
for j in 0...subarray.size
unless self[i+j] == subarray[j]
fail = 1
end
end
unless fail == 1
result += 1
end
end
result
end
Това не е Ruby програма. Това е C програма. При това - крива.
class Array
def to_hash
self.inject({}) { |k, v| k[v[0]] = v[1]; k }
end
def index_by
self.inject({}) { |k, v| k.merge!(yield(v) => v) }
end
end
Избягвайте да мутира аргумента на #inject
Тук #merge!
няма работа
class Array
def index_by(&block)
((map &block).zip self).to_hash
end
end
Имаш предвид map(&block).zip(self).to_hash
?
Впрочем, хитро решение
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
Модулите в 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.
#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 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]