tla-sbuilder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +328 -0
  3. data/VERSION +1 -0
  4. data/bin/sbuilder.rb +5 -0
  5. data/lib/cli/cli-customer.rb +420 -0
  6. data/lib/cli/cli-example.rb +92 -0
  7. data/lib/cli/cli-pet.rb +767 -0
  8. data/lib/cli/cli-text.rb +226 -0
  9. data/lib/cli/cli.rb +298 -0
  10. data/lib/sbuilder.rb +52 -0
  11. data/lib/sbuilder/constants.rb +72 -0
  12. data/lib/sbuilder/controller.rb +798 -0
  13. data/lib/sbuilder/default-sbuilder.yaml +372 -0
  14. data/lib/sbuilder/domain.rb +124 -0
  15. data/lib/sbuilder/domain_cardinality.rb +37 -0
  16. data/lib/sbuilder/domain_value.rb +81 -0
  17. data/lib/sbuilder/exception.rb +27 -0
  18. data/lib/sbuilder/extension_loader.rb +721 -0
  19. data/lib/sbuilder/factory.rb +234 -0
  20. data/lib/sbuilder/model.rb +356 -0
  21. data/lib/sbuilder/mustache/template.rb +125 -0
  22. data/lib/sbuilder/mustache/template_reader.rb +206 -0
  23. data/lib/sbuilder/mustache/template_reader_context.rb +371 -0
  24. data/lib/sbuilder/param_set.rb +132 -0
  25. data/lib/sbuilder/param_set_db.rb +20 -0
  26. data/lib/sbuilder/param_set_def.rb +57 -0
  27. data/lib/sbuilder/param_set_if.rb +68 -0
  28. data/lib/sbuilder/param_set_loader.rb +77 -0
  29. data/lib/sbuilder/param_set_loader_swagger.rb +424 -0
  30. data/lib/sbuilder/param_set_step.rb +62 -0
  31. data/lib/sbuilder/param_sets.rb +54 -0
  32. data/lib/sbuilder/parameter.rb +97 -0
  33. data/lib/sbuilder/parameter_container.rb +72 -0
  34. data/lib/sbuilder/parameter_dom.rb +70 -0
  35. data/lib/sbuilder/parameter_ref.rb +71 -0
  36. data/lib/sbuilder/resolver.rb +78 -0
  37. data/lib/sbuilder/resolver_loader.rb +79 -0
  38. data/lib/sbuilder/resolver_loader_yaml.rb +103 -0
  39. data/lib/sbuilder/resolver_rule.rb +36 -0
  40. data/lib/sbuilder/resolver_rule_match.rb +55 -0
  41. data/lib/sbuilder/resolver_rule_ref.rb +37 -0
  42. data/lib/utils/hash_inject.rb +12 -0
  43. data/lib/utils/logger.rb +80 -0
  44. data/lib/utils/netio.rb +58 -0
  45. data/lib/utils/string_inject.rb +10 -0
  46. data/lib/utils/version.rb +13 -0
  47. data/mustache/cfg/const_def.mustache +8 -0
  48. data/mustache/cfg/const_run.mustache +3 -0
  49. data/mustache/cfg/invariant-infrastructure-service.mustache +4 -0
  50. data/mustache/cfg/macro_run.mustache +6 -0
  51. data/mustache/cfg/module_footer.mustache +0 -0
  52. data/mustache/cfg/module_header.mustache +7 -0
  53. data/mustache/data-model-dump.mustache +19 -0
  54. data/mustache/data-model-footer.mustache +5 -0
  55. data/mustache/data-model-header.mustache +16 -0
  56. data/mustache/definition_types.mustache +40 -0
  57. data/mustache/domains.mustache +20 -0
  58. data/mustache/domains_assign.mustache +22 -0
  59. data/mustache/domains_run.mustache +21 -0
  60. data/mustache/extend/extend_assumptions.mustache +7 -0
  61. data/mustache/extend/extend_const.mustache +5 -0
  62. data/mustache/extend/extend_implementation.mustache +9 -0
  63. data/mustache/extend/extend_invariant.mustache +7 -0
  64. data/mustache/extend/extend_invariant_cfg.mustache +7 -0
  65. data/mustache/extend/extend_macros.mustache +19 -0
  66. data/mustache/extend/extend_operations.mustache +9 -0
  67. data/mustache/extend/extend_state.mustache +9 -0
  68. data/mustache/infrastructure-service-init.mustache +36 -0
  69. data/mustache/infrastructure-service-variables.mustache +10 -0
  70. data/mustache/interface_processes.mustache +38 -0
  71. data/mustache/interface_stubs_dummy.mustache +13 -0
  72. data/mustache/interface_types.mustache +52 -0
  73. data/mustache/markdown-header.mustache +24 -0
  74. data/mustache/markdown-toc.mustache +13 -0
  75. data/mustache/name_definition_type.mustache +5 -0
  76. data/mustache/name_domain.mustache +5 -0
  77. data/mustache/name_domain_value.mustache +5 -0
  78. data/mustache/name_domain_value_prefix.mustache +5 -0
  79. data/mustache/name_interface_response_type.mustache +6 -0
  80. data/mustache/name_interface_type.mustache +6 -0
  81. data/mustache/name_parameter_definition.mustache +5 -0
  82. data/mustache/name_parameter_type.mustache +6 -0
  83. data/mustache/name_process.mustache +6 -0
  84. data/mustache/name_type_invariant.mustache +5 -0
  85. data/mustache/name_variable.mustache +6 -0
  86. data/mustache/operator-infrastructure-service.mustache +13 -0
  87. data/mustache/possibility/module_extends.mustache +1 -0
  88. data/mustache/possibility/module_footer.mustache +1 -0
  89. data/mustache/possibility/module_header.mustache +8 -0
  90. data/mustache/possibility/possibility_definition.mustache +12 -0
  91. data/mustache/possibility/possibility_directive.mustache +1 -0
  92. data/mustache/possibility/possility_setup.mustache +28 -0
  93. data/mustache/setup/module_footer.mustache +1 -0
  94. data/mustache/setup/module_header.mustache +9 -0
  95. data/mustache/setup/operator_run.mustache +7 -0
  96. data/mustache/setup/operator_tick.mustache +2 -0
  97. data/mustache/setup/steps_run.mustache +22 -0
  98. data/mustache/setup/steps_run_bind_rule.mustache +51 -0
  99. data/mustache/setup/steps_run_bind_set.mustache +37 -0
  100. data/mustache/setup/steps_run_parameterBind.mustache +80 -0
  101. data/mustache/setup/steps_run_parameterExact.mustache +79 -0
  102. data/mustache/state_type_invariant-infrastructure-service.mustache +49 -0
  103. data/mustache/state_type_invariant.mustache +17 -0
  104. data/mustache/state_type_invariant_cfg.mustache +18 -0
  105. data/mustache/state_variables.mustache +20 -0
  106. data/mustache/tla/const_def.mustache +5 -0
  107. data/mustache/tla/const_run.mustache +3 -0
  108. data/mustache/tla/macro-infrastructure-service.mustache +14 -0
  109. data/mustache/tla/macro_run.mustache +40 -0
  110. data/mustache/tla/module_footer.mustache +2 -0
  111. data/mustache/tla/module_header.mustache +9 -0
  112. data/mustache/tla/operator_run.mustache +8 -0
  113. data/mustache/tla/operators-infrastructure-service.mustache +12 -0
  114. data/mustache/tla/plc_define_footer.mustache +1 -0
  115. data/mustache/tla/plc_define_header.mustache +1 -0
  116. data/mustache/tla/plc_define_run.mustache +59 -0
  117. data/mustache/tla/plc_footer.mustache +2 -0
  118. data/mustache/tla/plc_header.mustache +2 -0
  119. data/mustache/tla/plc_run_state.mustache +12 -0
  120. data/mustache/tla/plc_tail.mustache +8 -0
  121. data/mustache/tla/plc_translation.mustache +2 -0
  122. data/resources/schema/json_schema/draft-04.json +150 -0
  123. data/resources/schema/swagger/2.0/schema.json +1591 -0
  124. data/src-extend/README +2 -0
  125. data/src-extend/extend/extend_assumptions.mustache +7 -0
  126. data/src-extend/extend/extend_const.mustache +5 -0
  127. data/src-extend/extend/extend_implementation.mustache +9 -0
  128. data/src-extend/extend/extend_invariant.mustache +11 -0
  129. data/src-extend/extend/extend_invariant_cfg.mustache +7 -0
  130. data/src-extend/extend/extend_macros.mustache +19 -0
  131. data/src-extend/extend/extend_operations.mustache +9 -0
  132. data/src-extend/extend/extend_state.mustache +9 -0
  133. data/src-extend/extend_app/assumption +20 -0
  134. data/src-extend/extend_app/correctness +19 -0
  135. data/src-extend/extend_app/correctness.cfg +9 -0
  136. data/src-extend/extend_app/infrastructure +25 -0
  137. data/src-extend/extend_app/interface +11 -0
  138. data/src-extend/extend_app/operator +18 -0
  139. data/src-extend/extend_app/possibility +16 -0
  140. data/src-extend/extend_app/service +33 -0
  141. data/src-extend/extend_app/state +16 -0
  142. data/src-extend/extend_app/transaction +22 -0
  143. data/src/pet/assumption +29 -0
  144. data/src/pet/assumption_address_domains.tla +12 -0
  145. data/src/pet/assumption_domains.tla +16 -0
  146. data/src/pet/assumption_generic.tla +8 -0
  147. data/src/pet/assumption_id_domains.tla +2 -0
  148. data/src/pet/assumption_owner_domains.tla +14 -0
  149. data/src/pet/assumption_pet_domains.tla +16 -0
  150. data/src/pet/assumption_tag_domains.tla +13 -0
  151. data/src/pet/correctness +24 -0
  152. data/src/pet/correctness.cfg +9 -0
  153. data/src/pet/correctness_coherent_owner_address.tla +6 -0
  154. data/src/pet/correctness_pet_name.tla +4 -0
  155. data/src/pet/correctness_ref_tag.tla +13 -0
  156. data/src/pet/correctness_type_invariants.tla +12 -0
  157. data/src/pet/correctness_unique_pet.tla +3 -0
  158. data/src/pet/correctness_unique_tag.tla +3 -0
  159. data/src/pet/docs/Petstore.md +117 -0
  160. data/src/pet/extend/extend_assumptions.mustache +7 -0
  161. data/src/pet/extend/extend_implementation.mustache +9 -0
  162. data/src/pet/extend/extend_invariant.mustache +11 -0
  163. data/src/pet/extend/extend_invariant_cfg.mustache +7 -0
  164. data/src/pet/extend/extend_macros.mustache +19 -0
  165. data/src/pet/extend/extend_operations.mustache +9 -0
  166. data/src/pet/extend/extend_state.mustache +9 -0
  167. data/src/pet/infrastructure +25 -0
  168. data/src/pet/infrastructure_id_get.tla +24 -0
  169. data/src/pet/interface +12 -0
  170. data/src/pet/interface_delete_pet.tla +5 -0
  171. data/src/pet/interface_get_pet.tla +4 -0
  172. data/src/pet/interface_post_pet.tla +5 -0
  173. data/src/pet/interface_post_tag.tla +5 -0
  174. data/src/pet/interface_put_tag.tla +3 -0
  175. data/src/pet/operator +30 -0
  176. data/src/pet/operator_find_tag_by_owner_name.tla +1 -0
  177. data/src/pet/operator_get_pet.tla +4 -0
  178. data/src/pet/operator_get_pet_by_tag.tla +4 -0
  179. data/src/pet/operator_get_tag.tla +10 -0
  180. data/src/pet/operator_new_owner.tla +3 -0
  181. data/src/pet/operator_new_pet.tla +13 -0
  182. data/src/pet/operator_new_tag.tla +3 -0
  183. data/src/pet/operator_next_pet_id.tla +3 -0
  184. data/src/pet/operator_responses.tla +8 -0
  185. data/src/pet/operator_tag_exists.tla +2 -0
  186. data/src/pet/operator_tag_owner_validated.tla +2 -0
  187. data/src/pet/operator_tag_referenced.tla +4 -0
  188. data/src/pet/operator_valid_owner.tla +17 -0
  189. data/src/pet/operator_valid_pet.tla +6 -0
  190. data/src/pet/operator_valid_tag.tla +5 -0
  191. data/src/pet/possibility +18 -0
  192. data/src/pet/possibility_at_least_two_tags.tla +12 -0
  193. data/src/pet/possibility_invalid_tag_address.tla +8 -0
  194. data/src/pet/service +35 -0
  195. data/src/pet/service_pet_delete.tla +11 -0
  196. data/src/pet/service_pet_get.tla +27 -0
  197. data/src/pet/service_pet_post.tla +78 -0
  198. data/src/pet/service_tag_post.tla +53 -0
  199. data/src/pet/service_tag_put.tla +82 -0
  200. data/src/pet/state +16 -0
  201. data/src/pet/state_infra.tla +6 -0
  202. data/src/pet/state_pet.tla +5 -0
  203. data/src/pet/state_tag_id.tla +2 -0
  204. data/src/pet/transaction +23 -0
  205. data/src/pet/transaction_delete_pet.tla +13 -0
  206. data/src/pet/transaction_enter_pet.tla +13 -0
  207. data/src/pet/transaction_enter_tag.tla +56 -0
  208. data/src/pet/transaction_error.tla +23 -0
  209. data/tla-sbuilder.gemspec +43 -0
  210. metadata +353 -0
