rgen 0.4.2 → 0.4.3

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 (33) hide show
  1. data/CHANGELOG +7 -0
  2. data/lib/rgen/metamodel_builder.rb +5 -4
  3. data/lib/rgen/metamodel_builder.rb.bak +196 -0
  4. data/lib/rgen/metamodel_builder/builder_extensions.rb +51 -38
  5. data/lib/rgen/metamodel_builder/builder_extensions.rb.bak +437 -0
  6. data/lib/rgen/metamodel_builder/builder_runtime.rb +2 -20
  7. data/lib/rgen/metamodel_builder/builder_runtime.rb.bak +73 -0
  8. data/lib/rgen/name_helper.rb.bak +37 -0
  9. data/lib/rgen/template_language.rb +8 -0
  10. data/lib/rgen/template_language.rb.bak +289 -0
  11. data/lib/rgen/template_language/directory_template_container.rb +11 -0
  12. data/lib/rgen/template_language/directory_template_container.rb.bak +69 -0
  13. data/lib/rgen/template_language/output_handler.rb +3 -2
  14. data/lib/rgen/template_language/output_handler.rb.bak +88 -0
  15. data/lib/rgen/template_language/template_container.rb +5 -4
  16. data/lib/rgen/template_language/template_container.rb.bak +196 -0
  17. data/lib/rgen/transformer.rb.bak +381 -0
  18. data/test/environment_test.rb.bak +52 -0
  19. data/test/metamodel_builder_test.rb +6 -0
  20. data/test/metamodel_builder_test.rb.bak +443 -0
  21. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +34 -32
  22. data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +58 -58
  23. data/test/output_handler_test.rb +8 -0
  24. data/test/output_handler_test.rb.bak +50 -0
  25. data/test/template_language_test.rb +23 -0
  26. data/test/template_language_test.rb.bak +72 -0
  27. data/test/template_language_test/indentStringTestDefaultIndent.out +1 -0
  28. data/test/template_language_test/indentStringTestTabIndent.out +1 -0
  29. data/test/template_language_test/templates/indent_string_test.tpl +12 -0
  30. data/test/template_language_test/templates/null_context_test.tpl +12 -0
  31. data/test/transformer_test.rb.bak +223 -0
  32. metadata +65 -48
  33. data/lib/rgen/environment.rb.bak +0 -42
@@ -14,8 +14,8 @@ module BuilderRuntime
14
14
  include NameHelper
15
15
 
16
16
  def is_a?(c)
17
- return super unless c.respond_to?(:_class_module)
18
- kind_of?(c._class_module)
17
+ return super unless c.const_defined?(:ClassModule)
18
+ kind_of?(c::ClassModule)
19
19
  end
20
20
 
21
21
  def addGeneric(role, value)
@@ -34,24 +34,6 @@ module BuilderRuntime
34
34
  send("#{role}")
35
35
  end
36
36
 
37
- def _unregister(element, target, target_role, kind)
38
- return unless element and target and target_role
39
- if kind == 'one'
40
- target.send("#{target_role}=",nil)
41
- elsif kind == 'many'
42
- target.send("remove#{firstToUpper(target_role)}",element)
43
- end
44
- end
45
-
46
- def _register(element, target, target_role, kind)
47
- return unless element and target and target_role
48
- if kind == 'one'
49
- target.send("#{target_role}=",element)
50
- elsif kind == 'many'
51
- target.send("add#{firstToUpper(target_role)}",element)
52
- end
53
- end
54
-
55
37
  def _assignmentTypeError(target, value, expected)
56
38
  text = ""
57
39
  if target
