sbuilder-al 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+