Path: | docs/ValueIncapsulator |
Last Update: | Mon Jun 04 14:34:35 +0400 2007 |
Шаблон ValueIncapsulator предназначен для генерации C++ классов, которые только инкапсулируют в себе несколько значений и предоставляют публичные методы для получения/изменения этих значений. Примерами таких классов могут быть классы, содержащие конфигурацию приложения. Например, пусть нужен класс, который содержит имя хоста и номер порта для подключения к этому хосту через TCP/IP. Без использования кодогенерации пришлось бы написать следующий C++ код:
class host_config_t { private : std::string m_host; short m_port; public : host_config_t() : m_port( 0 ) {} const std::string & host() const { return m_host; } void set_host( const std::string & v ) { m_host = v; } short port() const { return m_port; } void set_port( short v ) { m_port = v; } };
Но такого же результата можно достичь с использованием шаблона ValueIncapsulator:
cpp_value_incapsulator :host_config_t do |c| c.decl_file :script_relative => "host_config.impl.hpp" c.impl_file :script_relative => "host_config.impl.cpp" c.attr_prefix "m_" c.attr :host, "std::string" c.attr :port, "short", default => 0 end
Шаблон ValueIncapsulator используется посредством метода cpp_value_incapsulator, который получает в качестве аргумента имя генерируемого C++ класса и требует наличие блока кода, в котором будут задаваться параметры кодогенерации. Этот блок кода вызывается внутри cpp_value_incapsulator с одним параметром: экземпляром класса RuCodeGen::ValueIncapsulator. С помощью именно этого экземпляра и задаются параметры кодогенерации.
После того, как блок кода внутри cpp_value_incapsulator отработает, шаблон создаст два генератора кода — один для генерации описания класса, второй для генерации реализации класса. В текущей версии ValueIncapsulator, описания и реализация класса должны размещаться в отдельных файлах, расположение и имена которых задаются посредством методов RuCodeGen::ValueIncapsulator#decl_file и RuCodeGen::ValueIncapsulator#impl_file. Созданные cpp_value_incapsulator генераторы запускаются на исполнение штатным образом при завершении работы скрипта.
Имена и расположение файлов задается посредством методов decl_file и impl_file:
c.decl_file <relative> => <name>
где <relative> это:
Например:
c.decl_file :script_relative => "h/decl.hpp" c.impl_file :script_relative => "decl.cpp"
Подробнее см. RuCodeGen::FilenameProducer#produce.
По умолчанию, ValueIncapsulator создает атрибуты сгенерированного класса с теми именами, которые были переданы в метод c.attr. Например, для описания:
c.attr :host, "std::string"
будет сгенерирован атрибут host типа std::string. Если требуется, чтобы у атрибутов класса были специфические префиксы или/и суффиксы, то следует задать их с помощью методов attr_prefix, attr_suffix. Например:
c.attr_prefix "m_" c.attr :host, "std::string"
приводит к генерации:
std::string m_host;
а описание:
c.attr_suffix "_" c.attr :host, "std::string"
приводит к генерации:
std::string host_;
Можно задать одновременно и префикс, и суффикс.
По умолчанию, ValueIncapsulator создает методы getter-/setter-ы с теми именами, которые были переданы в метод c.attr. Например:
c.attr :port, "short"
преобразуется в:
short port() const; void port( short v__ );
С помощью методов getter_prefix и setter_prefix можно указать префикс для соответствующего типа методов. Например:
c.getter_prefix "query_" c.attr :port, "short"
преобразуется в:
short query_port() const; void port( short v__ );
Или:
c.setter_prefix "set_" c.attr :port, "short"
приводит к:
short port() const; void set_port( short v__ );
Можно задать одновременно префиксы для getter-ов и setter-ов.
По умолчанию, для всех атрибутов примитивных типов (см. RuCodeGen::ClassAttribute::PRIMITIVE_TYPES) в конструкторе задается значение 0. Для атрибутов, тип которого не относится к примитивным типам начальное значение вообще не задается. Если это не желательно и нужно назначить атрибуту специфическое значение, то его следует указать в методе attr:
c.attr :host, "std::string", :default => "localhost" c.attr :port, "short", :default => 8080
Если начальное значение атрибута задается какой-либо C++ константой, элементом enum-а или даже вызовом C++ функции, то соответствующий C++ идентификатор нужно записывать в Ruby-коде в виде Symbol-а (идентификатора с предшествующим двоеточием):
c.attr :host, "std::string", :default => :"get_default_host()" c.attr :port, "short", :default => :default_port
тогда в конструкторе инициализация атрибутов будет иметь вид:
host( get_default_host() ), port( default_port )
Если тип атрибута не является примитивным (см. RuCodeGen::ClassAttribute::PRIMITIVE_TYPES), то метод getter возвращает константную ссылку на атрибут, а метод setter получает константную ссылку в качестве аргумента. Например:
c.attr :host, "std::string"
приводит к генерации:
const std::string & host() const; void host( const std::string & v__ );
Если по каким-то причинам использовать ссылки не желательно, то это можно указать при описании атрибута:
c.attr :host, "std::string", getter_returns_value => true
что приведет к генерации:
std::string host() const; void host( std::string v__ );