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