Обяснения на сгрешени въпроси.
Ще разгледаме няколко различни дреболии в различни части на Ruby, донякъде свързани и с грешките от тестовете.
#eql?
прави сравнение без type coercion.1 == 1.0 # true
1.eql?(1.0) # false
$!
е последното "възбудено" изключение$@
е stacktrace-а на последното изключениеretry
изпълнява begin
блока отначало.
retries_left = 3
begin
connect_to_facebook
rescue ConnectionError
retries_left -= 1
retry if retries_left > 0
end
Има много хубава семантика за тях.
излизане от... | рестартиране на... | |
---|---|---|
...блока | next | redo |
...метода | break | retry |
За нещастие, retry
не работи извън rescue
от Ruby 1.9 насам.
class Person
@@count = 0
def initialize
@@count += 1
end
def self.how_many
@@count
end
end
Person.new
Person.new
Person.how_many # 2
@@
NameError
(направете разлика с инстанционните променливи)
class B
@@foo = 1
def self.foo() @@foo end
def self.hmm() @@bar end
end
class D < B
@@bar = 2
def self.bar() @@bar end
def self.change() @@foo = 3; @@bar = 4; end
end
[B.foo, D.foo, D.bar] # [1, 1, 2]
B.hmm # error: NameError
D.change
[B.foo, D.foo, D.bar] # [3, 3, 4]
B.hmm # error: NameError
D.hmm # error: NameError
Всъщност, #initialize
е просто instance метод.
Class#new
е имплементиран горе-долу така:
class Class
def new
object = self.allocate
object.send :initialize
object
end
end
#dup
и #clone
правят копие на обект
#initialize_copy
#clone
копира singleton методи и freeze-ва обекта, ако е замразенObject#taint
- маркира даден обект като "зацапан", т.е. потенциално опасен
Object#tainted?
ще ви върне true
, ако обект е маркиран като замърсен
to_proc
метода - в Array
и в Hash
Бяхме дали този код само илюстративно:
class Student
attr_accessor :name, :points, :rank
def initialize(name, points, rank)
@name = name
@points = points
@rank = rank
end
end
ivan = Student.new 'Иван', 10, :second
mariya = Student.new 'Мария', 12, :first
neycho = Student.new 'Нейчо', 9, :third
students = [ivan, mariya, neycho]
students.map(&[:name, :rank]) # => [['Иван', :second], ['Мария', :first], ['Нейчо', :third]]
class Array
def to_proc
proc do |object|
map { |method| object.send(method) }
end
end
end
students.each &{points: 0, rank: :last}
students.map(&:rank) # => [:last, :last, :last]
class Hash
def to_proc
proc do |object|
each do |property, value|
object.send "#{property}=", value
end
end
end
end
class Array
def to_proc
Proc.new { |obj,*args| self.map {|method| obj.send(method,*args)} }
end
end
class Hash
def to_proc
Proc.new { |obj| self.map {|method,value| obj.send((method.to_s+"=").to_sym,value)} }
end
end
Из Array#to_proc
:
-> object { map(&object.method(:send)) }
# vs.
-> object { map { |method| object.send(method) } }
Или това:
Proc.new { |object| map { |item| item.to_sym.to_proc.call(object) } }
# vs.
proc object { map { |method| object.send(method) } }
*send
методите работят както със символи, така и с низове; тук to_sym
е излишно:
Proc.new { |object| map { |key, value| object.public_send("#{key.to_sym}=".to_sym, value) } }
Тук може да се ползва просто Enumerable#map
:
class Array
def to_proc
-> (object) do
each_with_object([]) do |property_name, result|
result << object.send(property_name.to_sym)
end
end
end
end
Или това:
setter = property_name.to_s.concat('=')
# vs.
setter = "#{property_name}="
Не използвайте map
, когато искате да кажете each
:
class Hash
def to_proc
-> object { map { |property, value| object.send("#{property}=", value) } }
end
end
class Hash
def to_proc
Proc.new { |element| map { |key, value| element.send key.to_s.concat("=").to_sym, value } }
end
end
class Hash
def to_proc
Proc.new do |obj|
self.map() { |element| obj.send(element.first.to_s + '=', element.last) }
end
end
end
class Hash
def to_proc
proc do |obj1|
self.each do |key, value|
obj1.send((key.to_s + "=").to_sym, value)
end
end
end
end
class Hash
def to_proc
proc do |object|
each do |field, value|
object.instance_variable_set("@#{field}".to_sym, value)
end
end
end
end
class Hash
def to_proc
Proc.new do |obj, *args|
map { |method_name, arg| obj.send (method_name.to_s + '=').to_sym, arg }
end
end
end
map
vs. collect
self.
lambda
vs. proc
- който и да е начин е окей
Proc.new
и proc
са едно и също от Ruby 1.9 насам; предпочитайте второто