tla-trace-filter 0.0.3 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2804fbc967c6c2816038bd6f3b6a8cfee973484
4
- data.tar.gz: 9fab9d64242a596da309fa119ef34401f608cc7b
3
+ metadata.gz: c26773e9c1c8523333a24665eb9f648f021b17a0
4
+ data.tar.gz: d5a1a47884bb9bb5b07eede01df7e567037b7e57
5
5
  SHA512:
6
- metadata.gz: 400432361333e1f8c3186c9ea77907877c1fc09ea7ee01c994f1b29d0f31ac15a39a5867422541c29dec1c4258136c700eb5d40072ee5ac9f8ff0437b7e9fd3c
7
- data.tar.gz: 30366f9fade7597713f53e02d62bad8e37449ce5b0f249ddd87039191fc5562ccbd677ffb2bc211ed3f69e9b41ad4f9da145fca83ece7810cd659d14df5ae659
6
+ metadata.gz: c47bd7b02c21164670b48fee9f5ede938c80e25673bb17864e1a25bd31b75296c54c6b7d72aaf667c0d079ac51b23879bafc3011ad8f8f1b06d70f80bc670855
7
+ data.tar.gz: 40ef12b948cf1b57fccd9a700bec5561a2ae33813c03a633d7f867c15718292c1214b18032e9ebdcff05fc5cbe9d1ffbe1f37083bd50d22f806efbcdf66b7ddd
@@ -0,0 +1,108 @@
1
+ # `tla-sbuilder-trace` - Post process trace output from model checking sbuilder formal models
2
+
3
+ Command line filter for
4
+ processing
5
+ [TLA+ Tools](http://research.microsoft.com/en-us/um/people/lamport/tla/tools.html) trace
6
+ output resulting from model
7
+ checking
8
+ [TLA+ language](http://research.microsoft.com/en-us/um/people/lamport/tla/book.html) specification
9
+ code generated
10
+ using [sbuilder](https://github.com/jarjuk/tla-sbuilder) -tool.
11
+
12
+ The tool implements two commands
13
+
14
+ * `add-links` : for adding links pointing 1) to *TLA+ language*
15
+ specification code and 2) to source code translated by sbuilder tool
16
+
17
+ * `api-calls` : for interpreting transitions in trace output as
18
+ interface calls on sbuilder source code translated by *sbuilder* tool
19
+
20
+
21
+ ## Installation
22
+
23
+
24
+ To install `tla-trace-filter` GEM create a `Gemfile` -file with the
25
+ content
26
+
27
+ ```
28
+ source "https://rubygems.org"
29
+ gem 'tla-trace-filter'
30
+ ```
31
+
32
+ and run
33
+
34
+ bundle install
35
+
36
+
37
+ ## Usage
38
+
39
+ ### tla-trace-filter.rb add-links
40
+
41
+ To add links to model checker trace output in file `gen/tlc.out`
42
+ resulting from model checking *TLA+ language* specification code in
43
+ file `gen/setup1/tla/model.tla`, and using YAML file
44
+ `gen/setup1/tla/interfaces.yaml` to map transition names back to
45
+ source code modules in directory `solidity` run:
46
+
47
+ bundle exec tla-trace-filter.rb add-links setup1
48
+
49
+
50
+ To embed links to trace output run:
51
+
52
+ bundle exec tla-trace-filter.rb add-links setup1 --embed
53
+
54
+
55
+ ### tla-trace-filter.rb api-calls
56
+
57
+ To create API calls run:
58
+
59
+ bundle exec tla-trace-filter.rb api-calls setup1
60
+
61
+
62
+ ### Getting help
63
+
64
+ Location of the files and directories can be changes using command
65
+ line options. To get a list of available command and their options
66
+ run:
67
+
68
+ bundle exec tla-trace-filter.rb help
69
+
70
+ ## Documentation
71
+
72
+ See [Cucumber](https://cucumber.io/) tests in GEM directory `features`.
73
+
74
+ For a demonstration of `api-call-init` -extension point refer to
75
+ a
76
+ [blog entry](https://jarjuk.wordpress.com/2017/12/06/sbuilder-wallet-3/).
77
+
78
+
79
+ ## <a id="API-CALL_INIT">`api-call-init`-extension point</a>
80
+
81
+ `tla-trace-filter.rb` -tool
82
+ uses [mustache](https://mustache.github.io/) templates to produce
83
+ output. Default templates used are located in GEM directory
84
+ `mustache`. Command line option `--mustache` can override the
85
+ location, where templates are searched for.
86
+
87
+ To show templates, used by the tool, issue the command
88
+
89
+ ls $(bundle show tla-trace-filter)/mustache
90
+
91
+ To get instructions, how to use `api-call-init` -extension point,
92
+ issue the command:
93
+
94
+ cat $(bundle show tla-trace-filter)/mustache/api-call-init.mustache
95
+
96
+
97
+ ## <a id="MUSTACHE-LAMBDAS">Mustache output lambdas</a>
98
+
99
+ Following lambda function are available in mustache template
100
+
101
+ * `{{#YAML_DUMP}}key{{/YAML_DUMP}}` : dump context `key` as YAML,
102
+ e.g. to dump `beforeState`, `api_input`, `api_return` or
103
+ `afterState` for `tla-trace-filter.rb api-calls` -command
104
+
105
+
106
+ ## License
107
+
108
+ MIT
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.6
@@ -2,6 +2,8 @@ require_relative "../tla-trace-filter.rb"
2
2
 
3
3
  require 'thor'
4
4
  require 'yaml'
5
+ require 'socket' # gethostname
6
+ require 'digest' # sha1
5
7
 
6
8
  module TlaTraceFilter
7
9
  class Cli < Thor
@@ -12,13 +14,16 @@ module TlaTraceFilter
12
14
  API_CALL_TEMPLATE = "api-call" # root template for command 'api-call'
13
15
  ADD_LINKS_TEMPLATE = "add-links" # root template for command 'add-links'
14
16
 
17
+ API_CALL_PRE = "api-call-pre" # render before anything other templates
18
+ API_CALL_POST = "api-call-post" # render last
19
+
15
20
 
16
21
 
17
22
  VERSION_BANNER = <<~EOS
18
23
  #{File.basename $0}: #{File.readlines( File.join File.dirname( __FILE__ ), "../../VERSION" ).first.gsub( /\n/, "" )}
19
24
  EOS
20
25
 
21
- MUSTACHE_DEFAULT = "mustache/"
26
+ MUSTACHE_DEFAULT = [ "mustache/" ]
22
27
  MUSTACHE_OPTION= <<-EOS
23
28
  Output is processed using mustache templates in directory
24
29
  #{File.dirname __FILE__}/../../mustache. Mustache templates can be
@@ -48,6 +53,9 @@ module TlaTraceFilter
48
53
  def rendering
49
54
  @rendering ||= TlaTraceFilter::Render.new( options )
50
55
  end
56
+
57
+ # @# @!attribute [Digest:SHA1] sha1
58
+ attr_accessor :sha1
51
59
 
52
60
  end
53
61
 
@@ -106,10 +114,11 @@ module TlaTraceFilter
106
114
  add_shared_option :tla_dir, :type=>:string, :desc=>"Override default specification code dir gen/SETUP/tla"
107
115
  add_shared_option :src_dir, :default=>"./solidity", :type=>:string, :desc=>"Source code root directory"
108
116
  add_shared_option :filter_src, :aliases => "-f", :type => :boolean, :default => false
109
- add_shared_option :mustache, :aliases => "-m", :type => :string, :desc => "Add a directory (ends with /-char) or GEM to search for mustache template", :default=> MUSTACHE_DEFAULT
117
+ add_shared_option :mustache, :aliases => "-m", :type => :array, :desc => "Add a directory (ends with /-char) or GEM to search for mustache template", :default=> MUSTACHE_DEFAULT
110
118
  add_shared_option :solc_line, :type => :boolean, :default=>false, :desc => "TRUE interpretes sourceLines as characters starting from source start"
111
119
  add_shared_option :debug_mustache, :type => :boolean, :default=>false, :desc => "Raise exception if referencing non-existing property"
112
120
  add_shared_option :embed, :type => :boolean, :default=>false, :desc => "TRUE adds link to trace output"
121
+ add_shared_option :sha1, :type => :boolean, :default=>true, :desc => "Make :sha1 available for template #{API_CALL_POST}"
113
122
 
114
123
  # @!endgroup
115
124
 
@@ -185,11 +194,10 @@ module TlaTraceFilter
185
194
  API calls are resolved using 'interface.yaml' YAML file found in
186
195
  specification code directory (option :tla-dir).
187
196
 
188
- Use command
189
197
 
190
- cat $(bundle show tla-trace-filter)/mustache/api-call-init.mustache
191
-
192
- for instructions to map interface operations to mustache partials.
198
+ Extension points:
199
+ - cat $(bundle show tla-trace-filter)/mustache/api-call-init.mustache:
200
+ dynamic distpatch based on context[:interface][:interface_operation]
193
201
 
194
202
 
195
203
  #{MUSTACHE_OPTION}
@@ -202,18 +210,25 @@ module TlaTraceFilter
202
210
  shared_options :state_dump
203
211
  shared_options :filter_src
204
212
  shared_options :solc_line
213
+ shared_options :sha1
205
214
 
206
215
  def api_calls( setup, file=nil)
207
216
 
208
217
  # unfreeze 'options' && set defaults (:tla_dir)
209
218
  setOptions( setup )
210
219
 
220
+ # init sha1 calculation
221
+ sha1Init
222
+
211
223
  # Load fixed named template - allow used to define mapping
212
224
  apiInitTemplate = "{{>#{API_CALL_INIT} }}"
213
225
  @logger.info "#{__method__}, apiInitTemplate=#{apiInitTemplate}"
214
226
  rendered = rendering.render(apiInitTemplate, options)
215
227
  @logger.info "#{__method__}, output from init '#{rendered}'"
216
- puts rendered if rendered.length > 0
228
+ # outputRendered(rendered)
229
+
230
+ # preamble partial
231
+ outputRendered( rendering.render( "{{>#{API_CALL_PRE}}}", preAndPostHash(options ) ) )
217
232
 
218
233
  # Default FILE vs. given on cmd line
219
234
  file = traceFile( setup, file )
@@ -222,54 +237,71 @@ module TlaTraceFilter
222
237
  @logger.info "#{__method__}, template=#{template}"
223
238
 
224
239
  # queue length of 1
225
- q = nil
226
- lastData = nil
240
+ interfaceBeforeState = nil
241
+ interfaceEnterState = nil
242
+ interfaceEndState = nil
227
243
 
228
244
  # read 'file' yielding String/Hash and parsedLines producing Hash
229
245
  processInput( file ) do |data, parsedLines|
230
246
 
231
247
  if data.is_a?(String)
232
- # api - call do not ouput trace lines
248
+ # api - call do not output trace lines
233
249
  elsif data.is_a?(Hash)
234
250
 
235
251
  # reason to output api-call
236
252
  if data[:interface_started]
237
253
 
238
- if q.nil?
239
- # init qeueu
240
- q = data
254
+ if interfaceBeforeState.nil?
255
+ # first time processing state 0
256
+ interfaceBeforeState = data
257
+ @logger.debug "loop: init interfaceBeforeState: #{interfaceBeforeState}" if @logger.debug?
258
+ elsif interfaceEnterState.nil?
259
+ # state 0 has been processed - is this the first interface
260
+ interfaceEnterState = data
241
261
  else
242
262
 
243
- # output prev element in queue
244
- q[:inputState] = q[:parsed][:state_space]
245
- q[:now] = q[:parsed][:state_space][:now]
246
- q[:outputState] = lastData[:parsed][:state_space]
247
- # render parsed data && output if any ouput
248
- rendered = rendering.render(template, q)
249
- puts rendered if rendered.length > 0
250
-
251
- # queue current data
252
- q = data
263
+ # New iterface has started to execute. Now we can render
264
+ # apiStep for previous interface call using state collected in
265
+ #
266
+ # * beforeState: takens from 'interfaceBeforeState': it s either the first
267
+ # 'data' parsed OR 'data' parsed , which was reached
268
+ # after executing previous interface call.
269
+
270
+ # * afterState: taken from preceding 'data' in 'interfaceEndState'
271
+ apiOutput = canonizeData( interfaceBeforeState, interfaceEnterState, interfaceEndState )
272
+ @logger.debug "loop: apiOutput #{apiOutput}" if @logger.debug?
273
+ rendered = rendering.render(template, apiOutput)
274
+ outputRendered( rendered )
275
+
276
+ # init 'interfaceBeforeState' as 'interfaceEndState'
277
+ # from the previous step (which was just rendered)
278
+ interfaceBeforeState = interfaceEndState
279
+ # init 'interfaceEnterState' to current 'data' parsed from inputfile
280
+ interfaceEnterState = data
281
+ @logger.debug "loop: set interfaceBeforeState #{interfaceBeforeState}" if @logger.debug?
253
282
  end
254
283
 
255
284
  end # interface_started
256
285
 
257
- # rememeber it
258
- lastData = data
286
+ # advance 'interfaceEndState' with current 'data'
287
+ interfaceEndState = data
259
288
 
260
289
  end # elsif Hash?
261
290
  end # block
262
291
 
263
- if !q.nil?
292
+ # flush interfaceBeforeState
293
+ if !interfaceBeforeState.nil?
264
294
  # render parsed data && output if any ouput
265
- q[:inputState] = q[:parsed][:state_space]
266
- q[:now] = q[:parsed][:state_space][:now]
267
- q[:outputState] = lastData[:parsed][:state_space]
268
- rendered = rendering.render(template, q)
269
- puts rendered if rendered.length > 0
295
+ apiOutput = canonizeData( interfaceBeforeState, interfaceEnterState || interfaceEndState, interfaceEndState )
296
+ @logger.debug "loop:exit: apiOutput (quit) #{apiOutput}" if @logger.debug?
297
+ rendered = rendering.render(template, apiOutput)
298
+ outputRendered( rendered )
270
299
 
271
300
  end #
272
-
301
+
302
+ # postamble (including setting sha1) - but not calculating it
303
+ rendered = rendering.render("{{>#{API_CALL_POST}}}", preAndPostHash(options ) )
304
+ puts rendered if rendered.length > 0
273
305
 
274
306
  end
275
307
 
@@ -278,10 +310,68 @@ module TlaTraceFilter
278
310
 
279
311
 
280
312
  # ------------------------------------------------------------------
281
- # @!group No commans
313
+ # @!group No commansd
282
314
 
283
315
  no_commands do
284
316
 
317
+ # INitialize sha1 opbject
318
+ def sha1Init
319
+ self.sha1 = Digest::SHA1.new if options[:sha1]
320
+ end
321
+
322
+ def sha1Update( data )
323
+ sha1.update( data ) if options[:sha1]
324
+ # @logger.debug "#{__method__}: lines=#{@lines}, sha1.hexdigest=#{sha1.hexdigest}, data=#{data}" if @logger.debug?
325
+ end
326
+
327
+
328
+ # Output 'rendered' line && calculate sha1
329
+ def outputRendered rendered
330
+ if rendered.length > 0
331
+ sha1Update( rendered )
332
+ puts rendered
333
+ end
334
+ end
335
+
336
+ # @return [Hash] data hash passed to pre/post templates.
337
+ def preAndPostHash( options)
338
+ {
339
+ :options => options,
340
+ :META => getMeta(),
341
+ :sha1 => sha1,
342
+ }
343
+ end
344
+
345
+ def getMeta
346
+ {
347
+ :timestamp => Time.new.strftime( "%Y-%m-%d %H:%M:%S" ),
348
+ :hostname => Socket.gethostname,
349
+ :user => ENV["USER"],
350
+ }
351
+ end
352
+
353
+ # @return [Hash] with properties from
354
+ # 'interfaceBeforeState','interfaceEnterState' and
355
+ # 'interfaceEndState'
356
+ def canonizeData( interfaceBeforeState, interfaceEnterState, interfaceEndState )
357
+ ret = {
358
+ options: interfaceBeforeState[:options], # cmd line options
359
+ interface_started: true,
360
+ beforeState: interfaceBeforeState[:parsed][:state_space],
361
+ parsed: interfaceEnterState[:parsed],
362
+ now: interfaceEndState[:parsed][:state_space][:now],
363
+ interface: interfaceEndState[:interface],
364
+ interface_operation: interfaceEndState[:interface_operation],
365
+ afterState: interfaceEndState[:parsed][:state_space],
366
+ }
367
+
368
+ # q[:beforeState] = q[:parsed][:state_space]
369
+ # q[:now] = lastData[:parsed][:state_space][:now]
370
+ # q[:interface] = lastData[:interface]
371
+ # q[:afterState] = lastData[:parsed][:state_space]
372
+ # q
373
+ end
374
+
285
375
  # @param parsed [Hash] parsed model checking state
286
376
  #
287
377
  # @param interfaceDefintion [type] interface for currently
@@ -433,43 +523,6 @@ module TlaTraceFilter
433
523
  interfaceHash
434
524
  end
435
525
 
436
- # # @param interface_operation [String] interface geth(mine)
437
- # # executing tla transition parsed in state space
438
- # #
439
- # # @param state_space [Hash] state space state parsed
440
- # #
441
- # # @return [Boolean] true if
442
- # # state_space[:pc][interface_operation] ends_with
443
- # # '_start', edge case return 'false' if
444
- # # 'interface_operation' not found in 'state_space'
445
- # #
446
-
447
- # def interfaceStarted?(interface_operation, state_space)
448
- # @logger.debug "#{__method__}: interface_operation, state_space=#{state_space.to_yaml}" if @logger.debug?
449
- # @logger.info "#{__method__}: look '#{interface_operation}' in #{state_space[:pc]}"
450
- # return false if interface_operation.nil? || interface_operation.length == 0
451
- # return false if state_space[:pc][interface_operation].nil?
452
- # # state_space[:pc][interface_operation].end_with? "_start"
453
- # isStart?( state_space[:pc][interface_operation] )
454
- # end
455
-
456
- # # @param interface_operation [String] interface geth(mine)
457
- # # executing tla transition parsed in state space
458
- # #
459
- # # @param state_space [Hash] state space state parsed
460
- # #
461
- # # @return [Boolean] true if
462
- # # state_space[:pc][interface_operation] does NOT ends
463
- # # '_start' && 'interface_operation' found in 'state_space'
464
- # #
465
-
466
- # def interfaceExecuting?(interface_operation, state_space)
467
- # # not valid interface_operation
468
- # return false if interface_operation.nil? || interface_operation.length == 0
469
- # return false if state_space[:pc][interface_operation].nil?
470
- # # toggle isStart?
471
- # return !isStart?( state_space[:pc][interface_operation] )
472
- # end
473
526
 
474
527
  # @param interface_operation [String] interface geth(mine)
475
528
  # executing tla transition parsed in state space
@@ -510,6 +563,7 @@ module TlaTraceFilter
510
563
 
511
564
  # unfreeze 'options' && set defaults (:tla_dir)
512
565
  def setOptions( setup )
566
+ @logger.info "#{__method__}, options=#{options.to_yaml}"
513
567
  # unfreeze options
514
568
  new_options = options.dup
515
569
  self.options = new_options
@@ -15,11 +15,11 @@ module TlaTraceFilter
15
15
  # ------------------------------------------------------------------
16
16
  # @!group Constants
17
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"
18
+ # Default templates for beforeState, call, and afterState
19
+ API_BEFORE_STATE_DEFAULT_PARTIAL = "api-call-default-beforeState"
20
+ API_CALL_DEFAULT_PARTIAL = "api-call-default-api_input"
21
+ API_RETURN_DEFAULT_PARTIAL = "api-call-default-api_return"
22
+ API_AFTER_STATE_DEFAULT_PARTIAL = "api-call-default-afterState"
23
23
 
24
24
  # Keys mapping to the output templates
25
25
  API_DEFAULT_KEY = "default"
@@ -46,13 +46,13 @@ module TlaTraceFilter
46
46
  # (with default) to partial name
47
47
  attr_accessor :returnPartials
48
48
 
49
- # @# @!attribute [Hash] inputStatePartials hash mapping interface-names
49
+ # @# @!attribute [Hash] beforeStatePartials hash mapping interface-names
50
50
  # (with default) to partial name
51
- attr_accessor :inputStatePartials
51
+ attr_accessor :beforeStatePartials
52
52
 
53
- # @# @!attribute [Hash] outputStatePartials hash mapping interface-names
53
+ # @# @!attribute [Hash] afterStatePartials hash mapping interface-names
54
54
  # (with default) to partial name
55
- attr_accessor :outputStatePartials
55
+ attr_accessor :afterStatePartials
56
56
 
57
57
  # @!endgroup
58
58
 
@@ -79,18 +79,18 @@ module TlaTraceFilter
79
79
  # default search only GEM templates
80
80
  self.templatePaths = [ File.join( File.dirname(__FILE__), "../../mustache/") ]
81
81
  # user defined template search path prepended
82
- self.templatePaths = [ options[:mustache] ] + templatePaths if options[:mustache]
82
+ self.templatePaths = options[:mustache] + templatePaths if options[:mustache]
83
83
  end
84
84
 
85
85
  def initPartials
86
86
  self.partials = {}
87
87
  API_CALL_INIT( "" )
88
88
  API_RETURN_INIT( "" )
89
- API_INPUT_STATE_INIT( "" )
90
- API_OUTPUT_STATE_INIT( "" )
89
+ API_BEFORE_STATE_INIT( "" )
90
+ API_AFTER_STATE_INIT( "" )
91
91
  # self.callPartials = {}
92
- # self.inputStatePartials = {}
93
- # self.outputStatePartials = {}
92
+ # self.beforeStatePartials = {}
93
+ # self.afterStatePartials = {}
94
94
  end
95
95
 
96
96
  # @!endgroup
@@ -154,15 +154,15 @@ module TlaTraceFilter
154
154
 
155
155
  # Initiliaze template calls. If no data given results calling to
156
156
  # default templates
157
- def API_INPUT_STATE_INIT( data)
157
+ def API_BEFORE_STATE_INIT( data)
158
158
  @logger.info "#{__method__}: data=#{data}"
159
159
  begin
160
- self.inputStatePartials = data.nil? || data == "" ? {} : YAML.load( data )
160
+ self.beforeStatePartials = data.nil? || data == "" ? {} : YAML.load( data )
161
161
  rescue Exception => e
162
162
  msg = <<-EOS
163
163
  #{e}
164
164
 
165
- Error parsing YAML data in API_INPUT_STATE_INIT:
165
+ Error parsing YAML data in API_BEFORE_STATE_INIT:
166
166
 
167
167
  #{data}
168
168
  EOS
@@ -170,20 +170,20 @@ module TlaTraceFilter
170
170
  raise Exception.new, msg, e.backtrace
171
171
  end
172
172
 
173
- @logger.debug "#{__method__}: inputStatePartials=#{inputStatePartials}" if @logger.debug?
173
+ @logger.debug "#{__method__}: beforeStatePartials=#{beforeStatePartials}" if @logger.debug?
174
174
 
175
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?
176
+ self.beforeStatePartials[API_DEFAULT_KEY] = API_BEFORE_STATE_DEFAULT_PARTIAL if beforeStatePartials[API_DEFAULT_KEY].nil?
177
+ self.beforeStatePartials[API_EMPTY_KEY] = API_AFTER_STATE_DEFAULT_PARTIAL if beforeStatePartials[API_EMPTY_KEY].nil?
178
178
 
179
179
  end
180
180
 
181
181
  # Lambda to initiliaze template calls. If no data given results
182
182
  # calling to default templates
183
- def API_OUTPUT_STATE_INIT( data)
183
+ def API_AFTER_STATE_INIT( data)
184
184
  @logger.info "#{__method__}: data=#{data}"
185
185
  begin
186
- self.outputStatePartials = data.nil? || data == "" ? {} : YAML.load( data )
186
+ self.afterStatePartials = data.nil? || data == "" ? {} : YAML.load( data )
187
187
  rescue Exception => e
188
188
  msg = <<-EOS
189
189
  #{e}
@@ -196,11 +196,11 @@ module TlaTraceFilter
196
196
  raise Exception.new, msg, e.backtrace
197
197
  end
198
198
 
199
- @logger.debug "#{__method__}: outputStatePartials=#{outputStatePartials}" if @logger.debug?
199
+ @logger.debug "#{__method__}: afterStatePartials=#{afterStatePartials}" if @logger.debug?
200
200
 
201
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?
202
+ self.afterStatePartials[API_DEFAULT_KEY] = API_AFTER_STATE_DEFAULT_PARTIAL if afterStatePartials[API_DEFAULT_KEY].nil?
203
+ self.afterStatePartials[API_EMPTY_KEY] = API_AFTER_STATE_DEFAULT_PARTIAL if afterStatePartials[API_EMPTY_KEY].nil?
204
204
 
205
205
  end
206
206
 
@@ -236,25 +236,25 @@ module TlaTraceFilter
236
236
  end
237
237
 
238
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
239
+ beforeStatePartialName = nil
240
+ beforeStatePartialName = beforeStatePartials[API_EMPTY_KEY] if interfaceOperation.nil?
241
+ beforeStatePartialName = beforeStatePartials[interfaceOperation] if beforeStatePartialName.nil?
242
+ beforeStatePartialName = beforeStatePartials[API_DEFAULT_KEY] if beforeStatePartialName.nil?
243
+ raise "Missing could not resolve '#{interfaceOperation}' in beforeStatePartials #{beforeStatePartials}" if beforeStatePartialName.nil?
244
+
245
+ @logger.info "#{__method__}: API-call to interfaceOperation '#{interfaceOperation}' render with '#{beforeStatePartialName}'"
246
+ beforeStatePartialName
247
247
  end
248
248
 
249
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
250
+ afterStatePartialName = nil
251
+ afterStatePartialName = afterStatePartials[API_EMPTY_KEY] if interfaceOperation.nil?
252
+ afterStatePartialName = afterStatePartials[interfaceOperation] if afterStatePartialName.nil?
253
+ afterStatePartialName = afterStatePartials[API_DEFAULT_KEY] if afterStatePartialName.nil?
254
+ raise "Missing could not resolve '#{interfaceOperation}' in afterStatePartials #{afterStatePartials}" if afterStatePartialName.nil?
255
+
256
+ @logger.info "#{__method__}: API-call to interfaceOperation '#{interfaceOperation}' render with '#{afterStatePartialName}'"
257
+ afterStatePartialName
258
258
  end
259
259
 
260
260
  # @!endgroup
@@ -297,18 +297,18 @@ module TlaTraceFilter
297
297
  lineCount
298
298
  end
299
299
 
300
- # Lamba called for 'API_INPUT_STATE' to dispatch dynamically rendering of
301
- # [:interface][:interface_operation] inputState.
302
- def API_INPUT_STATE
300
+ # Lamba called for 'API_BEFORE_STATE' to dispatch dynamically rendering of
301
+ # [:interface][:interface_operation] beforeState.
302
+ def API_BEFORE_STATE
303
303
  @logger.info "#{__method__}: [:interface][:interface_operation]=#{context[:interface][:interface_operation]}, now=#{context[:now]}"
304
304
  callPartialName = getInputStatePartialName( context[:interface][:interface_operation] )
305
305
  template = partial( callPartialName )
306
306
  render( template, context )
307
307
  end
308
308
 
309
- # Lamba called for 'API_OUTPUT_STATE' to dispatch dynamically rendering of
310
- # [:interface][:interface_operation] outputState.
311
- def API_OUTPUT_STATE
309
+ # Lamba called for 'API_AFTER_STATE' to dispatch dynamically rendering of
310
+ # [:interface][:interface_operation] afterState.
311
+ def API_AFTER_STATE
312
312
  @logger.info "#{__method__}: [:interface][:interface_operation]=#{context[:interface][:interface_operation]} now=#{context[:now]}"
313
313
  callPartialName = getOutputStatePartialName( context[:interface][:interface_operation] )
314
314
  template = partial( callPartialName )
@@ -316,6 +316,7 @@ module TlaTraceFilter
316
316
  end
317
317
 
318
318
  def API_RETURN
319
+ @logger.info "#{__method__}: [:interface][:interface_operation]=#{context[:interface][:interface_operation]} now=#{context[:now]}"
319
320
 
320
321
  interfaceOperation = context[:interface][:interface_operation]
321
322
  responseKey = context[:interface][:response_key]
@@ -325,8 +326,10 @@ module TlaTraceFilter
325
326
  template = partial( callPartialName )
326
327
 
327
328
  # context access likke i_Bank_saveAccount_
328
- # raise "keys=#{context[:outputState][:responses].to_yaml}"
329
- context[:api_return] = context[:outputState][:responses][responseKey]
329
+ # raise "keys=#{context[:afterState][:responses].to_yaml}"
330
+ @logger.debug "#{__method__}: context[:afterState]=#{context[:afterState].to_yaml}" if @logger.debug?
331
+
332
+ context[:api_return] = context[:afterState][:responses].nil? ? nil : context[:afterState][:responses][responseKey]
330
333
 
331
334
  render( template, context )
332
335
 
@@ -370,10 +373,10 @@ module TlaTraceFilter
370
373
  context[:parsed][:state_space][:step_input]
371
374
  else
372
375
 
373
- api = "#{context[:interface][:interface_name]}_input"
376
+ inputvariable = "#{context[:interface][:interface_name]}_input"
374
377
 
375
378
  # find name of procedure input varibable
376
- api = context[:parsed][:state_space].keys.find { |k| k.to_s.end_with?( api ) } unless api.nil?
379
+ api = context[:parsed][:state_space].keys.find { |k| k.to_s.end_with?( inputvariable) } unless inputvariable.nil?
377
380
 
378
381
  # access procedure input data
379
382
  api = context[:parsed][:state_space][api] unless api.nil?
@@ -381,7 +384,15 @@ module TlaTraceFilter
381
384
  # access procedure input for currently running interface opertaion
382
385
  api = api[context[:interface][:interface_operation]] unless api.nil?
383
386
 
384
- api = { :error => "No input found in context[:parsed][:state_space][:step_input] - maybe set 'SetStepInput = TRUE'"} if api.nil?
387
+ if api.nil?
388
+ msg = %Q{
389
+ No input found in context[:parsed][:state_space][:step_input] - maybe set 'SetStepInput = TRUE'
390
+
391
+ Tried to locate input variable ending with #{inputvariable} in context[:parsed][:state_space]
392
+ }
393
+
394
+ api = { :error => msg }
395
+ end
385
396
 
386
397
  api
387
398
  end
@@ -391,6 +402,26 @@ module TlaTraceFilter
391
402
  end
392
403
 
393
404
 
405
+ # @!endgroup
406
+
407
+ # # ------------------------------------------------------------------
408
+ # @!group DUmp
409
+
410
+ # dump 'contextKey' in in YAML, where 'contextKey' is path of hash
411
+ # keys repareated by '.'
412
+ def DUMP_YAML( contextKey )
413
+ # enable splitting key - just be sure
414
+ contextKey = contextKey.to_s unless contextKey.is_a? String
415
+ keys = contextKey.split(".")
416
+ c = context
417
+ keys.each do |key|
418
+ break if c.nil?
419
+ c = c[key.to_sym]
420
+ end
421
+ c.to_yaml
422
+ end
423
+
424
+
394
425
  # @!endgroup
395
426
 
396
427
 
@@ -494,7 +525,8 @@ module TlaTraceFilter
494
525
  # otherwiset (= also NOT even if installed locally in gems)
495
526
  def gem_location( gemName )
496
527
  gemSpec = Gem.loaded_specs[gemName]
497
- raise "Unknown gemName #{gemName}" if gemSpec.nil?
528
+ raise "Unknown gemName #{gemName} - known Gems #{Gem.loaded_specs.keys.join(",")} " if gemSpec.nil?
529
+ @logger.info "#{__method__}: gemName#{gemName} resolves to gemSpec.gem_dir#{gemSpec.gem_dir}"
498
530
  gemSpec.gem_dir
499
531
  end
500
532