rgen 0.4.5 → 0.4.6
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.
- data/CHANGELOG +7 -0
- data/MIT-LICENSE +1 -1
- data/Rakefile +45 -0
- data/lib/rgen/template_language/directory_template_container.rb +1 -2
- data/lib/rgen/template_language/template_container.rb +198 -180
- data/test/ea_serializer_test/ea_testmodel_regenerated.xml +570 -570
- data/test/template_language_test.rb +26 -5
- data/test/template_language_test/{expected_result.txt → expected_result1.txt} +0 -0
- data/test/template_language_test/expected_result2.txt +9 -0
- data/test/template_language_test/expected_result3.txt +4 -0
- data/test/template_language_test/templates/code/array.tpl +1 -1
- data/test/template_language_test/templates/no_backslash_r_test.tpl +5 -0
- data/test/template_language_test/templates/null_context_test.tpl +5 -0
- data/test/template_language_test/templates/root.tpl +1 -1
- metadata +7 -3
data/CHANGELOG
CHANGED
@@ -74,3 +74,10 @@
|
|
74
74
|
=0.4.5 (Nov 17th, 2008)
|
75
75
|
|
76
76
|
* Updated XMI1.1 serializer to support explicit placement of elements on content level of the XMI file
|
77
|
+
|
78
|
+
=0.4.6 (Mar 1st, 2009)
|
79
|
+
|
80
|
+
* Bugfix: expand :foreach silently assumed current context if :foreach evalutated to nil
|
81
|
+
* Bugfix: fixed unit test for non-Windows plattforms (\r\n)
|
82
|
+
* Bugfix: depending on the Ruby version and/or platform constants used in templates could not be resolved
|
83
|
+
* Added automatic line ending detection (\n or \r\n) for template language +nl+ command
|
data/MIT-LICENSE
CHANGED
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
|
4
|
+
RGenGemSpec = Gem::Specification.new do |s|
|
5
|
+
s.name = %q{rgen}
|
6
|
+
s.version = "0.4.6"
|
7
|
+
s.date = %q{2009-03-01}
|
8
|
+
s.summary = %q{Ruby Modelling and Generator Framework}
|
9
|
+
s.email = %q{martin dot thiede at gmx de}
|
10
|
+
s.homepage = %q{ruby-gen.org}
|
11
|
+
s.rubyforge_project = %q{rgen}
|
12
|
+
s.description = %q{RGen is a framework supporting Model Driven Software Development (MDSD). This means that it helps you build Metamodels, instantiate Models, modify and transform Models and finally generate arbitrary textual content from it.}
|
13
|
+
s.has_rdoc = true
|
14
|
+
s.authors = ["Martin Thiede"]
|
15
|
+
gemfiles = Rake::FileList.new
|
16
|
+
gemfiles.include("{lib,test,redist}/**/*")
|
17
|
+
gemfiles.include("README", "CHANGELOG", "MIT-LICENSE", "Rakefile")
|
18
|
+
gemfiles.exclude(/\b\.bak\b/)
|
19
|
+
s.files = gemfiles
|
20
|
+
s.rdoc_options = ["--main", "README", "-x", "redist", "-x", "test", "-x", "metamodels"]
|
21
|
+
s.extra_rdoc_files = ["README", "CHANGELOG", "MIT-LICENSE"]
|
22
|
+
end
|
23
|
+
|
24
|
+
Rake::RDocTask.new do |rd|
|
25
|
+
rd.main = "README"
|
26
|
+
rd.rdoc_files.include("README", "CHANGELOG", "MIT-LICENSE", "lib/**/*.rb")
|
27
|
+
rd.rdoc_files.exclude("lib/metamodels")
|
28
|
+
rd.rdoc_dir = "doc"
|
29
|
+
end
|
30
|
+
|
31
|
+
RGenPackageTask = Rake::GemPackageTask.new(RGenGemSpec) do |p|
|
32
|
+
p.need_zip = true
|
33
|
+
end
|
34
|
+
|
35
|
+
task :publish_doc do
|
36
|
+
sh %{pscp -r doc/* thiedem@rubyforge.org:/var/www/gforge-projects/rgen}
|
37
|
+
end
|
38
|
+
|
39
|
+
task :prepare_package_rdoc => :rdoc do
|
40
|
+
RGenPackageTask.package_files.include("doc/**/*")
|
41
|
+
end
|
42
|
+
|
43
|
+
task :release => [:prepare_package_rdoc, :package]
|
44
|
+
|
45
|
+
task :clobber => [:clobber_rdoc, :clobber_package]
|
@@ -19,11 +19,10 @@ class DirectoryTemplateContainer
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def load(dir)
|
22
|
-
#print "Loading templates in #{dir} ...\n"
|
23
22
|
Dir.foreach(dir) { |f|
|
24
23
|
qf = dir+"/"+f
|
25
24
|
if !File.directory?(qf) && f =~ /^(.*)\.tpl$/
|
26
|
-
(@containers[$1] = TemplateContainer.
|
25
|
+
(@containers[$1] = TemplateContainer.new(@metamodel, @output_path, self,qf)).load
|
27
26
|
elsif File.directory?(qf) && f != "." && f != ".."
|
28
27
|
(@containers[f] = DirectoryTemplateContainer.new(@metamodel, @output_path, self)).load(qf)
|
29
28
|
end
|
@@ -8,190 +8,208 @@ require 'rgen/template_language/template_helper'
|
|
8
8
|
|
9
9
|
module RGen
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
# if this container can handle the call, the expansion result is returned
|
39
|
-
# otherwise expand is called on the appropriate container and the result is added to @output
|
40
|
-
def expand(template, *all_args)
|
41
|
-
args, params = _splitArgsAndOptions(all_args)
|
42
|
-
if params[:foreach].is_a? Enumerable
|
43
|
-
_expand_foreach(template, args, params)
|
44
|
-
else
|
45
|
-
_expand(template, args, params)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def this
|
50
|
-
@context
|
51
|
-
end
|
52
|
-
|
53
|
-
def method_missing(name, *args)
|
54
|
-
@context.send(name, *args)
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.const_missing(name)
|
58
|
-
super unless @@metamodels
|
59
|
-
@@metamodels.each do |mm|
|
60
|
-
return mm.const_get(name) rescue NameError
|
61
|
-
end
|
62
|
-
super
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def nonl
|
68
|
-
@output.ignoreNextNL
|
69
|
-
end
|
70
|
-
|
71
|
-
def nows
|
72
|
-
@output.ignoreNextWS
|
73
|
-
end
|
74
|
-
|
75
|
-
def nl
|
76
|
-
_direct_concat("\n")
|
77
|
-
end
|
78
|
-
|
79
|
-
def ws
|
80
|
-
_direct_concat(" ")
|
81
|
-
end
|
82
|
-
|
83
|
-
def iinc
|
84
|
-
@indent += 1
|
85
|
-
@output.indent = @indent
|
86
|
-
end
|
87
|
-
|
88
|
-
def idec
|
89
|
-
@indent -= 1 if @indent > 0
|
90
|
-
@output.indent = @indent
|
11
|
+
module TemplateLanguage
|
12
|
+
|
13
|
+
class TemplateContainer
|
14
|
+
include TemplateHelper
|
15
|
+
|
16
|
+
def initialize(metamodels, output_path, parent, filename)
|
17
|
+
@templates = {}
|
18
|
+
@parent = parent
|
19
|
+
@filename = filename
|
20
|
+
@indent = 0
|
21
|
+
@output_path = output_path
|
22
|
+
@metamodels = metamodels
|
23
|
+
@metamodels = [ @metamodels ] unless @metamodels.is_a?(Array)
|
24
|
+
end
|
25
|
+
|
26
|
+
def load
|
27
|
+
File.open(@filename,"rb") do |f|
|
28
|
+
begin
|
29
|
+
@@metamodels = @metamodels
|
30
|
+
fileContent = f.read
|
31
|
+
_detectNewLinePattern(fileContent)
|
32
|
+
ERB.new(fileContent,nil,nil,'@output').result(binding)
|
33
|
+
rescue Exception => e
|
34
|
+
processAndRaise(e)
|
91
35
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# if this container can handle the call, the expansion result is returned
|
40
|
+
# otherwise expand is called on the appropriate container and the result is added to @output
|
41
|
+
def expand(template, *all_args)
|
42
|
+
args, params = _splitArgsAndOptions(all_args)
|
43
|
+
if params.has_key?(:foreach)
|
44
|
+
raise StandardError.new("expand :foreach argument is not enumerable") \
|
45
|
+
unless params[:foreach].is_a?(Enumerable)
|
46
|
+
_expand_foreach(template, args, params)
|
47
|
+
else
|
48
|
+
_expand(template, args, params)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def this
|
53
|
+
@context
|
54
|
+
end
|
55
|
+
|
56
|
+
def method_missing(name, *args)
|
57
|
+
@context.send(name, *args)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.const_missing(name)
|
61
|
+
super unless @@metamodels
|
62
|
+
@@metamodels.each do |mm|
|
63
|
+
return mm.const_get(name) rescue NameError
|
64
|
+
end
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def nonl
|
71
|
+
@output.ignoreNextNL
|
72
|
+
end
|
73
|
+
|
74
|
+
def nows
|
75
|
+
@output.ignoreNextWS
|
76
|
+
end
|
77
|
+
|
78
|
+
def nl
|
79
|
+
_direct_concat(@newLinePattern)
|
80
|
+
end
|
81
|
+
|
82
|
+
def ws
|
83
|
+
_direct_concat(" ")
|
84
|
+
end
|
85
|
+
|
86
|
+
def iinc
|
87
|
+
@indent += 1
|
88
|
+
@output.indent = @indent
|
89
|
+
end
|
90
|
+
|
91
|
+
def idec
|
92
|
+
@indent -= 1 if @indent > 0
|
93
|
+
@output.indent = @indent
|
94
|
+
end
|
95
|
+
|
96
|
+
def define(template, params={}, &block)
|
97
|
+
@templates[template] ||= {}
|
98
|
+
cls = params[:for] || Object
|
99
|
+
@templates[template][cls] = block
|
100
|
+
end
|
101
|
+
|
102
|
+
def file(name, indentString=nil)
|
103
|
+
old_output, @output = @output, OutputHandler.new(@indent, indentString || @parent.indentString)
|
104
|
+
begin
|
105
|
+
yield
|
106
|
+
rescue Exception => e
|
107
|
+
processAndRaise(e)
|
108
|
+
end
|
109
|
+
path = ""
|
110
|
+
path += @output_path+"/" if @output_path
|
111
|
+
dirname = File.dirname(path+name)
|
112
|
+
FileUtils.makedirs(dirname) unless File.exist?(dirname)
|
113
|
+
File.open(path+name,"wb") { |f| f.write(@output) }
|
114
|
+
@output = old_output
|
115
|
+
end
|
116
|
+
|
117
|
+
# private private
|
118
|
+
|
119
|
+
def _expand_foreach(template, args, params)
|
120
|
+
sep = params[:separator]
|
121
|
+
params[:foreach].each_with_index {|e,i|
|
122
|
+
single_params = params.dup
|
123
|
+
single_params[:for] = e
|
124
|
+
_direct_concat(sep.to_s) if sep && i > 0
|
125
|
+
_expand(template, args, single_params)
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
LOCAL_TEMPLATE_REGEX = /^:*(\w+)$/
|
130
|
+
|
131
|
+
def _expand(template, args, params)
|
132
|
+
raise StandardError.new("expand :for argument evaluates to nil") if params.has_key?(:for) && params[:for].nil?
|
133
|
+
context = params[:for]
|
134
|
+
@indent = params[:indent] || @indent
|
135
|
+
# if this is the first call to expand within this container, @output is nil
|
136
|
+
noIndentNextLine = params[:noIndentNextLine]
|
137
|
+
noIndentNextLine = (@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0]) if noIndentNextLine.nil?
|
138
|
+
old_context, @context = @context, context if context
|
139
|
+
local_output = nil
|
140
|
+
if template =~ LOCAL_TEMPLATE_REGEX
|
141
|
+
tplname = $1
|
142
|
+
raise StandardError.new("Template not found: #{$1}") unless @templates[tplname]
|
143
|
+
old_output, @output = @output, OutputHandler.new(@indent, @parent.indentString)
|
144
|
+
@output.noIndentNextLine if noIndentNextLine
|
145
|
+
_call_template(tplname, @context, args)
|
146
|
+
local_output, @output = @output, old_output
|
147
|
+
else
|
148
|
+
local_output = @parent.expand(template, *(args.dup << {:for => @context, :indent => @indent, :noIndentNextLine => noIndentNextLine}))
|
149
|
+
end
|
150
|
+
_direct_concat(local_output)
|
151
|
+
@context = old_context if old_context
|
152
|
+
local_output
|
153
|
+
end
|
154
|
+
|
155
|
+
def processAndRaise(e, tpl=nil)
|
156
|
+
bt = e.backtrace.dup
|
157
|
+
e.backtrace.each_with_index do |t,i|
|
158
|
+
if t =~ /\(erb\):(\d+):/
|
159
|
+
bt[i] = "#{@filename}:#{$1}"
|
160
|
+
bt[i] += ":in '#{tpl}'" if tpl
|
161
|
+
break
|
97
162
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
163
|
+
end
|
164
|
+
raise e, e.to_s, bt
|
165
|
+
end
|
166
|
+
|
167
|
+
def _call_template(tpl, context, args)
|
168
|
+
found = false
|
169
|
+
@templates[tpl].each_pair do |key, value|
|
170
|
+
if context.is_a?(key)
|
171
|
+
proc = @templates[tpl][key]
|
172
|
+
arity = proc.arity
|
173
|
+
arity = 0 if arity == -1 # if no args are given
|
174
|
+
raise StandardError.new("Wrong number of arguments calling template #{tpl}: #{args.size} for #{arity} "+
|
175
|
+
"(Beware: Hashes as last arguments are taken as options and are ignored)") \
|
176
|
+
if arity != args.size
|
101
177
|
begin
|
102
|
-
|
178
|
+
@@metamodels = @metamodels
|
179
|
+
proc.call(*args)
|
103
180
|
rescue Exception => e
|
104
|
-
processAndRaise(e)
|
105
|
-
end
|
106
|
-
path = ""
|
107
|
-
path += @output_path+"/" if @output_path
|
108
|
-
dirname = File.dirname(path+name)
|
109
|
-
FileUtils.makedirs(dirname) unless File.exist?(dirname)
|
110
|
-
File.open(path+name,"w") { |f| f.write(@output) }
|
111
|
-
@output = old_output
|
112
|
-
end
|
113
|
-
|
114
|
-
# private private
|
115
|
-
|
116
|
-
def _expand_foreach(template, args, params)
|
117
|
-
sep = params[:separator]
|
118
|
-
params[:foreach].each_with_index {|e,i|
|
119
|
-
single_params = params.dup
|
120
|
-
single_params[:for] = e
|
121
|
-
_direct_concat(sep.to_s) if sep && i > 0
|
122
|
-
_expand(template, args, single_params)
|
123
|
-
}
|
124
|
-
end
|
125
|
-
|
126
|
-
LOCAL_TEMPLATE_REGEX = /^:*(\w+)$/
|
127
|
-
|
128
|
-
def _expand(template, args, params)
|
129
|
-
raise StandardError.new("expand :for argument evaluates to nil") if params.has_key?(:for) && params[:for].nil?
|
130
|
-
context = params[:for]
|
131
|
-
@indent = params[:indent] || @indent
|
132
|
-
# if this is the first call to expand within this container, @output is nil
|
133
|
-
noIndentNextLine = params[:noIndentNextLine]
|
134
|
-
noIndentNextLine = (@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0]) if noIndentNextLine.nil?
|
135
|
-
old_context, @context = @context, context if context
|
136
|
-
local_output = nil
|
137
|
-
if template =~ LOCAL_TEMPLATE_REGEX
|
138
|
-
tplname = $1
|
139
|
-
raise StandardError.new("Template not found: #{$1}") unless @templates[tplname]
|
140
|
-
old_output, @output = @output, OutputHandler.new(@indent, @parent.indentString)
|
141
|
-
@output.noIndentNextLine if noIndentNextLine
|
142
|
-
_call_template(tplname, @context, args)
|
143
|
-
local_output, @output = @output, old_output
|
144
|
-
else
|
145
|
-
local_output = @parent.expand(template, *(args.dup << {:for => @context, :indent => @indent, :noIndentNextLine => noIndentNextLine}))
|
146
|
-
end
|
147
|
-
_direct_concat(local_output)
|
148
|
-
@context = old_context if old_context
|
149
|
-
local_output
|
150
|
-
end
|
151
|
-
|
152
|
-
def processAndRaise(e, tpl=nil)
|
153
|
-
bt = e.backtrace.dup
|
154
|
-
e.backtrace.each_with_index do |t,i|
|
155
|
-
if t =~ /\(erb\):(\d+):/
|
156
|
-
bt[i] = "#{@filename}:#{$1}"
|
157
|
-
bt[i] += ":in '#{tpl}'" if tpl
|
158
|
-
break
|
159
|
-
end
|
160
|
-
end
|
161
|
-
raise e, e.to_s, bt
|
162
|
-
end
|
163
|
-
|
164
|
-
def _call_template(tpl, context, args)
|
165
|
-
found = false
|
166
|
-
@templates[tpl].each_pair { |key, value|
|
167
|
-
if context.is_a?(key)
|
168
|
-
proc = @templates[tpl][key]
|
169
|
-
arity = proc.arity
|
170
|
-
arity = 0 if arity == -1 # if no args are given
|
171
|
-
raise StandardError.new("Wrong number of arguments calling template #{tpl}: #{args.size} for #{arity} "+
|
172
|
-
"(Beware: Hashes as last arguments are taken as options and are ignored)") \
|
173
|
-
if arity != args.size
|
174
|
-
begin
|
175
|
-
proc.call(*args)
|
176
|
-
rescue Exception => e
|
177
|
-
processAndRaise(e, tpl)
|
178
|
-
end
|
179
|
-
found = true
|
180
|
-
end
|
181
|
-
}
|
182
|
-
raise StandardError.new("Template class not matching: #{tpl} for #{context.class.name}") unless found
|
183
|
-
end
|
184
|
-
|
185
|
-
def _direct_concat(s)
|
186
|
-
if @output.is_a? OutputHandler
|
187
|
-
@output.direct_concat(s)
|
188
|
-
else
|
189
|
-
@output << s
|
190
|
-
end
|
181
|
+
processAndRaise(e, tpl)
|
191
182
|
end
|
192
|
-
|
183
|
+
found = true
|
193
184
|
end
|
194
|
-
|
195
185
|
end
|
196
|
-
|
197
|
-
end
|
186
|
+
raise StandardError.new("Template class not matching: #{tpl} for #{context.class.name}") unless found
|
187
|
+
end
|
188
|
+
|
189
|
+
def _direct_concat(s)
|
190
|
+
if @output.is_a? OutputHandler
|
191
|
+
@output.direct_concat(s)
|
192
|
+
else
|
193
|
+
@output << s
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def _detectNewLinePattern(text)
|
198
|
+
tests = 0
|
199
|
+
rnOccurances = 0
|
200
|
+
text.scan(/(\r?)\n/) do |groups|
|
201
|
+
tests += 1
|
202
|
+
rnOccurances += 1 if groups[0] == "\r"
|
203
|
+
break if tests >= 10
|
204
|
+
end
|
205
|
+
if rnOccurances > (tests / 2)
|
206
|
+
@newLinePattern = "\r\n"
|
207
|
+
else
|
208
|
+
@newLinePattern = "\n"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|