fabulator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +41 -0
- data/README.rdoc +61 -0
- data/Rakefile +54 -0
- data/lib/fabulator.rb +5 -0
- data/lib/fabulator/action.rb +46 -0
- data/lib/fabulator/action_lib.rb +438 -0
- data/lib/fabulator/context.rb +39 -0
- data/lib/fabulator/core.rb +8 -0
- data/lib/fabulator/core/actions.rb +514 -0
- data/lib/fabulator/core/actions/choose.rb +167 -0
- data/lib/fabulator/core/actions/for_each.rb +105 -0
- data/lib/fabulator/core/actions/variables.rb +52 -0
- data/lib/fabulator/core/constraint.rb +117 -0
- data/lib/fabulator/core/filter.rb +41 -0
- data/lib/fabulator/core/group.rb +123 -0
- data/lib/fabulator/core/parameter.rb +128 -0
- data/lib/fabulator/core/state.rb +91 -0
- data/lib/fabulator/core/state_machine.rb +153 -0
- data/lib/fabulator/core/transition.rb +164 -0
- data/lib/fabulator/expr.rb +37 -0
- data/lib/fabulator/expr/axis.rb +133 -0
- data/lib/fabulator/expr/axis_descendent_or_self.rb +26 -0
- data/lib/fabulator/expr/bin_expr.rb +178 -0
- data/lib/fabulator/expr/context.rb +368 -0
- data/lib/fabulator/expr/for_expr.rb +74 -0
- data/lib/fabulator/expr/function.rb +52 -0
- data/lib/fabulator/expr/if_expr.rb +22 -0
- data/lib/fabulator/expr/let_expr.rb +17 -0
- data/lib/fabulator/expr/literal.rb +39 -0
- data/lib/fabulator/expr/node.rb +216 -0
- data/lib/fabulator/expr/node_logic.rb +99 -0
- data/lib/fabulator/expr/parser.rb +1470 -0
- data/lib/fabulator/expr/path_expr.rb +49 -0
- data/lib/fabulator/expr/predicates.rb +45 -0
- data/lib/fabulator/expr/statement_list.rb +96 -0
- data/lib/fabulator/expr/step.rb +43 -0
- data/lib/fabulator/expr/unary_expr.rb +30 -0
- data/lib/fabulator/expr/union_expr.rb +21 -0
- data/lib/fabulator/template.rb +9 -0
- data/lib/fabulator/template/context.rb +51 -0
- data/lib/fabulator/template/parse_result.rb +153 -0
- data/lib/fabulator/template/parser.rb +17 -0
- data/lib/fabulator/template/standard_tags.rb +95 -0
- data/lib/fabulator/template/taggable.rb +88 -0
- data/lib/fabulator/version.rb +14 -0
- data/test/test_fabulator.rb +17 -0
- data/test/test_helper.rb +24 -0
- data/xslt/form.xsl +2161 -0
- 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
|