Parent

Class/Module Index [+]

Quicksearch

ClsRuby::Tag

Базовый класс CLS тегов.

Constants

TagChildTagInfo

Структура для хранения описания дочернего тега, полученного при помощи методов child_tag и mandatory_child_tag.

Public Class Methods

child_tag( name, type, params = {} ) click to toggle source

Вспомогательный метод для декларирования дочерних тегов во время описания собственного класса тега.

Пример использования.

Пусть необходимо парсить следующую структуру:
{params
  {min <int:1..100>}
  {max <int:100..1000>}
  {password <str>}
}

Для этого можно применить тег:
class TagParams < ClsRuby::TagNoValue
  child_tag :min, ClsRuby::TagScalar,
        :mandatory => true,
        :format => ClsRuby::SCALAR_INT,
        :constraint => 1..100
  child_tag :max, ClsRuby::TagScalar,
        :mandatory => true,
        :format => ClsRuby::SCALAR_INT,
        :constraint => 100..1000
  child_tag :password, ClsRuby::TagScalar,
        :mandatory => true,
        :format => ClsRuby::SCALAR_STRING

  default_tag_params :name => 'params'

  def query_params
    Params.new( @min.value, @max.value, @password.value )
  end
end

Если требуется, чтобы instance variables создавалось с одним именем (например, op_id), а тег во входном потоке имел иное название, то в списке параметров child_tag нужно указать значение с ключем :name

child_tag :op_id, ClsRuby::TagScalar,
      :name => 'op-id',
      :mandatory => true,
      :format => ClsRuby::SCALAR_STRING

Принцип использования см. в описании tag_metaclass.

# File lib/cls-ruby/tag.rb, line 206
def Tag.child_tag( name, type, params = {} )
  tag_metaclass.tag_add_child_tag_info( name, type, params )
end
default_tag_params( params ) click to toggle source

Вспомогательный метод, который позволяет задать параметры тега по умолчанию.

Если разрабатывается какой-то тег, который в большинстве случаев будет иметь одинаковое имя, то задать это имя можно двумя способами:

  • во-первых, можно сделать собственный конструктор:

    class TagMy < ClsRuby::TagNoValue
      def initialize( params = {} )
        super( { :name => 'my-tag' }.merge( params ) )
      end
      ...
    end
    ...
    t = TagMy.new                          # Используется имя my-tag.
    c = TagMy.new( :name => 'custom-tag' ) # Имя custom-tag вместо my-tag.
  • во-вторых, точно такого же эффекта можно достичь посредством метаметода default_tag_params:

    class TagMy < ClsRuby::TagNoValue
      default_tag_params :name => 'my-tag'
      ...
    end
    ...
    t = TagMy.new                          # Используется имя my-tag.
    c = TagMy.new( :name => 'custom-tag' ) # Имя custom-tag вместо my-tag.

Примечание. Если в цепочке базовых классов несколько раз используется default_tag_params, то все заданные параметры по умолчанию объединяются. Причем так, что значения из базовых классов затираются значениями из производных классов.

# File lib/cls-ruby/tag.rb, line 258
def Tag.default_tag_params( params )
  self.send( :define_method, :tag_default_params ) do
    super().merge( params )
  end
end
mandatory_child_tag( name, type, params = {} ) click to toggle source

Вспомогательный метод в дополнение к методу child_tag, который позволяет упростить объявление обязательных тегов.

Его использование:

mandatory_child_tag :min, ClsRuby::TagScalar,
    :format => ClsRuby::SCALAR_INT

полностью эквивалентно более многословному использованию child_tag:

child_tag :min, ClsRuby::TagScalar,
    :format => ClsRuby::SCALAR_INT,
    :mandatory => true
# File lib/cls-ruby/tag.rb, line 221
def Tag.mandatory_child_tag( name, type, params = {} )
  child_tag( name, type, params.merge( :mandatory => true ) )
end
new( args = {} ) click to toggle source

Конструктор.

