fabulator 0.0.1

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