@@ -0,0 +1,73 @@
1
+ # RGen Framework
2
+ # (c) Martin Thiede, 2006
3
+
4
+ require 'rgen/name_helper'
5
+
6
+ module RGen
7
+
8
+ module MetamodelBuilder
9
+
10
+ # This module is mixed into MetamodelBuilder::MMBase.
11
+ # The methods provided by this module are used by the methods generated
12
+ # by the class methods of MetamodelBuilder::BuilderExtensions
13
+ module BuilderRuntime
14
+ include NameHelper
15
+
16
+ def is_a?(c)
17
+ return super unless c.respond_to?(:_class_module)
18
+ kind_of?(c._class_module)
19
+ end
20
+
21
+ def addGeneric(role, value)
22
+ send("add#{firstToUpper(role)}",value)
23
+ end
24
+
25
+ def removeGeneric(role, value)
26
+ send("remove#{firstToUpper(role)}",value)
27
+ end
28
+
29
+ def setGeneric(role, value)
30
+ send("#{role}=",value)
31
+ end
32
+
33
+ def getGeneric(role)
34
+ send("#{role}")
35
+ end
36
+
37
+ def _unregister(element, target, target_role, kind)
38
+ return unless element and target and target_role
39
+ if kind == 'one'
40
+ target.send("#{target_role}=",nil)
41
+ elsif kind == 'many'
42
+ target.send("remove#{firstToUpper(target_role)}",element)
43
+ end
44
+ end
45
+
46
+ def _register(element, target, target_role, kind)
47
+ return unless element and target and target_role
48
+ if kind == 'one'
49
+ target.send("#{target_role}=",element)
50
+ elsif kind == 'many'
51
+ target.send("add#{firstToUpper(target_role)}",element)
52
+ end
53
+ end
54
+
55
+ def _assignmentTypeError(target, value, expected)
56
+ text = ""
57
+ if target
58
+ targetId = target.class.name
59
+ targetId += "(" + target.name + ")" if target.respond_to?(:name) and target.name
60
+ text += "In #{targetId} : "
61
+ end
62
+ valueId = value.class.name
63
+ valueId += "(" + value.name + ")" if value.respond_to?(:name) and value.name
64
+ valueId += "(:" + value.to_s + ")" if value.is_a?(Symbol)
65
+ text += "Can not use a #{valueId} where a #{expected} is expected"
66
+ StandardError.new(text)
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,37 @@
1
+ # RGen Framework
2
+ # (c) Martin Thiede, 2006
3
+
4
+ module RGen
5
+
6
+ module NameHelper
7
+
8
+ def normalize(name)
9
+ name.gsub(/\W/,'_')
10
+ end
11
+
12
+ def className(object)
13
+ object.class.name =~ /::(\w+)$/; $1
14
+ end
15
+
16
+ def firstToUpper(str)
17
+ str[0..0].upcase + ( str[1..-1] || "" )
18
+ end
19
+
20
+ def firstToLower(str)
21
+ str[0..0].downcase + ( str[1..-1] || "" )
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
35
+ end
36
+
37
+ end
@@ -145,6 +145,11 @@ module RGen
145
145
  # Initial indentation defaults to 0. Normally <code><%iinc%></code> and
146
146
  # <code><%idec%></code> are used to change the indentation.
147
147
  # The current indentation is kept for expansion of subtemplates.
148
+ #
149
+ # The string which is used to realize one indentation step can be set using
150
+ # DirectoryTemplateContainer#indentString or with the template language +file+ command.
151
+ # The default is " " (3 spaces), the indentation string given at a +file+ command
152
+ # overwrites the container's default which in turn overwrites the overall default.
148
153
  #
149
154
  # Note that commands to ignore whitespace and newlines are still useful if output
150
155
  # generated from multiple template lines should show up in one single output line.
@@ -242,6 +247,9 @@ module RGen
242
247
  #
243
248
  # The absolute position where the output file is created depends on the output
244
249
  # root directory passed to DirectoryTemplateContainer as described below.
250
+ #
251
+ # As a second argument, the +file+ command can take the indentation string which is
252
+ # used to indent output lines (see Formatting).
245
253
  #
246
254
  # =Setting up the Generator
247
255
  #
