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