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.
Files changed (145) hide show
  1. data/CHANGELOG +20 -1
  2. data/MIT-LICENSE +1 -1
  3. data/README +12 -9
  4. data/lib/instantiators/ea_instantiator.rb +36 -0
  5. data/lib/metamodels/uml13_metamodel.rb +559 -0
  6. data/lib/metamodels/uml13_metamodel_ext.rb +26 -0
  7. data/lib/mmgen/metamodel_generator.rb +5 -5
  8. data/lib/mmgen/mm_ext/ecore_ext.rb +95 -0
  9. data/lib/mmgen/mmgen.rb +6 -4
  10. data/lib/mmgen/templates/annotations.tpl +37 -0
  11. data/lib/mmgen/templates/metamodel_generator.tpl +171 -0
  12. data/lib/rgen/ecore/ecore.rb +190 -0
  13. data/lib/rgen/ecore/ecore_instantiator.rb +25 -0
  14. data/lib/rgen/ecore/ecore_transformer.rb +85 -0
  15. data/lib/rgen/environment.rb +9 -24
  16. data/lib/rgen/find_helper.rb +68 -0
  17. data/lib/rgen/{instantiator.rb → instantiator/abstract_instantiator.rb} +6 -2
  18. data/lib/rgen/instantiator/abstract_xml_instantiator.rb +59 -0
  19. data/lib/rgen/instantiator/default_xml_instantiator.rb +117 -0
  20. data/lib/rgen/instantiator/ecore_xml_instantiator.rb +144 -0
  21. data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +157 -0
  22. data/lib/rgen/instantiator/xmi11_instantiator.rb +164 -0
  23. data/lib/rgen/metamodel_builder.rb +103 -9
  24. data/lib/rgen/metamodel_builder/build_helper.rb +26 -4
  25. data/lib/rgen/metamodel_builder/builder_extensions.rb +285 -88
  26. data/lib/rgen/metamodel_builder/builder_runtime.rb +7 -1
  27. data/lib/rgen/metamodel_builder/data_types.rb +67 -0
  28. data/lib/rgen/metamodel_builder/intermediate/annotation.rb +30 -0
  29. data/lib/rgen/metamodel_builder/metamodel_description.rb +232 -0
  30. data/lib/rgen/metamodel_builder/mm_multiple.rb +23 -0
  31. data/lib/rgen/metamodel_builder/module_extension.rb +33 -0
  32. data/lib/rgen/model_comparator.rb +56 -0
  33. data/lib/rgen/model_dumper.rb +5 -5
  34. data/lib/rgen/name_helper.rb +17 -1
  35. data/lib/rgen/template_language.rb +148 -28
  36. data/lib/rgen/template_language/directory_template_container.rb +56 -38
  37. data/lib/rgen/template_language/output_handler.rb +93 -77
  38. data/lib/rgen/template_language/template_container.rb +186 -143
  39. data/lib/rgen/transformer.rb +19 -14
  40. data/lib/transformers/uml13_to_ecore.rb +75 -0
  41. data/redist/xmlscan/ChangeLog +1301 -0
  42. data/redist/xmlscan/README +34 -0
  43. data/redist/xmlscan/THANKS +11 -0
  44. data/redist/xmlscan/doc/changes.html +74 -0
  45. data/redist/xmlscan/doc/changes.rd +80 -0
  46. data/redist/xmlscan/doc/en/conformance.html +136 -0
  47. data/redist/xmlscan/doc/en/conformance.rd +152 -0
  48. data/redist/xmlscan/doc/en/manual.html +356 -0
  49. data/redist/xmlscan/doc/en/manual.rd +402 -0
  50. data/redist/xmlscan/doc/ja/conformance.ja.html +118 -0
  51. data/redist/xmlscan/doc/ja/conformance.ja.rd +134 -0
  52. data/redist/xmlscan/doc/ja/manual.ja.html +325 -0
  53. data/redist/xmlscan/doc/ja/manual.ja.rd +370 -0
  54. data/redist/xmlscan/doc/src/Makefile +41 -0
  55. data/redist/xmlscan/doc/src/conformance.rd.src +256 -0
  56. data/redist/xmlscan/doc/src/langsplit.rb +110 -0
  57. data/redist/xmlscan/doc/src/manual.rd.src +614 -0
  58. data/redist/xmlscan/install.rb +41 -0
  59. data/redist/xmlscan/lib/xmlscan/encoding.rb +311 -0
  60. data/redist/xmlscan/lib/xmlscan/htmlscan.rb +289 -0
  61. data/redist/xmlscan/lib/xmlscan/namespace.rb +352 -0
  62. data/redist/xmlscan/lib/xmlscan/parser.rb +299 -0
  63. data/redist/xmlscan/lib/xmlscan/scanner.rb +1109 -0
  64. data/redist/xmlscan/lib/xmlscan/version.rb +22 -0
  65. data/redist/xmlscan/lib/xmlscan/visitor.rb +158 -0
  66. data/redist/xmlscan/lib/xmlscan/xmlchar.rb +441 -0
  67. data/redist/xmlscan/memo/CONFORMANCE +1249 -0
  68. data/redist/xmlscan/memo/PRODUCTIONS +195 -0
  69. data/redist/xmlscan/memo/contentspec.ry +335 -0
  70. data/redist/xmlscan/samples/chibixml.rb +105 -0
  71. data/redist/xmlscan/samples/getxmlchar.rb +122 -0
  72. data/redist/xmlscan/samples/rexml.rb +159 -0
  73. data/redist/xmlscan/samples/xmlbench.rb +88 -0
  74. data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +22 -0
  75. data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +29 -0
  76. data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +62 -0
  77. data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +22 -0
  78. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +62 -0
  79. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +22 -0
  80. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +22 -0
  81. data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +99 -0
  82. data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +116 -0
  83. data/redist/xmlscan/samples/xmlconftest.rb +200 -0
  84. data/redist/xmlscan/test.rb +7 -0
  85. data/redist/xmlscan/tests/deftestcase.rb +73 -0
  86. data/redist/xmlscan/tests/runtest.rb +47 -0
  87. data/redist/xmlscan/tests/testall.rb +14 -0
  88. data/redist/xmlscan/tests/testencoding.rb +438 -0
  89. data/redist/xmlscan/tests/testhtmlscan.rb +752 -0
  90. data/redist/xmlscan/tests/testnamespace.rb +457 -0
  91. data/redist/xmlscan/tests/testparser.rb +591 -0
  92. data/redist/xmlscan/tests/testscanner.rb +1749 -0
  93. data/redist/xmlscan/tests/testxmlchar.rb +143 -0
  94. data/redist/xmlscan/tests/visitor.rb +34 -0
  95. data/test/array_extensions_test.rb +2 -2
  96. data/test/ea_instantiator_test.rb +41 -0
  97. data/test/ecore_self_test.rb +53 -0
  98. data/test/environment_test.rb +11 -6
  99. data/test/metamodel_builder_test.rb +404 -245
  100. data/test/metamodel_roundtrip_test.rb +52 -0
  101. data/test/metamodel_roundtrip_test/TestModel.rb +65 -0
  102. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +64 -0
  103. data/test/metamodel_roundtrip_test/houseMetamodel.ecore +32 -0
  104. data/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb +39 -0
  105. data/test/rgen_test.rb +3 -3
  106. data/test/template_language_test.rb +65 -39
  107. data/test/template_language_test/expected_result.txt +24 -3
  108. data/test/template_language_test/templates/code/array.tpl +11 -0
  109. data/test/template_language_test/templates/content/author.tpl +7 -0
  110. data/test/template_language_test/templates/content/chapter.tpl +1 -1
  111. data/test/template_language_test/templates/root.tpl +17 -8
  112. data/test/template_language_test/testout.txt +24 -3
  113. data/test/testmodel/class_model_checker.rb +119 -0
  114. data/test/{xmi_instantiator_test/testmodel.eap → testmodel/ea_testmodel.eap} +0 -0
  115. data/test/{xmi_instantiator_test/testmodel.xml → testmodel/ea_testmodel.xml} +81 -14
  116. data/test/testmodel/ea_testmodel_partial.xml +317 -0
  117. data/test/testmodel/ecore_model_checker.rb +101 -0
  118. data/test/testmodel/manual_testmodel.xml +22 -0
  119. data/test/testmodel/object_model_checker.rb +67 -0
  120. data/test/transformer_test.rb +18 -10
  121. data/test/xml_instantiator_test.rb +81 -8
  122. data/test/xml_instantiator_test/simple_ecore_model_checker.rb +94 -0
  123. data/test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb +53 -0
  124. data/test/xml_instantiator_test/simple_xmi_metamodel.rb +49 -0
  125. data/test/xml_instantiator_test/simple_xmi_to_ecore.rb +75 -0
  126. metadata +126 -28
  127. data/lib/ea/xmi_class_instantiator.rb +0 -46
  128. data/lib/ea/xmi_helper.rb +0 -26
  129. data/lib/ea/xmi_metamodel.rb +0 -34
  130. data/lib/ea/xmi_object_instantiator.rb +0 -46
  131. data/lib/ea/xmi_to_classmodel.rb +0 -78
  132. data/lib/ea/xmi_to_objectmodel.rb +0 -92
  133. data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +0 -71
  134. data/lib/mmgen/templates/uml_classmodel.tpl +0 -63
  135. data/lib/rgen/xml_instantiator.rb +0 -132
  136. data/lib/uml/objectmodel_instantiator.rb +0 -53
  137. data/lib/uml/uml_classmodel.rb +0 -92
  138. data/lib/uml/uml_objectmodel.rb +0 -65
  139. data/test/metamodel_generator_test.rb +0 -44
  140. data/test/metamodel_generator_test/TestModel.rb +0 -40
  141. data/test/metamodel_generator_test/expected_result.txt +0 -40
  142. data/test/xmi_class_instantiator_test.rb +0 -24
  143. data/test/xmi_instantiator_test/class_model_checker.rb +0 -97
  144. data/test/xmi_object_instantiator_test.rb +0 -65
  145. data/test/xml_instantiator_test/testmodel.xml +0 -7
