next
, break
, redo
, retry
Struct
, Comparable
, Marshal
, IO
& File
RubyVM::InstructionSequence
OpenStruct
The point is to find them early, before they make it into production. Fortunately, except for the few of us developing rocket guidance software at JPL, mistakes are rarely fatal in our industry, so we can, and should, learn, laugh, and move on.
Remember that the entire point of a review is to find problems, and problems will be found. Don't take it personally when one is uncovered.
Such an individual can teach you some new moves if you ask. Seek and accept input from others, especially when you think it's not needed.
There's a fine line between "fixing code" and "rewriting code." Know the difference, and pursue stylistic changes within the framework of a code review, not as a lone enforcer.
Nontechnical people who deal with developers on a regular basis almost universally hold the opinion that we are prima donnas at best and crybabies at worst. Don't reinforce this stereotype with anger and impatience.
Be open to it and accept it with a smile. Look at each change to your requirements, platform, or tool as a new challenge, not as some serious inconvenience to be fought.
Knowledge engenders authority, and authority engenders respect – so if you want respect in an egoless environment, cultivate knowledge.
Understand that sometimes your ideas will be overruled. Even if you do turn out to be right, don't take revenge or say, "I told you so" more than a few times at most, and don't make your dearly departed idea a martyr or rallying cry.
Don't be the guy coding in the dark office emerging only to buy cola. The guy in the room is out of touch, out of sight, and out of control and has no place in an open, collaborative environment.
As much as possible, make all of your comments positive and oriented to improving the code. Relate comments to local standards, program specs, increased performance, etc.
class CSS
PREFIXES = ['webkit', 'moz', 'ms', 'o']
def browser_prefixes_for(css_property_name)
PREFIXES.map do |prefix|
"-#{prefix}-#{css_property_name}"
end
end
end
class CSS
PREFIXES = ['webkit', 'moz', 'ms', 'o', nil]
def browser_prefixes_for(css_property_name)
PREFIXES.map do |prefix|
prefix ? "-#{prefix}-#{css_property_name}" : css_property_name
end
end
end
class CSS
PREFIXES = ['-webkit-', '-moz-', '-ms-', '-o-', '']
def browser_prefixes_for(css_property_name)
PREFIXES.map do |prefix|
prefix + css_property_name
end
end
end
challenges[6].solutions.size < 7 # true
challenges[6].solutions.one?(&:correct?) # true
(1..5).map(&P ** 2) # [1, 4, 9, 16, 25]
[[1, 2, 3, 8], [4, 5], [6]].map(&P.select(&:even?)) # [[2, 8], [4], [6]]
(1..5).map(&P) # [1, 2, 3, 4, 5]
class P
class << self
# ...
end
end
class P
class << self
def method_missing(method, *args, &block)
# ...
end
end
end
class P
class << self
def method_missing(method, *args, &block)
Proc.new { |object| object.send method, *args, &block }
end
end
end
class P
class << self
def method_missing(method, *args, &block)
Proc.new { |object| object.send method, *args, &block }
end
def to_proc
Proc.new { |object| object }
end
end
end
class P < BasicObject
class << self
def method_missing(method, *args, &block)
::Proc.new { |object| object.send method, *args, &block }
end
def to_proc
::Proc.new { |object| object }
end
end
end
class P < BasicObject
class << self
instance_methods.each do |instance_method|
undef_method instance_method
end
def method_missing(method, *args, &block)
::Proc.new { |object| object.send method, *args, &block }
end
def to_proc
::Proc.new { |object| object }
end
end
end
#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-ва обекта, ако е замразенcore
; сега ще видим още няколко интересни класаStruct
Виждате, че може да добавите и свои методи там
Customer = Struct.new(:name, :address) do
def greeting
"Hello #{name}!"
end
end
dave = Customer.new('Dave', '123 Main')
dave.name # "Dave"
dave.address # "123 Main"
dave.greeting # "Hello Dave!"
Обектите от тип Struct
приличат на колекции (хешове):
Customer = Struct.new(:name, :address, :zip)
john = Customer.new('John Doe', '123 Maple, Anytown NC', 12345)
john.name # "John Doe"
john['name'] # "John Doe"
john[:name] # "John Doe"
john[0] # "John Doe"
john.length # 3
john.each # #<Enumerator: #<struct Customer name="John Doe", address="123 Maple, Anytown NC", zip=12345>:each>
Удобно е да се ползва в тестове. За production код – по-рядко.
<=>
и правите include Comparable
<
, <=
, ==
, >=
, >
и between?
class Money
include Comparable
attr :amount, :currency
def initialize(amount, currency)
@amount, @currency = amount, currency
end
def <=>(money)
return unless currency == money.currency
amount <=> money.amount
end
end
Money.new(15, :BGN) < Money.new(30, :BGN) # true
Marshal.load
и Marshal.dump
marshal_dump
и marshal_load
data = [42, :answer, {foo: 'bar'}]
serizlized = Marshal.dump data
serizlized # "\x04\b[\bi/:\vanswer{\x06:\bfooI\"\bbar\x06:\x06ET"
Marshal.load(serizlized) == data # true
Marshal.load(serizlized) # [42, :answer, {:foo=>"bar"}]
Marshal
може да се ползва YAML
, от стандартната библиотека
Прочитане на цял файл като низ:
File.read('/etc/resolv.conf') # => "The contents of the file as a string."
Отваряне на файл, работа с обекта и автоматично затваряне на файла при излизане от блока:
File.open('foo/bar.txt', 'w') do |file|
file.write 'Some data.'
file.puts 'Some other data, with a newline at the end.'
file.puts 'File will be closed automatically, even in case of an exception in the block.'
end
code = 'puts ["a" * 10].first'
compiled = RubyVM::InstructionSequence.compile(code)
puts compiled.disasm
Резултат:
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== 0000 trace 1 ( 1) 0002 putself 0003 putstring "a" 0005 putobject 10 0007 opt_mult <callinfo!mid:*, argc:1, ARGS_SKIP> 0009 newarray 1 0011 opt_send_simple <callinfo!mid:first, argc:0, ARGS_SKIP> 0013 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP> 0015 leave
puts RubyVM::InstructionSequence.compile('a, b = 1, 2').disasm
Можем да видим, че a, b = 1, 2
минава през създаване на един обект тип Array
:
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== local table (size: 3, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@4] s1) [ 3] a [ 2] b 0000 trace 1 ( 1) 0002 duparray [1, 2] 0004 dup 0005 expandarray 2, 0 0008 setlocal_OP__WC__0 3 0010 setlocal_OP__WC__0 2 0012 leave
require 'somelib'
, например require 'bigdecimal'
abbrev base64 benchmark bigdecimal cgi cmath coverage csv curses date dbm debug delegate digest dl drb e2mmap English erb etc extmk fcntl fiddle fileutils find forwardable gdbm getoptlong gserver io/console io/nonblock io/wait ipaddr irb json logger mathn matrix minitest minitest/benchmark minitest/spec mkmf monitor mutex_m net/ftp net/http net/imap net/pop net/smtp net/telnet nkf objspace observer open-uri open3 openssl optparse ostruct pathname pp prettyprint prime profile profiler pstore psych pty racc racc/parser rake rdoc readline resolv resolv-replace rexml rinda ripper rss rubygems scanf sdbm securerandom set shell shellwords singleton socket stringio strscan sync syslog tempfile test/unit thread thwait time timeout tk tmpdir tracer tsort un uri weakref webrick win32ole xmlrpc yaml zlib
OpenStruct
require 'ostruct'
marshal_load
и marshal_dump
, може да видите как за пример
Hash
, като each_pair
и методите []
и []=
require 'ostruct'
john = OpenStruct.new
john.name = 'John Doe'
john.age = 33
john.name # "John Doe"
john.age # 33
john.address # nil