rgen 0.4.2 → 0.4.3

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