@@ -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?(:one_attributes) && obj.class.respond_to?(:many_attributes)
9
+ elsif obj.class.respond_to?(:ecore)
10
10
  ([obj.to_s] +
11
- obj.class.one_attributes.collect { |a|
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.many_attributes.collect { |a|
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
@@ -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
- # 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
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
- # <% define 'GenerateDBAdapter', :for => DBDescription do |dbtype| %>
43
- # Content to be generated; use ERB syntax here
44
- # <% end %>
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
- # <% expand 'GenerateDBAdapter', dbtype, :for => dbDesc %>
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
- # <% expand 'dbaccess::ExampleSQL' %>
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
- # <% expand '../headers/generic_headers::CHeader', :foreach => modules %>
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
- # <% expand '/headers/generic_headers::CHeader', :foreach => modules %>
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
- # =Output Files and Formatting
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
- # <% file 'dbadapter/'+adapter.name+'.c' do %>
119
- # all content within this block will be written to the specified file
120
- # <% end %>
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 the metamodel and the output
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
- # module MyMM
139
- # # metaclasses are defined here, e.g. using RGen::MetamodelBuilder
140
- # end
256
+ # module MyMM
257
+ # # metaclasses are defined here, e.g. using RGen::MetamodelBuilder
258
+ # end
141
259
  #
142
- # OUTPUT_DIR = File.dirname(__FILE__)+"/output"
143
- # TEMPLATES_DIR = File.dirname(__FILE__)+"/templates"
260
+ # OUTPUT_DIR = File.dirname(__FILE__)+"/output"
261
+ # TEMPLATES_DIR = File.dirname(__FILE__)+"/templates"
144
262
  #
145
- # tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new(MyMM, OUTPUT_DIR)
146
- # tc.load(TEMPLATES_DIR)
147
- # # testModel should hold an instance of the metamodel class expected by the root template
148
- # # the following line starts generation
149
- # tc.expand('root::Root', :for => testModel, :indent => 1)
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
- 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)).load(qf)
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
- args, params = _splitArgsAndOptions(all_args)
35
- element = params[:for]
36
- if template =~ /^\// && @parent
37
- @parent.expand(template, *all_args)
38
- elsif template =~ /^[\/]*(\w+)[:\/]+(.*)/
39
- throw "Template not found: #{$1}" unless @containers[$1]
40
- @containers[$1].expand($2, *all_args)
41
- elsif @parent
42
- @parent.expand(template, *all_args)
43
- else
44
- throw "Template not found: #{template}"
45
- end
46
- end
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
- 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
- def concat(s)
19
- return @output.concat(s) if s.is_a? OutputHandler
20
- s = s.to_str.gsub(/^[\t ]*\r?\n/,'') if @ignoreNextNL
21
- s = s.to_str.gsub(/^\s+/,'') if @ignoreNextWS
22
- @ignoreNextNL = @ignoreNextWS = false if s =~ /\S/
23
- if @mode == :direct
24
- @output.concat(s)
25
- elsif @mode == :explicit
26
- while s.size > 0
27
- #puts "DEGUB: #{@state} #{s.dump}"
28
- # s starts with whitespace
29
- if s =~ /\A(\s+)(.*)/m
30
- ws = $1; rest = $2
31
- #puts "DEGUB: ws #{ws.dump} rest #{rest.dump}"
32
- if @state == :wait_for_nl
33
- # ws contains a newline
34
- if ws =~ /\A[\t ]*(\r?\n)(\s*)/m
35
- @output.concat($1)
36
- @state = :wait_for_nonws
37
- s = $2 + rest
38
- else
39
- @output.concat(ws)
40
- s = rest
41
- end
42
- else
43
- s = rest
44
- end
45
- # s starts with non-whitespace
46
- elsif s =~ /\A(\S+)(.*)/m
47
- nonws = $1; rest = $2
48
- #puts "DEGUB: nonws #{nonws.dump} rest #{rest.dump}"
49
- @output.concat(" "*@indent) if @state == :wait_for_nonws
50
- @output.concat(nonws)
51
- @state = :wait_for_nl
52
- s = rest
53
- end
54
- end
55
- end
56
- end
57
- alias << concat
58
-
59
- def to_str
60
- @output
61
- end
62
- alias to_s to_str
63
-
64
- def direct_concat(s)
65
- @output.concat(s)
66
- end
67
-
68
- def ignoreNextNL
69
- @ignoreNextNL = true
70
- end
71
-
72
- def ignoreNextWS
73
- @ignoreNextWS = true
74
- end
75
-
76
- def mode=(m)
77
- raise StandardError.new("Unknown mode: #{m}") unless [:direct, :explicit].include?(m)
78
- @mode = m
79
- end
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