@@ -0,0 +1,289 @@
1
+ # RGen Framework
2
+ # (c) Martin Thiede, 2006
3
+
4
+ require 'rgen/template_language/directory_template_container'
5
+ require 'rgen/template_language/template_container'
6
+
7
+ module RGen
8
+
9
+ # The RGen template language has been designed to build complex generators.
10
+ # It is very similar to the EXPAND language of the Java based
11
+ # OpenArchitectureWare framework.
12
+ #
13
+ # =Templates
14
+ #
15
+ # The basic idea is to allow "templates" not only being template files
16
+ # but smaller parts. Those parts can be expanded from other parts very
17
+ # much like Ruby methods are called from other methods.
18
+ # Thus the term "template" refers to such a part within a "template file".
19
+ #
20
+ # Template files used by the RGen template language should have a
21
+ # filename with the postfix ".tpl". Those files can reside within (nested)
22
+ # template file directories.
23
+ #
24
+ # As an example a template directory could look like the following:
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
31
+ #
32
+ # A template is always called for a <i>context object</i>. The context object
33
+ # serves as the receiver of methods called within the template. Details are given
34
+ # below.
35
+ #
36
+ #
37
+ # =Defining Templates
38
+ #
39
+ # One or more templates can be defined in a template file using the +define+
40
+ # keyword as in the following example:
41
+ #
42
+ # <% define 'GenerateDBAdapter', :for => DBDescription do |dbtype| %>
43
+ # Content to be generated; use ERB syntax here
44
+ # <% end %>
45
+ #
46
+ # The template definition takes three kinds of parameters:
47
+ # 1. The name of the template within the template file as a String or Symbol
48
+ # 2. An optional class object describing the class of context objects for which
49
+ # this template is valid.
50
+ # 3. An arbitrary number of template parameters
51
+ # See RGen::TemplateLanguage::TemplateContainer for details about the syntax of +define+.
52
+ #
53
+ # Within a template, regular ERB syntax can be used. This is
54
+ # * <code><%</code> and <code>%></code> are used to embed Ruby code
55
+ # * <code><%=</code> and <code>%></code> are used to embed Ruby expressions with
56
+ # the expression result being written to the template output
57
+ # * <code><%#</code> and <code>%></code> are used for comments
58
+ # All content not within these tags is written to the template output verbatim.
59
+ # See below for details about output files and output formatting.
60
+ #
61
+ # All methods which are called from within the template are sent to the context
62
+ # object.
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
+ #
67
+ #
68
+ # =Expanding Templates
69
+ #
70
+ # Templates are normally expanded from within other templates. The only
71
+ # exception is the root template, which is expanded from the surrounding code.
72
+ #
73
+ # Template names can be specified in the following ways:
74
+ # * Non qualified name: use the template with the given name in the current template file
75
+ # * Relative qualified name: use the template within the template file specified by the relative path
76
+ # * Absolute qualified name: use the template within the template file specified by the absolute path
77
+ #
78
+ # The +expand+ keyword is used to expand templates.
79
+ #
80
+ # Here are some examples:
81
+ #
82
+ # <% expand 'GenerateDBAdapter', dbtype, :for => dbDesc %>
83
+ #
84
+ # <i>Non qualified</i>. Must be called within the file where 'GenerateDBAdapter' is defined.
85
+ # There is one template parameter passed in via variable +dbtype+.
86
+ # The context object is provided in variable +dbDesc+.
87
+ #
88
+ # <% expand 'dbaccess::ExampleSQL' %>
89
+ #
90
+ # <i>Qualified with filename</i>. Must be called from a file in the same directory as 'dbaccess.tpl'
91
+ # There are no parameters. The current context object will be used as the context
92
+ # object for this template expansion.
93
+ #
94
+ # <% expand '../headers/generic_headers::CHeader', :foreach => modules %>
95
+ #
96
+ # <i>Relatively qualified</i>. Must be called from a location from which the file
97
+ # 'generic_headers.tpl' is accessible via the relative path '../headers'.
98
+ # The template is expanded for each module in +modules+ (which has to be an Array).
99
+ # Each element of +modules+ will be the context object in turn.
100
+ #
101
+ # <% expand '/headers/generic_headers::CHeader', :foreach => modules %>
102
+ #
103
+ # Absolutely qualified: The same behaviour as before but with an absolute path from
104
+ # the template directory root (which in this example is 'templates', see above)
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:
142
+ #
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
223
+ #
224
+ # Normally the generated content is to be written into one or more output files.
225
+ # The RGen template language facilitates this by means of the +file+ keyword.
226
+ #
227
+ # When the +file+ keyword is used to define a block, all output generated
228
+ # from template code within this block will be written to the specified file.
229
+ # This includes output generated from template expansions.
230
+ # Thus all output from templates expanded within this block is written to
231
+ # the same file as long as those templates do not use the +file+ keyword to
232
+ # define a new file context.
233
+ #
234
+ # Here is an example:
235
+ #
236
+ # <% file 'dbadapter/'+adapter.name+'.c' do %>
237
+ # all content within this block will be written to the specified file
238
+ # <% end %>
239
+ #
240
+ # Note that the filename itself can be calculated dynamically by an arbitrary
241
+ # Ruby expression.
242
+ #
243
+ # The absolute position where the output file is created depends on the output
244
+ # root directory passed to DirectoryTemplateContainer as described below.
245
+ #
246
+ # =Setting up the Generator
247
+ #
248
+ # Setting up the generator consists of 3 steps:
249
+ # * Instantiate DirectoryTemplateContainer passing one or more metamodel(s) and the output
250
+ # directory to the constructor.
251
+ # * Load the templates into the template container
252
+ # * Expand the root template to start generation
253
+ #
254
+ # Here is an example:
255
+ #
256
+ # module MyMM
257
+ # # metaclasses are defined here, e.g. using RGen::MetamodelBuilder
258
+ # end
259
+ #
260
+ # OUTPUT_DIR = File.dirname(__FILE__)+"/output"
261
+ # TEMPLATES_DIR = File.dirname(__FILE__)+"/templates"
262
+ #
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)
268
+ #
269
+ # The metamodel is the Ruby module which contains the metaclasses.
270
+ # This information is required for the template container in order to resolve the
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.
274
+ #
275
+ # The output path is prepended to the relative paths provided to the +file+
276
+ # definitions in the template files.
277
+ #
278
+ # The template directory should contain template files as described above.
279
+ #
280
+ # Finally the generation process is started by calling +expand+ in the same way as it
281
+ # is used from within templates.
282
+ #
283
+ # Also see the unit tests for more examples.
284
+ #
285
+ module TemplateLanguage
286
+
287
+ end
288
+
289
+ end