sbuilder-al 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ module Sbuilder
2
+ module Al
3
+ ##
4
+ # Application model classes and Domain Scpecific (DSL) language
5
+ # to build application model for Sbuilder::Al
6
+ #
7
+ # Sub modules
8
+ #
9
+ # - Model {Sbuilder::Al::Model} Application model POJO classes
10
+ #
11
+ # - Builders {Sbuilder::Al::Model::Builders}
12
+ #
13
+ # - Builders {Sbuilder::Al::Model::Api} Api module to include into
14
+ # object to construct {Sbuilder::Al::Model} application
15
+ # model.
16
+ #
17
+ module Model
18
+ end
19
+ end
20
+ end
21
+
22
+ require_relative("constants")
23
+ require_relative("model")
24
+ require_relative("builders")
25
+ require_relative("api")
@@ -0,0 +1,247 @@
1
+ module Sbuilder
2
+ module Al
3
+ module Plugin
4
+ class Controller
5
+
6
+ # include logger
7
+ include Sbuilder::Al::Util::MyLogger # mix logger
8
+
9
+
10
+ # ------------------------------------------------------------------
11
+ # Module state
12
+
13
+ # @!attribute application [Array<RootObject>] array of
14
+ # Sbuilder::Al::Model objects
15
+ attr_accessor :application
16
+
17
+ # @!attribute [Hash] metaDefs which application objects use
18
+ # @option metaDefs [String] <key> name of metadefinition
19
+ # @option metaDefs [Hash] <value> hash with properties
20
+ # ':description' and optinally ':prefix'
21
+ attr_accessor :metaDefs
22
+
23
+ # @!attribute producer [Sbuilder::Al::Translator::Producer>]
24
+ attr_accessor :producer
25
+
26
+ # @!attribute producer [Sbuilder::Al::Translator::Translator>]
27
+ attr_accessor :translator
28
+
29
+ # @!attribute producer [Sbuilder::Al::Translator::Renderer>]
30
+ attr_accessor :renderer
31
+
32
+ # Fixed template to convert tlaSexp to tlaString
33
+ SNIPPET_TEMPLATE = "{|#EVAL|}template{|/EVAL|}" + "\n"
34
+ DOMAIN_TEMPLATE = "{|#EVAL|}template{|/EVAL|}"
35
+ SNIPPET_KEY = :template
36
+
37
+ #
38
+ PLUGIN_CONFIGURATION_REQUIRED= [ 'rubypaths' ]
39
+
40
+ # ------------------------------------------------------------------
41
+ # @!group Constructor
42
+
43
+ def initialize( options = {} )
44
+ @logger = getLogger( nil, options )
45
+ @logger.info( "#{__method__} sbuilder-al plugin controller initialized" )
46
+
47
+ self.application = []
48
+ self.metaDefs = {}
49
+ initTranlatePipe( self, options )
50
+ end
51
+
52
+ # Init state attributes for a pipe to translate 'alObject' to
53
+ # 'tlaString' in {Sbuilder::Al:Controller::Controller}
54
+ #
55
+ private def initTranlatePipe( c, options={} )
56
+ # traslate
57
+ tlaGen = Sbuilder::Al::Translator::TlaGenerator.start()
58
+ c.producer = Sbuilder::Al::Translator::Producer.start( tlaGen, options )
59
+ rules = Sbuilder::Al::Translator::AlRules.rules( producer )
60
+ c.translator = Sbuilder::Al::Translator::Translator.start( rules )
61
+ # render
62
+ c.renderer = Sbuilder::Al::Translator::Renderer.start( c.producer )
63
+ end
64
+
65
+ # Construct controller object with default configuration
66
+ #
67
+ def self.start( options={})
68
+
69
+ warn "Depracate method .start for Sbuilder::Al::Plugin::Controller"
70
+ o = Sbuilder::Al::Plugin::Controller.new( options )
71
+
72
+ o
73
+ end
74
+
75
+ # @!endgroup
76
+
77
+ # ------------------------------------------------------------------
78
+ # @!group Load application
79
+
80
+ # Load Ruby scripts from conf['rubypaths'], uses {#addAlobjects}
81
+ #
82
+ # @param conf [Hash] configuration hash with property 'rubypaths'
83
+ #
84
+ # @return [Controller] self to allow pipe
85
+ #
86
+ def initApplication( conf )
87
+ warn "Missing configuration 'rubypaths' in al-configuration #{conf}" if conf['rubypaths'].nil?
88
+ loadAlScripts( conf['rubypaths'] || [] )
89
+ end
90
+
91
+ # A method called when all plugins have had their
92
+ # initApplication called, and next phase in sbuilder loading
93
+ # starts
94
+ def initApplicationFinalize
95
+ # nop
96
+ end
97
+
98
+ # Load AL language Ruby scrips in 'filenames' to
99
+ # {#application} using {#addAlObjects}.
100
+ #
101
+ #
102
+ # @param filenames [String, Array<String>] path to file with
103
+ # Ruby scripts to evaluate and to load to {#application}
104
+ #
105
+ # @return [Controller] self to allow pipe
106
+ def loadAlScripts( filenames )
107
+ filenames = [ filenames ] unless filenames.is_a?(Array)
108
+ filenames.each do |filename|
109
+ # self.application = application + Sbuilder::Al::Util::ScriptEval.script_eval( filename )
110
+ addAlObjects( Sbuilder::Al::Util::ScriptEval.script_eval( filename ) )
111
+ end
112
+ # To allow pipe
113
+ self
114
+ end
115
+
116
+
117
+ # @!endgroup
118
+
119
+ # ------------------------------------------------------------------
120
+ # @!group Services used by child classes
121
+
122
+ ##
123
+ # Add AL language object 'alObjects' to {#application} elements
124
+ #
125
+ # @param alObjects [AlObject, Array<AlObject>] AL language
126
+ # object(s) to add
127
+ def addAlObjects( alObjects )
128
+ alObjects = [ alObjects ] unless alObjects.is_a?(Array)
129
+ @logger.info( "#{__method__} adding alObjects.length=#{alObjects.length}")
130
+ @logger.debug( "#{__method__} alObjects.length=#{alObjects.join("\n")}") if @logger.debug?
131
+ self.application = application + alObjects
132
+ end
133
+
134
+ # Add metatype definitions to controller contex.
135
+ #
136
+ # @param defs [Hash] a hash describing matetypes
137
+ def addMetatypes( defs )
138
+ self.metaDefs = metaDefs.merge(defs)
139
+ end
140
+
141
+ # @!endgroup
142
+
143
+
144
+ # ------------------------------------------------------------------
145
+ # @!group Translate & render
146
+
147
+ # Convert 'alObject' to tla language string.
148
+ #
149
+ # In the first step, implementation uses {#translator} to
150
+ # convert 'alObject' to 'tlaSexp', and ,in the second step,
151
+ # {#renderer} to create 'tlaString' for 'tlaSexp'. NB:
152
+ # renderer uses partial templates created by {#translator}.
153
+ #
154
+ # @param alObject [Sbuilder::Al::Moldel] AL language object to
155
+ # render to string
156
+ #
157
+ # @return [String] tlaString for 'alObject'
158
+ def alObject2tlaString( alObject )
159
+ tlaSexp = alObject2tlaSexp( alObject )
160
+ tlaSexp2tlaString( tlaSexp )
161
+ # tlaString = renderer.to_str( SNIPPET_TEMPLATE, { SNIPPET_KEY=>tlaSexp } )
162
+ # tlaString
163
+ end
164
+
165
+ def tlaSexp2tlaString(tlaSexp, template=SNIPPET_TEMPLATE)
166
+ tlaString = renderer.to_str( template, { SNIPPET_KEY=>tlaSexp } )
167
+ end
168
+
169
+
170
+ def alObject2tlaSexp( alObject )
171
+ tlaSexp = translator.translate( alObject )
172
+ end
173
+
174
+ # @!endgroup
175
+
176
+
177
+ # ------------------------------------------------------------------
178
+ # @!group Access Api Langauge (AL) objects in {#application}
179
+
180
+ # @return [Array<AlObject>] Al object array with type :domain
181
+
182
+ def domains
183
+ application.any? && application.select do |alObject|
184
+ alObject[:type] == :domain
185
+ end.map do |alObject|
186
+ @logger.debug "#{__method__}: alObject.values=#{alObject.values}" if @logger.debug?
187
+ alObject2tlaSexp(alObject)
188
+ end.
189
+ map do |domainDef|
190
+ @logger.debug "#{__method__}: before-domainDef[:values]=#{domainDef[:values]}" if @logger.debug?
191
+ domainDef[:values] = domainDef[:values].map { |tlaSexp| tlaSexp2tlaString(tlaSexp, template=DOMAIN_TEMPLATE) }
192
+ @logger.debug "#{__method__}: after-domainDef[:values]=#{domainDef[:values]}" if @logger.debug?
193
+ domainDef
194
+ end || []
195
+ end
196
+
197
+ # @return [Array<AlObject>] array of type defines (type ==
198
+ # :definition) or function defines ( type ==
199
+ # :function_definition)
200
+ def typeDefines
201
+ application.any? && application.select { |alObject| alObject[:type] == :definition || alObject[:type] == :function_definition } || []
202
+ end
203
+
204
+ # @return [Array<AlObject>] array of Al interface objects
205
+ def interfaces
206
+ application.any? && application.select { |alObject| alObject[:type] == :transaction } || []
207
+ end
208
+
209
+ #
210
+ # Implementation translates {#application}AlObjects for
211
+ # non-snippets types (:domain, :definition,
212
+ # :function_definition).
213
+ #
214
+ # Implemetation expect alObjects being processed to implement
215
+ # method #meta and #appName. Normally #appName is alias name
216
+ # for #name method, but, at least :transaction, :appName is
217
+ # results "#{name}(#{operation})"
218
+ #
219
+ # @return [Array<Hash>] array of snippet hashes with
220
+ # properties :metatype, :appName, :tlaString
221
+ def tlaSnippets
222
+ application.
223
+ reject do |alObject|
224
+ [:domain, :definition, :function_definition ].include?(alObject.type)
225
+ end.map do |alObject|
226
+ # No tlaString conversion for some alObjects (particularly
227
+ # :alias, which just associates appName to specName
228
+ # without implementation in :tlaString
229
+ tlaString = [:alias].include?(alObject.type) ? nil : alObject2tlaString(alObject)
230
+ {
231
+ :metatype => alObject.meta,
232
+ :appName => alObject.appName,
233
+ :specName => alObject.respond_to?(:specName) ? alObject.specName : nil,
234
+ :tlaString => tlaString,
235
+ }
236
+ end
237
+ end
238
+
239
+
240
+ # @!endgroup
241
+
242
+
243
+ end
244
+ end
245
+ end
246
+ end
247
+
@@ -0,0 +1,2 @@
1
+ require_relative( "controller")
2
+ require_relative( "plugin")
@@ -0,0 +1,352 @@
1
+ require 'sbuilder'
2
+
3
+ module Sbuilder
4
+ module Al
5
+ module Plugin
6
+ class Plugin < Sbuilder::LoaderPluginRoot
7
+
8
+
9
+ # mix api loader plugin services
10
+ include ApiLoaderPluginMixer
11
+
12
+ # mix snippet loader plugin services
13
+ include SnippetLoaderPluginMixer
14
+
15
+ # include logger
16
+ include Sbuilder::Al::Util::MyLogger # mix logger
17
+
18
+ # ------------------------------------------------------------------
19
+ # state
20
+
21
+ # @!attribute controller [Sbuilder::Al::Controller::Controller] state of application
22
+ attr_accessor :controller
23
+
24
+ # @!attribute options [Hash] init options rememeber
25
+ attr_accessor :options
26
+
27
+ # ------------------------------------------------------------------
28
+ # Configuration
29
+
30
+ # # @!attribute metatypes [Hash] hash with metatypes as keys,
31
+ # # and values as hash with properties :description (and
32
+ # # (optional :prefix)
33
+ # attr_accessor :metatypes
34
+
35
+ # ------------------------------------------------------------------
36
+ # Validation
37
+
38
+ PLUGIN_CONFIGURATION_REQUIRED=[]
39
+ PLUGIN_CONFIGURATION_ALLOWED=[ 'application', "metatypes", "rubypaths" ]
40
+
41
+
42
+ # ------------------------------------------------------------------
43
+ # @!group Constructor
44
+
45
+
46
+ def initialize( options={} )
47
+ super( options )
48
+ self.options = options
49
+ @logger = getLogger( "AlPlugin", options )
50
+ @logger.info( "#{__method__} sbuilder-al plugin init" )
51
+ self.controller = Sbuilder::Al::Plugin::Controller.new( options )
52
+ end
53
+
54
+ # @return [String] version from VERSION
55
+ def self.version
56
+ File.read( File.join( File.dirname( __FILE__), "../..", "VERSION"))
57
+ end
58
+
59
+ # @!endgroup
60
+
61
+ # ------------------------------------------------------------------
62
+ # @!group sbuilder configuration
63
+
64
+ # Class level configuration
65
+ #
66
+ # @param [Hash] configuration given in 'extend.loaders'
67
+ #
68
+ # @option configuration [String] solc_command path to solc
69
+ # executable
70
+ #
71
+ def self.configure( configuration )
72
+ end
73
+
74
+ # Instance level configuration
75
+ #
76
+ # @param [Hash] configuration for object instance, intercepts
77
+ # properties 'metatypes' and 'loader'. Configuration object
78
+ # passed as is to {#initApplication}
79
+ #
80
+ #
81
+ # @return [Boolean] true for success
82
+
83
+ def configure( configuration )
84
+ configuration = {} if configuration.nil?
85
+ # validateProperties( configuration, PLUGIN_CONFIGURATION_REQUIRED, PLUGIN_CONFIGURATION_ALLOWED )
86
+
87
+ # self.metatypes = configuration['metatypes'] unless configuration['metatypes'].nil?
88
+ # self.metatypes = metatypes || {}
89
+ controller.addMetatypes( configuration['metatypes'] ) if configuration['metatypes']
90
+
91
+
92
+ setController( configuration )
93
+ @logger.info "#{__method__}: calling initApplication with #{configuration}"
94
+ initApplication( configuration )
95
+
96
+ # success
97
+ true
98
+ end
99
+
100
+ # Set {#controller} if configuration['loader'] defined
101
+ private def setController( configuration )
102
+
103
+ # no change for controller
104
+ return if configuration['className'].nil?
105
+
106
+ # load class module to context - unless Class already defined
107
+ if ! Class.const_defined?( configuration['className'] )
108
+ if configuration['gem'].nil?
109
+ msg = <<-EOS
110
+ Missing 'gem' property for loader class #{configuration['className']}
111
+ in plugin configuration #{configuration}
112
+ EOS
113
+ @logger.error( "#{__method__} #{msg}" )
114
+ raise msg
115
+ end
116
+
117
+ if configuration['gem'][0] == '.'
118
+ require_relative configuration['gem']
119
+ else
120
+ require configuration['gem']
121
+ end
122
+
123
+ end
124
+
125
+ # create controller object
126
+ begin
127
+ @logger.info "#{__method__} configuration['className']=#{configuration['className']}"
128
+ klass = Object.const_get( configuration['className'] )
129
+ rescue Exception => e
130
+ msg = <<-EOS
131
+ Unknown class: #{configuration['className']}, #{e.message}
132
+
133
+ in plugin configuration #{configuration}
134
+ EOS
135
+ @logger.error( "#{__method__} #{msg}" )
136
+ raise NameError, msg, e.backtrace
137
+ end
138
+
139
+ # instantiate new controller object
140
+ self.controller = klass.new( options )
141
+
142
+ end # private def setController( configuration )
143
+
144
+ private def initApplication( configuration )
145
+
146
+ # init application using 'configuration'
147
+ controller.initApplication( configuration )
148
+ end
149
+
150
+ # Signal that application initalization has finished &&
151
+ # registaration starts
152
+ private def initApplicationFinalize
153
+ controller.initApplicationFinalize
154
+ end
155
+
156
+
157
+
158
+ # @!endgroup
159
+
160
+ # ------------------------------------------------------------------
161
+ # @!group Services
162
+
163
+ # @param metatype [String/Symbol] to check
164
+ #
165
+ # @return [Boolean] true if 'metatype' is valid sbuilderMetatype
166
+ def self.sbuilderMetatype?( metatype )
167
+ return true if baseMetatypes.map{ |h| h[:name] }.include?(metatype)
168
+ return( false )
169
+ end
170
+
171
+ # Accesss sbuilder service to convert 'operation' -name to a
172
+ # valid string in formal code.
173
+ def self.sbuilderOperation2name( operationName )
174
+ Sbuilder::ParamSetRoot.id2name( operationName )
175
+ end
176
+
177
+ # @!endgroup
178
+
179
+
180
+ # ------------------------------------------------------------------
181
+ # @!group sbuilder extension points
182
+
183
+ # Sbuilder API loader extension point. Load domains, defines
184
+ # and interfaces to Sbuilder using API facade.
185
+ #
186
+ def load( sbuilderConfig )
187
+
188
+ # signal plugin that initiazation has finihsed &&
189
+ # registration has started
190
+ initApplicationFinalize
191
+
192
+ # pass various AL-objects using Sbuilder API loader
193
+ # extension point
194
+ loadDomains
195
+ loadDefines
196
+ loadInterfaces
197
+ end
198
+
199
+ # Load domains to tla-sbuilder over api loader facade.
200
+ #
201
+ # Implementation queries domains from {#controller} and calls
202
+ # facade method 'defineDomain'
203
+ private def loadDomains
204
+ controller.domains.each do |domain|
205
+ @logger.info "#{__method__}: name=#{domain[:name]}, values=<#{domain[:values].is_a?(Array) ? domain[:values].join(',') : domain[:values]}>"
206
+ facade.defineDomain( domain[:name], domain[:values] )
207
+ end
208
+ end
209
+
210
+ # Load (type/funtion) defines to tla-sbuilder over api loader
211
+ # facade.
212
+ #
213
+ # Implementation queries typeDefines from {#controller},
214
+ # construcsts parameter set using 'newDefinition' or
215
+ # 'newFunctionDefinition', add parameters to the definition
216
+ # constructed using 'newParameter' and 'newParameterReference'
217
+ # facade methods.
218
+
219
+ private def loadDefines
220
+ controller.typeDefines.each do |definition|
221
+ @logger.info "#{__method__}: name: #{definition[:name]}, type=#{definition[:type]}"
222
+ case definition[:type]
223
+ when :definition
224
+ currentDefinition = facade.newDefinition( definition[:name] )
225
+ when :function_definition
226
+ currentDefinition = facade.newFunctionDefinition( definition[:name] )
227
+ else
228
+ raise "Unknown type '#{definition[:type]}' for #{definition}"
229
+ end
230
+ definition[:properties] && definition[:properties].each do |property|
231
+ # Add 'property' to 'currentDefinition'
232
+ addParameterSetProperty( currentDefinition, property )
233
+ end
234
+ facade.modelDefinition( currentDefinition )
235
+ end
236
+ end
237
+
238
+
239
+ private def loadInterfaces
240
+ controller.interfaces.each do |interface|
241
+ # Create interface object
242
+ # TODO: configuration for infrastructureService and interfaceService
243
+
244
+ infrastructureService = interface.returnOption # support return value
245
+ interfaceService = interface.interfaceOption # create interface process
246
+ currentInterface = facade.newInterface( interface[:name], interface[:operation], infrastructureService, interfaceService )
247
+ # add link to source - if it has been set
248
+ facade.setSourceLink( currentInterface, interface.sourceModule,
249
+ interface.sourceLine, interface.sourceColumn ) if interface.sourceModule && !interface.sourceLine.nil?
250
+ # Add request parameters
251
+ warn "No request defined for interface:'#{interface[:name]}(#{interface[:operation]})'"
252
+ interface[:request] && interface[:request].properties && interface[:request].properties.each do |property|
253
+ addParameterSetProperty( currentInterface, property )
254
+ end
255
+ interface[:response] && interface[:response].properties && interface[:response].properties.each do |property|
256
+ addParameterSetResponseProperty( currentInterface, property )
257
+ end
258
+ # Pass current interface to sbuilder
259
+ facade.modelInterface( currentInterface )
260
+ end
261
+ end
262
+
263
+ # Add 'property' to 'currentParameterSet'.
264
+ #
265
+ # Implementation uses '@facade' to construct parameters/parameter reference objects, which
266
+ # are added to the current parameter set.
267
+ #
268
+ # @param currentParameterSet [Sbuilder::Definition, Sbuilder::Interface] where to add the propery
269
+ # @param property [Hash] with properties :name and :domain/:definition
270
+ #
271
+ private def addParameterSetProperty( currentParameterSet, property )
272
+
273
+ raise "Expecting property :isArray on #{property}" unless property[:isArray].is_a?( TrueClass) || property[:isArray].is_a?( FalseClass)
274
+ isArray = property[:isArray]
275
+ if property[:definition]
276
+ newParameterReference = facade.newParameterReference( property[:name], property[:definition], isArray )
277
+ facade.addParameter( currentParameterSet, newParameterReference )
278
+ else
279
+ newParameter = facade.newParameter( property[:name], isArray )
280
+ facade.addParameter( currentParameterSet, newParameter, property[:domain] )
281
+ # else
282
+ # raise "Must define 'domain' or 'definition' for parameter '#{property.name}'"
283
+ end
284
+ end
285
+
286
+ private def addParameterSetResponseProperty( currentParameterSet, property )
287
+ raise "Expecting property :isArray on #{property}" unless property[:isArray].is_a?( TrueClass) || property[:isArray].is_a?( FalseClass)
288
+ isArray = property[:isArray]
289
+ if property[:definition]
290
+ newParameterReference = facade.newParameterReference( property[:name], property[:definition], isArray )
291
+ facade.addResponseParameter( currentParameterSet, newParameterReference )
292
+ else # property[:domain]
293
+ # raise "Must define :name and :domain on #{property}" unless !property[:name].nil? && !property[:domain].nil?
294
+ newParameter = facade.newParameter( property[:name], isArray )
295
+ facade.addResponseParameter( currentParameterSet, newParameter, property[:domain] )
296
+ # else
297
+ # raise "Must define 'domain' or 'definition' for parameter '#{property.name}'"
298
+ end
299
+ end
300
+
301
+
302
+
303
+ # Snippet loader extension point
304
+ #
305
+ # Overrides abstract method in parent class.
306
+ #
307
+ # Implementation loads metatypes and snippets to tla-sbuilder
308
+ # over snippet facade.
309
+ #
310
+ # @param [Hash:Array] snippetDefitions given in sbuilder.yaml
311
+ #
312
+ def doRegisterSnippets( snippetDefitions )
313
+
314
+ @logger.debug( "#{__method__}: starting") if @logger.debug?
315
+
316
+ loadMetatypes
317
+ loadSnippets
318
+
319
+ end
320
+
321
+ # Load metatypes to tla-sbuilder over snippet loader facade
322
+ #
323
+ # Implemetation extracts metatatypes from controller and calls
324
+ # snippetFacade.registerMetatype
325
+ private def loadMetatypes
326
+ # @logger.info "#{__method__}: metatypes=#{metatypes.keys.join(',')}"
327
+ # metatypes && metatypes.keys.each do |metatype|
328
+ # snippetFacade.registerMetatype( metatype, metatypes[metatype]["description"], metatypes[metatype]["prefix"] )
329
+ # end
330
+ controller.metaDefs.keys.each do |metatype|
331
+ snippetFacade.registerMetatype( metatype, controller.metaDefs[metatype]["description"], controller.metaDefs[metatype]["prefix"] )
332
+ end
333
+
334
+ end
335
+
336
+ # Load snippets to tla-sbuilder over snippet loader facade
337
+ #
338
+ # Implementation queries snippets from {#controller} and calls snippetFacade
339
+ # method 'handOver'
340
+ def loadSnippets
341
+ controller.tlaSnippets.each do |snippet|
342
+ snippetFacade.handOver( snippet[:metatype].to_s, snippet[:appName], snippet[:tlaString], snippet[:specName] )
343
+ end
344
+ end
345
+
346
+ # @!endgroup
347
+
348
+ end
349
+ end
350
+ end
351
+ end
352
+