Принимает аргументы в виде Hash. Распознаются ключи:

:name => имя тега.
:owner => родительский тег. Автоматически добавляет
          себя в список дочерних тегов к родителю.
:mandatory => true или false. Признак того, что тег
              должен быть обязательным.
              По умолчанию тег считается опциональным.

Остальные ключи игнорируются.

# File lib/cls-ruby/tag.rb, line 20
def initialize( args = {} )
  @tag_params = tag_default_params.merge( args )
  @tag_name = tag_params.fetch( :name, nil )

  owner = tag_params.fetch( :owner, nil )
  owner.tag_add( self ) if owner

  @tag_mandatory = tag_params.fetch( :mandatory, false )
  @tag_defined = false

  @tag_children = []

  tag_init_children_tags
end

Private Class Methods

tag_add_child_tag_info( name, type, params ) click to toggle source

Добавление описания очередного дочернего тега.

Используется в реализации методов child_tag и mandatory_child_tag.

Подробнее см. tag_metaclass.

# File lib/cls-ruby/tag.rb, line 316
def tag_add_child_tag_info( name, type, params )
  @tag_child_tags ||= []
  @tag_child_tags << TagChildTagInfo.new( name, type, params )
end
tag_child_tags() click to toggle source

Возвращает список описаний всех дочерних тегов, полученных с помощью методов child_tag и mandatory_child_tag.

Подробнее см. tag_metaclass.

# File lib/cls-ruby/tag.rb, line 325
def tag_child_tags
  @tag_child_tags || []
end
tag_metaclass() click to toggle source

Вспомогательный метод для реализации child_tag и mandatory_child_tag.

Принцип работы состоит в том, чтобы для текущего класса создать экземпляр класса-singleton в котором будут instance methods с именами tag_add_child_tag_info и tag_child_tags.

Фокус в том, что когда tag_metaclass вызывается на контексте класса Tag, то класс Tag расширяется методами tag_add_child_tag_info и tag_child_tags. Если же tag_metaclass вызывается на контексте производного от Tag класса, то производится расширение производного класса (т.к. self будет указывать на производный класс).

Таким образом, если есть цепочка наследования Tag <- First <- Second и в классах First, Second вызываются методы child_tag, то в классе First будет свой объект класса-singleton с описаниями присущих только классу First дочерних тегов. А в классе Second будет свой объект.

Следовательно, задача сводится к тому, чтобы в конструкторе Tag собрать описания из всех классов-singleton и сформировать полный список дочерних тегов. Для этого используется тот факт, что self в конструкторе Tag указывает на конкретный класс (т.е. на First или Second). Следовательно, можно проверить, есть ли в этом классе instance method с именем tag_child_tags и вызывать его. После чего перейти к базовому классу и т.д.:

child_tags = []
c = self.class
while c
  if c.respond_to?( :tag_child_tags )
    child_tags = c.tag_child_tags + child_tags
  end
  c = c.superclass
end

Такой сложный механизм хранения описаний дочерних тегов потребовался для того, чтобы сохранить строгий порядок следования тегов – в каком порядке вызывались child_tag, в таком порядке дочерние теги должны добавляться к родительскому тегу.

# File lib/cls-ruby/tag.rb, line 309
def Tag.tag_metaclass
  class <<self
    # Добавление описания очередного дочернего тега.
    #
    # Используется в реализации методов child_tag и mandatory_child_tag.
    #
    # Подробнее см. tag_metaclass.
    def tag_add_child_tag_info( name, type, params )
      @tag_child_tags ||= []
      @tag_child_tags << TagChildTagInfo.new( name, type, params )
    end

    # Возвращает список описаний всех дочерних тегов, полученных
    # с помощью методов child_tag и mandatory_child_tag.
    #
    # Подробнее см. tag_metaclass.
    def tag_child_tags
      @tag_child_tags || []
    end
  end
  self
end

Public Instance Methods

tag_add( child ) click to toggle source

