10. require и други неща

10. require и други неща

10. require и други неща

15 ноември 2011

Днес

Импортиране на файлове

В Ruby код от други файлове се импортира с require.

Например:

require 'bigdecimal'
require 'bigdecimal/util'

Какво търси require?

Load path

където Ruby търси файлове за require

Как работи require?

Типичната структура на един gem

skeptic опростен

.
├── README.rdoc
├── Rakefile
├── bin
│   └── skeptic
├── features
├── lib
│   ├── skeptic
│   │   ├── rules.rb
│   │   └── scope.rb
│   └── skeptic.rb
├── skeptic.gemspec
└── spec 

Особеностите

Останалите неща

Kernel#load

Следва

Ред малки, дребни, забавни неща в Ruby.

Object#eql?

1 == 1.0     # true
1.eql?(1.0)  # false

$! и $@

Плосък begin/end

Тялото на функция може да работи като begin/end.

def foo
  begin
    get_a_life
  ensure
    puts 'rm -rf ~/.history'
  end
end

def bar
  get_a_life
ensure
  puts 'rm -rf ~/.history'
end

Едно от любимите ми неща в Ruby.

retry в ensure

retry изпълнява begin блока отначало.

retries_left = 3

begin
  connect_to_facebook
rescue ConnectionError
  retries_left -= 1
  retry if retries_left > 0
end

next, break, redo, retry

Има много хубава семантика за тях.

излизане от...рестартиране на...
...блокаnextredo
...методаbreakretry

За нещастие, retry не работи извън rescue от Ruby 1.9 насам.

def self.foo

Има по-кратък начин за дефиниране на класови методи:

class Person
  def Person.count
    42
  end

  def self.count
    42
  end
end

Второто е по-криптично, по пък е по-DRY.

Клас променливи

class Person
  @@count = 0

  def initialize
    @@count += 1
  end

  def self.how_many
    @@count
  end
end

Person.new
Person.new
Person.how_many # 2

Клас променливи

семантиката

Клас променливи

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

Object#send

Object#send изпраща някакво съобщение на метод.

numbers = [1, 2, 3, 4, 5, 6]

numbers.inject(0) { |a, b| a + b }        # 21

numbers.send(:inject, 0) { |a, b| a + b } # 21

Object#send

и private методи

Object#method_missing

Object#method_missing

пример

class Hash
  def method_missing(name, *args, &block)
    args.empty? ? self[name] : super
  end
end

things = {fish: 'Nemo', lion: 'Simba'}

things.fish   # "Nemo"
things.lion   # "Simba"
things.larodi # nil
things.foo(1) # error: NoMethodError

Object#method_missing

капани

Има и коварни моменти:

class Hash
  def method_missing(name, *arg, &block)
    args.empty? ? self[name] : super
  end
end

things = {lion: 'Simba'}
things.lion# ~> -:3: stack level too deep (SystemStackError)

String#[]

швейцарското ножче в Ruby

a = "hello there"
a[1]                   #=> "e"
a[1,3]                 #=> "ell"
a[1..3]                #=> "ell"
a[-3,2]                #=> "er"
a[-4..-2]              #=> "her"
a[12..-1]              #=> nil
a[-2..-4]              #=> ""
a[/[aeiou](.)\1/]      #=> "ell"
a[/[aeiou](.)\1/, 0]   #=> "ell"
a[/[aeiou](.)\1/, 1]   #=> "l"
a[/[aeiou](.)\1/, 2]   #=> nil
a["lo"]                #=> "lo"
a["bye"]               #=> nil

Object#initialize

Всъщност, #initialize е просто instance метод.

Class#new е имплементиран горе-долу така:

class Class
  def new
    object = self.allocate
    object.send :initialize
    object
  end
end

Module#const_missing

module Unicode
  def self.const_missing(name)
    if name.to_s =~ /^U([0-9a-fA-F]{4,5}|10[0-9a-fA-F]{4})$/
      codepoint = $1.to_i(16)
      utf8 = [codepoint].pack('U')
      utf8.freeze
      const_set(name, utf8)
      utf8
    else
      super
    end
  end
end

Unicode::U20AC  # "\u20AC"
Unicode::U221E  # "\u221E"
Unicode::Baba   # error: NameError

Object#dup, Object#clone, #initialize_copy

Въпроси