rgen 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|