sbuilder-ial 0.0.1

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,160 @@
1
+ module Sbuilder
2
+ module Ial
3
+ module Action
4
+
5
+ # not catched in 'Fp'
6
+ class TranslatorException < ActionException; end
7
+ # catched in 'Fp'
8
+ class TranslatorError < ActionError; end
9
+
10
+ class Translator
11
+
12
+ PROGNAME = nil # progname for logger default class name
13
+ include Sbuilder::Ial::MyLogger # mix logger
14
+
15
+
16
+ # @attr [Hash] rules [rule->action]controlling translation
17
+ # @option rule [:Symbol] identify rule names
18
+ # @option action [Hash] actions
19
+ attr_accessor :rules
20
+
21
+ def initialize( rules, options={} )
22
+ self.rules = rules
23
+ @logger = getLogger( nil, options )
24
+ @logger.info "#{__method__}: starting options=#{options}"
25
+
26
+ end
27
+
28
+ def self.start( elementGenarator, options={} )
29
+ # elementGenarator = Sbuilder::Ial::Action::Render::TlaElementGenerator.start if elementGenarator.nil?
30
+ Translator.new( TlaRules.rules(elementGenarator), options )
31
+ end
32
+
33
+
34
+ def translate( node, rule=:start, ctx={} )
35
+
36
+ @logger.debug "#{__method__}: node=#{node}, rule=#{rule}, ctx.keys=#{ctx.keys.join(',')}" if @logger.debug?
37
+ # @logger.debug "#{__method__}: node=#{node}, ctx=#{ctx.to_yaml}" if @logger.debug?
38
+ # Lookup 'rule' from rules
39
+ raise TranslatorException, "Configuration error missing rule '#{rule}' - knonwn rules: #{rules.keys}" if rules[rule].nil?
40
+ raise TranslatorException, "Configuration error, node empty #{node.to_s}" if node.nil?
41
+ # raise TranslatorException, "Configuration error, node empty #{node.to_s}" if node.nil? or node == {}
42
+
43
+ if rules[rule][:debug]
44
+ puts <<-EOS.unindent
45
+ ------------------------------------------------------------------
46
+ #{rule}:
47
+
48
+ node=#{node}
49
+
50
+ ctx keys=#{ctx.keys.join(',')}
51
+
52
+ ctx=#{ctx.to_yaml}
53
+ EOS
54
+ end
55
+
56
+ # rule -name property in ctx holds current node, restored later
57
+ prev_rule = ctx[rule]
58
+ ctx[rule] = node;
59
+
60
+ # Collect 'navigationResults' to hash with key as
61
+ # 'navigation[:rule] and values with the result of
62
+ # translating the nodes navigated to navigation[:navigate]
63
+ navigationResults = {}
64
+
65
+ # translate :navigations (before translating current node)
66
+ navigations = rules[rule][:navigations] ? rules[rule][:navigations] : []
67
+ navigations = [ navigations ] unless navigations.is_a?( Array )
68
+ navigations.each do |navigation|
69
+
70
+ # Validate rule configration
71
+ raise TranslatorException, "Error in rule #{navigation} " if navigation[:rule].nil?
72
+
73
+ if navigation[:navigate].nil? && navigation[:iterate].nil?
74
+ # no change in node - run a new rule on current node
75
+ nodesToNaviagate = [node]
76
+ elsif navigation[:navigate]
77
+ navigateSteps = navigation[:navigate].is_a?(Array ) ? navigation[:navigate] : [ navigation[:navigate] ]
78
+ # real navigation: nodesToNaviagate must exist
79
+ begin
80
+ # walk array of navigation[:navigate] -steps
81
+ currentNode = node
82
+ navigateSteps.each do |navigateStep|
83
+ # Hash, Model: access by ':navigate' key , Struct: send message ':navigate' message
84
+ currentNode = !currentNode.is_a?( Struct ) ? currentNode[navigateStep] : currentNode.send( navigateStep )
85
+ end
86
+ nodesToNaviagate = currentNode
87
+ # nodesToNaviagate = !node.is_a?( Struct ) ? currentNote on[:navigate]] : node.send( navigation[:navigate] )
88
+ # nodesToNaviagate = !node.is_a?( Struct ) ? node[navigation[:navigate]] : node.send( navigation[:navigate] )
89
+
90
+ rescue NameError => err
91
+ raise $!, <<-EOS,
92
+ #{$!}
93
+
94
+ Error navigating to '#{navigation[:navigate]}' in node #{node}.
95
+
96
+ EOS
97
+ $!.backtrace
98
+ end
99
+ raise TranslatorError, "Navigation '#{navigation[:navigate]}' in node '#{node}' failed" if nodesToNaviagate.nil?
100
+ nodesToNaviagate = [nodesToNaviagate] unless nodesToNaviagate.is_a?(Array)
101
+ elsif navigation[:iterate]
102
+ # NB {} -node --> no iteration
103
+ nodesToNaviagate = node.keys.map { |key| node[key] }
104
+ # raise TranslatorError, "Navigation iterator '#{navigation[:iterate]}' in node '#{node}' failed" unless nodesToNaviagate.any?
105
+ else
106
+ raise TranslatorException, "Error in rule #{navigation} " if navigation[:rule].nil?
107
+ end
108
+
109
+
110
+ # nextRule possibly defined using a lamdba
111
+ traslationKey, nextRule = navigation[:rule].respond_to?( :call ) ? navigation[:rule].call( node ).flatten : [ navigation[:rule], navigation[:rule] ]
112
+ navigationResults[ traslationKey ] =
113
+ nodesToNaviagate.map do |nodeToNaviagate|
114
+ begin
115
+ # run translation
116
+ nextTranslate = nextRule ? translate( nodeToNaviagate, nextRule, ctx ) : []
117
+ rescue TranslatorError => e
118
+ msg = <<-EOS
119
+ #{e.message}
120
+
121
+ within
122
+
123
+ node: #{node}
124
+ rule: #{rule}
125
+ ctx: #{ctx.to_yaml}
126
+ EOS
127
+
128
+ raise e.class.new, msg, e.backtrace
129
+
130
+ end
131
+ nextTranslate
132
+ end
133
+ # puts "navigationResults=#{navigationResults}"
134
+
135
+ end # navigations.each
136
+
137
+ # translate current node
138
+ if rules[rule][:translator]
139
+ ret = rules[rule][:translator].call( ctx.merge( { :navigationResults => navigationResults } ))
140
+ if rules[rule][:debug]
141
+ puts <<-EOS.unindent
142
+
143
+ -----> translation
144
+
145
+ #{ret}
146
+ EOS
147
+
148
+ end
149
+
150
+ end
151
+
152
+ # out of scope
153
+ # ctx.delete(ctx[rule])
154
+ ctx[rule] = prev_rule
155
+ ret
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
data/lib/app/app.rb ADDED
@@ -0,0 +1,259 @@
1
+ # coding: utf-8
2
+ module Sbuilder
3
+ module Ial
4
+ module App
5
+ class App
6
+
7
+ PROGNAME = nil # progname for logger default class name
8
+ include Sbuilder::Ial::MyLogger # mix logger
9
+ attr_reader :logger
10
+
11
+
12
+ extend Forwardable # for easy delegation
13
+
14
+
15
+ TRANSLATION_TARGETS = [
16
+ :domains_defines
17
+ ]
18
+
19
+ SNIPPET_TEMPLATE =
20
+ <<-EOS.unindent
21
+ {|# comment |}(* {|{ comment }|} *)
22
+ {|/ comment |}{|!
23
+ Output comment (with newline)
24
+ |}{|#useEval|}{|#EVAL|}template{|/EVAL|}{|/useEval|}{|^useEval|}{|{body}|}{|/useEval|}
25
+ EOS
26
+
27
+ # @attr [Sbuilder::Ial::Action::ModelBuilder] modelBuilder sexp-> model
28
+ attr_accessor :modelBuilder
29
+
30
+ # # @attr [Sbuilder::Ial::Action::Translator] translator model -> snippet
31
+ attr_accessor :translator
32
+
33
+ # @attr [object] applicationConfiguration to pass to Ruby IAL application modules
34
+ attr_accessor :applicationConfiguration
35
+
36
+ # @attr [Sbuilder::Ial::Action::Render::Producer]
37
+ attr_accessor :gen
38
+
39
+ # # @attr [Hash] partial
40
+ # attr_accessor :partials
41
+
42
+ # @attr [Sbuilder::Ial::Action::Translator] extender snippet -> sbuilder
43
+ attr_accessor :extender
44
+
45
+ # @attr [Sbuilder::Ial::Action::Render::Renderer] renderer
46
+ attr_accessor :renderer
47
+
48
+ def_delegators :extender, # access extension point
49
+ :defineDomain,
50
+ :defineSnippet
51
+
52
+ # ------------------------------------------------------------------
53
+ # @!group Contruct & configure
54
+
55
+
56
+ def initialize( options = {} )
57
+ @logger = getLogger( nil, options )
58
+ @logger.info "#{__method__}: starting options=#{options}"
59
+ end
60
+
61
+ #
62
+ # @param [String] metatypes prefix to make specnames in TLA
63
+ # language unique
64
+ #
65
+ # @param [Object] applicationConfiguration passed to ial
66
+ # modules
67
+ #
68
+ # @return [App] app initilized with actions to implment steps
69
+ def self.start( options = {}, metatypes: nil, applicationConfiguration: nil )
70
+
71
+ app = App.new( options )
72
+
73
+ # remember configuration which will be passed to script-eval
74
+ app.applicationConfiguration = applicationConfiguration
75
+ app.logger.info "#{__method__}: applicationConfiguration=#{applicationConfiguration}"
76
+
77
+ # sexp -> model
78
+ app.modelBuilder = Sbuilder::Ial::Action::ModelBuilder.start
79
+
80
+ # produce snippets etc
81
+ app.gen = Sbuilder::Ial::Action::Render::ProducerEthereum.start( options, metatypes )
82
+ # # model -> translations
83
+ app.translator = Sbuilder::Ial::Action::Translator.start( app.gen, options )
84
+
85
+ # tempate -> data -> string
86
+ app.renderer = Sbuilder::Ial::Action::Render::Renderer.start( options )
87
+
88
+ # translation -> extension
89
+ app.extender = Sbuilder::Ial::Action::Extender.start
90
+
91
+ app
92
+ end
93
+
94
+ # @!endgroup
95
+
96
+ # ------------------------------------------------------------------
97
+ # @!group Workdflow
98
+
99
+ # Load IAL implemetations arrays from Ruby 'filenames'
100
+ #
101
+ # @return [Result|Error] Result holds an Array of Ruby IAL
102
+ # objects read, Error wraps an exception encounted when
103
+ # procesing 'filename'
104
+ def loadIalImplementation( filenames )
105
+
106
+
107
+ filenames = filenames.is_a?( Array ) ? filenames : [ filenames ]
108
+
109
+ errors = false
110
+ ret = Sequence( filenames ).
111
+ inject( [] ) do |memo,filename|
112
+ @logger.info "#{__method__}: evaluate script filename=#{filename}, applicationConfiguration=#{applicationConfiguration}"
113
+ evaluated = Sbuilder::Ial::Action::ScriptEval.script_eval( filename, applicationConfiguration )
114
+ errors ||= evaluated.isError
115
+ memo += evaluated.value.is_a?(Array) ? evaluated.value : [evaluated.value]
116
+ end
117
+ errors ? Error( ret ) : Result( ret )
118
+
119
+ end
120
+
121
+ #
122
+ # @return [Result|Error] Result wraps
123
+ # Sbuilder::Ial::Model::Model, Error wraps 'Array' (with at
124
+ # least one 'Error' ialObjects)
125
+
126
+ def buildModel( ialObjects )
127
+
128
+ return Error( "No objects to buidl model ialObjects.nil?=#{ialObjects.nil?}") if ialObjects.nil?
129
+
130
+ ret =
131
+ Sbuilder::Fp::Sequence( ialObjects ).and_then do |vo|
132
+ # modelBuilder.updateVo(vo)
133
+ # end.and_then do |vo|
134
+ # # remap Result to Sequence
135
+ # Sequence( vo )
136
+ # end.and_then do |vo|
137
+ # modelBuilder.validateVo(vo)
138
+ # end.and_then do |vo|
139
+ # # remap Result to Sequence
140
+ # Sequence( vo )
141
+ # end.and_then do |vo|
142
+ modelBuilder.defineVo(vo)
143
+ end
144
+
145
+ # # Returns 'Result' (no Error objects in block), or 'Error'
146
+ # # if sequence block found some error.
147
+
148
+ ret
149
+
150
+ end
151
+
152
+ def getModel
153
+ modelBuilder.getModelBuilt
154
+ end
155
+
156
+ # @!endgroup
157
+
158
+
159
+ # ------------------------------------------------------------------
160
+ # @!group Walk model
161
+
162
+ # Run 'translateTargets' on 'model' to return array of
163
+ # translation ':results' for tranlation types :domain,
164
+ # :snippet, :interface.
165
+ #
166
+ # @param [Sbuilder::Ial::Model::Model] model
167
+ #
168
+ # @param [:Symbol:Array] array of tranlation targets to run
169
+ #
170
+ # @return [Hash:Sequence] translations
171
+ # @option translations [:Symbol] :translation values :domain, :snippet, :interface
172
+ # @option translations [:Symbol] :results array of translation types
173
+
174
+ def translateModel( model, translateTargets=nil )
175
+
176
+ # default targets can be overridden on command line
177
+ translateTargets = TRANSLATION_TARGETS if translateTargets.nil?
178
+
179
+ # Wrap targets to a sequence, and process target in block
180
+ ret = Sbuilder::Fp::Sequence( translateTargets ).and_then do |target|
181
+
182
+ # Translate 'target' in 'model' --> { :translation=>.. , :results => [] .. }
183
+ translationResults = translator.translate( model, target )
184
+ translationResults
185
+ end
186
+
187
+ # Return
188
+ ret
189
+ end
190
+
191
+ # @!endgroup
192
+
193
+
194
+ # Render 'snippetTemplate' only if 'snippetTemplate[:template]' or 'snippetTemplate[:body]' defined
195
+ def renderSnippet( snippetTemplate )
196
+ return nil if snippetTemplate.nil? || ( snippetTemplate[:template].nil? && snippetTemplate[:body].nil? )
197
+ snippetTemplate[:useEval] = snippetTemplate[:template] ? true : false
198
+ renderer.partials = gen.partials
199
+ snippetBody = renderer.to_str( SNIPPET_TEMPLATE, snippetTemplate )
200
+ snippetBody
201
+ end
202
+
203
+ # # @return [Hash] metatypes
204
+ # # @option metatypes [Symbol|String] key metatype
205
+ # # @option metatypes [Symbol] :name
206
+ # # @option metatypes [Symbol] :prefix
207
+ def appMetatypes
208
+ gen.rule_metatypes
209
+ end
210
+
211
+ # ------------------------------------------------------------------
212
+ # @!group Pass forward
213
+
214
+ #
215
+ # @param [Result] translation with value { :translation=>..., :results=> ... }
216
+ #
217
+ def extendWithTranslations( translation )
218
+
219
+ # Extract Has from
220
+ translation = translation.value
221
+ raise "Error in translation=#{translation}" if translation.nil? || translation[:translation].nil? || translation[:results].nil?
222
+ case translation[:translation]
223
+ when :domain
224
+ translation[:results].each{ |domainDefinition| defineDomain( domainDefinition ) }
225
+ ret = Result( "Domains defined" )
226
+ when :snippet
227
+ warn "TODO: snippeet =#{translation}"
228
+ # translation[:results].each{ |snippetDefinition| defineSnippet( snippetDefinition ) }
229
+ translation[:results].each{ |snippetDefinition|
230
+ warn "snippetDefinition=#{snippetDefinition}"
231
+ metatype = 'metatype to set'
232
+ appName = 'apppi'
233
+ renderData =
234
+ {
235
+ :metatype => metatype,
236
+ :appName => appName,
237
+ :comment => 'commenttit',
238
+ :snippet => snippetDefinition
239
+ }
240
+ renderer.partials = elementGenarator.partials
241
+ snippetBody = renderer.to_str( SNIPPET_TEMPLATE, renderData )
242
+ specName = nil
243
+ defineSnippet( metatype, appName, snippetBody, specName )
244
+ }
245
+ ret = Result( "Snippets defined #{translation}" )
246
+ else
247
+ raise "Error in translation=#{translation}"
248
+ end
249
+ ret
250
+ end
251
+
252
+
253
+ # @!endgroup
254
+
255
+
256
+ end # class App
257
+ end
258
+ end
259
+ end