tla-trace-filter 0.0.3
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.
- 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
|