Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Ruby-новые грани.doc
Скачиваний:
143
Добавлен:
06.06.2015
Размер:
821.25 Кб
Скачать

4.18 Method_missing

Когда интерпретатор Ruby определяет, что у некоторого объекта вызывается какой-то метод, он ищет реализацию этого метода в классе объекта, затем во всех базовых классах и примесях (включая и singleton-классы). Если метод с искомым именем не находится, у объекта вызывается специальный метод method_missing. По умолчанию его реализацией является реализация в Kernel#method_missing, которая порождает исключение NoMethodError. Однако method_missing можно перекрыть в своем классе или объекте.

Переопределение method_missing является довольно распространенным приемом, который можно использовать для разных целей. Например, с его помощью можно сократить объем кодирования getter/setter-ов для объектов, хранящих большое количество разнообразных значений:

  classValueHolder

    definitialize

      # Этот hash-map будет содержать все помещаемые в объект значения.

      @values = {}

    end

  

    def method_missing(symbol, *args)

      name = symbol.id2name  # Идентификатор метода преобразовывается в строку.

      ifname =~ /(.+)=$/

        # Это setter в стандартном соглашении Ruby: a.b = x.

        @values[ $1 ] = *args

      else

        # Считаем, что происходит вызов getter-а: a.b.

        # Если значения для name еще не определено, то

        # будет возвращено nil.

        @values[ name ]

      end

    end

  end

  

  v = ValueHolder.new

  v.a                                 # => nil

  v.a = ’a’

  v.a                                 # => "a"

  v.something_else = :BlaBlaBla

  v.something_else                    # => :BlaBlaBla

Показанный выше класс ValueHolder является примитивной демонстрацией принципа работы класса OpenStruct [37] из стандартной библиотеки Ruby, в основе которого также лежит использование method_missing.

Но наибольшее значение method_missing имеет для построения DSL – настолько важное, что даже в документации к Kernel#method_missing приводится пример класса для хранения римских чисел, в котором method_missing служит для разбора римской нотации:

  class Roman

    def romanToInt(str)

      # ...

    end

    def method_missing(methId)

      str = methId.id2name

      romanToInt(str)

    end

  end

  

  r = Roman.new

  r.iv                                #=> 4

  r.xxiii                             #=> 23

  r.mm                                #=> 2000

Одним из самых ярких и впечатляющих примеров использования method_missing для организации DSL является библиотека Builder [38], которая позволяет записывать XML/HTML-конструкции в виде Ruby-кода:

  require ’rubygems’

  require_gem ’builder’, ’~> 2.0’

  

  builder = Builder::XmlMarkup.new

  xml = builder.person { |b|

    b.name    "Jim"

    b.phone   "555-1234"

    b.address { |a|

      a.town   "New-York"

      a.zip    "655374"

      a.street "Broadway"

    }

  }

  xml # => "<person><name>Jim</name><phone>555-1234</phone>

            <address><town>New-York</town><zip>655374</zip>

            <street>Broadway</street></address></person>"

Соседние файлы в папке Ruby