rgen 0.4.6 → 0.5.0
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 +95 -83
- data/Rakefile +4 -3
- data/lib/ea_support/ea_support.rb +54 -0
- data/lib/ea_support/id_store.rb +32 -0
- data/lib/ea_support/uml13_ea_metamodel.rb +562 -0
- data/lib/ea_support/uml13_ea_metamodel_ext.rb +45 -0
- data/lib/ea_support/uml13_ea_metamodel_generator.rb +43 -0
- data/lib/ea_support/uml13_ea_to_uml13.rb +72 -0
- data/lib/ea_support/uml13_to_uml13_ea.rb +82 -0
- data/lib/rgen/ecore/ecore.rb +16 -2
- data/lib/rgen/ecore/ecore_builder_methods.rb +81 -0
- data/lib/rgen/ecore/ecore_instantiator.rb +5 -1
- data/lib/rgen/metamodel_builder/builder_extensions.rb +11 -3
- data/lib/rgen/metamodel_builder/module_extension2.rb +205 -0
- data/lib/rgen/method_delegation.rb +99 -0
- data/lib/rgen/model_builder.rb +27 -0
- data/lib/rgen/model_builder/builder_context.rb +318 -0
- data/lib/rgen/model_builder/model_serializer.rb +201 -0
- data/lib/rgen/model_builder/reference_resolver.rb +156 -0
- data/lib/rgen/template_language/directory_template_container.rb +6 -2
- data/lib/rgen/template_language/output_handler.rb +2 -4
- data/lib/rgen/template_language/template_container.rb +212 -195
- data/lib/rgen/transformer.rb +95 -4
- data/lib/transformers/ecore_to_uml13.rb +66 -0
- data/lib/transformers/uml13_to_ecore.rb +16 -7
- data/test/ea_instantiator_test.rb +8 -14
- data/test/ea_serializer_test.rb +3 -9
- data/test/ea_serializer_test/ea_testmodel_regenerated.xml +2 -2
- data/test/ea_serializer_test/ea_testmodel_regenerated_import.log +3 -0
- data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +19 -19
- data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +44 -44
- data/test/method_delegation_test.rb +178 -0
- data/test/model_builder/builder_context_test.rb +59 -0
- data/test/model_builder/builder_test.rb +284 -0
- data/test/model_builder/ecore_internal.rb +103 -0
- data/test/model_builder/ecore_original.rb +163 -0
- data/test/model_builder/ecore_original_regenerated.rb +163 -0
- data/test/model_builder/reference_resolver_test.rb +156 -0
- data/test/model_builder/serializer_test.rb +63 -0
- data/test/model_builder_test.rb +4 -0
- data/test/rgen_test.rb +2 -0
- data/test/template_language_test.rb +41 -1
- data/test/template_language_test/expected_result1.txt +1 -3
- data/test/template_language_test/templates/define_local_test/local.tpl +8 -0
- data/test/template_language_test/templates/define_local_test/test.tpl +8 -0
- data/test/template_language_test/templates/evaluate_test/test.tpl +7 -0
- data/test/template_language_test/templates/no_indent_test/no_indent.tpl +3 -0
- data/test/template_language_test/templates/no_indent_test/sub1/no_indent.tpl +3 -0
- data/test/template_language_test/templates/no_indent_test/test.tpl +24 -0
- data/test/template_language_test/templates/no_indent_test/test2.tpl +13 -0
- data/test/template_language_test/templates/no_indent_test/test3.tpl +10 -0
- data/test/template_language_test/templates/template_resolution_test/sub1.tpl +9 -0
- data/test/template_language_test/templates/template_resolution_test/sub1/sub1.tpl +3 -0
- data/test/template_language_test/templates/template_resolution_test/test.tpl +4 -0
- data/test/template_language_test/testout.txt +1 -3
- data/test/testmodel/ea_testmodel_import.log +1 -0
- data/test/testmodel/ea_testmodel_regenerated.xml +808 -0
- data/test/transformer_test.rb +3 -5
- metadata +52 -3
- data/lib/instantiators/ea_instantiator.rb +0 -39
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'rgen/array_extensions'
|
2
|
+
|
3
|
+
module RGen
|
4
|
+
|
5
|
+
module ModelBuilder
|
6
|
+
|
7
|
+
class ReferenceResolver
|
8
|
+
ResolverJob = Struct.new(:receiver, :reference, :namespace, :string)
|
9
|
+
|
10
|
+
class ResolverException < Exception
|
11
|
+
end
|
12
|
+
|
13
|
+
class ToplevelNamespace
|
14
|
+
def initialize(ns)
|
15
|
+
raise "Namespace must be an Enumerable" unless ns.is_a?(Enumerable)
|
16
|
+
@ns = ns
|
17
|
+
end
|
18
|
+
def elements
|
19
|
+
@ns
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@jobs = []
|
25
|
+
@elementName = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def addJob(job)
|
29
|
+
@jobs << job
|
30
|
+
end
|
31
|
+
|
32
|
+
def setElementName(element, name)
|
33
|
+
@elementName[element] = name
|
34
|
+
end
|
35
|
+
|
36
|
+
def resolve(ns=[])
|
37
|
+
@toplevelNamespace = ToplevelNamespace.new(ns)
|
38
|
+
(@jobs || []).each_with_index do |job, i|
|
39
|
+
target = resolveReference(job.namespace || @toplevelNamespace, job.string.split("."))
|
40
|
+
raise ResolverException.new("Can not resolve reference #{job.string}") unless target
|
41
|
+
if job.reference.many
|
42
|
+
job.receiver.addGeneric(job.reference.name, target)
|
43
|
+
else
|
44
|
+
job.receiver.setGeneric(job.reference.name, target)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# TODO: if a reference can not be fully resolved, but a prefix can be found,
|
52
|
+
# the exception reported is that its first path element can not be found on
|
53
|
+
# toplevel
|
54
|
+
def resolveReference(namespace, nameParts)
|
55
|
+
element = resolveReferenceDownwards(namespace, nameParts)
|
56
|
+
if element.nil? && parentNamespace(namespace)
|
57
|
+
element = resolveReference(parentNamespace(namespace), nameParts)
|
58
|
+
end
|
59
|
+
element
|
60
|
+
end
|
61
|
+
|
62
|
+
def resolveReferenceDownwards(namespace, nameParts)
|
63
|
+
firstPart, *restParts = nameParts
|
64
|
+
element = namespaceElementByName(namespace, firstPart)
|
65
|
+
return nil unless element
|
66
|
+
if restParts.size > 0
|
67
|
+
resolveReferenceDownwards(element, restParts)
|
68
|
+
else
|
69
|
+
element
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def namespaceElementByName(namespace, name)
|
74
|
+
@namespaceElementsByName ||= {}
|
75
|
+
return @namespaceElementsByName[namespace][name] if @namespaceElementsByName[namespace]
|
76
|
+
hash = {}
|
77
|
+
namespaceElements(namespace).each do |e|
|
78
|
+
raise ResolverException.new("Multiple elements named #{elementName(e)} found in #{nsToS(namespace)}") if hash[elementName(e)]
|
79
|
+
hash[elementName(e)] = e if elementName(e)
|
80
|
+
end
|
81
|
+
@namespaceElementsByName[namespace] = hash
|
82
|
+
hash[name]
|
83
|
+
end
|
84
|
+
|
85
|
+
def parentNamespace(namespace)
|
86
|
+
if namespace.class.respond_to?(:ecore)
|
87
|
+
parents = elementParents(namespace)
|
88
|
+
raise ResolverException.new("Element #{nsToS(namespace)} has multiple parents") \
|
89
|
+
if parents.size > 1
|
90
|
+
parents.first || @toplevelNamespace
|
91
|
+
else
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def namespaceElements(namespace)
|
97
|
+
if namespace.is_a?(ToplevelNamespace)
|
98
|
+
namespace.elements
|
99
|
+
elsif namespace.class.respond_to?(:ecore)
|
100
|
+
elementChildren(namespace)
|
101
|
+
else
|
102
|
+
raise ResolverException.new("Element #{nsToS(namespace)} can not be used as a namespace")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def nsToS(namespace)
|
107
|
+
if namespace.is_a?(ToplevelNamespace)
|
108
|
+
"toplevel namespace"
|
109
|
+
else
|
110
|
+
result = namespace.class.name
|
111
|
+
result += ":\"#{elementName(namespace)}\"" if elementName(namespace)
|
112
|
+
result
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def elementName(element)
|
117
|
+
@elementName[element]
|
118
|
+
end
|
119
|
+
|
120
|
+
def elementChildren(element)
|
121
|
+
@elementChildren ||= {}
|
122
|
+
return @elementChildren[element] if @elementChildren[element]
|
123
|
+
children = containmentRefs(element).collect do |r|
|
124
|
+
element.getGeneric(r.name)
|
125
|
+
end.flatten.compact
|
126
|
+
@elementChildren[element] = children
|
127
|
+
end
|
128
|
+
|
129
|
+
def elementParents(element)
|
130
|
+
@elementParents ||= {}
|
131
|
+
return @elementParents[element] if @elementParents[element]
|
132
|
+
parents = parentRefs(element).collect do |r|
|
133
|
+
element.getGeneric(r.name)
|
134
|
+
end.flatten.compact
|
135
|
+
@elementParents[element] = parents
|
136
|
+
end
|
137
|
+
|
138
|
+
def containmentRefs(element)
|
139
|
+
@containmentRefs ||= {}
|
140
|
+
@containmentRefs[element.class] ||= eAllReferences(element).select{|r| r.containment}
|
141
|
+
end
|
142
|
+
|
143
|
+
def parentRefs(element)
|
144
|
+
@parentRefs ||= {}
|
145
|
+
@parentRefs[element.class] ||= eAllReferences(element).select{|r| r.eOpposite && r.eOpposite.containment}
|
146
|
+
end
|
147
|
+
|
148
|
+
def eAllReferences(element)
|
149
|
+
@eAllReferences ||= {}
|
150
|
+
@eAllReferences[element.class] ||= element.class.ecore.eAllReferences
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
@@ -13,6 +13,7 @@ class DirectoryTemplateContainer
|
|
13
13
|
|
14
14
|
def initialize(metamodel=nil, output_path=nil, parent=nil)
|
15
15
|
@containers = {}
|
16
|
+
@directoryContainers = {}
|
16
17
|
@parent = parent
|
17
18
|
@metamodel = metamodel
|
18
19
|
@output_path = output_path
|
@@ -24,7 +25,7 @@ class DirectoryTemplateContainer
|
|
24
25
|
if !File.directory?(qf) && f =~ /^(.*)\.tpl$/
|
25
26
|
(@containers[$1] = TemplateContainer.new(@metamodel, @output_path, self,qf)).load
|
26
27
|
elsif File.directory?(qf) && f != "." && f != ".."
|
27
|
-
(@
|
28
|
+
(@directoryContainers[f] = DirectoryTemplateContainer.new(@metamodel, @output_path, self)).load(qf)
|
28
29
|
end
|
29
30
|
}
|
30
31
|
end
|
@@ -64,9 +65,12 @@ class DirectoryTemplateContainer
|
|
64
65
|
private
|
65
66
|
|
66
67
|
def _expand(template, *all_args)
|
67
|
-
if template =~ /^\/?(
|
68
|
+
if template =~ /^\/?(\w+)::(\w.*)/
|
68
69
|
raise "Template not found: #{$1}" unless @containers[$1]
|
69
70
|
@containers[$1].expand($2, *all_args)
|
71
|
+
elsif template =~ /^\/?(\w+)\/(\w.*)/
|
72
|
+
raise "Template not found: #{$1}" unless @directoryContainers[$1]
|
73
|
+
@directoryContainers[$1].expand($2, *all_args)
|
70
74
|
else
|
71
75
|
raise "Invalid template name: #{template}"
|
72
76
|
end
|
@@ -7,6 +7,7 @@ module TemplateLanguage
|
|
7
7
|
|
8
8
|
class OutputHandler
|
9
9
|
attr_writer :indent
|
10
|
+
attr_accessor :noIndentNextLine
|
10
11
|
|
11
12
|
def initialize(indent=0, indentString=" ", mode=:explicit)
|
12
13
|
self.mode = mode
|
@@ -22,6 +23,7 @@ module TemplateLanguage
|
|
22
23
|
#
|
23
24
|
def concat(s)
|
24
25
|
return @output.concat(s) if s.is_a? OutputHandler
|
26
|
+
#puts [object_id, noIndentNextLine, @state, @output.to_s, s].inspect
|
25
27
|
s = s.to_str.gsub(/^[\t ]*\r?\n/,'') if @ignoreNextNL
|
26
28
|
s = s.to_str.gsub(/^\s+/,'') if @ignoreNextWS
|
27
29
|
@ignoreNextNL = @ignoreNextWS = false if s =~ /\S/
|
@@ -74,10 +76,6 @@ module TemplateLanguage
|
|
74
76
|
@ignoreNextWS = true
|
75
77
|
end
|
76
78
|
|
77
|
-
def noIndentNextLine
|
78
|
-
@noIndentNextLine = true
|
79
|
-
end
|
80
|
-
|
81
79
|
def mode=(m)
|
82
80
|
raise StandardError.new("Unknown mode: #{m}") unless [:direct, :explicit].include?(m)
|
83
81
|
@mode = m
|
@@ -8,208 +8,225 @@ require 'rgen/template_language/template_helper'
|
|
8
8
|
|
9
9
|
module RGen
|
10
10
|
|
11
|
-
module TemplateLanguage
|
12
|
-
|
13
|
-
class TemplateContainer
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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)
|
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)
|
35
24
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
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)
|
35
|
+
end
|
36
|
+
end
|
162
37
|
end
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
38
|
+
|
39
|
+
def expand(template, *all_args)
|
40
|
+
args, params = _splitArgsAndOptions(all_args)
|
41
|
+
if params.has_key?(:foreach)
|
42
|
+
raise StandardError.new("expand :foreach argument is not enumerable") \
|
43
|
+
unless params[:foreach].is_a?(Enumerable)
|
44
|
+
_expand_foreach(template, args, params)
|
45
|
+
else
|
46
|
+
_expand(template, args, params)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def evaluate(template, *all_args)
|
51
|
+
args, params = _splitArgsAndOptions(all_args)
|
52
|
+
raise StandardError.new(":foreach can not be used with evaluate") if params[:foreach]
|
53
|
+
_expand(template, args, params.merge({:_evalOnly => true}))
|
54
|
+
end
|
55
|
+
|
56
|
+
def this
|
57
|
+
@context
|
58
|
+
end
|
59
|
+
|
60
|
+
def method_missing(name, *args)
|
61
|
+
@context.send(name, *args)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.const_missing(name)
|
65
|
+
super unless @@metamodels
|
66
|
+
@@metamodels.each do |mm|
|
67
|
+
return mm.const_get(name) rescue NameError
|
68
|
+
end
|
69
|
+
super
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def nonl
|
75
|
+
@output.ignoreNextNL
|
76
|
+
end
|
77
|
+
|
78
|
+
def nows
|
79
|
+
@output.ignoreNextWS
|
80
|
+
end
|
81
|
+
|
82
|
+
def nl
|
83
|
+
_direct_concat(@newLinePattern)
|
84
|
+
end
|
85
|
+
|
86
|
+
def ws
|
87
|
+
_direct_concat(" ")
|
88
|
+
end
|
89
|
+
|
90
|
+
def iinc
|
91
|
+
@indent += 1
|
92
|
+
@output.indent = @indent
|
93
|
+
end
|
94
|
+
|
95
|
+
def idec
|
96
|
+
@indent -= 1 if @indent > 0
|
97
|
+
@output.indent = @indent
|
98
|
+
end
|
99
|
+
|
100
|
+
TemplateDesc = Struct.new(:block, :local)
|
101
|
+
|
102
|
+
def define(template, params={}, &block)
|
103
|
+
_define(template, params, &block)
|
104
|
+
end
|
105
|
+
|
106
|
+
def define_local(template, params={}, &block)
|
107
|
+
_define(template, params.merge({:local => true}), &block)
|
108
|
+
end
|
109
|
+
|
110
|
+
def file(name, indentString=nil)
|
111
|
+
old_output, @output = @output, OutputHandler.new(@indent, indentString || @parent.indentString)
|
177
112
|
begin
|
178
|
-
|
179
|
-
proc.call(*args)
|
113
|
+
yield
|
180
114
|
rescue Exception => e
|
181
|
-
processAndRaise(e
|
115
|
+
processAndRaise(e)
|
182
116
|
end
|
183
|
-
|
117
|
+
path = ""
|
118
|
+
path += @output_path+"/" if @output_path
|
119
|
+
dirname = File.dirname(path+name)
|
120
|
+
FileUtils.makedirs(dirname) unless File.exist?(dirname)
|
121
|
+
File.open(path+name,"wb") { |f| f.write(@output) }
|
122
|
+
@output = old_output
|
184
123
|
end
|
124
|
+
|
125
|
+
# private private
|
126
|
+
|
127
|
+
def _define(template, params={}, &block)
|
128
|
+
@templates[template] ||= {}
|
129
|
+
cls = params[:for] || Object
|
130
|
+
@templates[template][cls] = TemplateDesc.new(block, params[:local])
|
131
|
+
end
|
132
|
+
|
133
|
+
def _expand_foreach(template, args, params)
|
134
|
+
sep = params[:separator]
|
135
|
+
params[:foreach].each_with_index {|e,i|
|
136
|
+
_direct_concat(sep.to_s) if sep && i > 0
|
137
|
+
output = _expand(template, args, params.merge({:for => e}))
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
LOCAL_TEMPLATE_REGEX = /^:*(\w+)$/
|
142
|
+
|
143
|
+
def _expand(template, args, params)
|
144
|
+
raise StandardError.new("expand :for argument evaluates to nil") if params.has_key?(:for) && params[:for].nil?
|
145
|
+
context = params[:for]
|
146
|
+
@indent = params[:indent] || @indent
|
147
|
+
noIndentNextLine = params[:_noIndentNextLine] ||
|
148
|
+
(@output.is_a?(OutputHandler) && @output.noIndentNextLine) ||
|
149
|
+
(@output.to_s.size > 0 && @output.to_s[-1] != "\n"[0])
|
150
|
+
caller = params[:_caller] || self
|
151
|
+
old_context, @context = @context, context if context
|
152
|
+
local_output = nil
|
153
|
+
if template =~ LOCAL_TEMPLATE_REGEX
|
154
|
+
tplname = $1
|
155
|
+
raise StandardError.new("Template not found: #{$1}") unless @templates[tplname]
|
156
|
+
old_output, @output = @output, OutputHandler.new(@indent, @parent.indentString)
|
157
|
+
@output.noIndentNextLine = noIndentNextLine
|
158
|
+
_call_template(tplname, @context, args, caller == self)
|
159
|
+
old_output.noIndentNextLine = false if old_output.is_a?(OutputHandler) && !old_output.noIndentNextLine
|
160
|
+
local_output, @output = @output, old_output
|
161
|
+
else
|
162
|
+
local_output = @parent.expand(template, *(args.dup << {:for => @context, :indent => @indent, :_noIndentNextLine => noIndentNextLine, :_evalOnly => true, :_caller => caller}))
|
163
|
+
end
|
164
|
+
_direct_concat(local_output) unless params[:_evalOnly]
|
165
|
+
@context = old_context if old_context
|
166
|
+
local_output.to_s
|
167
|
+
end
|
168
|
+
|
169
|
+
def processAndRaise(e, tpl=nil)
|
170
|
+
bt = e.backtrace.dup
|
171
|
+
e.backtrace.each_with_index do |t,i|
|
172
|
+
if t =~ /\(erb\):(\d+):/
|
173
|
+
bt[i] = "#{@filename}:#{$1}"
|
174
|
+
bt[i] += ":in '#{tpl}'" if tpl
|
175
|
+
break
|
176
|
+
end
|
177
|
+
end
|
178
|
+
raise e, e.to_s, bt
|
179
|
+
end
|
180
|
+
|
181
|
+
def _call_template(tpl, context, args, localCall)
|
182
|
+
found = false
|
183
|
+
@templates[tpl].each_pair do |key, value|
|
184
|
+
if context.is_a?(key)
|
185
|
+
templateDesc = @templates[tpl][key]
|
186
|
+
proc = templateDesc.block
|
187
|
+
arity = proc.arity
|
188
|
+
arity = 0 if arity == -1 # if no args are given
|
189
|
+
raise StandardError.new("Wrong number of arguments calling template #{tpl}: #{args.size} for #{arity} "+
|
190
|
+
"(Beware: Hashes as last arguments are taken as options and are ignored)") \
|
191
|
+
if arity != args.size
|
192
|
+
raise StandardError.new("Template can only be called locally: #{tpl}") \
|
193
|
+
if templateDesc.local && !localCall
|
194
|
+
begin
|
195
|
+
@@metamodels = @metamodels
|
196
|
+
proc.call(*args)
|
197
|
+
rescue Exception => e
|
198
|
+
processAndRaise(e, tpl)
|
199
|
+
end
|
200
|
+
found = true
|
201
|
+
end
|
202
|
+
end
|
203
|
+
raise StandardError.new("Template class not matching: #{tpl} for #{context.class.name}") unless found
|
204
|
+
end
|
205
|
+
|
206
|
+
def _direct_concat(s)
|
207
|
+
if @output.is_a? OutputHandler
|
208
|
+
@output.direct_concat(s)
|
209
|
+
else
|
210
|
+
@output << s
|
211
|
+
end
|
212
|
+
end
|
185
213
|
|
214
|
+
def _detectNewLinePattern(text)
|
215
|
+
tests = 0
|
216
|
+
rnOccurances = 0
|
217
|
+
text.scan(/(\r?)\n/) do |groups|
|
218
|
+
tests += 1
|
219
|
+
rnOccurances += 1 if groups[0] == "\r"
|
220
|
+
break if tests >= 10
|
221
|
+
end
|
222
|
+
if rnOccurances > (tests / 2)
|
223
|
+
@newLinePattern = "\r\n"
|
224
|
+
else
|
225
|
+
@newLinePattern = "\n"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
186
229
|
end
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
def _direct_concat(s)
|
191
|
-
if @output.is_a? OutputHandler
|
192
|
-
@output.direct_concat(s)
|
193
|
-
else
|
194
|
-
@output << s
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def _detectNewLinePattern(text)
|
199
|
-
tests = 0
|
200
|
-
rnOccurances = 0
|
201
|
-
text.scan(/(\r?)\n/) do |groups|
|
202
|
-
tests += 1
|
203
|
-
rnOccurances += 1 if groups[0] == "\r"
|
204
|
-
break if tests >= 10
|
205
|
-
end
|
206
|
-
if rnOccurances > (tests / 2)
|
207
|
-
@newLinePattern = "\r\n"
|
208
|
-
else
|
209
|
-
@newLinePattern = "\n"
|
210
|
-
end
|
230
|
+
|
211
231
|
end
|
212
|
-
end
|
213
|
-
|
214
|
-
end
|
215
232
|
|
216
233
|
end
|