Класс, который позволяет разбирать во входном потоке последовательности тегов с разными именами (возможно разных типов).
Допустим, существуют теги:
{include <str>} {exclude <str>}
Для работы с которыми был создан класс:
class Filter INCLUDE = 1 EXCLUDE = 2 attr_reader :type, :regex def initialize( type, regex ) @type, @regex = type, regex end end class TagIncludeExclude < ClsRuby::TagStringScalar def initialize( params = {} ) super( params ) @type = Filter::INCLUDE end def tag_on_start( name ) @type = name == 'include' ? INCLUDE : EXCLUDE end def value Filter.new( @type, super ) end end
Далее требуется разбирать входной поток, в котором теги {include} и {exclude} будут встречаться более одного раза. Например:
{filter {(include|exclude) <str>}* }
причем важно сохранить порядок их следования во входном потоке.
Для того, чтобы повторно использовать для этого уже имеющийся класс TagExcludeInclude можно воспользоваться тегом TagVectorOfDifferentTags:
class TagFilter < ClsRuby::TagNoValue child_tag :filters, ClsRuby::TagVectorOfDifferentTags, :nested_tags => [ { :name => 'include', :type => TagIncludeExclude }, { :name => 'exclude', :type => TagIncludeExclude } ] ... end
Принцип работы TagVectorOfDifferentTags состоит в том, что TagVectorOfDifferentTags играет роль Proxy. Он перекрывает большинство базовых методов класса Tag и:
в методе tag_compare_name проверяет совпадение одного из имен, заданных в параметре :nested_tags;
в методе tag_on_start создает временный экземпляр объекта того типа, который был задан параметром :type (в приведенном выше примере это будет TagIncludeExclude), далее этот объект используется как временный тег;
переадресует методы tag_on_tag, tag_on_tok_*, tag_tags, tag_on_finish временному тегу;
в методе tag_on_finish, если временный тег отработал в tag_on_finish без ошибок, сохраняет временный тег в списке разобранных вложенных тегов.
После разбора входного потока список разобранных вложенных тегов можно получить с помощью метода nested_tags:
class TagFilter < ClsRuby::TagNoValue ... Description = Struct.new( :name, :fields ) ... def filters @filters.nested_tags.inject( [] ) do |r, f| r << f.value; r end end end
Так же можно воспользоваться методом TagVectorOfTags#collect_values:
def filters @filters.collect_values do |t| t.value end end
или методом TagVectorOfTags#collect_values_by:
def filters filters = @filters.collect_values_by( :value ) end
Конструктор.
Дополнительно к стандартным ключам распознает ключи:
типы вложенных тегов. В виде Array, элементами которого являются Hash с ключами :name и :type. Данный ключ обязательно должен присутствовать в args.
# File lib/cls-ruby/tag_vector_of_different_tags.rb, line 108 def initialize( args = {} ) super( args ) handle_nested_tags_descriptions @nested_tags = [] @current = nil end
Разрешает совпадение с любым из имен вложенных тегов.
# File lib/cls-ruby/tag_vector_of_different_tags.rb, line 118 def tag_compare_name( name ) @names_to_types[ name ] ? true : false end
Создает дочерний тег того типа, которому соответствует указанное имя.
# File lib/cls-ruby/tag_vector_of_different_tags.rb, line 123 def tag_on_start( name ) type = @names_to_types[ name ] next_tag = type.new( :name => name ) next_tag.tag_on_start( name ) @current = next_tag end
Generated with the Darkfish Rdoc Generator 2.