Класс, который позволяет разбирать во входном потоке последовательности однотипных тегов.
Допустим, существует тег:
{field {name <str>} {value <str>}}
Для работы с котором был создан класс:
class TagField < ClsRuby::TagNoValue
Values = Struct.new( :name, :value )
child_tag :name, ClsRuby::TagScalar,
:format => ClsRuby::SCALAR_STRING,
:mandatory => true
child_tag :value, ClsRuby::TagScalar,
:format => ClsRuby::SCALAR_STRING,
:mandatory => true
def value
Values.new( @name.value, @value.value )
end
end
Далее требуется разбирать входной поток, в котором тег {field} будет встречаться более одного раза. Например:
{message
{name <str>}
{field <TagField>}*
}
Для того, чтобы повторно использовать для этого уже имеющийся класс TagField можно воспользоваться тегом TagVectorOfTags:
class TagMessage < ClsRuby::TagNoValue
child_tag :name, ClsRuby::TagScalar,
:format => ClsRuby::SCALAR_STRING,
:mandatory => true
child_tag :field, ClsRuby::TagVectorOfTags,
:type => TagField
...
end
Принцип работы TagVectorOfTags состоит в том, что TagVectorOfTags играет роль Proxy. Он перекрывает большинство базовых методов класса Tag и:
в методе tag_on_start создает временный экземпляр объекта того типа, который был задан параметром :type (в приведенном выше примере это будет TagField), далее этот объект используется как временный тег;
переадресует методы tag_on_tag, tag_on_tok_*, tag_tags, tag_on_finish временному тегу;
в методе tag_on_finish, если временный тег отработал в tag_on_finish без ошибок, сохраняет временный тег в списке разобранных вложенных тегов.
После разбора входного потока список разобранных вложенных тегов можно получить с помощью метода nested_tags:
class TagMessage < ClsRuby::TagNoValue
...
Description = Struct.new( :name, :fields )
...
def description
fields = @field.nested_tags.inject( [] ) do |r, f| r << f.value; r end
Description.new( @name.value, fields )
end
end
Так же можно воспользоваться методом TagVectorOfTags#collect_values:
def description fields = @field.collect_values do |t| t.value end Description.new( @name.value, fields ) end
или методом TagVectorOfTags#collect_values_by:
def description fields = @field.collect_values_by( :value ) Description.new( @name.value, fields ) end
Конструктор.
Дополнительно к стандартным ключам распознает ключи:
тип вложенного тега. Данный ключ обязательно должен присутствовать в args.
# File lib/cls-ruby/tag_vector_of_tags.rb, line 94 def initialize( args = {} ) super( args ) @type = tag_params.fetch( :type, nil ) raise UndefinedTypeEx.new( "undefined type of nested tags for '#{tag_name}'" ) unless @type @nested_tags = [] @current = nil end
Реакция на начало парсинга тега во входном потоке.
Создает новый временный тег и переадресует вызов ему.
# File lib/cls-ruby/tag_vector_of_tags.rb, line 107 def tag_on_start( name ) next_tag = @type.new( :name => name ) next_tag.tag_on_start( name ) @current = next_tag end
Generated with the Darkfish Rdoc Generator 2.