Класс, который позволяет разбирать во входном потоке последовательности однотипных тегов.
Допустим, существует тег:
{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.