Какво прави 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
Какво ще има в ancestors chain-a?
module Foo; end
module Bar; end
module Baz; end
module Qux
include Foo
include Bar
end
class Garply
include Foo
include Qux
end
class Waldo < Garply
include Foo
include Baz
include Bar
end
Waldo.ancestors # =>
[Waldo, Baz, Garply, Qux, Bar, Foo, Object, Kernel, BasicObject]
Класовете и модулите могат да служат като именувани пространства.
module Useless
class Thing
end
end
class Grandfather
class StraightRazor
end
end
Useless::Thing.new # => #<Useless::Thing:0x002b794d68a708>
Grandfather::StraightRazor.new # => #<Grandfather::StraightRazor:0x002b794d68a348>
Ако се намирате в модул, няма нужда да ползвате пълния път до константите:
module Useless
class Thing
end
Thing.new # => #<Useless::Thing:0x002ba1fae11a00>
end
Useless::Thing.new # => #<Useless::Thing:0x002ba1fae11528>
Thing.new # => error: NameError
def
, module
и class
@foo
)bacon = 2
def foo
chunky = 10
1.times do
chunky # 10
chunky = 44
end
chunky # 44
bacon # error: NameError
end
foo()
module
и class
ви местят из дървото на константите
::
отпред (::Foo
)
Object
PLACE = 'root'
module Outer
PLACE = 'intermediate'
module Inner
PLACE = 'deep'
end
end
PLACE # => "root"
Outer::Inner::PLACE # => "deep"
module Outer
module Inner
PLACE # => "deep"
::PLACE # => "root"
end
PLACE # => "intermediate"
Inner::PLACE # => "deep"
end
Може да дефинирате класови методи така:
class Something
def Something.answer
42
end
end
Something.answer # => 42
Не може да ги викате неквалифицирано от инстанцията:
class Something
def Something.answer
42
end
def do_stuff
answer # => error: NameError
Something.answer # => 42
end
end
thing = Something.new
thing.answer # => error: NoMethodError
Something.answer # => 42
thing.do_stuff
Достъпни са в наследниците:
class Base
def Base.answer() 42 end
end
class Derived < Base
def Derived.say_answer
answer # => 42
Base.answer # => 42
end
end
Derived.answer # => 42
Base.answer # => 42
Derived.say_answer
Има и други начини за дефиниция на класови методи:
answer = 42
a, b = 1, 2
a # => 1
b # => 2
a, b = b, a
a # => 2
b # => 1
Има няколко различни случая, които ще разгледаме.
a = 1, 2, 3
a # => [1, 2, 3]
Практически същото като a = [1, 2, 3]
a, b = [1, 2, 3]
a # => 1
b # => 2
a, b = 1, 2, 3
a # => 1
b # => 2
nil
head, *tail = [1, 2, 3]
head # => 1
tail # => [2, 3]
first, *middle, last = 1, 2, 3, 4
first # => 1
middle # => [2, 3]
last # => 4
middle
и tail
обират всичко останало
first, *middle, last = 1, [2, 3, 4]
first # => 1
middle # => []
last # => [2, 3, 4]
first, *middle, last = 1, *[2, 3, 4]
first # => 1
middle # => [2, 3]
last # => 4
head, (title, body) = [1, [2, 3]]
head # => 1
title # => 2
body # => 3
head, (title, (body,)) = [1, [2, [3]]]
)
head, (title, *sentences) = 1, [2, 3, 4, 5, 6]
head # => 1
title # => 2
sentences # => [3, 4, 5, 6]
Бележка за реда на оценка при присвояване — първо отдясно, след това отляво:
x = 0
a, b, c = x, (x += 1), (x += 1)
x # => 2
a # => 0
b # => 1
c # => 2
Може да ползвате едно име само един път, когато то се среща в списък с параметри на метод, блок и прочее.
Proc.new { |a, b, a| } # SyntaxError: duplicated argument name
Proc.new { |_, b, _| } # => #<Proc:0x007f818af68de0@(irb):23>
Горното важи не само за блокове, но и за методи.
success, message = execute(job)
[[1, [2, 3]], [4, [5, 6]], [7, [8, 9]]].each do |a, (b, c)|
puts "#{a}, #{b}, #{c}"
end
# 1, 2, 3
# 4, 5, 6
# 7, 8, 9
Имате ли въпроси по тази тема?
Следните два реда са (почти) еквивалентни:
name = ->(object) { object.name }
name = :name.to_proc
Когато подавате блок на метод с &block
, Ruby извиква
#to_proc
, ако block
не е ламбда или proc.
Съответно, следните два реда са еквивалентни
%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}].reduce { |a, b| a.merge b } # => {:a=>1, :b=>2, :c=>3}
[{a: 1}, {b: 2}, {c: 3}].reduce(&:merge) # => {:a=>1, :b=>2, :c=>3}
Или дори:
[1, 2, 3, 4].reduce { |sum, b| sum + b } # => 10
[1, 2, 3, 4].reduce(&:+) # => 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
proc { |object, *args| object.public_send self, *args }
end
end
String.methods
)
String.class
) и той е Class
Долното работи:
a_hash_class = Hash
a_hash_class.new # => {}
Class.new
Module.new
ще създаде инстанция на анонимен модулanonymous_class = Class.new
anonymous_class.new # => #<#<Class:0x002b6c26530df0>:0x002b6c26530da0>
Class.new.new # => #<#<Class:0x002b6c26530710>:0x002b6c26530698>
Module.new # => #<Module:0x002b6c265300f8>
Можем да подадем блок на Class.new
:
duck = Class.new do
def quack_to(creature_name)
"Quack, #{creature_name}, quack!"
end
end
duck.new.quack_to("swan") # => "Quack, swan, quack!"
class Person
end
class
е просто синтаксис, който прави обект от тип "клас"
class
е scope gate, докато блоковете не са
class
го присвоява и на константа
Когато присвоим анонимен клас на константа, попадаме в специален случай:
Person = Class.new
Class.new # => #<Class:0x002b8b21c218e8>
Person = Class.new # => Person
Module.new # => #<Module:0x002b8b21c21000>
Larodi = Module.new # => Larodi
::
Object
Object::FOO
и ::FOO
в (почти) всички случаи са едно и също
::Object::FOO
и ::FOO
са едно и също винагиObject
Можете да видите тази "таблица" през constants
:
module MyLibrary
class Object
end
end
MyLibrary.constants # => [:Object]
MyLibrary::Object == Object # => false
->_{_%_}["->_{_%%_}[%p]"]
v=0000;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP
4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_><wS5rtWk@*a+Y5
yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)'Iof*nm.,$C5Nyt=
PPu01Avw^<IiQ=5$'D-y? "##: ###############" g6`YT+qLw9k^ch|K'),tc
6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u
}RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U'
$*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5
PFixrPvl&<p[]1IJ " ############:#### %#####" EGgDt8Lm#;bc4zS^
y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V
zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"%
(;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)%
360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<<
126}";d.gsub!(/ "##########. #######% " |\s|".*"/,"");;
require"zlib"|| "########### :######. " ;d=d.unpack"C*"
d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91};
e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib::
Inflate.inflate( " ######% .####% :: " &&e).unpack("b*"
)[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-(
(y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w*
2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End\
oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010
Може да пуснете quine-а от предния слайд като го запазите във файл quine.rb
и ползвате това скриптче:
#!/bin/sh
while true
do
ruby quine.rb | tee quine_result
mv quine_result quine.rb
sleep 0.2
done
Да кажем, че имаме следния код:
CURRENCY_NAMES = {
BGN: 'Bulgarian lev',
EUR: 'Euro',
USD: 'United States dollar',
CHF: 'Swiss frank',
}.freeze
[:BGN, :CHF, :EUR].map { |currency_code| CURRENCY_NAMES[currency_code] }
# => ["Bulgarian lev", "Swiss frank", "Euro"]
Нека предположим, че имаме следната имплементация на Hash#to_proc
:
class Hash
def to_proc
proc { |key| self[key] }
end
end
Тогава можем да направим следното:
CURRENCY_NAMES = {
BGN: 'Bulgarian lev',
EUR: 'Euro',
USD: 'United States dollar',
CHF: 'Swiss frank',
}.freeze
[:BGN, :CHF, :EUR].map &CURRENCY_NAMES
# => ["Bulgarian lev", "Swiss frank", "Euro"]
Удобни изглеждат и следните хипотетични употреби:
VALID_CURRENCIES = {
BGN: true,
EUR: true,
USD: true,
CHF: true,
}.freeze
valid_currencies = [:BGN, :CHF, :EUR].select(&VALID_CURRENCIES)
# Or:
if currencies.any? &VALID_CURRENCIES
end
# Or:
words.reject(&FORBIDDEN_WORDS)
class Foo::Bar
# In the Bar scope, but not in the Foo scope
end
class
и module
В този пример:
class Foo::Bar
Larodi
end
Bar
и я записваме в таблицата с константи на Foo
Foo
трябва да съществува предварително; може да бъде или модул, или клас
Larodi
ще се търси в таблицата на Bar
и след това в root scope-а
Foo
module A::B
module C::D
Foo # Where does Ruby look for Foo?
end
end
D
B
Object
)Имате ли въпроси?