tla-sbuilder 0.2.2 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +150 -116
- data/VERSION +1 -1
- data/lib/cli/cli-customer.rb +23 -3
- data/lib/cli/cli-pet.rb +66 -12
- data/lib/cli/cli-text.rb +127 -8
- data/lib/cli/cli.rb +49 -6
- data/lib/sbuilder.rb +26 -3
- data/lib/sbuilder/constants.rb +165 -6
- data/lib/sbuilder/controller.rb +943 -169
- data/lib/sbuilder/controller_utils.rb +122 -0
- data/lib/sbuilder/default-sbuilder.yaml +38 -44
- data/lib/sbuilder/domain.rb +160 -36
- data/lib/sbuilder/domain_cardinality.rb +1 -1
- data/lib/sbuilder/domain_range.rb +102 -0
- data/lib/sbuilder/domain_type.rb +150 -0
- data/lib/sbuilder/domain_value.rb +21 -13
- data/lib/sbuilder/exception.rb +16 -0
- data/lib/sbuilder/extension_loader.rb +67 -686
- data/lib/sbuilder/extension_loader_deprecated_step_extensions.rb +711 -0
- data/lib/sbuilder/extension_loader_step_generator.rb +876 -0
- data/lib/sbuilder/facade/{api_loader.rb → api_loader_facade.rb} +176 -45
- data/lib/sbuilder/facade/api_loader_plugin.rb +6 -32
- data/lib/sbuilder/facade/api_loader_plugin_mixer.rb +35 -0
- data/lib/sbuilder/facade/facade_constants.rb +23 -0
- data/lib/sbuilder/facade/loader_plugin_root.rb +56 -0
- data/lib/sbuilder/facade/param_set_root.rb +55 -0
- data/lib/sbuilder/facade/snippet_loader_facade.rb +600 -0
- data/lib/sbuilder/facade/snippet_loader_plugin.rb +76 -0
- data/lib/sbuilder/facade/snippet_loader_plugin_mixer.rb +56 -0
- data/lib/sbuilder/factory.rb +224 -45
- data/lib/sbuilder/model.rb +125 -45
- data/lib/sbuilder/mustache/template.rb +107 -58
- data/lib/sbuilder/mustache/template_reader.rb +56 -46
- data/lib/sbuilder/mustache/template_reader_context.rb +64 -234
- data/lib/sbuilder/mustache/template_resolve.rb +103 -0
- data/lib/sbuilder/mustache/template_root.rb +71 -0
- data/lib/sbuilder/param_set.rb +30 -15
- data/lib/sbuilder/param_set_db.rb +1 -1
- data/lib/sbuilder/param_set_def.rb +6 -1
- data/lib/sbuilder/param_set_def_func.rb +39 -0
- data/lib/sbuilder/param_set_if.rb +45 -10
- data/lib/sbuilder/param_set_loader_swagger.rb +56 -26
- data/lib/sbuilder/param_set_step.rb +1 -1
- data/lib/sbuilder/param_sets.rb +2 -1
- data/lib/sbuilder/parameter.rb +9 -3
- data/lib/sbuilder/parameter_container.rb +1 -1
- data/lib/sbuilder/parameter_dom.rb +17 -5
- data/lib/sbuilder/parameter_ref.rb +39 -10
- data/lib/sbuilder/parser/parser_facade.rb +310 -0
- data/lib/sbuilder/resolver.rb +11 -6
- data/lib/sbuilder/resolver_loader.rb +1 -1
- data/lib/sbuilder/resolver_loader_yaml.rb +1 -1
- data/lib/sbuilder/resolver_rule.rb +1 -1
- data/lib/sbuilder/resolver_rule_match.rb +10 -4
- data/lib/sbuilder/resolver_rule_ref.rb +1 -1
- data/lib/sbuilder/setup_loader.rb +49 -0
- data/lib/sbuilder/setup_loader_env.rb +478 -0
- data/lib/sbuilder/setup_loader_pref.rb +56 -0
- data/lib/sbuilder/snippet_loader_simple.rb +125 -0
- data/lib/sbuilder/spec/api_loader.rb +34 -0
- data/lib/sbuilder/spec/api_loader_facade.rb +169 -32
- data/lib/sbuilder/spec/loader_plugin.rb +98 -0
- data/lib/sbuilder/spec/snippet_loader.rb +228 -0
- data/lib/sbuilder/symbol_table.rb +279 -0
- data/lib/utils/{cache_lines.rb → fileio.rb} +8 -1
- data/lib/utils/logger.rb +2 -1
- data/lib/utils/powerset.rb +13 -0
- data/lib/utils/validate.rb +38 -0
- data/mustache/cfg/const_def.mustache +2 -0
- data/mustache/cfg/macro_run.mustache +1 -4
- data/mustache/data-model-header.mustache +1 -0
- data/mustache/definition_types.mustache +34 -4
- data/mustache/domains.mustache +1 -1
- data/mustache/domains_assign.mustache +1 -1
- data/mustache/infrastructure-service-init.mustache +1 -1
- data/mustache/interface_processes.mustache +16 -10
- data/mustache/interface_types.mustache +37 -11
- data/mustache/operator-infrastructure-service.mustache +1 -1
- data/mustache/resources/schedule_operator_new_step.tla +8 -0
- data/mustache/resources/schedule_process_macro.tla +37 -0
- data/mustache/resources/schedule_process_procedure.tla +22 -0
- data/mustache/resources/schedule_throw.tla +16 -0
- data/mustache/setup/domains_run.mustache +8 -2
- data/mustache/setup/operator_run.mustache +0 -4
- data/mustache/setup/steps_run.mustache +4 -3
- data/mustache/setup/steps_run_parameterBind.mustache +14 -6
- data/mustache/setup/steps_run_parameterExact.mustache +7 -3
- data/mustache/state_type_invariant-infrastructure-service.mustache +9 -4
- data/mustache/tla/const_def.mustache +1 -1
- data/mustache/tla/macro_run.mustache +7 -1
- data/mustache/tla/module_header.mustache +1 -1
- data/mustache/tla/operator_run.mustache +8 -5
- data/mustache/tla/plc_define_run.mustache +45 -36
- data/mustache/tla/plc_run_state.mustache +12 -5
- data/src-extend/extend/extend_assumptions.mustache +3 -0
- data/src-extend/extend/extend_const.mustache +3 -0
- data/src-extend/extend/extend_implementation.mustache +3 -0
- data/src-extend/extend/extend_invariant.mustache +3 -0
- data/src-extend/extend/extend_macros.mustache +3 -0
- data/src-extend/extend/extend_operations.mustache +3 -0
- data/src-extend/extend/extend_state.mustache +3 -0
- data/src/pet/extend/extend_assumptions.mustache +4 -0
- data/src/pet/extend/extend_implementation.mustache +3 -0
- data/src/pet/extend/extend_invariant.mustache +3 -0
- data/src/pet/extend/extend_macros.mustache +3 -0
- data/src/pet/extend/extend_operations.mustache +4 -0
- data/src/pet/extend/extend_state.mustache +3 -0
- data/src/pet/interface +5 -5
- data/src/pet/interface_delete_pet.tla +1 -1
- data/src/pet/interface_get_pet.tla +1 -1
- data/src/pet/interface_post_pet.tla +4 -2
- data/src/pet/interface_post_tag.tla +1 -1
- data/src/pet/interface_put_tag.tla +1 -1
- data/tla-sbuilder.gemspec +3 -3
- metadata +44 -19
- data/mustache/name_definition_type.mustache +0 -5
- data/mustache/name_domain.mustache +0 -5
- data/mustache/name_domain_value.mustache +0 -5
- data/mustache/name_domain_value_prefix.mustache +0 -5
- data/mustache/name_interface_response_type.mustache +0 -6
- data/mustache/name_interface_type.mustache +0 -6
- data/mustache/name_parameter_type.mustache +0 -6
- data/mustache/name_process.mustache +0 -6
- data/mustache/state_type_invariant.mustache +0 -17
- data/mustache/state_variables.mustache +0 -20
- data/src-extend/extend/extend_invariant_cfg.mustache +0 -7
@@ -0,0 +1,711 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
|
3
|
+
# To complete runnable code Sbuilder uses setups. A setup
|
4
|
+
# is a sequence of interface operations, and their input parameters.
|
5
|
+
# In addition, a setup may define domain cardinalities, or domain
|
6
|
+
# values. The tools allows defining multiple setups, each setup
|
7
|
+
# resulting to a complete, runnable TLA+ code, allowing system model
|
8
|
+
# to be run in various environment context
|
9
|
+
#
|
10
|
+
# User defines sequence of interface operations, and their input
|
11
|
+
# parameters using 'step-extension'. A 'step-extension' is an array
|
12
|
+
# with
|
13
|
+
#
|
14
|
+
# - 'interface' property
|
15
|
+
#
|
16
|
+
# - 'input' property (or 'inputs' array with elements containing 'input' propperty)
|
17
|
+
#
|
18
|
+
# - 'bindExact' optional boolean property (default false) controlling,
|
19
|
+
# how 'input' properties are intepreted. In short 'bindExact' == true results to
|
20
|
+
# 'bindSet', and 'bindExact' == false results to 'bindRule' (see description below)
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# In sbuilder, 'setup' 'step-extension' is used to create
|
24
|
+
# environment context for the setup as follows:
|
25
|
+
#
|
26
|
+
# * sbuilder maps 'step-extension' to a template data array 'steps',
|
27
|
+
# which can be passed to mustache rendering. Elements in 'steps'
|
28
|
+
# array define properties 'interface_operation', 'process',
|
29
|
+
# 'bindRule', and 'bindSet'.
|
30
|
+
#
|
31
|
+
# * sbuilder uses template data array 'steps' to render 'RunSteps' -array
|
32
|
+
# in 'setup.tla'. Array elements have the same properties as
|
33
|
+
# 'steps' array described above.
|
34
|
+
#
|
35
|
+
# * In specification code, 'process' -field of the head element in
|
36
|
+
# 'RunSteps' array chooses the TLA process to execute. The process
|
37
|
+
# models interface operation of the 'interface' property in
|
38
|
+
# 'step-extension'. Input to the process is controlled either
|
39
|
+
# using 'bindRule' or 'bindSet' -field on the head element. When
|
40
|
+
# using 'bindRule', input to the process can be any value in
|
41
|
+
# process input domain satistfying 'bindRule' condition. When
|
42
|
+
# using 'bindSet', process input is chosen from the elements in
|
43
|
+
# the 'bindSet'.
|
44
|
+
|
45
|
+
|
46
|
+
module ExtensionLoader_Deprecated_Step_Extensions
|
47
|
+
|
48
|
+
@@validStepExtension_required = ["interface" ]
|
49
|
+
@@validStepExtension_allowed = @@validStepExtension_required + ["input", "bindExact", "inputs"]
|
50
|
+
|
51
|
+
@@validStepExtension_input = [ "input" ]
|
52
|
+
|
53
|
+
# ------------------------------------------------------------------
|
54
|
+
# extend steps: recurse 'stepExtensionDef' and create a hash, which
|
55
|
+
# can passed to mustache templates
|
56
|
+
|
57
|
+
def extendStep( stepExtensionDef )
|
58
|
+
@logger.info( "#{__method__} stepExtensionDef=#{stepExtensionDef}" )
|
59
|
+
|
60
|
+
validateProperties( stepExtensionDef, @@validStepExtension_required, @@validStepExtension_allowed )
|
61
|
+
|
62
|
+
# access paramSet for interface being extenedd && assert that it also exists
|
63
|
+
interface = controller.getInterface( stepExtensionDef['interface'] )
|
64
|
+
|
65
|
+
# create new param-set && configure it
|
66
|
+
stepParamSet = controller.createParamSet( Sbuilder::Constants::PARAM_SET_STEPS )
|
67
|
+
stepParamSet.setInterfaceReference( interface )
|
68
|
+
stepParamSet.setBindExact( stepExtensionDef["bindExact"] )
|
69
|
+
|
70
|
+
# iterate stepParamSet['inputs']/stepParamSet['input'] to create
|
71
|
+
# mustacheTemplateData & add use 'stepParamSet.addInput' add it
|
72
|
+
# to 'stepParamSet'
|
73
|
+
extendStep_Inputs( interface, stepParamSet, stepExtensionDef )
|
74
|
+
|
75
|
+
# pass extension for controller - to delegate to model
|
76
|
+
controller.extendStep( stepParamSet )
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
# ------------------------------------------------------------------
|
81
|
+
# Implementation
|
82
|
+
|
83
|
+
|
84
|
+
def extendStep_Inputs( interface, stepParamSet, stepExtensionDef )
|
85
|
+
|
86
|
+
raise ExtensionException.new <<-EOS if stepExtensionDef['input'] && stepExtensionDef['inputs']
|
87
|
+
Property 'input' cannot be defined together with 'inputs' in #{stepExtensionDef.to_yaml}
|
88
|
+
|
89
|
+
Use
|
90
|
+
|
91
|
+
inputs:
|
92
|
+
- input:
|
93
|
+
...
|
94
|
+
- input:
|
95
|
+
...
|
96
|
+
|
97
|
+
or for a single input
|
98
|
+
|
99
|
+
input:
|
100
|
+
....
|
101
|
+
EOS
|
102
|
+
|
103
|
+
raise ExtensionException.new <<-EOS if stepExtensionDef['inputs'] && stepExtensionDef['bindExact'] != true
|
104
|
+
Property 'inputs' cannot be defined unless 'bindExact' true.
|
105
|
+
|
106
|
+
Error in in #{stepExtensionDef.to_yaml}
|
107
|
+
|
108
|
+
EOS
|
109
|
+
|
110
|
+
|
111
|
+
# process either 'inputs' or 'input'
|
112
|
+
stepExtensionDefInputs = stepExtensionDef['inputs'] ? stepExtensionDef['inputs'] : [ { 'input' => stepExtensionDef['input'] } ]
|
113
|
+
|
114
|
+
# loop
|
115
|
+
stepExtensionDefInputs.each do |stepExtensionDefInput|
|
116
|
+
|
117
|
+
# single case: create 'mustacheTemplateData' and add it to
|
118
|
+
# 'stepParamSet'
|
119
|
+
begin
|
120
|
+
|
121
|
+
validateProperties( stepExtensionDefInput, @@validStepExtension_input )
|
122
|
+
|
123
|
+
mustacheTemplateData = extendStep_Input( interface, stepParamSet, stepExtensionDefInput['input'] )
|
124
|
+
@logger.debug "#{__method__}, mustacheTemplateData=#{mustacheTemplateData.to_yaml}"
|
125
|
+
stepParamSet.addInput( mustacheTemplateData )
|
126
|
+
|
127
|
+
rescue ExtensionException => ee
|
128
|
+
msg = "Error #{ee} caused by #{ee.backtrace.join("\n")} when extending interface '#{stepExtensionDef['interface']}'\n\n"
|
129
|
+
@logger.error( "#{__method__} #{msg}" )
|
130
|
+
raise ExtensionException.new( msg )
|
131
|
+
end
|
132
|
+
|
133
|
+
end # iterate
|
134
|
+
|
135
|
+
end # def extendStep_Inputs( interface, stepParamSet, stepExtensionDef )
|
136
|
+
|
137
|
+
|
138
|
+
# expand one input to a mustache template
|
139
|
+
def extendStep_Input( interface, stepParamSet, stepExtensionDefInputs )
|
140
|
+
|
141
|
+
# convert input paramters for the interface to datastructure, which
|
142
|
+
# can passed to template rendering
|
143
|
+
mustacheTemplateData = extendStepInputs( interface, stepExtensionDefInputs )
|
144
|
+
|
145
|
+
# add missing sub-documents in 'stepExtensionDef'
|
146
|
+
expandedStepExtensionDef = expandStepInputForDefaults( interface, stepExtensionDefInputs )
|
147
|
+
|
148
|
+
# add _default values for parameters not defined
|
149
|
+
# NB: expandedStepExtensionDef = stepExtensionDef['input']
|
150
|
+
mustacheTemplateData = extendStepDefaults( interface, expandedStepExtensionDef, mustacheTemplateData )
|
151
|
+
|
152
|
+
# assign unique number to hash element in 'mustacheTemplateData'
|
153
|
+
mustacheTemplateData = extendNumbering( mustacheTemplateData )
|
154
|
+
|
155
|
+
# added to stepParameterSet
|
156
|
+
return mustacheTemplateData
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# 'expandedInputs' includes all 'interaface' fields (recurisively)
|
162
|
+
def expandStepInputForDefaults( interface, stepExtensionInputs )
|
163
|
+
|
164
|
+
# make a deeeep copy
|
165
|
+
# puts( "expandStepInputForDefaults: stepExtensionInputs=#{stepExtensionInputs.to_yaml}\n\n" )
|
166
|
+
expandedInputs = Marshal.load( Marshal.dump( stepExtensionInputs ))
|
167
|
+
|
168
|
+
# recurse 'interface' and ensure that 'expandedInputs' structure
|
169
|
+
# corresponds 'interface' structure
|
170
|
+
expandStepInputForDefaultsRecursion( interface, expandedInputs )
|
171
|
+
|
172
|
+
# puts( "expandStepInputForDefaults: expandedInputs=#{expandedInputs.to_yaml}\n\n" )
|
173
|
+
return expandedInputs
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
# recurs 'paramSet' in synch with 'stepExtensionDef': for each
|
178
|
+
# non-leaf paramter (i.e. a a parameter referencing to an other
|
179
|
+
# paramset) ensure that 'stepExtensionDef' also this entry
|
180
|
+
def expandStepInputForDefaultsRecursion( paramSet, stepExtensionInput )
|
181
|
+
|
182
|
+
@logger.debug( "#{__method__} paramSet=#{paramSet}, stepExtensionInput=#{stepExtensionInput}, stepExtensionInput.nil?=#{stepExtensionInput.nil?}" )
|
183
|
+
|
184
|
+
# when no 'input' on 'step-extension'
|
185
|
+
stepExtensionInput = {} if stepExtensionInput.nil?
|
186
|
+
|
187
|
+
paramSet.parameters.each do |parameter|
|
188
|
+
if parameter.isReference && stepExtensionInput.is_a?( Hash ) then
|
189
|
+
# add empty input parameter (if not defined) for records (ie. Hashe).
|
190
|
+
# rows are not expanded (we do not know many we should add)
|
191
|
+
# stepExtensionInput[parameter.name] = initRecord( parameter.name ) unless stepExtensionInput.has_key?( parameter.name )
|
192
|
+
stepExtensionInput[parameter.name] = {} unless stepExtensionInput.has_key?( parameter.name )
|
193
|
+
# recurse referenced 'paramSet' together with 'stepExtensionDef'
|
194
|
+
expandStepInputForDefaultsRecursion( parameter.getResolvedReference, stepExtensionInput[parameter.name] )
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
|
201
|
+
# ------------------------------------------------------------------
|
202
|
+
# recurse 'stepExtensionInputs' and use it to set default values
|
203
|
+
# in 'mustacheTemplateData' structure.
|
204
|
+
|
205
|
+
def extendStepDefaults( interface, stepExtensionInputs, mustacheTemplateData )
|
206
|
+
# puts "extendStepDefaults - starting"
|
207
|
+
# recrurse 'stepExtensionInputs' and yield 'rows' && 'records'
|
208
|
+
recurseStepDefaults( stepExtensionInputs ) do |type, keys, indexes, stepExtensionInput, defaultValues|
|
209
|
+
# puts "type=#{type}, keys=#{keys}, indexes=#{indexes}, stepExtensionInput=#{stepExtensionInput}, defaultValues=#{defaultValues}"
|
210
|
+
|
211
|
+
# configuration in model
|
212
|
+
interfaceParameters = locateParameter( interface, keys )
|
213
|
+
|
214
|
+
# what we have expanded so far - using 'stepExtensionInputs'
|
215
|
+
templateData = locateTemplateData( mustacheTemplateData, keys, indexes )
|
216
|
+
|
217
|
+
# default value is on the top of the stack
|
218
|
+
# defaultValue = defaultValues.last
|
219
|
+
# defaultValue is the last non-nil value on stack 'defaultValues'
|
220
|
+
defaultValue = defaultValues.reverse.find { |v| !v.nil? }
|
221
|
+
|
222
|
+
next unless defaultValue
|
223
|
+
|
224
|
+
# create an entry in 'mustacheTemplateData' if path 'keys'/'indexes' no configuration
|
225
|
+
# in 'step-extension' 'input'
|
226
|
+
templateData = addTemplateData( mustacheTemplateData, keys, indexes ) unless templateData
|
227
|
+
expandDefaults( interfaceParameters, defaultValue, templateData )
|
228
|
+
|
229
|
+
# case type
|
230
|
+
# when "row"
|
231
|
+
# next unless defaultValue
|
232
|
+
# # access data row 'index'
|
233
|
+
# index = indexes.last
|
234
|
+
# # expandDefaults( interfaceParameters, defaultValue, templateData['rows'][index] )
|
235
|
+
# puts "row-expansion templateData=#{templateData}"
|
236
|
+
# expandDefaults( interfaceParameters, defaultValue, templateData )
|
237
|
+
# when "record"
|
238
|
+
# # possibly no default value defined
|
239
|
+
# next unless defaultValue
|
240
|
+
# expandDefaults( interfaceParameters, defaultValue, templateData )
|
241
|
+
# else
|
242
|
+
# # should not happen
|
243
|
+
# raise "Unknown type #{type}"
|
244
|
+
# end
|
245
|
+
end
|
246
|
+
# empty is returnet as boolean false
|
247
|
+
mustacheTemplateData = false if mustacheTemplateData == {}
|
248
|
+
|
249
|
+
mustacheTemplateData
|
250
|
+
end # def extendStepDefaults
|
251
|
+
|
252
|
+
# recurse 'stepExtensionInputs' and yield
|
253
|
+
# - record|row, [keys], parameterDef
|
254
|
+
def recurseStepDefaults( stepExtensionInputs, keys=[], indexes=[], defaultValues=nil, &block )
|
255
|
+
# puts "recurseStepDefaults(enter) stepExtensionInputs=#{stepExtensionInputs}"
|
256
|
+
return unless stepExtensionInputs
|
257
|
+
# init defaultValues
|
258
|
+
defaultValues = [ stepExtensionInputs["_default"] ] unless defaultValues
|
259
|
+
if !keys.any? then
|
260
|
+
# puts "recurseStepDefaults(init) #{stepExtensionInputs}"
|
261
|
+
yield "record", keys, indexes, stepExtensionInputs, defaultValues
|
262
|
+
end
|
263
|
+
stepExtensionInputs.each do |parameterName, parameterDef|
|
264
|
+
if parameterDef.is_a?( Array ) then
|
265
|
+
parameterDef.each.with_index do |parameterDefRow,index|
|
266
|
+
defaultValues.push( parameterDefRow["_default"] )
|
267
|
+
# puts "recurseStepDefaults:(array) resolved-defaultValues=#{defaultValues} index=#{index}, for parameterDefRow=#{parameterDefRow}"
|
268
|
+
yield "row", keys + [parameterName], indexes + [index], parameterDefRow, defaultValues
|
269
|
+
recurseStepDefaults( parameterDefRow, keys + [parameterName], indexes + [index], defaultValues, &block)
|
270
|
+
defaultValues.pop
|
271
|
+
end
|
272
|
+
elsif parameterDef.is_a?( Hash ) then
|
273
|
+
defaultValues.push( parameterDef["_default"] )
|
274
|
+
# puts "recurseStepDefaults:(hash): resolved-defaultValues=#{defaultValues} keys=#{keys}, for parameterDef=#{parameterDef}"
|
275
|
+
yield "record", keys + [parameterName], indexes + [nil], parameterDef, defaultValues
|
276
|
+
recurseStepDefaults( parameterDef, keys + [parameterName], indexes + [nil], defaultValues, &block)
|
277
|
+
defaultValues.pop
|
278
|
+
else
|
279
|
+
# puts "recurseStepDefaults:(else): resolved-defaultValues=#{defaultValues} keys=#{keys}, for parameterDef=#{parameterDef}"
|
280
|
+
# leaf entry
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|
284
|
+
|
285
|
+
end # def recurseStepDefaults
|
286
|
+
|
287
|
+
|
288
|
+
# add expanded parameters to 'templateData'
|
289
|
+
def expandDefaults( interfaceParameters, defaultValue, templateData )
|
290
|
+
|
291
|
+
# puts "\nexpandDefaults defaultValue=#{defaultValue} on '#{templateData}' missing from #{interfaceParameters}"
|
292
|
+
# return unless templateData
|
293
|
+
|
294
|
+
# array of 'parameter_name' fields found on templateData
|
295
|
+
definedParameters = templateData && templateData['columns'] ? templateData['columns'].map { |column| column[:parameter_name] } : []
|
296
|
+
|
297
|
+
# select parameters, which are not defined on 'templateData'
|
298
|
+
# (i.e. missing from 'definedParameters') append new entries in
|
299
|
+
# 'templateData' with 'defaultValue' expanded
|
300
|
+
|
301
|
+
parametersToBe( interfaceParameters ).select do |param|
|
302
|
+
|
303
|
+
# puts "expandDefaults param=#{param} of #{param.class}"
|
304
|
+
# select for expsion
|
305
|
+
# if NOT already defined i.e. NOT in definedParameters
|
306
|
+
# if CARDNIALITY defined (ie. paramter_dom object)
|
307
|
+
|
308
|
+
!definedParameters.include?( param[:parameter_name] ) && !param[:cardinality].nil?
|
309
|
+
|
310
|
+
end.each do |param|
|
311
|
+
# one more added - modify comm
|
312
|
+
templateData['columns'].last["_comma"] = ',' if templateData && templateData['columns'] && templateData['columns'].length > 0
|
313
|
+
|
314
|
+
# puts "added fied #{param[:parameter_name]}"
|
315
|
+
# create default entry
|
316
|
+
expadedElement = {
|
317
|
+
:parameter_name => param[:parameter_name],
|
318
|
+
"_comma" => '',
|
319
|
+
"rows" => false,
|
320
|
+
"columns" => false,
|
321
|
+
}
|
322
|
+
|
323
|
+
expadedElement = expandDefaultValue( expadedElement, defaultValue, param )
|
324
|
+
# ensure that 'columns' array exists (espeically case when
|
325
|
+
# only _default defined in step extension)
|
326
|
+
templateData['columns'] = [] unless templateData && templateData['columns']
|
327
|
+
templateData['columns'] << expadedElement
|
328
|
+
|
329
|
+
end # apped new entries to 'templateData'
|
330
|
+
|
331
|
+
templateData
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
# retrurn array of hashes(:parameter_name, :cardinality, :domain_prefix)
|
336
|
+
# on an interface parameters
|
337
|
+
def parametersToBe( interfaceParameters )
|
338
|
+
@logger.debug( "#{__method__} interfaceParameters=#{interfaceParameters}" )
|
339
|
+
parameters = interfaceParameters.parameters.map do |parameter|
|
340
|
+
# puts "parameter=#{parameter}"
|
341
|
+
{
|
342
|
+
:parameter_name => parameter.name,
|
343
|
+
:cardinality => parameter.respond_to?( :resolvedDomain) ? parameter.resolvedDomain.cardinality : nil,
|
344
|
+
# :domain_prefix => parameter.respond_to?( :resolvedDomain) ? parameter.resolvedDomain.domain_prefix : nil,
|
345
|
+
:domain_name => parameter.respond_to?( :resolvedDomain) ? parameter.resolvedDomain.domain_name : nil,
|
346
|
+
}
|
347
|
+
|
348
|
+
end
|
349
|
+
return parameters
|
350
|
+
end
|
351
|
+
|
352
|
+
|
353
|
+
# update :domain_value (whewn 'defaultValue' is String), or :domain_element= #{param[:domain_prefix]}#{:domain_prefix}" otherwise
|
354
|
+
def expandDefaultValue( expadedElement, defaultValue, param )
|
355
|
+
|
356
|
+
# Case 'String'
|
357
|
+
return expadedElement.merge( { :domain_value => defaultValue, :domain_element => false }) if defaultValue.is_a?( String )
|
358
|
+
|
359
|
+
# Case 'Interger'
|
360
|
+
# puts "expandDefaultValue param=#{param}"
|
361
|
+
if defaultValue.is_a?( Integer ) then
|
362
|
+
raise ExtensionException.new <<-EOS if defaultValue > param[:cardinality]
|
363
|
+
Cardinality of the default exceeds the cardinality of the parameter domain
|
364
|
+
|
365
|
+
cardinality of default : #{defaultValue}
|
366
|
+
cardinality on domain : #{param[:cardinality]}
|
367
|
+
name of parameter : #{param[:parameter_name]}
|
368
|
+
domain name : #{param[:domain_name]}
|
369
|
+
|
370
|
+
EOS
|
371
|
+
return expadedElement.merge( { :domain_element => getDomainElement( param, defaultValue ), :domain_value => false } )
|
372
|
+
end
|
373
|
+
|
374
|
+
# else - unknown value
|
375
|
+
raise raise ExtensionException.new <<-EOS
|
376
|
+
Unknown type #{defaultValue.class} for default #{defaultValue} value encountered.
|
377
|
+
|
378
|
+
Exteding paramter #{param}
|
379
|
+
EOS
|
380
|
+
end
|
381
|
+
|
382
|
+
def getDomainElement2( extededParameter, domainElement )
|
383
|
+
# puts( "extededParameter=#{extededParameter}, domainElement=#{domainElement}" )
|
384
|
+
return extededParameter.resolvedDomain.domain_entry( domainElement )
|
385
|
+
# "#{extededParameter.resolvedDomain.name}_#{domainElement}"
|
386
|
+
end
|
387
|
+
def getDomainElement( param, defaultValue )
|
388
|
+
# ret = "#{param[:domain_prefix]}#{defaultValue}"
|
389
|
+
ret = model.getDomain(param[:domain_name]).domain_entry( defaultValue )
|
390
|
+
# puts( "getDomainElement: param=#{param}, defaultValue=#{defaultValue} --> #{ret}" )
|
391
|
+
return ret
|
392
|
+
|
393
|
+
end
|
394
|
+
|
395
|
+
# ------------------------------------------------------------------
|
396
|
+
# number elements
|
397
|
+
|
398
|
+
# assign '_first' element for hash within 'mustacheTemplateData'
|
399
|
+
#
|
400
|
+
# @param mustacheTemplateData [Hash]
|
401
|
+
# @return [Hash] 'mustacheTemplateData' with record elements numbered
|
402
|
+
def extendNumbering( mustacheTemplateData )
|
403
|
+
|
404
|
+
recurseHash( mustacheTemplateData ) do |h,k,v,i|
|
405
|
+
v["_index"] = i
|
406
|
+
end
|
407
|
+
return mustacheTemplateData
|
408
|
+
end
|
409
|
+
|
410
|
+
# recurse hash, and yield 'hash', 'key', 'value', 'index' for each
|
411
|
+
# entry within the hash structure, which is_a?(Hash).
|
412
|
+
|
413
|
+
def recurseHash( hash, &block )
|
414
|
+
|
415
|
+
hash && hash.each_with_index do |(k,v),index|
|
416
|
+
if v.is_a?( Hash ) then
|
417
|
+
yield hash, k, v, index
|
418
|
+
recurseHash( v, &block)
|
419
|
+
elsif v.is_a?( Array ) then
|
420
|
+
v.each_with_index do |array_element,i|
|
421
|
+
if array_element.is_a?(Hash)
|
422
|
+
yield hash, k, array_element, i
|
423
|
+
recurseHash( array_element, &block)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
# ------------------------------------------------------------------
|
431
|
+
# recurse 'stepExtensionInputs' configuration and create a hash
|
432
|
+
# structure, which can be passed to mustache template
|
433
|
+
|
434
|
+
def extendStepInputs( interface, stepExtensionInputs )
|
435
|
+
@logger.debug( "#{__method__} stepExtensionInputs=#{stepExtensionInputs}" )
|
436
|
+
|
437
|
+
# recursion uses this as a stack
|
438
|
+
subDocumentStack = []
|
439
|
+
subDocumentStack.push( {} )
|
440
|
+
|
441
|
+
|
442
|
+
stepExtensionInputs && recurseStepInputs( stepExtensionInputs ) do |act,keys,domainElement,row|
|
443
|
+
# puts "#{act}, keys=#{keys},domainElement=#{domainElement}, #{row}"
|
444
|
+
|
445
|
+
# uses path [keys] in 'interface' to locate parameter to extend
|
446
|
+
extededParameter = locateParameter( interface, keys )
|
447
|
+
parameterName = keys.last
|
448
|
+
next if parameterName[0] == "_"
|
449
|
+
|
450
|
+
case act
|
451
|
+
when "="
|
452
|
+
@logger.debug( "#{__method__} extededParameter=#{extededParameter.name}, extededParameter.resolvedDomain=#{extededParameter.resolvedDomain}" )
|
453
|
+
input = {
|
454
|
+
:parameter_name => parameterName,
|
455
|
+
:domain_element => getDomainElement2(extededParameter, domainElement),
|
456
|
+
"rows" => false,
|
457
|
+
"columns" => false,
|
458
|
+
"_comma" => ','
|
459
|
+
}
|
460
|
+
# create new parameter && add it to the paramSet
|
461
|
+
raise ExtensionException.new <<-EOS if domainElement.is_a?( Integer ) && extededParameter.resolvedDomain.cardinality < domainElement
|
462
|
+
The cardinality on step exceeds the cardinality of the parameter domain
|
463
|
+
|
464
|
+
Name of parameter : #{extededParameter.name}
|
465
|
+
Name of parameter domain : #{extededParameter.resolvedDomain.name}
|
466
|
+
Cardinality of the parameter domain : #{extededParameter.resolvedDomain.cardinality}
|
467
|
+
Cardinality defined: #{domainElement}
|
468
|
+
|
469
|
+
EOS
|
470
|
+
|
471
|
+
subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
|
472
|
+
subDocumentStack.last["columns"] << input
|
473
|
+
when "["
|
474
|
+
input = initRecord( parameterName )
|
475
|
+
# {
|
476
|
+
# :parameter_name => parameterName,
|
477
|
+
# "rows" => false,
|
478
|
+
# "columns" => false,
|
479
|
+
# }
|
480
|
+
subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
|
481
|
+
subDocumentStack.last["columns"] << input
|
482
|
+
subDocumentStack.push( input )
|
483
|
+
when "]"
|
484
|
+
# end of sub-record
|
485
|
+
input = subDocumentStack.pop
|
486
|
+
# last element has no comma
|
487
|
+
input['columns'].last["_comma"] = '' if input['columns']
|
488
|
+
when "<<"
|
489
|
+
if row == 0 then
|
490
|
+
# start of array processing = start of row
|
491
|
+
input = initRecord( parameterName )
|
492
|
+
# {
|
493
|
+
# :parameter_name => parameterName,
|
494
|
+
# "rows" => false,
|
495
|
+
# "columns" => false,
|
496
|
+
# }
|
497
|
+
subDocumentStack.push( addColumn( subDocumentStack.last, input ))
|
498
|
+
|
499
|
+
# subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
|
500
|
+
# subDocumentStack.last["columns"] << input
|
501
|
+
# subDocumentStack.push( input )
|
502
|
+
else
|
503
|
+
# start a new row in an array
|
504
|
+
input = {
|
505
|
+
"rows" => false,
|
506
|
+
"columns" => false,
|
507
|
+
"_comma" => ",",
|
508
|
+
}
|
509
|
+
subDocumentStack.push( input )
|
510
|
+
end
|
511
|
+
|
512
|
+
when ">>"
|
513
|
+
if row == 0 then
|
514
|
+
# end of array
|
515
|
+
input = subDocumentStack.pop
|
516
|
+
input['rows'].last["_comma"] = '' if input['rows']
|
517
|
+
input['columns'].last["_comma"] = '' if input['columns']
|
518
|
+
|
519
|
+
else
|
520
|
+
input = subDocumentStack.pop
|
521
|
+
input['rows'].last["_comma"] = '' if input['rows']
|
522
|
+
input['columns'].last["_comma"] = '' if input['columns']
|
523
|
+
# puts "subDocumentStack=#{subDocumentStack}"
|
524
|
+
subDocumentStack.last["rows"] = [] unless subDocumentStack.last["rows"]
|
525
|
+
subDocumentStack.last["rows"] << input
|
526
|
+
end
|
527
|
+
else
|
528
|
+
raise "Unknown act #{act}"
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
raise "subDocumentStack should have been empty #{subDocumentStack}" unless subDocumentStack.length == 1
|
533
|
+
ret = subDocumentStack.first
|
534
|
+
|
535
|
+
# last element has no _comma always
|
536
|
+
ret['columns'].last["_comma"] = '' if ret['columns']
|
537
|
+
|
538
|
+
@logger.info( "#{__method__} return=#{ret}" )
|
539
|
+
return ret
|
540
|
+
|
541
|
+
end # def extendStepInputs( interface, stepExtensionInputs )
|
542
|
+
|
543
|
+
# Recurse 'stepExtensionInputs' (i.e. hash under key 'step-extension' ).
|
544
|
+
# During recursion yield:
|
545
|
+
# = : reference parameter, domainElement
|
546
|
+
# [ : starts hash
|
547
|
+
# ] : end hash
|
548
|
+
# << : array
|
549
|
+
# >> : end array
|
550
|
+
def recurseStepInputs( stepExtensionInputs, keys=[], row=0, &block )
|
551
|
+
stepExtensionInputs.each do |parameterName, parameterDef|
|
552
|
+
begin
|
553
|
+
if parameterDef.is_a?( Array ) then
|
554
|
+
yield "<<", keys + [parameterName], nil, 0
|
555
|
+
parameterDef.each.with_index do |parameterDefRow,index|
|
556
|
+
yield "<<", keys + [parameterName], nil, index+1
|
557
|
+
recurseStepInputs( parameterDefRow, keys + [parameterName], index+1, &block )
|
558
|
+
yield ">>", keys + [parameterName], nil, index+1
|
559
|
+
end
|
560
|
+
yield ">>", keys + [parameterName], nil, 0
|
561
|
+
|
562
|
+
elsif parameterDef.is_a?( Hash ) then
|
563
|
+
yield "[", keys + [parameterName], nil, row
|
564
|
+
recurseStepInputs( parameterDef, keys + [parameterName], row, &block )
|
565
|
+
yield "]", keys + [parameterName], nil, row
|
566
|
+
else
|
567
|
+
# do not process "meta fields" e.g '_default'
|
568
|
+
yield "=", keys + [parameterName], parameterDef, row
|
569
|
+
end
|
570
|
+
rescue SbuilderException => e
|
571
|
+
msg = <<-EOS.gsub( /^\s*/, '' )
|
572
|
+
Error:
|
573
|
+
|
574
|
+
#{e.message}
|
575
|
+
|
576
|
+
|
577
|
+
when processing parameter #{parameterName} with definition:
|
578
|
+
|
579
|
+
#{parameterDef.to_yaml}
|
580
|
+
|
581
|
+
EOS
|
582
|
+
@logger.error( "#{__method__} #{msg}" )
|
583
|
+
raise Sbuilder::LoaderException.new, msg, e.backtrace
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end # recurseStepInputs
|
587
|
+
|
588
|
+
|
589
|
+
# uses path [keys] in 'interface' to locate parameter
|
590
|
+
def locateParameter( interface, keys )
|
591
|
+
extededParameter = interface
|
592
|
+
if keys.any?
|
593
|
+
extededParameter = keys.inject(interface) { |p,key|
|
594
|
+
# _default paramtes not real parameters
|
595
|
+
next if key == "_default"
|
596
|
+
p = p.locateParameter( key )
|
597
|
+
# resolve in model context - possible for paramter_ref
|
598
|
+
# p = p.getResolvedReference( controller.model ) if p.respond_to?( :getResolvedReference )
|
599
|
+
p = p.getResolvedReference if p.respond_to?( :getResolvedReference )
|
600
|
+
p
|
601
|
+
}
|
602
|
+
@logger.debug( "#{__method__} keys #{keys}->extededParameter=#{extededParameter}" )
|
603
|
+
end
|
604
|
+
return extededParameter
|
605
|
+
end
|
606
|
+
|
607
|
+
# ensure that templateData element in ['keys'] and ['indexes']
|
608
|
+
# exists in 'mustacheTemplateData'.
|
609
|
+
def addTemplateData( mustacheTemplateData, keys, indexes )
|
610
|
+
|
611
|
+
templateData = mustacheTemplateData
|
612
|
+
prev = templateData
|
613
|
+
keys.each_with_index do |key,i|
|
614
|
+
index = indexes[i]
|
615
|
+
# puts "addTemplateData: key=#{key}, #{i}, index #{index}"
|
616
|
+
templateData = templateData['columns'].select{ |column| column[:parameter_name] == key }.first
|
617
|
+
if templateData.nil? then
|
618
|
+
templateData = initRecord( key )
|
619
|
+
addColumn( prev, templateData )
|
620
|
+
# puts "addTemplateData: added #{templateData} for key #{key} --> #{mustacheTemplateData}"
|
621
|
+
else
|
622
|
+
# puts "addTemplateData: exists #{templateData} for key #{key}"
|
623
|
+
end
|
624
|
+
|
625
|
+
prev = templateData
|
626
|
+
|
627
|
+
# # puts "data1=#{data}"
|
628
|
+
# if !index.nil? then
|
629
|
+
# templateData = templateData['rows'][index]
|
630
|
+
# # puts "data2=#{data}"
|
631
|
+
# end
|
632
|
+
end # iterate
|
633
|
+
|
634
|
+
return templateData
|
635
|
+
end
|
636
|
+
|
637
|
+
|
638
|
+
# uses path in [keys] and ['indexes'] to locate data 'mustacheTemplateData'.
|
639
|
+
def locateTemplateData( mustacheTemplateData, keys, indexes )
|
640
|
+
ret = mustacheTemplateData
|
641
|
+
i = 0
|
642
|
+
if keys.any?
|
643
|
+
ret = keys.inject(ret) { |data,key|
|
644
|
+
index = indexes[i]
|
645
|
+
i += 1
|
646
|
+
# puts "\n\nindex=#{index} of #{indexes}, i=#{i}, key=#{key} on '#{data}'"
|
647
|
+
break unless data
|
648
|
+
data = data['columns'].select{ |column| column[:parameter_name] == key }.first
|
649
|
+
# puts "data1=#{data}"
|
650
|
+
if !index.nil? then
|
651
|
+
data = data['rows'][index]
|
652
|
+
# puts "data2=#{data}"
|
653
|
+
end
|
654
|
+
|
655
|
+
# if index.nil? then
|
656
|
+
# else
|
657
|
+
# data = data['rows'][index]['columns'].select{ |column| column[:parameter_name] == key }.first
|
658
|
+
# end
|
659
|
+
data
|
660
|
+
}
|
661
|
+
end
|
662
|
+
return ret
|
663
|
+
end
|
664
|
+
|
665
|
+
# ------------------------------------------------------------------
|
666
|
+
# Build a hash structure, which can be passed to mustache template
|
667
|
+
|
668
|
+
# create record entry
|
669
|
+
private
|
670
|
+
def initRecord( parameterName )
|
671
|
+
{
|
672
|
+
:parameter_name => parameterName,
|
673
|
+
"rows" => false,
|
674
|
+
"columns" => false,
|
675
|
+
"_comma" => ",", # assume that comma get removed if -needed
|
676
|
+
}
|
677
|
+
end
|
678
|
+
|
679
|
+
def addColumn( columns, column )
|
680
|
+
# subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
|
681
|
+
# subDocumentStack.last["columns"] << input
|
682
|
+
# subDocumentStack.push( input )
|
683
|
+
columns['columns'] = [] unless columns['columns']
|
684
|
+
|
685
|
+
# la
|
686
|
+
columns['columns'].last["_comma"] = ',' if columns['columns'].length > 0
|
687
|
+
|
688
|
+
# no comma here
|
689
|
+
column["_comma"] = ''
|
690
|
+
|
691
|
+
columns['columns'] << column
|
692
|
+
return column
|
693
|
+
end
|
694
|
+
|
695
|
+
# # validate 'defintionHash' all 'required'/only 'allowed' props set
|
696
|
+
private def validateProperties( defintionHash, required, allowed=nil )
|
697
|
+
|
698
|
+
allowed = required unless allowed
|
699
|
+
|
700
|
+
missingProps = required - defintionHash.keys
|
701
|
+
raise ExtensionException.new "Missing properties #{missingProps} in #{defintionHash} - required #{required}" if missingProps.any?
|
702
|
+
|
703
|
+
invalidProps = defintionHash.keys - allowed
|
704
|
+
raise ExtensionException.new "Unknown properties #{invalidProps} in #{defintionHash} - allowed #{allowed}" if invalidProps.any?
|
705
|
+
|
706
|
+
end
|
707
|
+
|
708
|
+
end
|
709
|
+
|
710
|
+
end
|
711
|
+
|