tla-trace-filter 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.org +66 -0
- data/VERSION +1 -0
- data/bin/tla-trace-filter.rb +5 -0
- data/lib/cli/cli.rb +563 -0
- data/lib/filter/filter.rb +134 -0
- data/lib/parser/grammar.treetop +132 -0
- data/lib/parser/node_extensions.rb +267 -0
- data/lib/parser/parser.rb +85 -0
- data/lib/render/render.rb +510 -0
- data/lib/tla-trace-filter.rb +6 -0
- data/lib/util/logger.rb +82 -0
- data/mustache/add-links-interface.mustache +33 -0
- data/mustache/add-links-state-dump.mustache +28 -0
- data/mustache/add-links-transition.mustache +14 -0
- data/mustache/add-links.mustache +43 -0
- data/mustache/api-call-default.mustache +14 -0
- data/mustache/api-call-init.mustache +70 -0
- data/mustache/api-call-input.mustache +20 -0
- data/mustache/api-call-link.mustache +2 -0
- data/mustache/api-call-main.mustache +86 -0
- data/mustache/api-call-output.mustache +18 -0
- data/mustache/api-call-return.mustache +13 -0
- data/mustache/api-call.mustache +34 -0
- data/spec/cli/cli_spec.rb +73 -0
- data/spec/filter/filter_spec.rb +53 -0
- data/spec/fixtures/interfaces.yaml +22 -0
- data/spec/fixtures/model.tla +1195 -0
- data/spec/fixtures/trace.txt +102 -0
- data/spec/parser/node_extensions_spec.rb +9 -0
- data/spec/parser/parser_spec.rb +392 -0
- data/spec/render/render_spec.rb +177 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/test_spec.rb +8 -0
- data/tla-trace-filter.gemspec +45 -0
- metadata +171 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "treetop"
|
3
|
+
|
4
|
+
require File.join( File.dirname( __FILE__), 'node_extensions.rb')
|
5
|
+
|
6
|
+
module TlaTraceFilter
|
7
|
+
module Parser
|
8
|
+
|
9
|
+
class ParseException < Exception; end
|
10
|
+
|
11
|
+
class Parser
|
12
|
+
|
13
|
+
# @# @!attribute [TlaTracefilter::Parser::Parser] parser
|
14
|
+
# Load the Treetop grammar from the 'sexp_parser' file, and
|
15
|
+
# create a new instance of that parser as a class variable
|
16
|
+
# so we don't have to re-create it every time we need to
|
17
|
+
# parse a string
|
18
|
+
@@parser = nil
|
19
|
+
|
20
|
+
def initialize( options={} )
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.parser_instance
|
24
|
+
return @@parser if @@parser
|
25
|
+
grammarPath = File.join( File.dirname( __FILE__), "grammar.treetop")
|
26
|
+
Treetop.load( grammarPath )
|
27
|
+
@@parser = TlaTraceFilter::Parser::GrammarParser.new
|
28
|
+
end
|
29
|
+
|
30
|
+
# ------------------------------------------------------------------
|
31
|
+
# @!group Services
|
32
|
+
|
33
|
+
# Parse 'data' starting with symbol start.
|
34
|
+
#
|
35
|
+
# @param start [Symbol] treetop grammar rule where to start
|
36
|
+
#
|
37
|
+
# @return [SyntaxNode] Parser tree
|
38
|
+
def parse( data, start = nil )
|
39
|
+
parser = self.class.parser_instance
|
40
|
+
tree = parser.parse(data, :root=>start )
|
41
|
+
|
42
|
+
# If the AST is nil then there was an error during parsing
|
43
|
+
# we need to report a simple error message to help the user
|
44
|
+
if(tree.nil?)
|
45
|
+
# adopted from http://whitequark.org/blog/2011/09/08/treetop-typical-errors/
|
46
|
+
parser.failure_reason =~ /(Expected .*) after/m
|
47
|
+
expected = $1.nil? ? parser.failure_reason : $1
|
48
|
+
msg= <<~EOS
|
49
|
+
Parse error:
|
50
|
+
Line : #{parser.failure_line}, offset : #{parser.index}
|
51
|
+
#{expected.gsub( "\n", '$NEWLINE')}
|
52
|
+
#{data.lines.to_a[ parser.failure_line()-1 ]}
|
53
|
+
#{'~' * (parser.failure_column-1)}^
|
54
|
+
EOS
|
55
|
+
# puts msg
|
56
|
+
raise ParseException.new msg
|
57
|
+
end
|
58
|
+
|
59
|
+
# self.class.clean_tree( tree )
|
60
|
+
|
61
|
+
tree
|
62
|
+
end
|
63
|
+
|
64
|
+
# @!endgroup
|
65
|
+
|
66
|
+
# ------------------------------------------------------------------
|
67
|
+
# @!group prvate helpser
|
68
|
+
|
69
|
+
# we have created a tree from our input, but it has a lot of
|
70
|
+
# extraneous nodes that we don’t need or care about. Let’s put in
|
71
|
+
# a system for cleaning up the tree:
|
72
|
+
def self.clean_tree(root_node)
|
73
|
+
return if(root_node.elements.nil?)
|
74
|
+
# comment the following line if parse loosees nodes
|
75
|
+
root_node.elements.delete_if{|node| node.class.name == "Treetop::Runtime::SyntaxNode" }
|
76
|
+
root_node.elements.each {|node| self.clean_tree(node) }
|
77
|
+
end
|
78
|
+
|
79
|
+
# @!endgroup
|
80
|
+
|
81
|
+
|
82
|
+
end # class parser
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,510 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require "mustache"
|
3
|
+
require "json"
|
4
|
+
require "yaml"
|
5
|
+
module TlaTraceFilter
|
6
|
+
|
7
|
+
|
8
|
+
class RenderException < Exception; end
|
9
|
+
|
10
|
+
|
11
|
+
class Render < Mustache
|
12
|
+
|
13
|
+
include TlaTraceFilter::Util::MyLogger
|
14
|
+
|
15
|
+
# ------------------------------------------------------------------
|
16
|
+
# @!group Constants
|
17
|
+
|
18
|
+
# Default templates for inputState, call, and outputState
|
19
|
+
API_INPUT_STATE_DEFAULT_PARTIAL = "api-call-input"
|
20
|
+
API_CALL_DEFAULT_PARTIAL = "api-call-default"
|
21
|
+
API_RETURN_DEFAULT_PARTIAL = "api-call-return"
|
22
|
+
API_OUTPUT_STATE_DEFAULT_PARTIAL = "api-call-output"
|
23
|
+
|
24
|
+
# Keys mapping to the output templates
|
25
|
+
API_DEFAULT_KEY = "default"
|
26
|
+
API_EMPTY_KEY = "empty"
|
27
|
+
|
28
|
+
# @!endgroup
|
29
|
+
|
30
|
+
|
31
|
+
# ------------------------------------------------------------------
|
32
|
+
# @!group Attributes
|
33
|
+
|
34
|
+
# @# @!attribute [Hash] hash mapping partial names to mustache templates
|
35
|
+
attr_accessor :partials
|
36
|
+
|
37
|
+
# @# @!attribute [Array] templatePath array of path to search for
|
38
|
+
# templates
|
39
|
+
attr_accessor :templatePaths
|
40
|
+
|
41
|
+
# @# @!attribute [Hash] callPartials hash mapping interface-names
|
42
|
+
# (with default) to partial name
|
43
|
+
attr_accessor :callPartials
|
44
|
+
|
45
|
+
# @# @!attribute [Hash] returnPartials hash mapping interface-names
|
46
|
+
# (with default) to partial name
|
47
|
+
attr_accessor :returnPartials
|
48
|
+
|
49
|
+
# @# @!attribute [Hash] inputStatePartials hash mapping interface-names
|
50
|
+
# (with default) to partial name
|
51
|
+
attr_accessor :inputStatePartials
|
52
|
+
|
53
|
+
# @# @!attribute [Hash] outputStatePartials hash mapping interface-names
|
54
|
+
# (with default) to partial name
|
55
|
+
attr_accessor :outputStatePartials
|
56
|
+
|
57
|
+
# @!endgroup
|
58
|
+
|
59
|
+
|
60
|
+
# ------------------------------------------------------------------
|
61
|
+
# @!group Constructor
|
62
|
+
|
63
|
+
def initialize( options = {} )
|
64
|
+
# super
|
65
|
+
@logger = getLogger( nil, options )
|
66
|
+
@logger.info "#{__method__}: initalized"
|
67
|
+
|
68
|
+
configMustache( options )
|
69
|
+
|
70
|
+
initPartials
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def configMustache( options )
|
75
|
+
|
76
|
+
# exception for non existing reference
|
77
|
+
self.raise_on_context_miss=options[:debug_mustache]
|
78
|
+
|
79
|
+
# default search only GEM templates
|
80
|
+
self.templatePaths = [ File.join( File.dirname(__FILE__), "../../mustache/") ]
|
81
|
+
# user defined template search path prepended
|
82
|
+
self.templatePaths = [ options[:mustache] ] + templatePaths if options[:mustache]
|
83
|
+
end
|
84
|
+
|
85
|
+
def initPartials
|
86
|
+
self.partials = {}
|
87
|
+
API_CALL_INIT( "" )
|
88
|
+
API_RETURN_INIT( "" )
|
89
|
+
API_INPUT_STATE_INIT( "" )
|
90
|
+
API_OUTPUT_STATE_INIT( "" )
|
91
|
+
# self.callPartials = {}
|
92
|
+
# self.inputStatePartials = {}
|
93
|
+
# self.outputStatePartials = {}
|
94
|
+
end
|
95
|
+
|
96
|
+
# @!endgroup
|
97
|
+
|
98
|
+
# ------------------------------------------------------------------
|
99
|
+
# @!group Initialize dynamic dispatchers
|
100
|
+
|
101
|
+
# Lambda to configure API_CALL dynamic dispatch. If no data given
|
102
|
+
# results calling to default templates
|
103
|
+
def API_CALL_INIT( data )
|
104
|
+
@logger.info "#{__method__}: data=#{data}"
|
105
|
+
begin
|
106
|
+
self.callPartials = data.nil? || data == "" ? {} : YAML.load( data )
|
107
|
+
rescue Exception => e
|
108
|
+
msg = <<-EOS
|
109
|
+
#{e}
|
110
|
+
|
111
|
+
Error parsing YAML data in API_CALL_INIT:
|
112
|
+
|
113
|
+
#{data}
|
114
|
+
EOS
|
115
|
+
@logger.error( "#{__method__}: #{msg}" )
|
116
|
+
raise Exception.new, msg, e.backtrace
|
117
|
+
end
|
118
|
+
|
119
|
+
@logger.debug "#{__method__}: callPartials=#{callPartials}" if @logger.debug?
|
120
|
+
|
121
|
+
# ensure that 'default' and 'empty' partials are defined
|
122
|
+
self.callPartials[API_DEFAULT_KEY] = API_CALL_DEFAULT_PARTIAL if callPartials[API_DEFAULT_KEY].nil?
|
123
|
+
self.callPartials[API_EMPTY_KEY] = API_CALL_DEFAULT_PARTIAL if callPartials[API_EMPTY_KEY].nil?
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# Initiliaze template api return templates. If no data given
|
129
|
+
# results calling to default templates
|
130
|
+
def API_RETURN_INIT( data )
|
131
|
+
|
132
|
+
@logger.info "#{__method__}: data=#{data}"
|
133
|
+
begin
|
134
|
+
self.returnPartials = data.nil? || data == "" ? {} : YAML.load( data )
|
135
|
+
rescue Exception => e
|
136
|
+
msg = <<-EOS
|
137
|
+
#{e}
|
138
|
+
|
139
|
+
Error parsing YAML data in API_RETURN_INIT:
|
140
|
+
|
141
|
+
#{data}
|
142
|
+
EOS
|
143
|
+
@logger.error( "#{__method__}: #{msg}" )
|
144
|
+
raise Exception.new, msg, e.backtrace
|
145
|
+
end
|
146
|
+
|
147
|
+
@logger.debug "#{__method__}: returnPartials=#{returnPartials}" if @logger.debug?
|
148
|
+
|
149
|
+
# ensure that 'default' and 'empty' partials are defined
|
150
|
+
self.returnPartials[API_DEFAULT_KEY] = API_RETURN_DEFAULT_PARTIAL if returnPartials[API_DEFAULT_KEY].nil?
|
151
|
+
self.returnPartials[API_EMPTY_KEY] = API_RETURN_DEFAULT_PARTIAL if returnPartials[API_EMPTY_KEY].nil?
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
# Initiliaze template calls. If no data given results calling to
|
156
|
+
# default templates
|
157
|
+
def API_INPUT_STATE_INIT( data)
|
158
|
+
@logger.info "#{__method__}: data=#{data}"
|
159
|
+
begin
|
160
|
+
self.inputStatePartials = data.nil? || data == "" ? {} : YAML.load( data )
|
161
|
+
rescue Exception => e
|
162
|
+
msg = <<-EOS
|
163
|
+
#{e}
|
164
|
+
|
165
|
+
Error parsing YAML data in API_INPUT_STATE_INIT:
|
166
|
+
|
167
|
+
#{data}
|
168
|
+
EOS
|
169
|
+
@logger.error( "#{__method__}: #{msg}" )
|
170
|
+
raise Exception.new, msg, e.backtrace
|
171
|
+
end
|
172
|
+
|
173
|
+
@logger.debug "#{__method__}: inputStatePartials=#{inputStatePartials}" if @logger.debug?
|
174
|
+
|
175
|
+
# ensure that 'default' and 'empty' partials are defined
|
176
|
+
self.inputStatePartials[API_DEFAULT_KEY] = API_INPUT_STATE_DEFAULT_PARTIAL if inputStatePartials[API_DEFAULT_KEY].nil?
|
177
|
+
self.inputStatePartials[API_EMPTY_KEY] = API_OUTPUT_STATE_DEFAULT_PARTIAL if inputStatePartials[API_EMPTY_KEY].nil?
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
# Lambda to initiliaze template calls. If no data given results
|
182
|
+
# calling to default templates
|
183
|
+
def API_OUTPUT_STATE_INIT( data)
|
184
|
+
@logger.info "#{__method__}: data=#{data}"
|
185
|
+
begin
|
186
|
+
self.outputStatePartials = data.nil? || data == "" ? {} : YAML.load( data )
|
187
|
+
rescue Exception => e
|
188
|
+
msg = <<-EOS
|
189
|
+
#{e}
|
190
|
+
|
191
|
+
Error parsing YAML data in API_INIT:
|
192
|
+
|
193
|
+
#{data}
|
194
|
+
EOS
|
195
|
+
@logger.error( "#{__method__}: #{msg}" )
|
196
|
+
raise Exception.new, msg, e.backtrace
|
197
|
+
end
|
198
|
+
|
199
|
+
@logger.debug "#{__method__}: outputStatePartials=#{outputStatePartials}" if @logger.debug?
|
200
|
+
|
201
|
+
# ensure that 'default' and 'empty' partials are defined
|
202
|
+
self.outputStatePartials[API_DEFAULT_KEY] = API_OUTPUT_STATE_DEFAULT_PARTIAL if outputStatePartials[API_DEFAULT_KEY].nil?
|
203
|
+
self.outputStatePartials[API_EMPTY_KEY] = API_OUTPUT_STATE_DEFAULT_PARTIAL if outputStatePartials[API_EMPTY_KEY].nil?
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
# @return [String] name of partial template to render API-return for
|
209
|
+
# interfaceOperation, use default if not found
|
210
|
+
#
|
211
|
+
# Implementation makes a lookup to returnPartials
|
212
|
+
def getReturnPartialName( interfaceOperation ) #
|
213
|
+
returnPartialName = nil
|
214
|
+
returnPartialName = returnPartials[API_EMPTY_KEY] if interfaceOperation.nil?
|
215
|
+
returnPartialName = returnPartials[interfaceOperation] if returnPartialName.nil?
|
216
|
+
returnPartialName = returnPartials[API_DEFAULT_KEY] if returnPartialName.nil?
|
217
|
+
raise "Missing could not resolve '#{interfaceOperation}' in returnPartials #{returnPartials}" if returnPartialName.nil?
|
218
|
+
@logger.info "#{__method__}: API-return to interfaceOperation '#{interfaceOperation}' render with '#{returnPartialName}'"
|
219
|
+
returnPartialName
|
220
|
+
end
|
221
|
+
|
222
|
+
# @return [String] name of partial template to render API-call for
|
223
|
+
# interfaceOperation, use default if not found
|
224
|
+
#
|
225
|
+
# Implementation makes a lookup to callPartials
|
226
|
+
def getCallPartialName( interfaceOperation ) #
|
227
|
+
|
228
|
+
callPartialName = nil
|
229
|
+
callPartialName = callPartials[API_EMPTY_KEY] if interfaceOperation.nil?
|
230
|
+
callPartialName = callPartials[interfaceOperation] if callPartialName.nil?
|
231
|
+
callPartialName = callPartials[API_DEFAULT_KEY] if callPartialName.nil?
|
232
|
+
raise "Missing could not resolve '#{interfaceOperation}' in callPartials #{callPartials}" if callPartialName.nil?
|
233
|
+
|
234
|
+
@logger.info "#{__method__}: API-call to interfaceOperation '#{interfaceOperation}' render with '#{callPartialName}'"
|
235
|
+
callPartialName
|
236
|
+
end
|
237
|
+
|
238
|
+
def getInputStatePartialName( interfaceOperation )
|
239
|
+
inputStatePartialName = nil
|
240
|
+
inputStatePartialName = inputStatePartials[API_EMPTY_KEY] if interfaceOperation.nil?
|
241
|
+
inputStatePartialName = inputStatePartials[interfaceOperation] if inputStatePartialName.nil?
|
242
|
+
inputStatePartialName = inputStatePartials[API_DEFAULT_KEY] if inputStatePartialName.nil?
|
243
|
+
raise "Missing could not resolve '#{interfaceOperation}' in inputStatePartials #{inputStatePartials}" if inputStatePartialName.nil?
|
244
|
+
|
245
|
+
@logger.info "#{__method__}: API-call to interfaceOperation '#{interfaceOperation}' render with '#{inputStatePartialName}'"
|
246
|
+
inputStatePartialName
|
247
|
+
end
|
248
|
+
|
249
|
+
def getOutputStatePartialName( interfaceOperation )
|
250
|
+
outputStatePartialName = nil
|
251
|
+
outputStatePartialName = outputStatePartials[API_EMPTY_KEY] if interfaceOperation.nil?
|
252
|
+
outputStatePartialName = outputStatePartials[interfaceOperation] if outputStatePartialName.nil?
|
253
|
+
outputStatePartialName = outputStatePartials[API_DEFAULT_KEY] if outputStatePartialName.nil?
|
254
|
+
raise "Missing could not resolve '#{interfaceOperation}' in outputStatePartials #{outputStatePartials}" if outputStatePartialName.nil?
|
255
|
+
|
256
|
+
@logger.info "#{__method__}: API-call to interfaceOperation '#{interfaceOperation}' render with '#{outputStatePartialName}'"
|
257
|
+
outputStatePartialName
|
258
|
+
end
|
259
|
+
|
260
|
+
# @!endgroup
|
261
|
+
|
262
|
+
|
263
|
+
# ------------------------------------------------------------------
|
264
|
+
# @!group Mustache actions
|
265
|
+
|
266
|
+
|
267
|
+
# @return [Integer] line number correspoding character
|
268
|
+
# 'interface.source.sourceLine' in file
|
269
|
+
# 'options.src_dir'/'interface.source.sourceModule', 0 if path
|
270
|
+
# not found
|
271
|
+
def SOLC_LINE( data=nil )
|
272
|
+
|
273
|
+
# Access mustache context
|
274
|
+
options = context[:options]
|
275
|
+
interface = context[:interface]
|
276
|
+
|
277
|
+
@logger.debug "#{__method__}: options=#{options}, interface #{interface}" if @logger.debug?
|
278
|
+
|
279
|
+
|
280
|
+
# options defines valid data
|
281
|
+
return 0 unless options && options["src_dir"] && File.exists?( options["src_dir"] )
|
282
|
+
|
283
|
+
return 0 unless interface && interface[:source] && interface[:source][:sourceModule] && File.exists?( File.join( options["src_dir"], interface[:source][:sourceModule] ))
|
284
|
+
|
285
|
+
fileName = File.join( options["src_dir"], interface[:source][:sourceModule] )
|
286
|
+
# now possible access line
|
287
|
+
characters = 0
|
288
|
+
lineCount = 0
|
289
|
+
File.open( fileName ).each do |line|
|
290
|
+
# count characters && increment line number
|
291
|
+
characters += line.length
|
292
|
+
lineCount += 1
|
293
|
+
break if characters > interface[:source][:sourceLine]
|
294
|
+
end
|
295
|
+
@logger.info "#{__method__}: lineCount=#{lineCount} for "
|
296
|
+
# number of 'characters' mapped to lineCount
|
297
|
+
lineCount
|
298
|
+
end
|
299
|
+
|
300
|
+
# Lamba called for 'API_INPUT_STATE' to dispatch dynamically rendering of
|
301
|
+
# [:interface][:interface_operation] inputState.
|
302
|
+
def API_INPUT_STATE
|
303
|
+
@logger.info "#{__method__}: [:interface][:interface_operation]=#{context[:interface][:interface_operation]}, now=#{context[:now]}"
|
304
|
+
callPartialName = getInputStatePartialName( context[:interface][:interface_operation] )
|
305
|
+
template = partial( callPartialName )
|
306
|
+
render( template, context )
|
307
|
+
end
|
308
|
+
|
309
|
+
# Lamba called for 'API_OUTPUT_STATE' to dispatch dynamically rendering of
|
310
|
+
# [:interface][:interface_operation] outputState.
|
311
|
+
def API_OUTPUT_STATE
|
312
|
+
@logger.info "#{__method__}: [:interface][:interface_operation]=#{context[:interface][:interface_operation]} now=#{context[:now]}"
|
313
|
+
callPartialName = getOutputStatePartialName( context[:interface][:interface_operation] )
|
314
|
+
template = partial( callPartialName )
|
315
|
+
render( template, context )
|
316
|
+
end
|
317
|
+
|
318
|
+
def API_RETURN
|
319
|
+
|
320
|
+
interfaceOperation = context[:interface][:interface_operation]
|
321
|
+
responseKey = context[:interface][:response_key]
|
322
|
+
|
323
|
+
# partial access like Bank(saveAccout)
|
324
|
+
callPartialName = getReturnPartialName( interfaceOperation )
|
325
|
+
template = partial( callPartialName )
|
326
|
+
|
327
|
+
# context access likke i_Bank_saveAccount_
|
328
|
+
# raise "keys=#{context[:outputState][:responses].to_yaml}"
|
329
|
+
context[:api_return] = context[:outputState][:responses][responseKey]
|
330
|
+
|
331
|
+
render( template, context )
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
|
336
|
+
|
337
|
+
# Mustache lamba to render API calls with input data.
|
338
|
+
#
|
339
|
+
# Lambda depends on context having corect information.
|
340
|
+
#
|
341
|
+
# context[:state_space][:step] ->
|
342
|
+
#
|
343
|
+
def API_CALL( data=nil)
|
344
|
+
# partialName = data || context[:interface][:interface_operation] if context && context[:interface]
|
345
|
+
# state_space = context[:parsed][:state_space] if context && context[:parsed]
|
346
|
+
# raise "Missing callPartial - error in API_INIT?" if callPartial.nil?
|
347
|
+
# return "" if state_space.nil?
|
348
|
+
|
349
|
+
callPartialName = getCallPartialName( context[:interface][:interface_operation] )
|
350
|
+
template = partial( callPartialName )
|
351
|
+
|
352
|
+
# # string procedure input variables ends with
|
353
|
+
# api = "#{context[:interface][:interface_name]}_input"
|
354
|
+
|
355
|
+
# # find name of procedure input varibable
|
356
|
+
# api = context[:parsed][:state_space].keys.find { |k| k.to_s.end_with?( api ) } unless api.nil?
|
357
|
+
|
358
|
+
# # access procedure input data
|
359
|
+
# api = context[:parsed][:state_space][api] unless api.nil?
|
360
|
+
|
361
|
+
# # access procedure input for currently running interface opertaion
|
362
|
+
# api = api[context[:interface][:interface_operation]] unless api.nil?
|
363
|
+
|
364
|
+
# # create context
|
365
|
+
# context[:api_input] = api
|
366
|
+
|
367
|
+
context[:api_input] =
|
368
|
+
|
369
|
+
if context[:parsed] && context[:parsed][:state_space] && context[:parsed][:state_space][:step_input]
|
370
|
+
context[:parsed][:state_space][:step_input]
|
371
|
+
else
|
372
|
+
|
373
|
+
api = "#{context[:interface][:interface_name]}_input"
|
374
|
+
|
375
|
+
# find name of procedure input varibable
|
376
|
+
api = context[:parsed][:state_space].keys.find { |k| k.to_s.end_with?( api ) } unless api.nil?
|
377
|
+
|
378
|
+
# access procedure input data
|
379
|
+
api = context[:parsed][:state_space][api] unless api.nil?
|
380
|
+
|
381
|
+
# access procedure input for currently running interface opertaion
|
382
|
+
api = api[context[:interface][:interface_operation]] unless api.nil?
|
383
|
+
|
384
|
+
api = { :error => "No input found in context[:parsed][:state_space][:step_input] - maybe set 'SetStepInput = TRUE'"} if api.nil?
|
385
|
+
|
386
|
+
api
|
387
|
+
end
|
388
|
+
|
389
|
+
# render output
|
390
|
+
render( template, context )
|
391
|
+
end
|
392
|
+
|
393
|
+
|
394
|
+
# @!endgroup
|
395
|
+
|
396
|
+
|
397
|
+
|
398
|
+
# ------------------------------------------------------------------
|
399
|
+
# @!group Mustache extesion points
|
400
|
+
|
401
|
+
# Override from mustache.rb to use my 'get_partial'.
|
402
|
+
def partial(name)
|
403
|
+
get_partial(name)
|
404
|
+
end
|
405
|
+
|
406
|
+
|
407
|
+
# @!endgroup
|
408
|
+
|
409
|
+
|
410
|
+
# ------------------------------------------------------------------
|
411
|
+
# @!group Service intefaces
|
412
|
+
|
413
|
+
# @param partial [String] name of partial for rendering
|
414
|
+
# @param data [Hash] hash to render
|
415
|
+
def render_str( template, data )
|
416
|
+
render( template, data )
|
417
|
+
end
|
418
|
+
|
419
|
+
# @!endgroup
|
420
|
+
|
421
|
+
# ------------------------------------------------------------------
|
422
|
+
# @!group Service implementation
|
423
|
+
|
424
|
+
# Return cached partial, use {#read_partial} to read if not
|
425
|
+
# defined
|
426
|
+
#
|
427
|
+
# @param name [String] partial name to read
|
428
|
+
def get_partial(name)
|
429
|
+
return partials[name] if partials[name]
|
430
|
+
@logger.info "#{__method__}: reading partial #{name}"
|
431
|
+
|
432
|
+
self.partials[name] = read_partial(name)
|
433
|
+
@logger.debug "#{__method__}: partial #{name} --> #{partials[name]}" if @logger.debug?
|
434
|
+
|
435
|
+
partials[name]
|
436
|
+
end
|
437
|
+
|
438
|
+
# Read partial with name 'name'
|
439
|
+
#
|
440
|
+
# @param name [String] name of partial to read
|
441
|
+
def read_partial(name)
|
442
|
+
|
443
|
+
tName = templateName(name)
|
444
|
+
templatePaths.each do |path|
|
445
|
+
|
446
|
+
# read from file (ends with / ) or from gem-directory
|
447
|
+
content = if path[-1] == '/'
|
448
|
+
read_partial_file( path, tName )
|
449
|
+
else
|
450
|
+
read_gem_partial_file( path, tName )
|
451
|
+
end
|
452
|
+
return content unless content.nil?
|
453
|
+
end
|
454
|
+
|
455
|
+
# Error if not found, else read file content
|
456
|
+
raise <<-EOS
|
457
|
+
Could not find template '#{name}' in directories #{templatePaths.join(',')}
|
458
|
+
EOS
|
459
|
+
|
460
|
+
end
|
461
|
+
|
462
|
+
# @return [String,nil] read content of file 'path/templateName',
|
463
|
+
# nil if not found
|
464
|
+
def read_partial_file( path, templateName )
|
465
|
+
raise RenderException.new "Expected '#{path}' to end with / character" unless path[-1,1] == '/'
|
466
|
+
filePath = File.join( path, templateName )
|
467
|
+
return File.read( filePath ) if File.exist? filePath
|
468
|
+
end
|
469
|
+
|
470
|
+
def templateName( name )
|
471
|
+
"#{name}.mustache"
|
472
|
+
end
|
473
|
+
|
474
|
+
|
475
|
+
# # @return [Array<String>] array of template paths
|
476
|
+
# def templatePaths
|
477
|
+
# ["/tmp", File.join( File.dirname(__FILE__), "../../mustache") ]
|
478
|
+
# end
|
479
|
+
|
480
|
+
|
481
|
+
# @!endgroup
|
482
|
+
|
483
|
+
# # ------------------------------------------------------------------
|
484
|
+
# @!group Access partial from GEM
|
485
|
+
|
486
|
+
# Read 'templateName' from '@gemName/mustache' -directory
|
487
|
+
def read_gem_partial_file( gemName , templateName)
|
488
|
+
gemPath = gem_location( gemName )
|
489
|
+
read_partial_file( File.join(gemPath, "mustache" ) + "/", templateName )
|
490
|
+
end
|
491
|
+
|
492
|
+
# Find installation directory of 'gemName' Should find gems
|
493
|
+
# defined in gemspec and Gemfile. Should not find gemName
|
494
|
+
# otherwiset (= also NOT even if installed locally in gems)
|
495
|
+
def gem_location( gemName )
|
496
|
+
gemSpec = Gem.loaded_specs[gemName]
|
497
|
+
raise "Unknown gemName #{gemName}" if gemSpec.nil?
|
498
|
+
gemSpec.gem_dir
|
499
|
+
end
|
500
|
+
|
501
|
+
|
502
|
+
|
503
|
+
# @!endgroup
|
504
|
+
|
505
|
+
|
506
|
+
|
507
|
+
|
508
|
+
|
509
|
+
end
|
510
|
+
end
|