fabulator 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.
Files changed (50) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +41 -0
  3. data/README.rdoc +61 -0
  4. data/Rakefile +54 -0
  5. data/lib/fabulator.rb +5 -0
  6. data/lib/fabulator/action.rb +46 -0
  7. data/lib/fabulator/action_lib.rb +438 -0
  8. data/lib/fabulator/context.rb +39 -0
  9. data/lib/fabulator/core.rb +8 -0
  10. data/lib/fabulator/core/actions.rb +514 -0
  11. data/lib/fabulator/core/actions/choose.rb +167 -0
  12. data/lib/fabulator/core/actions/for_each.rb +105 -0
  13. data/lib/fabulator/core/actions/variables.rb +52 -0
  14. data/lib/fabulator/core/constraint.rb +117 -0
  15. data/lib/fabulator/core/filter.rb +41 -0
  16. data/lib/fabulator/core/group.rb +123 -0
  17. data/lib/fabulator/core/parameter.rb +128 -0
  18. data/lib/fabulator/core/state.rb +91 -0
  19. data/lib/fabulator/core/state_machine.rb +153 -0
  20. data/lib/fabulator/core/transition.rb +164 -0
  21. data/lib/fabulator/expr.rb +37 -0
  22. data/lib/fabulator/expr/axis.rb +133 -0
  23. data/lib/fabulator/expr/axis_descendent_or_self.rb +26 -0
  24. data/lib/fabulator/expr/bin_expr.rb +178 -0
  25. data/lib/fabulator/expr/context.rb +368 -0
  26. data/lib/fabulator/expr/for_expr.rb +74 -0
  27. data/lib/fabulator/expr/function.rb +52 -0
  28. data/lib/fabulator/expr/if_expr.rb +22 -0
  29. data/lib/fabulator/expr/let_expr.rb +17 -0
  30. data/lib/fabulator/expr/literal.rb +39 -0
  31. data/lib/fabulator/expr/node.rb +216 -0
  32. data/lib/fabulator/expr/node_logic.rb +99 -0
  33. data/lib/fabulator/expr/parser.rb +1470 -0
  34. data/lib/fabulator/expr/path_expr.rb +49 -0
  35. data/lib/fabulator/expr/predicates.rb +45 -0
  36. data/lib/fabulator/expr/statement_list.rb +96 -0
  37. data/lib/fabulator/expr/step.rb +43 -0
  38. data/lib/fabulator/expr/unary_expr.rb +30 -0
  39. data/lib/fabulator/expr/union_expr.rb +21 -0
  40. data/lib/fabulator/template.rb +9 -0
  41. data/lib/fabulator/template/context.rb +51 -0
  42. data/lib/fabulator/template/parse_result.rb +153 -0
  43. data/lib/fabulator/template/parser.rb +17 -0
  44. data/lib/fabulator/template/standard_tags.rb +95 -0
  45. data/lib/fabulator/template/taggable.rb +88 -0
  46. data/lib/fabulator/version.rb +14 -0
  47. data/test/test_fabulator.rb +17 -0
  48. data/test/test_helper.rb +24 -0
  49. data/xslt/form.xsl +2161 -0
  50. metadata +182 -0
