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,167 @@
1
+ module Fabulator
2
+ module Core
3
+ module Actions
4
+ class Choose < Fabulator::Action
5
+ def compile_xml(xml, context)
6
+ super
7
+
8
+ @choices = [ ]
9
+ @default = nil
10
+
11
+ xml.each_element do |e|
12
+ next unless e.namespaces.namespace.href == FAB_NS
13
+ case e.name
14
+ when 'when':
15
+ @choices << When.new.compile_xml(e, @context)
16
+ when 'otherwise':
17
+ @default = When.new.compile_xml(e, @context)
18
+ end
19
+ end
20
+ self
21
+ end
22
+
23
+ def run(context, autovivify = false)
24
+ @context.with(context) do |ctx|
25
+ @choices.each do |c|
26
+ if c.run_test(ctx)
27
+ return c.run(ctx)
28
+ end
29
+ end
30
+ return @default.run(ctx) unless @default.nil?
31
+ return []
32
+ end
33
+ end
34
+ end
35
+
36
+ class When < Fabulator::Action
37
+ namespace Fabulator::FAB_NS
38
+ attribute :test, :eval => true, :static => false
39
+
40
+ has_actions
41
+
42
+ def run_test(context)
43
+ return true if @test.nil?
44
+ result = @test.run(@context.merge(context)).collect{ |a| !!a.value }
45
+ return false if result.nil? || result.empty? || !result.include?(true)
46
+ return true
47
+ end
48
+
49
+ def run(context, autovivify = false)
50
+ return @actions.run(@context.merge(context))
51
+ end
52
+ end
53
+
54
+ class If < Fabulator::Action
55
+ namespace Fabulator::FAB_NS
56
+ attribute :test, :eval => true, :static => false
57
+
58
+ has_actions
59
+
60
+ def run(context, autovivify = false)
61
+ return [ ] if @test.nil?
62
+ @context.with(context) do |ctx|
63
+ test_res = @test.run(ctx).collect{ |a| !!a.value }
64
+ return [ ] if test_res.nil? || test_res.empty? || !test_res.include?(true)
65
+ return @actions.run(ctx)
66
+ end
67
+ end
68
+ end
69
+
70
+ class Block < Fabulator::Action
71
+
72
+ namespace Fabulator::FAB_NS
73
+ has_actions
74
+
75
+ def run(context, autovivify = false)
76
+ return @actions.run(@context.merge(context),autovivify)
77
+ end
78
+ end
79
+
80
+ class Goto < Fabulator::Action
81
+ namespace Fabulator::FAB_NS
82
+ attribute :test, :eval => true, :static => false
83
+ attribute :state, :static => true
84
+
85
+ def run(context, autovivify = false)
86
+ raise Fabulator::StateChangeException, @state, caller if @test.nil?
87
+ test_res = @test.run(@context.merge(context)).collect{ |a| !!a.value }
88
+ return [ ] if test_res.nil? || test_res.empty? || !test_res.include?(true)
89
+ raise Fabulator::StateChangeException, @state, caller
90
+ end
91
+ end
92
+
93
+ class Catch < Fabulator::Action
94
+ namespace Fabulator::FAB_NS
95
+ attribute :test, :eval => true, :static => false
96
+ attribute :as, :static => true
97
+
98
+ has_actions
99
+
100
+ def run_test(context)
101
+ return true if @test.nil?
102
+ @context.with(context) do |ctx|
103
+ ctx.set_var(@as, context) if @as
104
+ result = @test.run(context).collect{ |a| !!a.value }
105
+ return false if result.nil? || result.empty? || !result.include?(true)
106
+ return true
107
+ end
108
+ end
109
+
110
+ def run(context, autovivify = false)
111
+ @context.with(context) do |ctx|
112
+ ctx.set_var(@as, context) if @as
113
+ return @actions.run(context)
114
+ end
115
+ end
116
+ end
117
+
118
+ class Raise < Fabulator::Action
119
+
120
+ namespace Fabulator::FAB_NS
121
+ attribute :test, :eval => true, :static => false
122
+ has_actions
123
+
124
+ def run(context, autovivify = false)
125
+ @context.with(context) do |ctx|
126
+ select = ctx.get_select
127
+ if !@test.nil?
128
+ test_res = @test.run(ctx).collect{ |a| !!a.value }
129
+ return [ ] if test_res.nil? || test_res.empty? || !test_res.include?(true)
130
+ end
131
+ res = [ ]
132
+ if select.nil? && !@actions.nil?
133
+ res = @actions.run(ctx, autovivify)
134
+ elsif !select.nil?
135
+ res = select.run(ctx, autovivify)
136
+ else
137
+ raise ctx # default if <raise/> with no attributes
138
+ end
139
+
140
+ return [ ] if res.empty?
141
+
142
+ raise Fabulator::Expr::Exception.new(res.first)
143
+ end
144
+ end
145
+ end
146
+
147
+ class Super < Fabulator::Action
148
+ namespace Fabulator::FAB_NS
149
+ has_select
150
+ has_actions :super
151
+
152
+ def run(context, autovivify = false)
153
+ return [] if @actions.nil?
154
+
155
+ @context.with(context) do |ctx|
156
+ new_context = @select.run(ctx,autovivify)
157
+
158
+ new_context = [ new_context ] unless new_context.is_a?(Array)
159
+
160
+ return new_context.collect { |c| @actions.run(ctx.with_root(c), autovivify) }.flatten
161
+ end
162
+ end
163
+ end
164
+
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,105 @@
1
+ module Fabulator
2
+ module Core
3
+ module Actions
4
+ class ForEach < Fabulator::Action
5
+ namespace Fabulator::FAB_NS
6
+ attribute :as, :static => true
7
+ has_select
8
+ has_actions
9
+
10
+ def compile_xml(xml, context)
11
+ super
12
+ @sort = [ ]
13
+
14
+ xml.each_element do |e|
15
+ next unless e.namespaces.namespace.href == FAB_NS
16
+ case e.name
17
+ when 'sort-by':
18
+ @sort << Sort.new.compile_xml(e, @context)
19
+ end
20
+ end
21
+ self
22
+ end
23
+
24
+ def run(context, autovivify = false)
25
+ @context.with(context) do |ctx|
26
+ items = @select.run(ctx)
27
+ res = nil
28
+ ctx.in_context do |c|
29
+ if !@sort.empty?
30
+ items = items.sort_by{ |i|
31
+ c.set_var(@as, i) unless @as.nil?
32
+ @sort.collect{|s| s.run(c.with_root(i)) }.join("\0")
33
+ }
34
+ end
35
+ res = [ ]
36
+ items.each do |i|
37
+ c.set_var(@as, i) unless @as.nil?
38
+ res = res + @actions.run(c.with_root(i))
39
+ end
40
+ end
41
+ return res
42
+ end
43
+ end
44
+ end
45
+
46
+ class Sort < Fabulator::Action
47
+ namespace Fabulator::FAB_NS
48
+ has_select
49
+
50
+ def run(context, autovivify = false)
51
+ (@select.run(@context.merge(context)).first.to_s rescue '')
52
+ end
53
+ end
54
+
55
+ class Considering < Fabulator::Action
56
+ namespace Fabulator::FAB_NS
57
+ attribute :as, :static => true
58
+ has_select
59
+ has_actions
60
+
61
+ def run(context, autovivify = false)
62
+ return [] if @select.nil?
63
+ res = [ ]
64
+ @context.with(context) do |ctx|
65
+ c = @select.run(ctx)
66
+ root = nil
67
+ if @as.nil?
68
+ if c.size == 1
69
+ root = c.first
70
+ else
71
+ root = Fabulator::Expr::Node.new('data', context.root.roots, nil, c)
72
+ end
73
+ res = @actions.run(ctx.with_root(root))
74
+ else
75
+ ctx.in_context do |ctx2|
76
+ ctx2.set_var(@as, c)
77
+ res = @actions.run(ctx2)
78
+ end
79
+ end
80
+ end
81
+ res
82
+ end
83
+ end
84
+
85
+ class While < Fabulator::Action
86
+ namespace Fabulator::FAB_NS
87
+ attribute :test, :eval => true, :static => false
88
+ attribute :limit, :default => 1000
89
+ has_actions
90
+
91
+ def run(context, autovivify = false)
92
+ res = [ ]
93
+ counter = 0
94
+ @context.with(context) do |ctx|
95
+ lim = @limit.nil? ? 1000 : @limit.run(ctx).first.value
96
+ while counter < @limit && (!!@test.run(ctx).first.value rescue false)
97
+ res = res + @actions.run(ctx)
98
+ end
99
+ end
100
+ res
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,52 @@
1
+ module Fabulator
2
+ module Core
3
+ module Actions
4
+ class ValueOf < Fabulator::Action
5
+ namespace Fabulator::FAB_NS
6
+ has_select
7
+
8
+ def run(context, autovivify = false)
9
+ @select.run(@context.merge(context), autovivify)
10
+ end
11
+ end
12
+
13
+ class Value < Fabulator::Action
14
+ attr_accessor :select, :name
15
+
16
+ namespace Fabulator::FAB_NS
17
+ attribute :path, :static => true
18
+ has_select nil
19
+ has_actions
20
+
21
+ def run(context, autovivify = false)
22
+ @context.with(context) do |ctx|
23
+ ctx.set_value(@path, @select.nil? ? @actions : @select )
24
+ end
25
+ end
26
+ end
27
+
28
+ class Variable < Fabulator::Action
29
+ namespace Fabulator::FAB_NS
30
+ attribute :name, :eval => false, :static => true
31
+ has_select
32
+ has_actions
33
+
34
+ def run(context, autovivify = false)
35
+ return [] if @name.nil?
36
+ res = [ ]
37
+ @context.with(context) do |ctx|
38
+ if @select
39
+ res = @select.run(ctx, autovivify)
40
+ elsif !@actions.empty?
41
+ @actions.each do |a|
42
+ res = a.run(ctx, autovivify)
43
+ end
44
+ end
45
+ end
46
+ context.set_var(@name, res)
47
+ res
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,117 @@
1
+ module Fabulator
2
+ module Core
3
+ class Constraint < Fabulator::Action
4
+
5
+ namespace Fabulator::FAB_NS
6
+ attribute :invert, :static => true, :default => 'false'
7
+ attribute :name, :as => :c_type, :static => true
8
+ has_select
9
+
10
+ def compile_xml(xml, ctx)
11
+ super
12
+ @constraints = [ ]
13
+ @values = [ ]
14
+ @params = [ ]
15
+ @attributes = { }
16
+
17
+ if xml.name == 'value'
18
+ @c_type = 'any'
19
+ @values << xml.content
20
+ else
21
+ xml.each_attr do |attr|
22
+ next unless attr.ns.href == FAB_NS
23
+ next if attr.name == 'name' || attr.name == 'invert'
24
+ @attributes[attr.name] = attr.value
25
+ end
26
+ xml.each_element do |e|
27
+ next unless e.namespaces.namespace.href == FAB_NS
28
+ e_ctx = @context.merge(e)
29
+ case e.name
30
+ when 'param':
31
+ pname = e_ctx.attribute(FAB_NS, 'name') # (e.get_attribute_ns(FAB_NS, 'name').value rescue nil)
32
+ if !pname.nil?
33
+ v = e_ctx.attribute(FAB_NS, 'value', { :default => e_ctx.get_select })
34
+ @params[pname] = v unless v.nil?
35
+ end
36
+ when 'constraint':
37
+ @constraints << Constraint.new.compile_xml(e, @context)
38
+ when 'value':
39
+ v = e_ctx.get_select
40
+ if v.nil?
41
+ v = e.content
42
+ end
43
+ @values << v unless v.nil?
44
+ end
45
+ end
46
+ end
47
+ self
48
+ end
49
+
50
+ def error_message(context)
51
+ "#{context.path} does not pass the constraint"
52
+ end
53
+
54
+ def test_constraint(context)
55
+ # do special ones first
56
+ @context.with(context) do |ctx|
57
+ paths = [ [ ctx.root.path ], [] ]
58
+ r = paths
59
+
60
+ inv = (@invert == 'true' || @invert == 'yes') ? true : false
61
+ sense = !inv ? Proc.new { |r| r } : Proc.new { |r| r.reverse }
62
+ not_sense = inv ? Proc.new { |r| r } : Proc.new { |r| r.reverse }
63
+
64
+ case @c_type
65
+ when nil, '':
66
+ return sense.call(paths) if select.nil?
67
+ opts = @select.run(ctx).collect { |o| o.to_s }
68
+ if !opts.include?(ctx.root.to_s)
69
+ paths[0] -= [ ctx.root.path ]
70
+ paths[1] += [ ctx.root.path ]
71
+ end
72
+ return sense.call(paths)
73
+ when 'all':
74
+ # we have enclosed constraints
75
+ @constraints.each do |c|
76
+ r = c.test_constraint(ctx)
77
+ return sense.call(r) unless r[1].empty?
78
+ end
79
+ return not_sense.call(r)
80
+ when 'any':
81
+ if @values.empty?
82
+ @constraints.each do |c|
83
+ r = c.test_constraint(ctx)
84
+ return not_sense.call(r) if r[1].empty?
85
+ end
86
+ return sense.call(r)
87
+ else
88
+ calc_values = [ ]
89
+ @values.each do |v|
90
+ if v.is_a?(String)
91
+ calc_values << v
92
+ else
93
+ calc_values = calc_values + v.run(ctx).collect{ |i| i.value }
94
+ end
95
+ end
96
+ if !calc_values.include?(ctx.root.value)
97
+ paths[0] -= [ ctx.root.path ]
98
+ paths[1] += [ ctx.root.path ]
99
+ end
100
+ return sense.call(paths)
101
+ end
102
+ when 'range':
103
+ fl = (@params['floor'].run(ctx) rescue nil)
104
+ ce = (@params['ceiling'].run(ctx) rescue nil)
105
+ if !fl.nil? && fl > c.value || !ce.nil? && ce < c.value
106
+ paths[0] -= [ c.path ]
107
+ paths[1] += [ c.path ]
108
+ end
109
+ return sense.call(r)
110
+ else
111
+ return not_sense.call(r)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,41 @@
1
+ module Fabulator
2
+ module Core
3
+ class Filter < Fabulator::Action
4
+ namespace Fabulator::FAB_NS
5
+ attribute :name, :static => true
6
+
7
+ # def compile_xml(xml, context)
8
+ # @context = context.merge(xml)
9
+ # filter_type = @context.attribute(FAB_NS, 'name', {:static => true}).split(/:/, 2)
10
+ # if filter_type.size == 2
11
+ # @ns = @context.get_ns(filter_type[0])
12
+ # @name = filter_type[1]
13
+ # else
14
+ # @ns = FAB_NS
15
+ # @name = filter_type[0]
16
+ # end
17
+ # self
18
+ # end
19
+
20
+ def run(context)
21
+ filtered = [ ]
22
+ @context.with(context) do |ctx|
23
+ filter_type = @name.split(/:/,2)
24
+ ns = nil
25
+ name = nil
26
+ if filter_type.size == 2
27
+ ns = @context.get_ns(filter_type[0])
28
+ name = filter_type[1]
29
+ else
30
+ ns = FAB_NS
31
+ name = filter_type[0]
32
+ end
33
+
34
+ ctx.run_filter(ns, name)
35
+ filtered << ctx.root.path
36
+ end
37
+ return filtered
38
+ end
39
+ end
40
+ end
41
+ end