Добавление дочернего тега в список дочерних тегов.

# File lib/cls-ruby/tag.rb, line 49
def tag_add( child )
  @tag_children << child
end
tag_compare_name( name ) click to toggle source

Сравнение имени тега с указанным именем.

Предназначен для перекрытия в производных классах для случая, когда один тег может иметь несколько имен.

# File lib/cls-ruby/tag.rb, line 44
def tag_compare_name( name )
  @tag_name == name
end
tag_defined?() click to toggle source

Является ли тег полностью определенным в процессе разбора?

По умолчанию возвращает значение атрибута @tag_defined (он принимает значение true либо в методе tag_on_finish, либо в методе tag_make_defined).

# File lib/cls-ruby/tag.rb, line 65
def tag_defined?; @tag_defined; end
tag_format( formatter ) click to toggle source

Выполнить форматирование тега.

Объект formatter поддерживает интерфейс TagFormatter.

Реализация в базовом классе выполняет следующие действия:

  • вызывает у formatter метод start;

  • вызывает собственный метод tag_on_format;

  • вызывает метод tag_format у всех дочерних тегов;

  • вызывает у formatter метод finish.

Таким образом, если производному классу нужно отобразить собственное содержимое, то он должен переопределить у себя метод tag_on_format.

# File lib/cls-ruby/tag.rb, line 95
def tag_format( formatter )
  if tag_defined?
    formatter.start( tag_name )
    
    tag_on_format( formatter )
    tag_tags.each do |child| child.tag_format( formatter ) end

    formatter.finish
  end

  self
end
tag_make_defined() click to toggle source

Установить признак, что тег полностью определен.

# File lib/cls-ruby/tag.rb, line 68
def tag_make_defined; @tag_defined = true; end
tag_mandatory?() click to toggle source

Является ли тег обязательным?

По умолчанию возвращает значение атрибута @tag_mandatory.

# File lib/cls-ruby/tag.rb, line 59
def tag_mandatory?; @tag_mandatory; end
tag_name() click to toggle source

Имя тега.

Возвращает nil, если в конструкторе имя тега не было задано.

# File lib/cls-ruby/tag.rb, line 38
def tag_name; @tag_name; end
tag_on_finish() click to toggle source

Реакция на завершение парсинга тега во входном потоке.

Просматривает все дочерние теги и если находит неопределенный обязательный тег, то порождает исключение UndefinedMandatoryTagEx.

После чего делает самого себя полностью определенным.

# File lib/cls-ruby/tag.rb, line 120
def tag_on_finish
  @tag_children.each do |tag|
    raise UndefinedMandatoryTagEx.new( tag.tag_name ) if
        tag.tag_mandatory? && !tag.tag_defined?
  end

  tag_make_defined
end
tag_on_format( formatter ) click to toggle source

Вызывается для форматирования собственного содержимого.

В базовом классе ничего не делает. Предназначен для переопределения в производных классах.

# File lib/cls-ruby/tag.rb, line 161
def tag_on_format( formatter )
end
tag_on_start( name ) click to toggle source

Реакция на начало парсинга тега во входном потоке.

В базовом классе ничего не делает. Предназначен для предоставления возможности перекрытия в производных классах.

# File lib/cls-ruby/tag.rb, line 112
def tag_on_start( name ); end
tag_on_tag( tag ) click to toggle source

Реакция на завершение разбора дочернего тега во входном потоке.

Ничего не делает. Метод предназначен для перекрытия в производных классах для предоставления возможности сделать что-нибудь полезное.

# File lib/cls-ruby/tag.rb, line 133
def tag_on_tag( tag )
end
tag_on_tok_nonspace( token ) click to toggle source

Реакция на токен :tok_nonspace.

Порождает исключение UnexpectedTokenEx.

# File lib/cls-ruby/tag.rb, line 144
def tag_on_tok_nonspace( token )
  raise UnexpectedTokenEx.new(
      "unexpected token :tok_nonspace ('#{token}')" )