@@ -0,0 +1,368 @@
1
+ module Fabulator
2
+ module Expr
3
+ class Context
4
+
5
+ def initialize(parent_c = nil, xml = nil)
6
+ @parent = parent_c
7
+ @run_time_parent = nil
8
+ @ns = { }
9
+ @attributes = { }
10
+ @variables = { }
11
+ @position = nil
12
+ @last = nil
13
+
14
+ if parent_c.nil?
15
+ if xml.nil? || (xml.root rescue nil).nil?
16
+ roots = { }
17
+ roots['data'] = Fabulator::Expr::Node.new('data', roots, nil, [])
18
+ @root = roots['data']
19
+ end
20
+ end
21
+
22
+ if !xml.nil?
23
+ if xml.is_a?(self.class)
24
+ @run_time_parent = xml
25
+ else
26
+ parser = Fabulator::Expr::Parser.new
27
+
28
+ xml.namespaces.each do |ns|
29
+ @ns[ns.prefix] = ns.href
30
+ end
31
+ begin
32
+ @ns[''] = xml.namespaces.default.href
33
+ rescue
34
+ end
35
+
36
+ xml.each_attr do |attr|
37
+ v = attr.value
38
+ if !v.nil?
39
+ @attributes[attr.ns.href.to_s] ||= {}
40
+ @attributes[attr.ns.href.to_s][attr.name.to_s] = v
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def last?
48
+ return @last unless @last.nil?
49
+ return @last if @run_time_parent.nil?
50
+ return @run_time_parent.last?
51
+ end
52
+
53
+ def last=(l)
54
+ @last = !!l
55
+ end
56
+
57
+ def position
58
+ return @position unless @position.nil?
59
+ return @position if @run_time_parent.nil?
60
+ return @run_time_parent.position
61
+ end
62
+
63
+ def position=(p)
64
+ @position = p
65
+ end
66
+
67
+ def merge(s = nil)
68
+ self.class.new(self, s)
69
+ end
70
+
71
+ def attribute(ns, attr, popts = { })
72
+ opts = { :static => !@run_time_parent.nil? && !self.root.nil? }.update(popts)
73
+ value = nil
74
+ if @attributes.nil? || @attributes[ns].nil? || @attributes[ns].empty? || @attributes[ns][attr].nil?
75
+ if opts[:inherited]
76
+ value = @parent.nil? ? nil : @parent.attribute(ns, attr, opts)
77
+ end
78
+ else
79
+ value = @attributes[ns][attr]
80
+ end
81
+ if value.nil? && !opts[:default].nil?
82
+ value = opts[:default]
83
+ end
84
+
85
+ if !value.nil? && value.is_a?(String)
86
+ e = nil
87
+ if !opts[:eval]
88
+ if value =~ /^\{(.*)\}$/
89
+ e = $1
90
+ end
91
+ else
92
+ e = value
93
+ end
94
+ if !e.nil?
95
+ p = Fabulator::Expr::Parser.new
96
+ value = p.parse(e, self)
97
+ else
98
+ value = Fabulator::Expr::Literal.new(value, [ FAB_NS, value =~ /^\d+$/ ? 'numeric' : value =~ /^\d*\.\d+$/ || value =~ /^\d+\.\d*$/ ? 'numeric' : 'string' ])
99
+ end
100
+ if opts[:static]
101
+ value = value.run(self).collect{ |v| v.value }
102
+ if value.empty?
103
+ value = nil
104
+ elsif value.size == 1
105
+ value = value.first
106
+ end
107
+ end
108
+ end
109
+
110
+ value
111
+ end
112
+
113
+ def get_select(default = nil)
114
+ self.attribute(FAB_NS, 'select', { :eval => true, :static => false, :default => default })
115
+ end
116
+
117
+ def with_root(r)
118
+ ctx = self.class.new(self)
119
+ ctx.root = r
120
+ ctx
121
+ end
122
+
123
+ def root
124
+ if @root.nil?
125
+ return @run_time_parent.nil? ?
126
+ ( @parent.nil? ? nil : @parent.root ) : @run_time_parent.root
127
+ end
128
+ @root
129
+ end
130
+
131
+ def root=(r)
132
+ @root = r
133
+ end
134
+
135
+ def get_var(v)
136
+ if !@variables.has_key?(v)
137
+ if @run_time_parent.nil?
138
+ if @parent.nil?
139
+ nil
140
+ else
141
+ @parent.get_var(v)
142
+ end
143
+ else
144
+ @run_time_parent.get_var(v)
145
+ end
146
+ else
147
+ @variables[v]
148
+ end
149
+ end
150
+
151
+ def set_var(v,vv)
152
+ @variables[v] = vv
153
+ end
154
+
155
+ def get_ns(n)
156
+ return @ns[n] if @ns.has_key?(n)
157
+ return @parent.get_ns(n) unless @parent.nil?
158
+ return nil
159
+ end
160
+
161
+ def set_ns(n,h)
162
+ @ns[n] = h
163
+ end
164
+
165
+ def each_namespace(&block)
166
+ if !@parent.nil?
167
+ @parent.each_namespace do |k,v|
168
+ yield k, v
169
+ end
170
+ end
171
+ @ns.each_pair do |k,v|
172
+ yield k, v
173
+ end
174
+ end
175
+
176
+ def eval_expression(selection)
177
+ if selection.is_a?(String)
178
+ p = Fabulator::Expr::Parser.new
179
+ selection = p.parse(selection, self)
180
+ end
181
+
182
+ if selection.nil?
183
+ res = [ ]
184
+ else
185
+ # run selection against current context
186
+ res = selection.run(self)
187
+ end
188
+ return res
189
+ end
190
+
191
+ def run(action, autovivify = false)
192
+ action.run(self, autovivify)
193
+ end
194
+
195
+ def traverse_path(path, autovivify = false)
196
+ return [ self.root ] if path.nil? || path.is_a?(Array) && path.empty?
197
+
198
+ path = [ path ] unless path.is_a?(Array)
199
+
200
+ current = [ self.root ]
201
+
202
+ path.each do |c|
203
+ set = [ ]
204
+ current.each do |cc|
205
+ if c.is_a?(String)
206
+ cset = cc.children(c)
207
+ else
208
+ cset = c.run(self.with_root(cc), autovivify)
209
+ end
210
+ if cset.nil? || cset.empty?
211
+ if autovivify
212
+ if c.is_a?(String)
213
+ cset = [ cc.create_child(c) ]
214
+ else
215
+ cset = [ c.create_node(cc) ]
216
+ end
217
+ end
218
+ end
219
+ set = set + cset
220
+ end
221
+ current = set
222
+ end
223
+ return current
224
+ end
225
+
226
+ def set_value(p, v)
227
+ if p.is_a?(String) || v.is_a?(String)
228
+ parser = Fabulator::Expr::Parser.new
229
+ p = parser.parse(p,self) if p.is_a?(String)
230
+ v = parser.parse(v,self) if v.is_a?(String)
231
+ end
232
+
233
+ return [] if p.nil?
234
+
235
+ p = [ p ] unless p.is_a?(Array)
236
+
237
+ ret = [ ]
238
+
239
+ p.each do |pp|
240
+ tgts = pp.run(self, true)
241
+ src = nil
242
+ if !v.nil?
243
+ src = v.run(self)
244
+ end
245
+
246
+ tgts.each do |tgt|
247
+ tgt.prune
248
+ if src.nil? || src.empty?
249
+ tgt.value = nil
250
+ ret << tgt
251
+ elsif src.size == 1
252
+ tgt.copy(src.first)
253
+ ret << tgt
254
+ else
255
+ pp = tgt.parent
256
+ nom = tgt.name
257
+ pp.prune(pp.children(nom))
258
+ src.each do |s|
259
+ tgt = pp.create_child(nom,nil)
260
+ tgt.copy(s)
261
+ ret << tgt
262
+ end
263
+ end
264
+ end
265
+ end
266
+ ret
267
+ end
268
+
269
+ def get_values(ln = nil)
270
+ return [] if ln.nil?
271
+ self.eval_expression(ln).collect{ |c| c.value} - [ nil ]
272
+ end
273
+
274
+ def merge_data(d,p = nil)
275
+ # we have a hash or array based on root (r)
276
+ if p.nil?
277
+ root_context = [ self.root ]
278
+ else
279
+ root_context = self.traverse_path(p,true)
280
+ end
281
+ if root_context.size > 1
282
+ # see if we need to prune
283
+ new_rc = [ ]
284
+ root_context.each do |c|
285
+ if c.children.size == 0 && c.value.nil?
286
+ c.parent.prune(c) if c.parent
287
+ else
288
+ new_rc << c
289
+ end
290
+ end
291
+ if new_rc.size > 0
292
+ raise "Unable to merge data into multiple places simultaneously"
293
+ else
294
+ root_context = new_rc
295
+ end
296
+ else
297
+ root_context = root_context.first
298
+ end
299
+ if d.is_a?(Array)
300
+ node_name = root_context.name
301
+ root_context = root_context.parent
302
+ # get rid of empty children so we don't have problems later
303
+ root_context.children.each do |c|
304
+ if c.children.size == 0 && c.name == node_name && c.value.nil?
305
+ c.parent.prune(c)
306
+ end
307
+ end
308
+ d.each do |i|
309
+ c = root_context.create_child(node_name)
310
+ self.with_root(c).merge_data(i)
311
+ end
312
+ elsif d.is_a?(Hash)
313
+ d.each_pair do |k,v|
314
+ bits = k.split('.')
315
+ c = self.with_root(root_context).traverse_path(bits,true).first
316
+ if v.is_a?(Hash) || v.is_a?(Array)
317
+ self.with_root(c).merge_data(v)
318
+ else
319
+ c.value = v
320
+ end
321
+ end
322
+ else
323
+ c = root_context.parent.create_child(root_context.name, d)
324
+ end
325
+ end
326
+
327
+ def compile_actions(xml)
328
+ actions = Fabulator::Expr::StatementList.new
329
+ local_ctx = self.merge(xml)
330
+ xml.each_element do |e|
331
+ ns = e.namespaces.namespace.href
332
+ next unless Fabulator::ActionLib.namespaces.include?(ns)
333
+ if ns == FAB_NS && e.name == 'ensure'
334
+ actions.add_ensure(local_ctx.compile_actions(e))
335
+ elsif ns == FAB_NS && e.name == 'catch'
336
+ actions.add_catch(local_ctx.compile_action(e))
337
+ else
338
+ actions.add_statement(local_ctx.compile_action(e)) # rescue nil)
339
+ end
340
+ end
341
+ return actions
342
+ end
343
+
344
+ def compile_action(e)
345
+ ns = e.namespaces.namespace.href
346
+ return unless Fabulator::ActionLib.namespaces.include?(ns)
347
+ Fabulator::ActionLib.namespaces[ns].compile_action(e, self)
348
+ end
349
+
350
+ def in_context(&block)
351
+ ctx = self.merge
352
+ yield ctx
353
+ end
354
+
355
+ def with(ctx2, &block)
356
+ ctx = self.merge(ctx2)
357
+ yield ctx
358
+ end
359
+
360
+ def run_filter(ns, name)
361
+ handler = Fabulator::ActionLib.namespaces[ns]
362
+ return [] if handler.nil?
363
+ handler.run_filter(self, name)
364
+ end
365
+
366
+ end
367
+ end
368
+ end
@@ -0,0 +1,74 @@
1
+ module Fabulator
2
+ module Expr
3
+ class ForExpr
4
+ def initialize(v, e)
5
+ if v.size > 1
6
+ @var = v.shift
7
+ @expr = Fabulator::Expr::ForExpr.new(v, e)
8
+ else
9
+ @var = v.first
10
+ @expr = e
11
+ end
12
+ end
13
+
14
+ def expr_type(context)
15
+ @expr.expr_type(context)
16
+ end
17
+
18
+ def run(context, autovivify = false)
19
+ result = [ ]
20
+ return result if @var.nil? || @expr.nil?
21
+
22
+ @var.each_binding(context, autovivify) do |b|
23
+ result = result + @expr.run(b)
24
+ end
25
+ return result
26
+ end
27
+ end
28
+
29
+ class EveryExpr < ForExpr
30
+ def expr_type(context)
31
+ [ FAB_NS, 'boolean' ]
32
+ end
33
+
34
+ def run(context, autovivify = false)
35
+ result = super
36
+ result.each do |r|
37
+ return [ context.root.anon_node(false) ] unless !!r.value
38
+ end
39
+ return [ context.root.anon_node(true) ]
40
+ end
41
+ end
42
+
43
+ class SomeExpr < ForExpr
44
+ def expr_type(context)
45
+ [ FAB_NS, 'boolean' ]
46
+ end
47
+
48
+ def run(context, autovivify = false)
49
+ result = super
50
+ result.each do |r|
51
+ return [ context.root.anon_node(true) ] if !!r.value
52
+ end
53
+ return [ context.root.anon_node(false) ]
54
+ end
55
+ end
56
+
57
+ class ForVar
58
+ def initialize(n, e)
59
+ n =~ /^\$?(.*)$/
60
+ @var_name = $1
61
+ @expr = e
62
+ end
63
+
64
+ def each_binding(context, autovivify = false, &block)
65
+ @expr.run(context, autovivify).each do |e|
66
+ context.in_context do |ctx|
67
+ ctx.set_var(@var_name, e)
68
+ yield ctx
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,52 @@
1
+ module Fabulator
2
+ module Expr
3
+ class Function
4
+ def initialize(ctx, nom, args)
5
+ bits = nom.split(/:/, 2)
6
+ @ns = ctx.get_ns(bits[0])
7
+ @name = bits[1]
8
+ @args = args
9
+ @ctx = ctx
10
+ end
11
+
12
+ def expr_type(context)
13
+ klass = ActionLib.namespaces[@ns]
14
+ (klass.function_return_type(@name) rescue nil)
15
+ end
16
+
17
+ def run(context, autovivify = false)
18
+ klass = ActionLib.namespaces[@ns]
19
+ return [] if klass.nil?
20
+ ctx = @ctx.merge(context)
21
+ return klass.run_function(
22
+ ctx, @name, @args.run(ctx)
23
+ )
24
+ end
25
+ end
26
+
27
+ class List
28
+ def initialize(args)
29
+ @args = args
30
+ end
31
+
32
+ def run(context, autovivify = false)
33
+ @args.collect{ |arg| arg.run(context, autovivify).flatten }
34
+ end
35
+ end
36
+
37
+ class Tuple
38
+ def initialize(args)
39
+ @args = args
40
+ end
41
+
42
+ def run(context, autovivify = false)
43
+ items = @args.collect{ |arg| arg.run(context, autovivify).flatten }.flatten
44
+ ret = context.root.anon_node(nil, [ FAB_NS, 'tuple' ])
45
+ ret.value = items
46
+ ret.vtype = [ FAB_NS, 'tuple' ]
47
+ ret.set_attribute('size', items.size)
48
+ [ ret ]
49
+ end
50
+ end
51
+ end
52
+ end