Path: | docs/Principle |
Last Update: | Mon Jun 04 14:34:35 +0400 2007 |
RuCodeGen расчитан на использования языка Ruby в качестве DSL (Domain Specific Language) для описания какой-либо кодогенерации. Это означает, что тип и параметры кодогенерации задаются в виде Ruby-скрипта. Этот скрипт затем запускается на выполнение (как обычный Ruby-скрипт) и в результате получается один или несколько результирующих файлов со сгенерированным кодом.
Ниже приведен сценарий использования шаблона RuCodeGen::ValueIncapsulator.
В скрипте для генерации C++ класса с использованием RuCodeGen::ValueIncapsulator необходимо сделать две вещи:
Например:
# Загрузка Gem RuCodeGen. require 'rubygems' require_gem 'RuCodeGen' # Описание для кодогенерации. 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", :default => "localhost" c.attr :post, "short", :default => 8080 end
Пусть приведенный код размещается в файле src/cg-host_config.rb.
Приведенный выше скрипт будет генерировать два файла: src/host_config.impl.hpp и src/host_config.impl.cpp. Для этого всего лишь необходимо запустить скрипт src/cg-host_config.rb:
$ruby src/cg-host_config.rb
Далее полученные файлы нужно включить в С++ проект.
По умолчанию, скрипт с описанием кодогенерации выполняет кодогенерацию. Но это всего лишь один из возможных режимов его работы. Чтобы узнать остальные возможные режимы, нужно запустить скрипт с аргументом —help:
$ruby src/cg-host_config.rb --help Usage: cg-host_config [options] -m, --mode MODE run mode (build, rebuild, clean, dry-run) -h, --help show this screen
Если аргумент —mode не задан, то подразумевается, что скрипт запускается с параметром —mode build. Но, указав аргумент —mode в командной строке явно, можно выбрать любой из поддерживаемых режимов:
Идея RuCodeGen состоит в том, чтобы для каждого типа кодогенерации был создан свой шаблон (как, например, RuCodeGen::ValueIncapsulator). Скрипты с описанием параметров кодогенерации использовали бы возможности конкретного шаблона. Роль RuCodeGen в таком случае заключалась бы в следующем:
В качестве базового фреймворка для поддержки кодогенерации RuCodeGen требует, чтобы каждый шаблон в результате своей работы формировал один или несколько объектов-генераторов и регистрировал их в классе RuCodeGen::Generators. Пока каждый генератор должен быть связан с уникальным именем результирующего файла (т.е. на данный момент нельзя сделать так, чтобы несколько генераторов перезаписывали один и тот же файл).
Генераторы должны поддерживать следующий интерфейс:
def generate(to) ... end
где в качестве аргумента to будет передаваться объек-поток, в который нужно записывать результаты генерации.
Примерами готовых генераторов являются классы RuCodeGen::ValueIncapsulator::Generation::DeclGenerator и RuCodeGen::ValueIncapsulator::Generation::ImplGenerator.
Если скрипт с описанием кодогенерации запускается в режиме build, то генерация выполняется при завершении работы скрипта следующим образом:
Если скрипт с описанием кодогенерации запускается в режиме clean, то удаляются все файлы с результатами кодогенерации и файл с контрольной суммой.
В принципе, каждый кодогенерирующий шаблон может применять собственные правила расположения сгенерированных им файлов. RuCodeGen предоставляет класс RuCodeGen::FilenameProducer, который помогает формировать имена для трех типовых ситуаций:
Например, в приведенном выше примере с src/cg-host_config.rb, имена результирущих файлов заданы относительно скрипта cg-host_config.rb. Поэтому, скажем, если скрипт находится в каталоге ~/sandboxes/some_prj/src, а текущим каталогом является ~/sandboxes, то запуск кодогенерации:
ruby some_prj/src/cg-host_config.rb
приведет к созданию файлов ~/sandboxes/some_prj/src/host_config.impl.hpp и ~/sandboxes/some_prj/src/host_config.impl.cpp.