end
tag_on_tok_space( token ) click to toggle source

Реакция на токен :tok_space.

Ничего не делает.

# File lib/cls-ruby/tag.rb, line 139
def tag_on_tok_space( token ); end
tag_on_tok_string( token ) click to toggle source

Реакция на токен :tok_string.

Порождает исключение UnexpectedTokenEx.

# File lib/cls-ruby/tag.rb, line 152
def tag_on_tok_string( token )
  raise UnexpectedTokenEx.new(
      "unexpected token :tok_string ('#{token}')" )
end
tag_reset() click to toggle source

Сбросить содержимое тега.

Переводит тег в состояние, предшествующее парсингу.

По умолчанию вызывает метод tag_reset у всех дочерних тегов, после чего устанавливает @tag_defined в false.

# File lib/cls-ruby/tag.rb, line 76
def tag_reset
  @tag_children.each do |tag| tag.tag_reset end

  @tag_defined = false
end
tag_tags() click to toggle source

Получение списка дочерних тегов.

# File lib/cls-ruby/tag.rb, line 54
def tag_tags; @tag_children; end

Private Instance Methods

tag_default_params() click to toggle source

Возвращает список параметров тега по умолчанию.

Этот список затем в конструкторе дополняется явно указанными параметрами и уже из результирующего списка конструктор берет значения для инициализации тега.

Производный класс может переопределить данный метод, чтобы назначить собственные параметры по умолчанию.

См. так же default_tag_params

В базовом классе возвращает пустой Hash.

# File lib/cls-ruby/tag.rb, line 351
def tag_default_params
  {}
end
tag_handle_opt_param( key ) { |value| ... } click to toggle source

Вспомогательный метод, который находит в параметрах тега указанный ключ и запускает указанный блок со значением данного ключа.

Данный метод позволяет упростить обработку, например, ключей :value, когда тег нужно сразу же в конструкторе инициализировать. Простое решение этой задачи выглядит как:

def initialize( params )
  super( params )

  v = tag_params.fetch( :value, nil )
  if v
    ...
    tag_make_defined
  end
end

Основная проблема здесь в том, что можно забыть обратиться к tag_params, чтобы получить доступ ко всем параметрам, включая параметры по-умолчанию. С использованием метода tag_handle_opt_param этот код будет выглядеть так:

def initialize( params )
  super( params )

  tag_handle_opt_param( :value ) do |v|
    ...
    tag_make_defined
  end
end

Возвращает значение блока, если ключ был найден и блок вызывался или nil, если ключ найден не был.

# File lib/cls-ruby/tag.rb, line 416
def tag_handle_opt_param( key, &block )
  v = tag_params.fetch( key, nil )
  if v
    block.call( v )
  else
    nil
  end
end
tag_init_children_tags() click to toggle source

Метод, который вызывается в конструкторе Tag для инициализации всех дочерних тегов, описанных в производных классах при помощи метаметодов child_tag и mandatory_child_tag.

Подробнее см. tag_metaclass.

# File lib/cls-ruby/tag.rb, line 361
def tag_init_children_tags
  # Сначала формируем список всех дочерних тегов.
  child_tags = []
  c = self.class
  while c
    if c.respond_to?( :tag_child_tags )
      child_tags = c.tag_child_tags + child_tags
    end
    c = c.superclass
  end

  # А затем для всех дочерних тегов определяем свои instance variables.
  child_tags.each do |info|
    additional_params = { :owner => self }
    additional_params[ :name ] = info.name.to_s unless
        info.params.has_key?( :name )

    self.instance_variable_set( "@#{info.name}".to_sym,
        info.type.new( info.params.merge( additional_params ) ) )
  end
end
tag_params() click to toggle source

Возвращает список параметров, который были переданы в конструктор базового класса и объеденены с параметрами по-умолчанию.

# File lib/cls-ruby/tag.rb, line 334
def tag_params
  @tag_params
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.