rgen 0.3.0 → 0.4.0

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