Для задания параметров конструктуру тегов в ClsRuby используется единственный аргумент типа Hash, который содержит пары <ключ,значение>. Синтаксис Ruby позволяет задавать этот аргумент как будто используются именованные аргументы в других языках программирования:
root = ClsRuby::TagNoValue.new :name => 'root', :mandatory => true
здесь :name и :mandatory являются ключами единственного аргумента типа Hash для объекта ClsRuby::TagNoValue.
Использование единственного аргумента типа Hash позволяет легко расширять параметры тега в производных классах. Например, тег ClsRuby::TagNoValue поддерживает параметры класса ClsRuby::Tag и, в дополнение к этому, распознает собственный ключ :once.
Подход с аргументом типа Hash так же позволяет задавать в производных классах необходимые умолчания. Во-первых, с помощью значения по умолчанию для аргумента:
class MyTag < ClsRuby::Tag def initialize( params = { :mandatory = true } ) super( params ) ... end end
В таком случае, если при создании объекта MyTag не будет передано аргументов, то в базовый класс уйдет объект Hash со значением {:mandatory=>true}.
Во-вторых, значения по умолчанию легко комбинировать с явно заданными пользователем параметрами:
class MyTag < ClsRuby::Tag def initialize( params = {} ) super( { :name => 'root', :mandatory => false }.merge( params ) ) ... end end
В этом случае, если пользователь явно не задал ключи :name и :mandatory, то будут взяты соответствующие им значения по умолчанию. Если же пользователь задал эти ключи в аргументе params, то вместо значений по умолчанию будут использоваться заданные пользователем значения.
Следствием такого решения является возможность использовать методы ClsRuby::Tag#child_tag, Tag#mandatory_child_tag и Tag#default_tag_params. Принцип их действия основан на том, что параметры дочерних тегов сохраняются в виде объекта Hash, а затем используются для создания и инициализации дочерних тегов.
Вместо использования метода Hash#merge для задания параметров по умолчанию:
def initialize( params ) super( { :name => 'root' }.merge( params ) ) ... end
можно воспользоваться методом ClsRuby::Tag#default_tag_params, что делает описание тега более декларативным:
class MyTag < ClsRuby::Tag default_tag_params :name => 'root' ... end
Еще одной важной особенностью метода ClsRuby::Tag#default_tag_params является то, что в случае наследования параметры по умолчанию накапливаются:
require 'cls-ruby' require 'cls-ruby/tag' class MyBase < ClsRuby::Tag default_tag_params :name => 'root' end class MyDerived < MyBase default_tag_params :mandatory => true end class MyNextDerived < MyDerived default_tag_params :once => true def show_params p tag_params end end t = MyNextDerived.new t.show_params
что дает в результате:
{:name=>"root", :mandatory=>true, :once=>true}
Класс ClsRuby::Tag обрабатывает следующие ключи в аргументах конструктора:
имя тега;
признак обязательности/необязательности тега;
ссылка на родительский тег. Если эта ссылка задана, то конструктор автоматически вызывает tag_add для родительского тега.
Если тег должен содержать какое-либо значение (например, как в случае с ClsRuby::TagScalar), то это значение может быть задано в конструкторе с помощью ключа :value.
Специализированные теги могут поддерживать собственные ключи (например, :format для ClsRuby::TagScalar и :once для ClsRuby::TagNoValue). Для того, чтобы определить список поддерживаемых тегом ключей необходимо обратиться к описанию данного тега.
Когда параметры тега попадают в конструктор базового класса ClsRuby::Tag, то они объединяются со списком параметров по умолчанию (заданных посредством default_tag_params). Поэтому для получения доступа к полному списку параметров тега необходимо использовать метод ClsRuby::Tag#tag_params, т.к. он возвращает ссылку на Hash с результирующим списком параметров.
В связи с тем, что легко забыть про наличие параметров по умолчанию, легко можно написать неправильный код обработки необязательных параметров в конструкторе собственного тега. Например, если нужно обрабатывать тег :value для того, чтобы сразу сделать тег определенным:
def initialize( params = {} ) super( params ) value = params.fetch( :value ) if value ... # Обработка end end
Ошибка здесь в том, что здесь используется значение аргумента конструктора, но полностью игнорируются возможные значения по умолчанию. Правильный код должен использовать метод tag_params:
def initialize( params = {} ) super( params ) value = tag_params.fetch( :value ) if value ... # Обработка end end
либо, что более декларативно, использовать метод Tag#tag_handle_opt_param:
def initialize( params ) super( params ) tag_handle_opt_param( :value ) do |v| ... tag_make_defined end end
# vim:ts=2:sts=2:sw=2:expandtab:ft=txt:tw=78
Generated with the Darkfish Rdoc Generator 2.