rgen 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +20 -1
- data/MIT-LICENSE +1 -1
- data/README +12 -9
- data/lib/instantiators/ea_instantiator.rb +36 -0
- data/lib/metamodels/uml13_metamodel.rb +559 -0
- data/lib/metamodels/uml13_metamodel_ext.rb +26 -0
- data/lib/mmgen/metamodel_generator.rb +5 -5
- data/lib/mmgen/mm_ext/ecore_ext.rb +95 -0
- data/lib/mmgen/mmgen.rb +6 -4
- data/lib/mmgen/templates/annotations.tpl +37 -0
- data/lib/mmgen/templates/metamodel_generator.tpl +171 -0
- data/lib/rgen/ecore/ecore.rb +190 -0
- data/lib/rgen/ecore/ecore_instantiator.rb +25 -0
- data/lib/rgen/ecore/ecore_transformer.rb +85 -0
- data/lib/rgen/environment.rb +9 -24
- data/lib/rgen/find_helper.rb +68 -0
- data/lib/rgen/{instantiator.rb → instantiator/abstract_instantiator.rb} +6 -2
- data/lib/rgen/instantiator/abstract_xml_instantiator.rb +59 -0
- data/lib/rgen/instantiator/default_xml_instantiator.rb +117 -0
- data/lib/rgen/instantiator/ecore_xml_instantiator.rb +144 -0
- data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +157 -0
- data/lib/rgen/instantiator/xmi11_instantiator.rb +164 -0
- data/lib/rgen/metamodel_builder.rb +103 -9
- data/lib/rgen/metamodel_builder/build_helper.rb +26 -4
- data/lib/rgen/metamodel_builder/builder_extensions.rb +285 -88
- data/lib/rgen/metamodel_builder/builder_runtime.rb +7 -1
- data/lib/rgen/metamodel_builder/data_types.rb +67 -0
- data/lib/rgen/metamodel_builder/intermediate/annotation.rb +30 -0
- data/lib/rgen/metamodel_builder/metamodel_description.rb +232 -0
- data/lib/rgen/metamodel_builder/mm_multiple.rb +23 -0
- data/lib/rgen/metamodel_builder/module_extension.rb +33 -0
- data/lib/rgen/model_comparator.rb +56 -0
- data/lib/rgen/model_dumper.rb +5 -5
- data/lib/rgen/name_helper.rb +17 -1
- data/lib/rgen/template_language.rb +148 -28
- data/lib/rgen/template_language/directory_template_container.rb +56 -38
- data/lib/rgen/template_language/output_handler.rb +93 -77
- data/lib/rgen/template_language/template_container.rb +186 -143
- data/lib/rgen/transformer.rb +19 -14
- data/lib/transformers/uml13_to_ecore.rb +75 -0
- data/redist/xmlscan/ChangeLog +1301 -0
- data/redist/xmlscan/README +34 -0
- data/redist/xmlscan/THANKS +11 -0
- data/redist/xmlscan/doc/changes.html +74 -0
- data/redist/xmlscan/doc/changes.rd +80 -0
- data/redist/xmlscan/doc/en/conformance.html +136 -0
- data/redist/xmlscan/doc/en/conformance.rd +152 -0
- data/redist/xmlscan/doc/en/manual.html +356 -0
- data/redist/xmlscan/doc/en/manual.rd +402 -0
- data/redist/xmlscan/doc/ja/conformance.ja.html +118 -0
- data/redist/xmlscan/doc/ja/conformance.ja.rd +134 -0
- data/redist/xmlscan/doc/ja/manual.ja.html +325 -0
- data/redist/xmlscan/doc/ja/manual.ja.rd +370 -0
- data/redist/xmlscan/doc/src/Makefile +41 -0
- data/redist/xmlscan/doc/src/conformance.rd.src +256 -0
- data/redist/xmlscan/doc/src/langsplit.rb +110 -0
- data/redist/xmlscan/doc/src/manual.rd.src +614 -0
- data/redist/xmlscan/install.rb +41 -0
- data/redist/xmlscan/lib/xmlscan/encoding.rb +311 -0
- data/redist/xmlscan/lib/xmlscan/htmlscan.rb +289 -0
- data/redist/xmlscan/lib/xmlscan/namespace.rb +352 -0
- data/redist/xmlscan/lib/xmlscan/parser.rb +299 -0
- data/redist/xmlscan/lib/xmlscan/scanner.rb +1109 -0
- data/redist/xmlscan/lib/xmlscan/version.rb +22 -0
- data/redist/xmlscan/lib/xmlscan/visitor.rb +158 -0
- data/redist/xmlscan/lib/xmlscan/xmlchar.rb +441 -0
- data/redist/xmlscan/memo/CONFORMANCE +1249 -0
- data/redist/xmlscan/memo/PRODUCTIONS +195 -0
- data/redist/xmlscan/memo/contentspec.ry +335 -0
- data/redist/xmlscan/samples/chibixml.rb +105 -0
- data/redist/xmlscan/samples/getxmlchar.rb +122 -0
- data/redist/xmlscan/samples/rexml.rb +159 -0
- data/redist/xmlscan/samples/xmlbench.rb +88 -0
- data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +29 -0
- data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +62 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +62 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +99 -0
- data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +116 -0
- data/redist/xmlscan/samples/xmlconftest.rb +200 -0
- data/redist/xmlscan/test.rb +7 -0
- data/redist/xmlscan/tests/deftestcase.rb +73 -0
- data/redist/xmlscan/tests/runtest.rb +47 -0
- data/redist/xmlscan/tests/testall.rb +14 -0
- data/redist/xmlscan/tests/testencoding.rb +438 -0
- data/redist/xmlscan/tests/testhtmlscan.rb +752 -0
- data/redist/xmlscan/tests/testnamespace.rb +457 -0
- data/redist/xmlscan/tests/testparser.rb +591 -0
- data/redist/xmlscan/tests/testscanner.rb +1749 -0
- data/redist/xmlscan/tests/testxmlchar.rb +143 -0
- data/redist/xmlscan/tests/visitor.rb +34 -0
- data/test/array_extensions_test.rb +2 -2
- data/test/ea_instantiator_test.rb +41 -0
- data/test/ecore_self_test.rb +53 -0
- data/test/environment_test.rb +11 -6
- data/test/metamodel_builder_test.rb +404 -245
- data/test/metamodel_roundtrip_test.rb +52 -0
- data/test/metamodel_roundtrip_test/TestModel.rb +65 -0
- data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +64 -0
- data/test/metamodel_roundtrip_test/houseMetamodel.ecore +32 -0
- data/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb +39 -0
- data/test/rgen_test.rb +3 -3
- data/test/template_language_test.rb +65 -39
- data/test/template_language_test/expected_result.txt +24 -3
- data/test/template_language_test/templates/code/array.tpl +11 -0
- data/test/template_language_test/templates/content/author.tpl +7 -0
- data/test/template_language_test/templates/content/chapter.tpl +1 -1
- data/test/template_language_test/templates/root.tpl +17 -8
- data/test/template_language_test/testout.txt +24 -3
- data/test/testmodel/class_model_checker.rb +119 -0
- data/test/{xmi_instantiator_test/testmodel.eap → testmodel/ea_testmodel.eap} +0 -0
- data/test/{xmi_instantiator_test/testmodel.xml → testmodel/ea_testmodel.xml} +81 -14
- data/test/testmodel/ea_testmodel_partial.xml +317 -0
- data/test/testmodel/ecore_model_checker.rb +101 -0
- data/test/testmodel/manual_testmodel.xml +22 -0
- data/test/testmodel/object_model_checker.rb +67 -0
- data/test/transformer_test.rb +18 -10
- data/test/xml_instantiator_test.rb +81 -8
- data/test/xml_instantiator_test/simple_ecore_model_checker.rb +94 -0
- data/test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb +53 -0
- data/test/xml_instantiator_test/simple_xmi_metamodel.rb +49 -0
- data/test/xml_instantiator_test/simple_xmi_to_ecore.rb +75 -0
- metadata +126 -28
- data/lib/ea/xmi_class_instantiator.rb +0 -46
- data/lib/ea/xmi_helper.rb +0 -26
- data/lib/ea/xmi_metamodel.rb +0 -34
- data/lib/ea/xmi_object_instantiator.rb +0 -46
- data/lib/ea/xmi_to_classmodel.rb +0 -78
- data/lib/ea/xmi_to_objectmodel.rb +0 -92
- data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +0 -71
- data/lib/mmgen/templates/uml_classmodel.tpl +0 -63
- data/lib/rgen/xml_instantiator.rb +0 -132
- data/lib/uml/objectmodel_instantiator.rb +0 -53
- data/lib/uml/uml_classmodel.rb +0 -92
- data/lib/uml/uml_objectmodel.rb +0 -65
- data/test/metamodel_generator_test.rb +0 -44
- data/test/metamodel_generator_test/TestModel.rb +0 -40
- data/test/metamodel_generator_test/expected_result.txt +0 -40
- data/test/xmi_class_instantiator_test.rb +0 -24
- data/test/xmi_instantiator_test/class_model_checker.rb +0 -97
- data/test/xmi_object_instantiator_test.rb +0 -65
- data/test/xml_instantiator_test/testmodel.xml +0 -7
data/lib/rgen/model_dumper.rb
CHANGED
|
@@ -6,13 +6,13 @@ module ModelDumper
|
|
|
6
6
|
obj ||= self
|
|
7
7
|
if obj.is_a?(Array)
|
|
8
8
|
obj.collect {|o| dump(o)}.join("\n\n")
|
|
9
|
-
elsif obj.class.respond_to?(:
|
|
9
|
+
elsif obj.class.respond_to?(:ecore)
|
|
10
10
|
([obj.to_s] +
|
|
11
|
-
obj.class.
|
|
12
|
-
" #{a} => #{obj.getGeneric(a)}"
|
|
11
|
+
obj.class.ecore.eAllStructuralFeatures.select{|f| !f.many}.collect { |a|
|
|
12
|
+
" #{a} => #{obj.getGeneric(a.name)}"
|
|
13
13
|
} +
|
|
14
|
-
obj.class.
|
|
15
|
-
" #{a} => [ #{obj.getGeneric(a).join(', ')} ]"
|
|
14
|
+
obj.class.ecore.eAllStructuralFeatures.select{|f| f.many}.collect { |a|
|
|
15
|
+
" #{a} => [ #{obj.getGeneric(a.name).join(', ')} ]"
|
|
16
16
|
}).join("\n")
|
|
17
17
|
else
|
|
18
18
|
obj.to_s
|
data/lib/rgen/name_helper.rb
CHANGED
|
@@ -4,18 +4,34 @@
|
|
|
4
4
|
module RGen
|
|
5
5
|
|
|
6
6
|
module NameHelper
|
|
7
|
+
|
|
7
8
|
def normalize(name)
|
|
8
|
-
name.gsub(
|
|
9
|
+
name.gsub(/\W/,'_')
|
|
9
10
|
end
|
|
11
|
+
|
|
10
12
|
def className(object)
|
|
11
13
|
object.class.name =~ /::(\w+)$/; $1
|
|
12
14
|
end
|
|
15
|
+
|
|
13
16
|
def firstToUpper(str)
|
|
14
17
|
str[0..0].upcase + ( str[1..-1] || "" )
|
|
15
18
|
end
|
|
19
|
+
|
|
16
20
|
def firstToLower(str)
|
|
17
21
|
str[0..0].downcase + ( str[1..-1] || "" )
|
|
18
22
|
end
|
|
23
|
+
|
|
24
|
+
def saneClassName(str)
|
|
25
|
+
firstToUpper(normalize(str)).sub(/^Class$/, 'Clazz')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def saneMethodName(str)
|
|
29
|
+
firstToLower(normalize(str)).sub(/^class$/, 'clazz')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def camelize(str)
|
|
33
|
+
str.split(/[\W_]/).collect{|s| firstToUpper(s.downcase)}.join
|
|
34
|
+
end
|
|
19
35
|
end
|
|
20
36
|
|
|
21
37
|
end
|
|
@@ -23,11 +23,11 @@ module RGen
|
|
|
23
23
|
#
|
|
24
24
|
# As an example a template directory could look like the following:
|
|
25
25
|
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
26
|
+
# templates/root.tpl
|
|
27
|
+
# templates/dbaccess/dbaccess.tpl
|
|
28
|
+
# templates/dbaccess/schema.tpl
|
|
29
|
+
# templates/headers/generic_headers.tpl
|
|
30
|
+
# templates/headers/specific/component.tpl
|
|
31
31
|
#
|
|
32
32
|
# A template is always called for a <i>context object</i>. The context object
|
|
33
33
|
# serves as the receiver of methods called within the template. Details are given
|
|
@@ -39,10 +39,10 @@ module RGen
|
|
|
39
39
|
# One or more templates can be defined in a template file using the +define+
|
|
40
40
|
# keyword as in the following example:
|
|
41
41
|
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
42
|
+
# <% define 'GenerateDBAdapter', :for => DBDescription do |dbtype| %>
|
|
43
|
+
# Content to be generated; use ERB syntax here
|
|
44
|
+
# <% end %>
|
|
45
|
+
#
|
|
46
46
|
# The template definition takes three kinds of parameters:
|
|
47
47
|
# 1. The name of the template within the template file as a String or Symbol
|
|
48
48
|
# 2. An optional class object describing the class of context objects for which
|
|
@@ -61,6 +61,9 @@ module RGen
|
|
|
61
61
|
# All methods which are called from within the template are sent to the context
|
|
62
62
|
# object.
|
|
63
63
|
#
|
|
64
|
+
# Experience shows that one easily forgets the +do+ at the end of the first
|
|
65
|
+
# line of a template definition. This will result in an ERB parse error.
|
|
66
|
+
#
|
|
64
67
|
#
|
|
65
68
|
# =Expanding Templates
|
|
66
69
|
#
|
|
@@ -76,32 +79,147 @@ module RGen
|
|
|
76
79
|
#
|
|
77
80
|
# Here are some examples:
|
|
78
81
|
#
|
|
79
|
-
#
|
|
82
|
+
# <% expand 'GenerateDBAdapter', dbtype, :for => dbDesc %>
|
|
80
83
|
#
|
|
81
84
|
# <i>Non qualified</i>. Must be called within the file where 'GenerateDBAdapter' is defined.
|
|
82
85
|
# There is one template parameter passed in via variable +dbtype+.
|
|
83
86
|
# The context object is provided in variable +dbDesc+.
|
|
84
87
|
#
|
|
85
|
-
#
|
|
88
|
+
# <% expand 'dbaccess::ExampleSQL' %>
|
|
86
89
|
#
|
|
87
90
|
# <i>Qualified with filename</i>. Must be called from a file in the same directory as 'dbaccess.tpl'
|
|
88
91
|
# There are no parameters. The current context object will be used as the context
|
|
89
92
|
# object for this template expansion.
|
|
90
93
|
#
|
|
91
|
-
#
|
|
94
|
+
# <% expand '../headers/generic_headers::CHeader', :foreach => modules %>
|
|
92
95
|
#
|
|
93
96
|
# <i>Relatively qualified</i>. Must be called from a location from which the file
|
|
94
97
|
# 'generic_headers.tpl' is accessible via the relative path '../headers'.
|
|
95
98
|
# The template is expanded for each module in +modules+ (which has to be an Array).
|
|
96
99
|
# Each element of +modules+ will be the context object in turn.
|
|
97
100
|
#
|
|
98
|
-
#
|
|
101
|
+
# <% expand '/headers/generic_headers::CHeader', :foreach => modules %>
|
|
99
102
|
#
|
|
100
103
|
# Absolutely qualified: The same behaviour as before but with an absolute path from
|
|
101
104
|
# the template directory root (which in this example is 'templates', see above)
|
|
102
105
|
#
|
|
106
|
+
# Sometimes it is neccessary to generate some text (e.g. a ',') in between the single
|
|
107
|
+
# template expansion results from a <code>:foreach</code> expansion. This can be achieved by
|
|
108
|
+
# using the <code>:separator</code> keyword:
|
|
109
|
+
#
|
|
110
|
+
# <% expand 'ColumnName', :foreach => column, :separator => ', ' %>
|
|
111
|
+
#
|
|
112
|
+
# Note that the separator may also contain newline characters (\n). See below for
|
|
113
|
+
# details about formatting.
|
|
114
|
+
#
|
|
115
|
+
#
|
|
116
|
+
# =Formatting
|
|
117
|
+
#
|
|
118
|
+
# For many generator tools a formatting postprocess (e.g. using a pretty printer) is
|
|
119
|
+
# required in order to make the output readable. However, depending on the kind of
|
|
120
|
+
# generated output, such a tool might not be available.
|
|
121
|
+
#
|
|
122
|
+
# The RGen template language has been design for generators which do not need a
|
|
123
|
+
# postprocessing step. The basic idea is to eliminate all whitespace at the beginning
|
|
124
|
+
# of template lines (the indentation that makes the _template_ readable) and output
|
|
125
|
+
# newlines only after at least on character has been generated in the corresponding
|
|
126
|
+
# line. This way there are no empty lines in the output and each line will start with
|
|
127
|
+
# a non-whitspace character.
|
|
128
|
+
#
|
|
129
|
+
# Starting from this point one can add indentation and newlines as required by using
|
|
130
|
+
# explicit formatting commands:
|
|
131
|
+
# * <code><%nl%></code> (newline) starts a new line
|
|
132
|
+
# * <code><%iinc%></code> (indentation increment) increases the current indentation
|
|
133
|
+
# * <code><%idec%></code> (indentation decrement) decreases the current indentation
|
|
134
|
+
# * <code><%nonl%></code> (no newline) ignore next newline
|
|
135
|
+
# * <code><%nows%></code> (no whitespace) ignore next whitespace
|
|
136
|
+
#
|
|
137
|
+
# Indentation takes place for every new line in the output unless it is 0.
|
|
138
|
+
# The initial indentation can be specified with a root +expand+ command by using
|
|
139
|
+
# the <code>:indent</code> keyword.
|
|
140
|
+
#
|
|
141
|
+
# Here is an example:
|
|
103
142
|
#
|
|
104
|
-
#
|
|
143
|
+
# expand 'GenerateDBAdapter', dbtype, :for => dbDesc, :indent => 1
|
|
144
|
+
#
|
|
145
|
+
# Initial indentation defaults to 0. Normally <code><%iinc%></code> and
|
|
146
|
+
# <code><%idec%></code> are used to change the indentation.
|
|
147
|
+
# The current indentation is kept for expansion of subtemplates.
|
|
148
|
+
#
|
|
149
|
+
# Note that commands to ignore whitespace and newlines are still useful if output
|
|
150
|
+
# generated from multiple template lines should show up in one single output line.
|
|
151
|
+
#
|
|
152
|
+
# Here is an example of a template generating a C program:
|
|
153
|
+
#
|
|
154
|
+
# #include <stdio.h>
|
|
155
|
+
# <%nl%>
|
|
156
|
+
# int main() {<%iinc%>
|
|
157
|
+
# printf("Hello World\n");
|
|
158
|
+
# return 0;<%idec>
|
|
159
|
+
# }
|
|
160
|
+
#
|
|
161
|
+
# The result is:
|
|
162
|
+
#
|
|
163
|
+
# #include <stdio.h>
|
|
164
|
+
#
|
|
165
|
+
# int main() {
|
|
166
|
+
# printf("Hello World\n");
|
|
167
|
+
# return 0;
|
|
168
|
+
# }
|
|
169
|
+
#
|
|
170
|
+
# Note that without the explicit formatting commands, the output generated from the
|
|
171
|
+
# example above would not have any empty lines or whitespace in the beginning of lines.
|
|
172
|
+
# This may seem like unneccessary extra work for the example above which could also
|
|
173
|
+
# have been generated by passing the template to the output verbatimly.
|
|
174
|
+
# However in most cases templates will contain more template specific indentation and
|
|
175
|
+
# newlines which should be eliminated than formatting that should be visible in the
|
|
176
|
+
# output.
|
|
177
|
+
#
|
|
178
|
+
# Here is a more realistic example for generating C function prototypes:
|
|
179
|
+
#
|
|
180
|
+
# <% define 'Prototype', :for => CFunction do %>
|
|
181
|
+
# <%= getType.name %> <%= name %>(<%nows%>
|
|
182
|
+
# <% expand 'Signature', :foreach => argument, :separator => ', ' %>);
|
|
183
|
+
# <% end %>
|
|
184
|
+
#
|
|
185
|
+
# <% define 'Signature', :for => CFunctionArgument do %>
|
|
186
|
+
# <%= getType.name %> <%= name%><%nows%>
|
|
187
|
+
# <% end %>
|
|
188
|
+
#
|
|
189
|
+
# The result could look something like:
|
|
190
|
+
#
|
|
191
|
+
# void somefunc(int a, float b, int c);
|
|
192
|
+
# int otherfunc(short x);
|
|
193
|
+
#
|
|
194
|
+
# In this example a separator is used to join the single arguments of the C functions.
|
|
195
|
+
# Note that the template generating the argument type and name needs to contain
|
|
196
|
+
# a <code><%nows%></code> if the result should consist of a single line.
|
|
197
|
+
#
|
|
198
|
+
# Here is one more example for generating C array initializations:
|
|
199
|
+
#
|
|
200
|
+
# <% define 'Array', :for => CArray do %>
|
|
201
|
+
# <%= getType.name %> <%= name %>[<%= size %>] = {<%iinc%>
|
|
202
|
+
# <% expand 'InitValue', :foreach => initvalue, :separator => ",\n" %><%nl%><%idec%>
|
|
203
|
+
# };
|
|
204
|
+
# <% end %>
|
|
205
|
+
#
|
|
206
|
+
# <% define 'InitValue', :for => PrimitiveInitValue do %>
|
|
207
|
+
# <%= value %><%nows%>
|
|
208
|
+
# <% end %>
|
|
209
|
+
#
|
|
210
|
+
# The result could look something like:
|
|
211
|
+
#
|
|
212
|
+
# int myArray[3] = {
|
|
213
|
+
# 1,
|
|
214
|
+
# 2,
|
|
215
|
+
# 3
|
|
216
|
+
# };
|
|
217
|
+
#
|
|
218
|
+
# Note that in this example, the separator contains a newline. The current increment
|
|
219
|
+
# will be applied to each single expansion result since it starts in a new line.
|
|
220
|
+
#
|
|
221
|
+
#
|
|
222
|
+
# =Output Files
|
|
105
223
|
#
|
|
106
224
|
# Normally the generated content is to be written into one or more output files.
|
|
107
225
|
# The RGen template language facilitates this by means of the +file+ keyword.
|
|
@@ -115,9 +233,9 @@ module RGen
|
|
|
115
233
|
#
|
|
116
234
|
# Here is an example:
|
|
117
235
|
#
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
236
|
+
# <% file 'dbadapter/'+adapter.name+'.c' do %>
|
|
237
|
+
# all content within this block will be written to the specified file
|
|
238
|
+
# <% end %>
|
|
121
239
|
#
|
|
122
240
|
# Note that the filename itself can be calculated dynamically by an arbitrary
|
|
123
241
|
# Ruby expression.
|
|
@@ -128,29 +246,31 @@ module RGen
|
|
|
128
246
|
# =Setting up the Generator
|
|
129
247
|
#
|
|
130
248
|
# Setting up the generator consists of 3 steps:
|
|
131
|
-
# * Instantiate DirectoryTemplateContainer passing
|
|
249
|
+
# * Instantiate DirectoryTemplateContainer passing one or more metamodel(s) and the output
|
|
132
250
|
# directory to the constructor.
|
|
133
251
|
# * Load the templates into the template container
|
|
134
252
|
# * Expand the root template to start generation
|
|
135
253
|
#
|
|
136
254
|
# Here is an example:
|
|
137
255
|
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
#
|
|
256
|
+
# module MyMM
|
|
257
|
+
# # metaclasses are defined here, e.g. using RGen::MetamodelBuilder
|
|
258
|
+
# end
|
|
141
259
|
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
260
|
+
# OUTPUT_DIR = File.dirname(__FILE__)+"/output"
|
|
261
|
+
# TEMPLATES_DIR = File.dirname(__FILE__)+"/templates"
|
|
144
262
|
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
#
|
|
148
|
-
#
|
|
149
|
-
#
|
|
263
|
+
# tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new(MyMM, OUTPUT_DIR)
|
|
264
|
+
# tc.load(TEMPLATES_DIR)
|
|
265
|
+
# # testModel should hold an instance of the metamodel class expected by the root template
|
|
266
|
+
# # the following line starts generation
|
|
267
|
+
# tc.expand('root::Root', :for => testModel, :indent => 1)
|
|
150
268
|
#
|
|
151
269
|
# The metamodel is the Ruby module which contains the metaclasses.
|
|
152
270
|
# This information is required for the template container in order to resolve the
|
|
153
271
|
# metamodel classes used within the template file.
|
|
272
|
+
# If several metamodels shall be used, an array of modules can be passed instead
|
|
273
|
+
# of a single module.
|
|
154
274
|
#
|
|
155
275
|
# The output path is prepended to the relative paths provided to the +file+
|
|
156
276
|
# definitions in the template files.
|
|
@@ -5,47 +5,65 @@ require 'rgen/template_language/template_container'
|
|
|
5
5
|
require 'rgen/template_language/template_helper'
|
|
6
6
|
|
|
7
7
|
module RGen
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
module TemplateLanguage
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
class DirectoryTemplateContainer
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
12
|
+
include TemplateHelper
|
|
13
|
+
|
|
14
|
+
def initialize(metamodel=nil, output_path=nil, parent=nil)
|
|
15
|
+
@containers = {}
|
|
16
|
+
@parent = parent
|
|
17
|
+
@metamodel = metamodel
|
|
18
|
+
@output_path = output_path
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def load(dir)
|
|
22
|
+
#print "Loading templates in #{dir} ...\n"
|
|
23
|
+
Dir.foreach(dir) { |f|
|
|
24
|
+
qf = dir+"/"+f
|
|
25
|
+
if !File.directory?(qf) && f =~ /^(.*)\.tpl$/
|
|
26
|
+
(@containers[$1] = TemplateContainer.dup.new(@metamodel, @output_path, self,qf)).load
|
|
27
|
+
elsif File.directory?(qf) && f != "." && f != ".."
|
|
28
|
+
(@containers[f] = DirectoryTemplateContainer.new(@metamodel, @output_path, self)).load(qf)
|
|
29
|
+
end
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def expand(template, *all_args)
|
|
34
|
+
if template =~ /^\//
|
|
35
|
+
if @parent
|
|
36
|
+
# pass to parent
|
|
37
|
+
@parent.expand(template, *all_args)
|
|
38
|
+
else
|
|
39
|
+
# this is root
|
|
40
|
+
_expand(template, *all_args)
|
|
41
|
+
end
|
|
42
|
+
elsif template =~ /^\.\.\/(.*)/
|
|
43
|
+
if @parent
|
|
44
|
+
# pass to parent
|
|
45
|
+
@parent.expand($1, *all_args)
|
|
46
|
+
else
|
|
47
|
+
raise "No parent directory for root"
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
_expand(template, *all_args)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def _expand(template, *all_args)
|
|
57
|
+
if template =~ /^\/?([^:\/]+)(?:::|\/)([^:\/].*)/
|
|
58
|
+
raise "Template not found: #{$1}" unless @containers[$1]
|
|
59
|
+
@containers[$1].expand($2, *all_args)
|
|
60
|
+
else
|
|
61
|
+
raise "Invalid template name: #{template}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
47
65
|
end
|
|
48
66
|
|
|
49
67
|
end
|
|
50
|
-
|
|
68
|
+
|
|
51
69
|
end
|
|
@@ -2,83 +2,99 @@
|
|
|
2
2
|
# (c) Martin Thiede, 2006
|
|
3
3
|
|
|
4
4
|
module RGen
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
module TemplateLanguage
|
|
7
|
-
|
|
8
|
-
class OutputHandler
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
7
|
+
|
|
8
|
+
class OutputHandler
|
|
9
|
+
attr_writer :indent
|
|
10
|
+
|
|
11
|
+
def initialize(indent=0, mode=:explicit)
|
|
12
|
+
self.mode = mode
|
|
13
|
+
@indent = indent
|
|
14
|
+
@state = :wait_for_nonws
|
|
15
|
+
@output = ""
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# ERB will call this method for every string s which is part of the
|
|
19
|
+
# template file in between %> and <%. If s contains a newline, it will
|
|
20
|
+
# call this method for every part of s which is terminated by a \n
|
|
21
|
+
#
|
|
22
|
+
def concat(s)
|
|
23
|
+
return @output.concat(s) if s.is_a? OutputHandler
|
|
24
|
+
s = s.to_str.gsub(/^[\t ]*\r?\n/,'') if @ignoreNextNL
|
|
25
|
+
s = s.to_str.gsub(/^\s+/,'') if @ignoreNextWS
|
|
26
|
+
@ignoreNextNL = @ignoreNextWS = false if s =~ /\S/
|
|
27
|
+
if @mode == :direct
|
|
28
|
+
@output.concat(s)
|
|
29
|
+
elsif @mode == :explicit
|
|
30
|
+
while s.size > 0
|
|
31
|
+
#puts "DEGUB: #{@state} #{s.dump}"
|
|
32
|
+
# s starts with whitespace
|
|
33
|
+
if s =~ /\A(\s+)(.*)/m
|
|
34
|
+
ws = $1; rest = $2
|
|
35
|
+
#puts "DEGUB: ws #{ws.dump} rest #{rest.dump}"
|
|
36
|
+
if @state == :wait_for_nl
|
|
37
|
+
# ws contains a newline
|
|
38
|
+
if ws =~ /\A[\t ]*(\r?\n)(\s*)/m
|
|
39
|
+
@output.concat($1)
|
|
40
|
+
@state = :wait_for_nonws
|
|
41
|
+
s = $2 + rest
|
|
42
|
+
else
|
|
43
|
+
@output.concat(ws)
|
|
44
|
+
s = rest
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
s = rest
|
|
48
|
+
end
|
|
49
|
+
# s starts with non-whitespace
|
|
50
|
+
elsif s =~ /\A(\S+)(.*)/m
|
|
51
|
+
nonws = $1; rest = $2
|
|
52
|
+
#puts "DEGUB: nonws #{nonws.dump} rest #{rest.dump}"
|
|
53
|
+
if @state == :wait_for_nonws
|
|
54
|
+
# within the same output handle we can recognize a newline by ourselves
|
|
55
|
+
# but if the output handler is changed, someone has to tell us
|
|
56
|
+
if !@noIndentNextLine && !(@output =~ /[^\n]\z/)
|
|
57
|
+
@output.concat(" "*@indent)
|
|
58
|
+
else
|
|
59
|
+
@noIndentNextLine = false
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
@output.concat(nonws)
|
|
63
|
+
@state = :wait_for_nl
|
|
64
|
+
s = rest
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
alias << concat
|
|
70
|
+
|
|
71
|
+
def to_str
|
|
72
|
+
@output
|
|
73
|
+
end
|
|
74
|
+
alias to_s to_str
|
|
75
|
+
|
|
76
|
+
def direct_concat(s)
|
|
77
|
+
@output.concat(s)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def ignoreNextNL
|
|
81
|
+
@ignoreNextNL = true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ignoreNextWS
|
|
85
|
+
@ignoreNextWS = true
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def noIndentNextLine
|
|
89
|
+
@noIndentNextLine = true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def mode=(m)
|
|
93
|
+
raise StandardError.new("Unknown mode: #{m}") unless [:direct, :explicit].include?(m)
|
|
94
|
+
@mode = m
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
80
98
|
end
|
|
81
|
-
|
|
82
|
-
end
|
|
83
|
-
|
|
99
|
+
|
|
84
100
|
end
|