Какво ще има в 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]
"Всичко наследява от Object
"
Class.ancestors # => [Class, Module, Object, Kernel, BasicObject]
Object
не наследява от Object
BasicObject
BasicObject
е nil
BasicObject
е минималистичен клас, подходящ за прокситаClass.ancestors # => [Class, Module, Object, Kernel, BasicObject]
Kernel
е миксиран в Object
Kernel
(#puts
, #eval
и т.н.)
Object
(#inspect
, #tap
, #methods
и т.н.)
Object
Само обекти от същия клас могат да викат protected методи
class Vector
def initialize(x, y) @x, @y = x, y end
def inspect() "Vector.new(#@x, #@y)" end
def +(other)
Vector.new(*coords.zip(other.coords).map { |a, b| a + b })
end
protected
def coords() [@x, @y] end
end
vector = Vector.new(1, 2) + Vector.new(3, 4)
vector # => Vector.new(4, 6)
vector.coords # => error: NoMethodError
private
се ползва постоянно
protected
почти никога
protected
, защото могат да се викат със self.
отпред
public
. Не го ползваме, а просто слагаме публичните методи отгоре
Module
и Class
Понеже private
и protected
са методи:
class Person
def name() end
def age() end
private :name, :age
end
Или дори:
class String
private :upcase!, :downcase!
end
"Foo".upcase! # => error: NoMethodError
Помните ли, че дефиницията на метод връща името на метод като символ?
def foo() end # :foo
Значи може да направите така:
class Person
private def name
"My name is a secret."
end
private def age
"I'm feeling feminine, so my age is a secret, too."
end
end
alias
Module#alias_method
(клас макро)
String#size
и String#length
alias
: alias :new_method :old_method
alias new_method old_method
(забележете, че това не са символи или низове, a идентификатори)
Module#alias_method
:
alias_method :new_method, :old_method
alias_method 'new_method', 'old_method'
Въпреки името си, alias
прави копие на метод.
class Array
alias old_reduce reduce
def reduce(*args, &block)
puts "I see you are using #reduce. Let me help!"
old_reduce(*args, &block) * 0.01
end
end
[1, 2, 3, 4, 5, 6].reduce { |a, b| a + b } # => 0.21
Пример за реална употреба:
def to_s
to_html
end
По-добре да се запише така:
alias_method :to_s, :to_html
Или така:
alias to_s to_html
alias
е ключова дума, докато alias_method
е обикновен метод от Module
(клас макро)
alias
може да подавате като аргументи направо идентификатори на методи, например:
alias original_to_s to_s
ще направи нов синоним на to_s
под името original_to_s
alias_method original_to_s, to_s
ще интерпретира original_to_s
и to_s
като имена на променливи
alias
това не ставаclass Array
[:size, :count, :length].each do |method_name|
alias_method "old_#{method_name}", :size
end
def size
0
end
end
[1, 2, 3].size # => 0
[1, 2, 3].old_size # => 3
alias
е ключова дума и подлежи на статичен синтактичен анализ, такива инструменти разпознават тези синоними
Module#alias_method
обикновено не се разпознава в тези случаи, понеже не може да ползвате статичен синтактичен анализ за целтаКласовете и модулите могат да служат като именувани пространства.
module Useless
class Thing
end
end
class Grandfather
class StraightRazor
end
end
Useless::Thing.new # => #<Useless::Thing:0x002b3e0ec017b0>
Grandfather::StraightRazor.new # => #<Grandfather::StraightRazor:0x002b3e0ec01328>
Ако се намирате в модул, няма нужда да ползвате пълния път до константите:
module Useless
class Thing
end
Thing.new # => #<Useless::Thing:0x002b563b230958>
end
Useless::Thing.new # => #<Useless::Thing:0x002b563b2304f8>
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
Имате ли въпроси по тази тема?
->_{_%_}["->_{_%%_}[%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