@@ -0,0 +1,37 @@
1
+
2
+ module Sbuilder
3
+
4
+ class DomainCardinality < Domain
5
+
6
+ attr_reader :cardinality
7
+
8
+ # ------------------------------------------------------------------
9
+ # mixer
10
+ PROGNAME = "CardDomain" # progname for logger
11
+ include Sbuilder::Utils::MyLogger # mix logger
12
+
13
+
14
+ def initialize( options = {} )
15
+ super( options )
16
+ @logger = getLogger( PROGNAME, options )
17
+ @logger.info( "#{__method__} initialized" )
18
+
19
+ # default values one
20
+ @cardinality = 1
21
+ end
22
+
23
+ # ------------------------------------------------------------------
24
+ # build
25
+ def setCardinality( cardinality )
26
+ @cardinality = cardinality
27
+ self
28
+ end
29
+
30
+
31
+ end
32
+
33
+
34
+ end
35
+
36
+
37
+
@@ -0,0 +1,81 @@
1
+
2
+ module Sbuilder
3
+
4
+ class DomainValue < Domain
5
+
6
+ attr_reader :values
7
+
8
+ # ------------------------------------------------------------------
9
+ # mixer
10
+ PROGNAME = "ValueDomain" # progname for logger
11
+ include Sbuilder::Utils::MyLogger # mix logger
12
+
13
+
14
+ def initialize( options = {} )
15
+ super( options )
16
+ @logger = getLogger( PROGNAME, options )
17
+ @logger.info( "#{__method__} initialized" )
18
+
19
+ # default values one
20
+ @values = []
21
+ end
22
+
23
+
24
+ # ------------------------------------------------------------------
25
+ # cardinality overriden
26
+ def cardinality
27
+ @values.size
28
+ end
29
+
30
+
31
+ # @param i [integer|string] domain entry to access
32
+ # @return value in location `i-1` ie. indexing from 1,2,3,.. when i:integer
33
+ # value with the given name when i:string
34
+ def domain_entry( i )
35
+ case i
36
+ when Integer
37
+ @values[i-1]
38
+ when String
39
+ ret = @values.select { |val| val == i }.first
40
+ if ret.nil?
41
+ raise DomainException.new <<-EOS
42
+ Unknown domain entry #{i}
43
+
44
+ Known domain entries: #{values.join(',')}
45
+ EOS
46
+ end
47
+ return ret
48
+ else
49
+ raise DomainException.new <<-EOS
50
+ Unknown type #{i.class} in 'domain_entry' #{name}.
51
+
52
+ Support only for Integer, String
53
+ EOS
54
+ end
55
+ end
56
+
57
+
58
+ # ------------------------------------------------------------------
59
+ # return array of strings for entries in domain - overides super
60
+ def domain_entries
61
+ @logger.debug( "#{__method__} #{name}: added domain_entries #{values.join(',')}" )
62
+ values
63
+ end
64
+
65
+ # ------------------------------------------------------------------
66
+ # build
67
+
68
+ def addValue( value )
69
+ @logger.debug( "#{__method__} #{name}: added value #{value}" )
70
+ @values << value
71
+ self
72
+ end
73
+
74
+
75
+ end
76
+
77
+
78
+ end
79
+
80
+
81
+
@@ -0,0 +1,27 @@
1
+ module Sbuilder
2
+
3
+ class TemplateReaderException < Exception
4
+ end
5
+
6
+
7
+ class ResolverException < Exception
8
+ end
9
+
10
+ class ExtensionException < Exception
11
+ end
12
+
13
+
14
+ class DomainException < Exception
15
+ end
16
+
17
+ class ControllerException < Exception
18
+ end
19
+
20
+ class ModelException < Exception
21
+ end
22
+
23
+ class LoaderException < Exception
24
+ end
25
+
26
+
27
+ end
@@ -0,0 +1,721 @@
1
+ module Sbuilder
2
+
3
+ class ExtensionLoader
4
+
5
+ attr_accessor :controller # get sets when load starts
6
+
7
+ # ------------------------------------------------------------------
8
+ # mixer
9
+ PROGNAME = "ExtensionLoader" # progname for logger
10
+ include Sbuilder::Utils::MyLogger # mix logger
11
+
12
+ @@extensionDefProperties = ['domain-extension', 'interface-extension', 'step-extension']
13
+
14
+ @@extensionDoaminProperties = ['domain', 'cardinality']
15
+
16
+ @@extensionValuesProperties = ['domain', 'values']
17
+
18
+ @@validStepExtension_required = ["interface" ]
19
+ @@validStepExtension_allowed = @@validStepExtension_required + ["input", "bindExact", "inputs"]
20
+
21
+ @@validStepExtension_input = [ "input" ]
22
+
23
+
24
+ # ------------------------------------------------------------------
25
+ # constructore
26
+
27
+ def initialize( options = {} )
28
+ @logger = getLogger( PROGNAME, options )
29
+ @logger.info( "#{__method__} initialized" )
30
+ self
31
+ end
32
+
33
+ # ------------------------------------------------------------------
34
+ # model - is found using contorller
35
+ def model
36
+ controller.model
37
+ end
38
+
39
+ def factory
40
+ controller.factory
41
+ end
42
+
43
+ # ------------------------------------------------------------------
44
+ # load
45
+ def load( filePath, controller )
46
+ @logger.info( "#{__method__} filePath=#{filePath}" )
47
+ @controller = controller
48
+ doLoad( filePath )
49
+ end
50
+
51
+ def doLoad( fileUri )
52
+
53
+ yaml = Sbuilder::Utils::NetIo.read_lines( fileUri )
54
+ domains_hash = YAML.load( yaml )
55
+ loadExtensions( domains_hash )
56
+ end
57
+
58
+
59
+ # iterate domains
60
+ def loadExtensions( extensionsArr )
61
+ extensionsArr && extensionsArr.each do |extensionDef|
62
+ raise ExtensionException.new "Invalid extension definition #{extensionDef}" unless (extensionDef.keys.length == 1)
63
+ validateProperties( extensionDef, [], @@extensionDefProperties )
64
+ key = extensionDef.keys.first
65
+ case key
66
+ when 'domain-extension'
67
+ extensionDef[key].each do |domainDef|
68
+ if !domainDef['cardinality'].nil? then
69
+ extendDomainWithCardinality( domainDef )
70
+ else
71
+ extendDomainWithValues( domainDef )
72
+ end
73
+ end
74
+ when 'interface-extension'
75
+ extensionDef[key].each do |interfaceExtesionDef|
76
+ extendInterface( interfaceExtesionDef )
77
+ end
78
+ when 'step-extension'
79
+ extensionDef[key].each do |stepExtensionDef|
80
+ extendStep( stepExtensionDef )
81
+ end
82
+ else
83
+ raise ExtensionException.new "Unknown extension type #{key} in #{extensionDef}"
84
+ end
85
+ end
86
+ end
87
+
88
+ # validate 'defintionHash' all 'required'/only 'allowed' props set
89
+ private def validateProperties( defintionHash, required, allowed=nil )
90
+
91
+ allowed = required unless allowed
92
+
93
+ missingProps = required - defintionHash.keys
94
+ raise ExtensionException.new "Missing properties #{missingProps} in #{defintionHash} - required #{required}" if missingProps.any?
95
+
96
+ invalidProps = defintionHash.keys - allowed
97
+ raise ExtensionException.new "Unknown properties #{invalidProps} in #{defintionHash} - allowed #{allowed}" if invalidProps.any?
98
+
99
+ end
100
+ # ------------------------------------------------------------------
101
+ # extend one domain with cardinality
102
+ def extendDomainWithValues( domainDef )
103
+ @logger.info( "#{__method__} domainDef=#{domainDef}" )
104
+ validateProperties( domainDef, @@extensionValuesProperties )
105
+
106
+ # create & configure
107
+ domain = factory.createDomain( Sbuilder::Constants::TYPE_VALUE_DOMAIN )
108
+ domain.setName( domainDef['domain'] )
109
+ domainDef['values'].each { |value| domain.addValue( value ) }
110
+
111
+ # pass to model via controller
112
+ controller.extendDomain( domain )
113
+
114
+ end
115
+
116
+ # ------------------------------------------------------------------
117
+ # extend one domain with cardinality
118
+ def extendDomainWithCardinality( domainDef )
119
+ @logger.info( "#{__method__} domainDef=#{domainDef}" )
120
+ validateProperties( domainDef, @@extensionDoaminProperties )
121
+
122
+ # create & configure
123
+ domain = factory.createDomain( Sbuilder::Constants::TYPE_CARDINALITY_DOMAIN )
124
+ domain.setName( domainDef['domain'] )
125
+ domain.setCardinality( domainDef['cardinality'] )
126
+
127
+ # pass to model via controller
128
+ controller.extendDomain( domain )
129
+ end
130
+
131
+ # ------------------------------------------------------------------
132
+ # extend interface
133
+ def extendInterface( interfaceExtensionDef )
134
+ @logger.info( "#{__method__} interfaceExtensionDef=#{interfaceExtensionDef}" )
135
+ controller.extendInterface( interfaceExtensionDef )
136
+ end
137
+
138
+ # ------------------------------------------------------------------
139
+ # extend steps: recurse 'stepExtensionDef' and create a hash, which
140
+ # can passed to mustache templates
141
+
142
+ def extendStep( stepExtensionDef )
143
+ @logger.info( "#{__method__} stepExtensionDef=#{stepExtensionDef}" )
144
+
145
+ validateProperties( stepExtensionDef, @@validStepExtension_required, @@validStepExtension_allowed )
146
+
147
+ # access paramSet for interface being extenedd && assert that it also exists
148
+ interface = controller.getInterface( stepExtensionDef['interface'] )
149
+
150
+ # create new param-set && configure it
151
+ stepParamSet = controller.createParamSet( Sbuilder::Constants::PARAM_SET_STEPS )
152
+ stepParamSet.setInterfaceReference( interface )
153
+ stepParamSet.setBindExact( stepExtensionDef["bindExact"] )
154
+
155
+ # iterate stepParamSet['inputs']/stepParamSet['input'] to create
156
+ # mustacheTemplateData & add use 'stepParamSet.addInput' add it
157
+ # to 'stepParamSet'
158
+ extendStep_Inputs( interface, stepParamSet, stepExtensionDef )
159
+
160
+ # pass extension for controller - to delegate to model
161
+ controller.extendStep( stepParamSet )
162
+
163
+ end
164
+
165
+ def extendStep_Inputs( interface, stepParamSet, stepExtensionDef )
166
+
167
+ raise ExtensionException.new <<-EOS if stepExtensionDef['input'] && stepExtensionDef['inputs']
168
+ Property 'input' cannot be defined together with 'inputs' in #{stepExtensionDef.to_yaml}
169
+
170
+ Use
171
+
172
+ inputs:
173
+ - input:
174
+ ...
175
+ - input:
176
+ ...
177
+
178
+ or for a single input
179
+
180
+ input:
181
+ ....
182
+ EOS
183
+
184
+ raise ExtensionException.new <<-EOS if stepExtensionDef['inputs'] && stepExtensionDef['bindExact'] != true
185
+ Property 'inputs' cannot be defined unless 'bindExact' true.
186
+
187
+ Error in in #{stepExtensionDef.to_yaml}
188
+
189
+ EOS
190
+
191
+
192
+ # process either 'inputs' or 'input'
193
+ stepExtensionDefInputs = stepExtensionDef['inputs'] ? stepExtensionDef['inputs'] : [ { 'input' => stepExtensionDef['input'] } ]
194
+
195
+ # loop
196
+ stepExtensionDefInputs.each do |stepExtensionDefInput|
197
+
198
+ # single case: create 'mustacheTemplateData' and add it to
199
+ # 'stepParamSet'
200
+ begin
201
+
202
+ validateProperties( stepExtensionDefInput, @@validStepExtension_input )
203
+
204
+ mustacheTemplateData = extendStep_Input( interface, stepParamSet, stepExtensionDefInput['input'] )
205
+ stepParamSet.addInput( mustacheTemplateData )
206
+
207
+ rescue ExtensionException => ee
208
+ msg = "Error #{ee} caused by #{ee.backtrace.join("\n")} when extending interface '#{stepExtensionDef['interface']}'\n\n"
209
+ @logger.error( "#{__method__} #{msg}" )
210
+ raise ExtensionException.new( msg )
211
+ end
212
+
213
+ end # iterate
214
+
215
+ end # def extendStep_Inputs( interface, stepParamSet, stepExtensionDef )
216
+
217
+
218
+ # expand one input to a mustache template
219
+ def extendStep_Input( interface, stepParamSet, stepExtensionDefInputs )
220
+
221
+ # convert input paramters for the interface to datastructure, which
222
+ # can passed to template rendering
223
+ mustacheTemplateData = extendStepInputs( interface, stepExtensionDefInputs )
224
+
225
+ # add missing sub-documents in 'stepExtensionDef'
226
+ expandedStepExtensionDef = expandStepInputForDefaults( interface, stepExtensionDefInputs )
227
+
228
+ # add _default values for parameters not defined
229
+ # NB: expandedStepExtensionDef = stepExtensionDef['input']
230
+ mustacheTemplateData = extendStepDefaults( interface, expandedStepExtensionDef, mustacheTemplateData )
231
+
232
+ # added to stepParameterSet
233
+ return mustacheTemplateData
234
+
235
+ end
236
+
237
+
238
+ # 'expandedInputs' includes all 'interaface' fields (recurisively)
239
+ def expandStepInputForDefaults( interface, stepExtensionInputs )
240
+
241
+ # make a deeeep copy
242
+ # puts( "expandStepInputForDefaults: stepExtensionInputs=#{stepExtensionInputs.to_yaml}\n\n" )
243
+ expandedInputs = Marshal.load( Marshal.dump( stepExtensionInputs ))
244
+
245
+ # recurse 'interface' and ensure that 'expandedInputs' structure
246
+ # corresponds 'interface' structure
247
+ expandStepInputForDefaultsRecursion( interface, expandedInputs )
248
+
249
+ # puts( "expandStepInputForDefaults: expandedInputs=#{expandedInputs.to_yaml}\n\n" )
250
+ return expandedInputs
251
+
252
+ end
253
+
254
+ # recurs 'paramSet' in synch with 'stepExtensionDef': for each
255
+ # non-leaf paramter (i.e. a a parameter referencing to an other
256
+ # paramset) ensure that 'stepExtensionDef' also this entry
257
+ def expandStepInputForDefaultsRecursion( paramSet, stepExtensionInput )
258
+
259
+ @logger.debug( "#{__method__} paramSet=#{paramSet}, stepExtensionInput=#{stepExtensionInput}, stepExtensionInput.nil?=#{stepExtensionInput.nil?}" )
260
+
261
+ # when no 'input' on 'step-extension'
262
+ stepExtensionInput = {} if stepExtensionInput.nil?
263
+
264
+ paramSet.parameters.each do |parameter|
265
+ if parameter.isReference && stepExtensionInput.is_a?( Hash ) then
266
+ # add empty input parameter (if not defined) for records (ie. Hashe).
267
+ # rows are not expanded (we do not know many we should add)
268
+ # stepExtensionInput[parameter.name] = initRecord( parameter.name ) unless stepExtensionInput.has_key?( parameter.name )
269
+ stepExtensionInput[parameter.name] = {} unless stepExtensionInput.has_key?( parameter.name )
270
+ # recurse referenced 'paramSet' together with 'stepExtensionDef'
271
+ expandStepInputForDefaultsRecursion( parameter.getResolvedReference( model ), stepExtensionInput[parameter.name] )
272
+ end
273
+ end
274
+ end
275
+
276
+ # ------------------------------------------------------------------
277
+ # recurse 'stepExtensionInputs' and use it to set default values
278
+ # in 'mustacheTemplateData' structure.
279
+
280
+ def extendStepDefaults( interface, stepExtensionInputs, mustacheTemplateData )
281
+ # puts "extendStepDefaults - starting"
282
+ # recrurse 'stepExtensionInputs' and yield 'rows' && 'records'
283
+ recurseStepDefaults( stepExtensionInputs ) do |type, keys, indexes, stepExtensionInput, defaultValues|
284
+ # puts "type=#{type}, keys=#{keys}, indexes=#{indexes}, stepExtensionInput=#{stepExtensionInput}, defaultValues=#{defaultValues}"
285
+
286
+ # configuration in model
287
+ interfaceParameters = locateParameter( interface, keys )
288
+
289
+ # what we have expanded so far - using 'stepExtensionInputs'
290
+ templateData = locateTemplateData( mustacheTemplateData, keys, indexes )
291
+
292
+ # default value is on the top of the stack
293
+ # defaultValue = defaultValues.last
294
+ # defaultValue is the last non-nil value on stack 'defaultValues'
295
+ defaultValue = defaultValues.reverse.find { |v| !v.nil? }
296
+
297
+ next unless defaultValue
298
+
299
+ # create an entry in 'mustacheTemplateData' if path 'keys'/'indexes' no configuration
300
+ # in 'step-extension' 'input'
301
+ templateData = addTemplateData( mustacheTemplateData, keys, indexes ) unless templateData
302
+ expandDefaults( interfaceParameters, defaultValue, templateData )
303
+
304
+ # case type
305
+ # when "row"
306
+ # next unless defaultValue
307
+ # # access data row 'index'
308
+ # index = indexes.last
309
+ # # expandDefaults( interfaceParameters, defaultValue, templateData['rows'][index] )
310
+ # puts "row-expansion templateData=#{templateData}"
311
+ # expandDefaults( interfaceParameters, defaultValue, templateData )
312
+ # when "record"
313
+ # # possibly no default value defined
314
+ # next unless defaultValue
315
+ # expandDefaults( interfaceParameters, defaultValue, templateData )
316
+ # else
317
+ # # should not happen
318
+ # raise "Unknown type #{type}"
319
+ # end
320
+ end
321
+ # empty is returnet as boolean false
322
+ mustacheTemplateData = false if mustacheTemplateData == {}
323
+
324
+ mustacheTemplateData
325
+ end # def extendStepDefaults
326
+
327
+ # recurse 'stepExtensionInputs' and yield
328
+ # - record|row, [keys], parameterDef
329
+ def recurseStepDefaults( stepExtensionInputs, keys=[], indexes=[], defaultValues=nil, &block )
330
+ # puts "recurseStepDefaults(enter) stepExtensionInputs=#{stepExtensionInputs}"
331
+ return unless stepExtensionInputs
332
+ # init defaultValues
333
+ defaultValues = [ stepExtensionInputs["_default"] ] unless defaultValues
334
+ if !keys.any? then
335
+ # puts "recurseStepDefaults(init) #{stepExtensionInputs}"
336
+ yield "record", keys, indexes, stepExtensionInputs, defaultValues
337
+ end
338
+ stepExtensionInputs.each do |parameterName, parameterDef|
339
+ if parameterDef.is_a?( Array ) then
340
+ parameterDef.each.with_index do |parameterDefRow,index|
341
+ defaultValues.push( parameterDefRow["_default"] )
342
+ # puts "recurseStepDefaults:(array) resolved-defaultValues=#{defaultValues} index=#{index}, for parameterDefRow=#{parameterDefRow}"
343
+ yield "row", keys + [parameterName], indexes + [index], parameterDefRow, defaultValues
344
+ recurseStepDefaults( parameterDefRow, keys + [parameterName], indexes + [index], defaultValues, &block)
345
+ defaultValues.pop
346
+ end
347
+ elsif parameterDef.is_a?( Hash ) then
348
+ defaultValues.push( parameterDef["_default"] )
349
+ # puts "recurseStepDefaults:(hash): resolved-defaultValues=#{defaultValues} keys=#{keys}, for parameterDef=#{parameterDef}"
350
+ yield "record", keys + [parameterName], indexes + [nil], parameterDef, defaultValues
351
+ recurseStepDefaults( parameterDef, keys + [parameterName], indexes + [nil], defaultValues, &block)
352
+ defaultValues.pop
353
+ else
354
+ # puts "recurseStepDefaults:(else): resolved-defaultValues=#{defaultValues} keys=#{keys}, for parameterDef=#{parameterDef}"
355
+ # leaf entry
356
+ end
357
+
358
+ end
359
+
360
+ end # def recurseStepDefaults
361
+
362
+
363
+ # add expanded parameters to 'templateData'
364
+ def expandDefaults( interfaceParameters, defaultValue, templateData )
365
+
366
+ # puts "\nexpandDefaults defaultValue=#{defaultValue} on '#{templateData}' missing from #{interfaceParameters}"
367
+ # return unless templateData
368
+
369
+ # array of 'parameter_name' fields found on templateData
370
+ definedParameters = templateData && templateData['columns'] ? templateData['columns'].map { |column| column[:parameter_name] } : []
371
+
372
+ # select parameters, which are not defined on 'templateData'
373
+ # (i.e. missing from 'definedParameters') append new entries in
374
+ # 'templateData' with 'defaultValue' expanded
375
+
376
+ parametersToBe( interfaceParameters ).select do |param|
377
+
378
+ # puts "expandDefaults param=#{param} of #{param.class}"
379
+ # select for expsion
380
+ # if NOT already defined i.e. NOT in definedParameters
381
+ # if CARDNIALITY defined (ie. paramter_dom object)
382
+
383
+ !definedParameters.include?( param[:parameter_name] ) && !param[:cardinality].nil?
384
+
385
+ end.each do |param|
386
+ # one more added - modify comm
387
+ templateData['columns'].last["_comma"] = ',' if templateData && templateData['columns'] && templateData['columns'].length > 0
388
+
389
+ # puts "added fied #{param[:parameter_name]}"
390
+ # create default entry
391
+ expadedElement = {
392
+ :parameter_name => param[:parameter_name],
393
+ "_comma" => '',
394
+ "rows" => false,
395
+ "columns" => false,
396
+ }
397
+
398
+ expadedElement = expandDefaultValue( expadedElement, defaultValue, param )
399
+ # ensure that 'columns' array exists (espeically case when
400
+ # only _default defined in step extension)
401
+ templateData['columns'] = [] unless templateData && templateData['columns']
402
+ templateData['columns'] << expadedElement
403
+
404
+ end # apped new entries to 'templateData'
405
+
406
+ templateData
407
+
408
+ end
409
+
410
+ # retrurn array of hashes(:parameter_name, :cardinality, :domain_prefix)
411
+ # on an interface parameters
412
+ def parametersToBe( interfaceParameters )
413
+ @logger.debug( "#{__method__} interfaceParameters=#{interfaceParameters}" )
414
+ parameters = interfaceParameters.parameters.map do |parameter|
415
+ # puts "parameter=#{parameter}"
416
+ {
417
+ :parameter_name => parameter.name,
418
+ :cardinality => parameter.respond_to?( :resolvedDomain) ? parameter.resolvedDomain.cardinality : nil,
419
+ # :domain_prefix => parameter.respond_to?( :resolvedDomain) ? parameter.resolvedDomain.domain_prefix : nil,
420
+ :domain_name => parameter.respond_to?( :resolvedDomain) ? parameter.resolvedDomain.domain_name : nil,
421
+ }
422
+
423
+ end
424
+ return parameters
425
+ end
426
+
427
+
428
+ # update :domain_value (whewn 'defaultValue' is String), or :domain_element= #{param[:domain_prefix]}#{:domain_prefix}" otherwise
429
+ def expandDefaultValue( expadedElement, defaultValue, param )
430
+
431
+ # Case 'String'
432
+ return expadedElement.merge( { :domain_value => defaultValue, :domain_element => false }) if defaultValue.is_a?( String )
433
+
434
+ # Case 'Interger'
435
+ # puts "expandDefaultValue param=#{param}"
436
+ if defaultValue.is_a?( Integer ) then
437
+ raise ExtensionException.new <<-EOS if defaultValue > param[:cardinality]
438
+ Cardinality of the default exceeds the cardinality of the parameter domain
439
+
440
+ cardinality of default : #{defaultValue}
441
+ cardinality on domain : #{param[:cardinality]}
442
+ name of parameter : #{param[:parameter_name]}
443
+ domain name : #{param[:domain_name]}
444
+
445
+ EOS
446
+ return expadedElement.merge( { :domain_element => getDomainElement( param, defaultValue ), :domain_value => false } )
447
+ end
448
+
449
+ # else - unknown value
450
+ raise raise ExtensionException.new <<-EOS
451
+ Unknown type #{defaultValue.class} for default #{defaultValue} value encountered.
452
+
453
+ Exteding paramter #{param}
454
+ EOS
455
+ end
456
+
457
+ def getDomainElement2( extededParameter, domainElement )
458
+ # puts( "extededParameter=#{extededParameter}, domainElement=#{domainElement}" )
459
+ return extededParameter.resolvedDomain.domain_entry( domainElement )
460
+ # "#{extededParameter.resolvedDomain.name}_#{domainElement}"
461
+ end
462
+ def getDomainElement( param, defaultValue )
463
+ # ret = "#{param[:domain_prefix]}#{defaultValue}"
464
+ ret = model.getDomain(param[:domain_name]).domain_entry( defaultValue )
465
+ # puts( "getDomainElement: param=#{param}, defaultValue=#{defaultValue} --> #{ret}" )
466
+ return ret
467
+
468
+ end
469
+
470
+ # ------------------------------------------------------------------
471
+ # recurse 'stepExtensionInputs' configuration and create a hash
472
+ # structure, which can be passed to mustache template
473
+
474
+ def extendStepInputs( interface, stepExtensionInputs )
475
+ @logger.debug( "#{__method__} stepExtensionInputs=#{stepExtensionInputs}" )
476
+
477
+ # recursion uses this as a stack
478
+ subDocumentStack = []
479
+ subDocumentStack.push( {} )
480
+
481
+
482
+ stepExtensionInputs && recurseStepInputs( stepExtensionInputs ) do |act,keys,domainElement,row|
483
+ # puts "#{act}, keys=#{keys},domainElement=#{domainElement}, #{row}"
484
+
485
+ # uses path [keys] in 'interface' to locate parameter to extend
486
+ extededParameter = locateParameter( interface, keys )
487
+ parameterName = keys.last
488
+ next if parameterName[0] == "_"
489
+
490
+ case act
491
+ when "="
492
+ @logger.debug( "#{__method__} extededParameter=#{extededParameter.name}, extededParameter.resolvedDomain=#{extededParameter.resolvedDomain}" )
493
+ input = {
494
+ :parameter_name => parameterName,
495
+ :domain_element => getDomainElement2(extededParameter, domainElement),
496
+ "rows" => false,
497
+ "columns" => false,
498
+ "_comma" => ','
499
+ }
500
+ # create new parameter && add it to the paramSet
501
+ raise ExtensionException.new <<-EOS if domainElement.is_a?( Integer ) && extededParameter.resolvedDomain.cardinality < domainElement
502
+ The cardinality on step exceeds the cardinality of the parameter domain
503
+
504
+ Name of parameter : #{extededParameter.name}
505
+ Name of parameter domain : #{extededParameter.resolvedDomain.name}
506
+ Cardinality of the parameter domain : #{extededParameter.resolvedDomain.cardinality}
507
+ Cardinality defined: #{domainElement}
508
+
509
+ EOS
510
+
511
+ subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
512
+ subDocumentStack.last["columns"] << input
513
+ when "["
514
+ input = initRecord( parameterName )
515
+ # {
516
+ # :parameter_name => parameterName,
517
+ # "rows" => false,
518
+ # "columns" => false,
519
+ # }
520
+ subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
521
+ subDocumentStack.last["columns"] << input
522
+ subDocumentStack.push( input )
523
+ when "]"
524
+ # end of sub-record
525
+ input = subDocumentStack.pop
526
+ # last element has no comma
527
+ input['columns'].last["_comma"] = '' if input['columns']
528
+ when "<<"
529
+ if row == 0 then
530
+ # start of array processing = start of row
531
+ input = initRecord( parameterName )
532
+ # {
533
+ # :parameter_name => parameterName,
534
+ # "rows" => false,
535
+ # "columns" => false,
536
+ # }
537
+ subDocumentStack.push( addColumn( subDocumentStack.last, input ))
538
+
539
+ # subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
540
+ # subDocumentStack.last["columns"] << input
541
+ # subDocumentStack.push( input )
542
+ else
543
+ # start a new row in an array
544
+ input = {
545
+ "rows" => false,
546
+ "columns" => false,
547
+ "_comma" => ",",
548
+ }
549
+ subDocumentStack.push( input )
550
+ end
551
+
552
+ when ">>"
553
+ if row == 0 then
554
+ # end of array
555
+ input = subDocumentStack.pop
556
+ input['rows'].last["_comma"] = '' if input['rows']
557
+ input['columns'].last["_comma"] = '' if input['columns']
558
+
559
+ else
560
+ input = subDocumentStack.pop
561
+ input['rows'].last["_comma"] = '' if input['rows']
562
+ input['columns'].last["_comma"] = '' if input['columns']
563
+ # puts "subDocumentStack=#{subDocumentStack}"
564
+ subDocumentStack.last["rows"] = [] unless subDocumentStack.last["rows"]
565
+ subDocumentStack.last["rows"] << input
566
+ end
567
+ else
568
+ raise "Unknown act #{act}"
569
+ end
570
+ end
571
+
572
+ raise "subDocumentStack should have been empty #{subDocumentStack}" unless subDocumentStack.length == 1
573
+ ret = subDocumentStack.first
574
+
575
+ # last element has no _comma always
576
+ ret['columns'].last["_comma"] = '' if ret['columns']
577
+
578
+ @logger.info( "#{__method__} return=#{ret}" )
579
+ return ret
580
+
581
+ end # def extendStepInputs( interface, stepExtensionInputs )
582
+
583
+ # Recurse 'stepExtensionInputs' (i.e. hash under key 'step-extension' ).
584
+ # During recursion yield:
585
+ # = : reference parameter, domainElement
586
+ # [ : starts hash
587
+ # ] : end hash
588
+ # << : array
589
+ # >> : end array
590
+ def recurseStepInputs( stepExtensionInputs, keys=[], row=0, &block )
591
+ stepExtensionInputs.each do |parameterName, parameterDef|
592
+ if parameterDef.is_a?( Array ) then
593
+ yield "<<", keys + [parameterName], nil, 0
594
+ parameterDef.each.with_index do |parameterDefRow,index|
595
+ yield "<<", keys + [parameterName], nil, index+1
596
+ recurseStepInputs( parameterDefRow, keys + [parameterName], index+1, &block )
597
+ yield ">>", keys + [parameterName], nil, index+1
598
+ end
599
+ yield ">>", keys + [parameterName], nil, 0
600
+
601
+ elsif parameterDef.is_a?( Hash ) then
602
+ yield "[", keys + [parameterName], nil, row
603
+ recurseStepInputs( parameterDef, keys + [parameterName], row, &block )
604
+ yield "]", keys + [parameterName], nil, row
605
+ else
606
+ # do not process "meta fields" e.g '_default'
607
+ yield "=", keys + [parameterName], parameterDef, row
608
+ end
609
+ end
610
+ end # recurseStepInputs
611
+
612
+
613
+ # uses path [keys] in 'interface' to locate parameter
614
+ def locateParameter( interface, keys )
615
+ extededParameter = interface
616
+ if keys.any?
617
+ extededParameter = keys.inject(interface) { |p,key|
618
+ # _default paramtes not real parameters
619
+ next if key == "_default"
620
+ p = p.locateParameter( key )
621
+ # resolve in model context - possible for paramter_ref
622
+ p = p.getResolvedReference( controller.model ) if p.respond_to?( :getResolvedReference )
623
+ p
624
+ }
625
+ @logger.debug( "#{__method__} keys #{keys}->extededParameter=#{extededParameter}" )
626
+ end
627
+ return extededParameter
628
+ end
629
+
630
+ # ensure that templateData element in ['keys'] and ['indexes']
631
+ # exists in 'mustacheTemplateData'.
632
+ def addTemplateData( mustacheTemplateData, keys, indexes )
633
+
634
+ templateData = mustacheTemplateData
635
+ prev = templateData
636
+ keys.each_with_index do |key,i|
637
+ index = indexes[i]
638
+ # puts "addTemplateData: key=#{key}, #{i}, index #{index}"
639
+ templateData = templateData['columns'].select{ |column| column[:parameter_name] == key }.first
640
+ if templateData.nil? then
641
+ templateData = initRecord( key )
642
+ addColumn( prev, templateData )
643
+ # puts "addTemplateData: added #{templateData} for key #{key} --> #{mustacheTemplateData}"
644
+ else
645
+ # puts "addTemplateData: exists #{templateData} for key #{key}"
646
+ end
647
+
648
+ prev = templateData
649
+
650
+ # # puts "data1=#{data}"
651
+ # if !index.nil? then
652
+ # templateData = templateData['rows'][index]
653
+ # # puts "data2=#{data}"
654
+ # end
655
+ end # iterate
656
+
657
+ return templateData
658
+ end
659
+
660
+
661
+ # uses path in [keys] and ['indexes'] to locate data 'mustacheTemplateData'.
662
+ def locateTemplateData( mustacheTemplateData, keys, indexes )
663
+ ret = mustacheTemplateData
664
+ i = 0
665
+ if keys.any?
666
+ ret = keys.inject(ret) { |data,key|
667
+ index = indexes[i]
668
+ i += 1
669
+ # puts "\n\nindex=#{index} of #{indexes}, i=#{i}, key=#{key} on '#{data}'"
670
+ break unless data
671
+ data = data['columns'].select{ |column| column[:parameter_name] == key }.first
672
+ # puts "data1=#{data}"
673
+ if !index.nil? then
674
+ data = data['rows'][index]
675
+ # puts "data2=#{data}"
676
+ end
677
+
678
+ # if index.nil? then
679
+ # else
680
+ # data = data['rows'][index]['columns'].select{ |column| column[:parameter_name] == key }.first
681
+ # end
682
+ data
683
+ }
684
+ end
685
+ return ret
686
+ end
687
+
688
+ # ------------------------------------------------------------------
689
+ # Build a hash structure, which can be passed to mustache template
690
+
691
+ # create record entry
692
+ private
693
+ def initRecord( parameterName )
694
+ {
695
+ :parameter_name => parameterName,
696
+ "rows" => false,
697
+ "columns" => false,
698
+ "_comma" => "",
699
+ }
700
+ end
701
+
702
+ def addColumn( columns, column )
703
+ # subDocumentStack.last["columns"] = [] unless subDocumentStack.last["columns"]
704
+ # subDocumentStack.last["columns"] << input
705
+ # subDocumentStack.push( input )
706
+ columns['columns'] = [] unless columns['columns']
707
+
708
+ # la
709
+ columns['columns'].last["_comma"] = ',' if columns['columns'].length > 0
710
+
711
+ columns['columns'] << column
712
+ return column
713
+ end
714
+
715
+
716
+
717
+
718
+ end # class ExtensionLoader
719
+
720
+ end # module
721
+