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.
- 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,164 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Core
|
3
|
+
class Transition < Fabulator::Action
|
4
|
+
attr_accessor :state, :validations, :tags
|
5
|
+
|
6
|
+
namespace Fabulator::FAB_NS
|
7
|
+
attribute :view, :as => :lstate, :static => true
|
8
|
+
attribute :tag, :as => :ltags, :static => true, :default => ''
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@state = nil
|
12
|
+
@tags = nil
|
13
|
+
@groups = { }
|
14
|
+
@params = [ ]
|
15
|
+
@actions = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def compile_xml(xml, ctx)
|
19
|
+
super
|
20
|
+
|
21
|
+
inheriting = !@state.nil?
|
22
|
+
|
23
|
+
if !inheriting
|
24
|
+
@state = @lstate
|
25
|
+
@tags = @ltags
|
26
|
+
end
|
27
|
+
|
28
|
+
# TODO: figure out some way to reference inherited actions
|
29
|
+
# figure out 'super' vs. 'inner' -- only supporting 'super'
|
30
|
+
# for now
|
31
|
+
ActionLib.with_super(@actions) do
|
32
|
+
t = @context.compile_actions(xml)
|
33
|
+
@actions = t if @actions.nil? || !t.is_noop?
|
34
|
+
end
|
35
|
+
parser = Fabulator::Expr::Parser.new
|
36
|
+
|
37
|
+
xml.each_element do |e|
|
38
|
+
next unless e.namespaces.namespace.href == FAB_NS
|
39
|
+
case e.name
|
40
|
+
# TODO: handle parameters when inheriting
|
41
|
+
when 'params':
|
42
|
+
p_ctx = @context.merge(e)
|
43
|
+
@select = p_ctx.get_select('/')
|
44
|
+
|
45
|
+
e.each_element do |ee|
|
46
|
+
next unless ee.namespaces.namespace.href == FAB_NS
|
47
|
+
case ee.name
|
48
|
+
when 'group':
|
49
|
+
if !inheriting
|
50
|
+
g = Group.new.compile_xml(ee, p_ctx)
|
51
|
+
@params << g
|
52
|
+
else
|
53
|
+
tags = (ee.attributes.get_attribute_ns(FAB_NS, 'tag').value rescue '').split(/\s+/)
|
54
|
+
end
|
55
|
+
when 'param':
|
56
|
+
if !inheriting
|
57
|
+
p = Parameter.new.compile_xml(ee, p_ctx)
|
58
|
+
@params << p
|
59
|
+
else
|
60
|
+
tags = (ee.attributes.get_attribute_ns(FAB_NS, 'tag').value rescue '').split(/\s+/)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
def param_names
|
70
|
+
(@params.collect{|w| w.param_names}.flatten).uniq
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_params(context,params)
|
74
|
+
ctx = @context.merge(context)
|
75
|
+
my_params = params
|
76
|
+
|
77
|
+
param_context = Fabulator::Expr::Node.new(
|
78
|
+
'ext',
|
79
|
+
ctx.root.roots,
|
80
|
+
nil,
|
81
|
+
[]
|
82
|
+
)
|
83
|
+
ctx.root.roots['ext'] = param_context
|
84
|
+
p_ctx = ctx.with_root(param_context)
|
85
|
+
p_ctx.merge_data(my_params)
|
86
|
+
|
87
|
+
if @select.nil?
|
88
|
+
self.apply_filters(p_ctx)
|
89
|
+
else
|
90
|
+
@select.run(p_ctx).each{ |c| self.apply_filters(p_ctx.with_root(c)) }
|
91
|
+
end
|
92
|
+
|
93
|
+
res = {
|
94
|
+
:unknown => [ ],
|
95
|
+
:valid => [ ],
|
96
|
+
:invalid => [ ],
|
97
|
+
:missing => [ ],
|
98
|
+
:messages => [ ],
|
99
|
+
}
|
100
|
+
|
101
|
+
if @select.nil?
|
102
|
+
rr = self.apply_constraints(p_ctx)
|
103
|
+
res[:invalid] += rr[:invalid]
|
104
|
+
res[:valid] += rr[:valid]
|
105
|
+
res[:unknown] += rr[:unknown]
|
106
|
+
res[:messages] += rr[:messages]
|
107
|
+
else
|
108
|
+
@select.run(p_ctx).each do |c|
|
109
|
+
rr = self.apply_constraints(p_ctx.with_root(c))
|
110
|
+
res[:invalid] += rr[:invalid]
|
111
|
+
res[:valid] += rr[:valid]
|
112
|
+
res[:unknown] += rr[:unknown]
|
113
|
+
res[:messages] += rr[:messages]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
res[:unknown] = [ ]
|
118
|
+
|
119
|
+
res[:invalid].uniq!
|
120
|
+
res[:invalid].each do |k|
|
121
|
+
res[:valid].delete(k.path)
|
122
|
+
res[:unknown].delete(k.path)
|
123
|
+
end
|
124
|
+
#res[:unknown] = res[:unknown].collect{|k| @select + k}
|
125
|
+
res[:unknown].each do |k|
|
126
|
+
res[:valid].delete(k)
|
127
|
+
end
|
128
|
+
|
129
|
+
res[:score] = (res[:valid].size+1)*(params.size)
|
130
|
+
res[:score] = res[:score] / (res[:missing].size + 1)
|
131
|
+
res[:score] = res[:score] / (res[:invalid].size + 1)
|
132
|
+
res[:score] = res[:score] / (res[:unknown].size + 1)
|
133
|
+
return res
|
134
|
+
end
|
135
|
+
|
136
|
+
def apply_filters(ctx)
|
137
|
+
@params.collect { |p|
|
138
|
+
p.apply_filters(ctx)
|
139
|
+
}.flatten
|
140
|
+
end
|
141
|
+
|
142
|
+
def apply_constraints(ctx)
|
143
|
+
invalid = [ ]
|
144
|
+
missing = [ ]
|
145
|
+
valid = [ ]
|
146
|
+
msgs = [ ]
|
147
|
+
@params.each do |p|
|
148
|
+
res = p.apply_constraints(ctx)
|
149
|
+
invalid = invalid + res[:invalid]
|
150
|
+
missing = missing + res[:missing]
|
151
|
+
valid = valid + res[:valid]
|
152
|
+
msgs = msgs + res[:messages]
|
153
|
+
end
|
154
|
+
return { :missing => missing, :invalid => invalid, :valid => valid, :messages => msgs, :unknown => [ ] }
|
155
|
+
end
|
156
|
+
|
157
|
+
def run(context)
|
158
|
+
# do queries, denials, assertions in the order given
|
159
|
+
@actions.run(@context.merge(context))
|
160
|
+
return []
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'fabulator/expr/context'
|
2
|
+
require 'fabulator/expr/axis_descendent_or_self'
|
3
|
+
require 'fabulator/expr/axis'
|
4
|
+
require 'fabulator/expr/bin_expr'
|
5
|
+
require 'fabulator/expr/node_logic'
|
6
|
+
require 'fabulator/expr/node'
|
7
|
+
require 'fabulator/expr/parser'
|
8
|
+
require 'fabulator/expr/path_expr'
|
9
|
+
require 'fabulator/expr/step'
|
10
|
+
require 'fabulator/expr/unary_expr'
|
11
|
+
require 'fabulator/expr/union_expr'
|
12
|
+
require 'fabulator/expr/literal'
|
13
|
+
|
14
|
+
require 'fabulator/expr/for_expr'
|
15
|
+
require 'fabulator/expr/function'
|
16
|
+
require 'fabulator/expr/if_expr'
|
17
|
+
require 'fabulator/expr/let_expr'
|
18
|
+
require 'fabulator/expr/path_expr'
|
19
|
+
require 'fabulator/expr/predicates'
|
20
|
+
require 'fabulator/expr/step'
|
21
|
+
|
22
|
+
require 'fabulator/expr/statement_list'
|
23
|
+
|
24
|
+
module Fabulator
|
25
|
+
module Expr
|
26
|
+
class ParserError < StandardError
|
27
|
+
end
|
28
|
+
|
29
|
+
class Exception < StandardError
|
30
|
+
attr_accessor :node
|
31
|
+
|
32
|
+
def initialize(n)
|
33
|
+
@node = n
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class Axis
|
4
|
+
def initialize(axis, n = nil)
|
5
|
+
case axis
|
6
|
+
when 'attribute':
|
7
|
+
@axis = AxisAttribute.new(n)
|
8
|
+
when 'child':
|
9
|
+
@axis = AxisChild.new(n)
|
10
|
+
when 'child-or-self':
|
11
|
+
when 'descendent':
|
12
|
+
when 'descendent-or-self':
|
13
|
+
@axis = AxisDescendentOrSelf.new(n)
|
14
|
+
when 'parent':
|
15
|
+
@axis = AxisParent.new(n)
|
16
|
+
else
|
17
|
+
@root = axis
|
18
|
+
@axis = n.nil? ? nil : AxisChild.new(n)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(context, autovivify = false)
|
23
|
+
if @root.nil? || @root == ''
|
24
|
+
return @axis.run(context, autovivify)
|
25
|
+
else
|
26
|
+
if context.root.roots[@root].nil? && !Fabulator::ActionLib.axes[@root].nil?
|
27
|
+
context.root.roots[@root] = Fabulator::ActionLib.axes[@root].call(context)
|
28
|
+
end
|
29
|
+
return context.root.roots[@root].nil? ? [ ] :
|
30
|
+
@axis.nil? ? [ context.root.roots[@root] ] :
|
31
|
+
[ @axis.run(context.with_root(context.root.roots[@root])) ]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class AxisChild
|
37
|
+
def initialize(n)
|
38
|
+
@node_test = n
|
39
|
+
end
|
40
|
+
|
41
|
+
def run(context, autovivify = false)
|
42
|
+
if @node_test.is_a?(String)
|
43
|
+
n = @node_test
|
44
|
+
else
|
45
|
+
n = (@node_test.run(context).last.to_s rescue nil)
|
46
|
+
end
|
47
|
+
return [ ] if n.nil?
|
48
|
+
if n == '*'
|
49
|
+
possible = context.is_a?(Array) ? context.collect{|c| c.root.children}.flatten : context.root.children
|
50
|
+
else
|
51
|
+
possible = context.is_a?(Array) ? context.collect{|c| c.root.children(n)}.flatten : context.root.children(n)
|
52
|
+
if possible.empty? && autovivify
|
53
|
+
possible = context.traverse_path([ n ], true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
return possible
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class AxisDescendentOrSelf
|
61
|
+
def initialize(step = nil)
|
62
|
+
@step = step
|
63
|
+
end
|
64
|
+
|
65
|
+
def run(context, autovivify = false)
|
66
|
+
if context.is_a?(Array)
|
67
|
+
stack = context.collect{ |c| c.root }
|
68
|
+
else
|
69
|
+
stack = [ context.root ]
|
70
|
+
end
|
71
|
+
possible = [ ]
|
72
|
+
while !stack.empty?
|
73
|
+
c = stack.shift
|
74
|
+
|
75
|
+
stack = stack + c.children
|
76
|
+
|
77
|
+
possible = possible + @step.run(context.with_root(c), autovivify)
|
78
|
+
end
|
79
|
+
return possible.uniq
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class AxisParent
|
84
|
+
def run(context, autovivify = false)
|
85
|
+
if context.is_a?(Array)
|
86
|
+
context.collect { |c| c.root.parent }.uniq
|
87
|
+
else
|
88
|
+
context.root.parent
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class AxisAttribute
|
94
|
+
def initialize(n)
|
95
|
+
@name = n
|
96
|
+
end
|
97
|
+
|
98
|
+
def run(context, autovivify = false)
|
99
|
+
res = [ ]
|
100
|
+
context = [ context ] unless context.is_a?(Array)
|
101
|
+
|
102
|
+
res = context.collect { |c|
|
103
|
+
if @name.is_a?(String)
|
104
|
+
nom = @name
|
105
|
+
else
|
106
|
+
nom = (@name.run(c).last.to_s rescue nil)
|
107
|
+
end
|
108
|
+
if nom == 'type'
|
109
|
+
if c.root.vtype.nil?
|
110
|
+
nil
|
111
|
+
else
|
112
|
+
n = c.root.anon_node(nil)
|
113
|
+
n.parent = c.root
|
114
|
+
n.set_attribute('namespace', c.root.vtype[0])
|
115
|
+
n.set_attribute('name', c.root.vtype[1])
|
116
|
+
n.name = 'type'
|
117
|
+
n.vtype = [ FAB_NS, 'uri' ]
|
118
|
+
n
|
119
|
+
end
|
120
|
+
else
|
121
|
+
t = c.root.get_attribute(nom)
|
122
|
+
if(t.nil? && autovivify)
|
123
|
+
c.root.set_attribute(nom, nil)
|
124
|
+
t = c.root.get_attribute(nom)
|
125
|
+
end
|
126
|
+
t
|
127
|
+
end
|
128
|
+
}
|
129
|
+
res = res - [ nil ]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class AxisDescendentOrSelf
|
4
|
+
def initialize(step = nil)
|
5
|
+
@step = step
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(context, autovivify = false)
|
9
|
+
if context.is_a?(Array)
|
10
|
+
stack = context.root
|
11
|
+
else
|
12
|
+
stack = [ context.root ]
|
13
|
+
end
|
14
|
+
possible = [ ]
|
15
|
+
while !stack.empty?
|
16
|
+
c = stack.shift
|
17
|
+
|
18
|
+
stack = stack + c.children
|
19
|
+
|
20
|
+
possible = possible + context.with_root(c).run(@step, autovivify)
|
21
|
+
end
|
22
|
+
return possible.uniq
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class BinExpr
|
4
|
+
def initialize(left, right)
|
5
|
+
@left = left
|
6
|
+
@right = right
|
7
|
+
end
|
8
|
+
|
9
|
+
def expr_type(context)
|
10
|
+
lt = @left.expr_type(context)
|
11
|
+
rt = @right.expr_type(context)
|
12
|
+
Fabulator::ActionLib.unify_types([ lt, rt ])
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(context, autovivify = false)
|
16
|
+
l = @left.run(context, autovivify)
|
17
|
+
r = @right.run(context, autovivify)
|
18
|
+
|
19
|
+
l = [ l ] unless l.is_a?(Array)
|
20
|
+
r = [ r ] unless r.is_a?(Array)
|
21
|
+
|
22
|
+
res = []
|
23
|
+
|
24
|
+
l.each do |i|
|
25
|
+
r.each do |j|
|
26
|
+
ut = Fabulator::ActionLib.unify_types([ i.vtype, j.vtype ])
|
27
|
+
op = ActionLib.find_op(ut, self.op)
|
28
|
+
if(op && op[:proc])
|
29
|
+
calc = op[:proc].call(i.to(ut), j.to(ut))
|
30
|
+
else
|
31
|
+
calc = self.calculate(i.to(ut).value,j.to(ut).value)
|
32
|
+
end
|
33
|
+
calc = [ calc ] unless calc.is_a?(Array)
|
34
|
+
|
35
|
+
rut = self.result_type(ut)
|
36
|
+
res = res + calc.collect { |c| c.is_a?(Fabulator::Expr::Node) ? c : context.root.anon_node(c, rut) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return res
|
40
|
+
end
|
41
|
+
|
42
|
+
def result_type(t)
|
43
|
+
t
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class AddExpr < BinExpr
|
48
|
+
def op
|
49
|
+
:plus
|
50
|
+
end
|
51
|
+
|
52
|
+
def calculate(a,b)
|
53
|
+
return nil if a.nil? || b.nil?
|
54
|
+
a + b
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class SubExpr < BinExpr
|
59
|
+
def op
|
60
|
+
:minus
|
61
|
+
end
|
62
|
+
|
63
|
+
def calculate(a,b)
|
64
|
+
return nil if a.nil? || b.nil?
|
65
|
+
a - b
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class BoolBinExpr < BinExpr
|
70
|
+
def expr_type(context)
|
71
|
+
[ FAB_NS, 'boolean' ]
|
72
|
+
end
|
73
|
+
|
74
|
+
def result_type(t)
|
75
|
+
[ FAB_NS, 'boolean' ]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class LtExpr < BoolBinExpr
|
80
|
+
def op
|
81
|
+
:lt
|
82
|
+
end
|
83
|
+
|
84
|
+
def calculate(a,b)
|
85
|
+
return nil if a.nil? || b.nil?
|
86
|
+
a < b
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class LteExpr < BoolBinExpr
|
91
|
+
def op
|
92
|
+
:lte
|
93
|
+
end
|
94
|
+
|
95
|
+
def calculate(a,b)
|
96
|
+
return nil if a.nil? || b.nil?
|
97
|
+
a <= b
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class EqExpr < BoolBinExpr
|
102
|
+
def op
|
103
|
+
:eq
|
104
|
+
end
|
105
|
+
|
106
|
+
def calculate(a,b)
|
107
|
+
a == b
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class NeqExpr < BoolBinExpr
|
112
|
+
def op
|
113
|
+
:neq
|
114
|
+
end
|
115
|
+
|
116
|
+
def calculate(a,b)
|
117
|
+
a != b
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class MpyExpr < BinExpr
|
122
|
+
def op
|
123
|
+
:times
|
124
|
+
end
|
125
|
+
|
126
|
+
def calculate(a,b)
|
127
|
+
return nil if a.nil? || b.nil?
|
128
|
+
a * b
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class DivExpr < BinExpr
|
133
|
+
def op
|
134
|
+
:div
|
135
|
+
end
|
136
|
+
|
137
|
+
def calculate(a,b)
|
138
|
+
return nil if b.nil? || a.nil?
|
139
|
+
a / b
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class ModExpr < BinExpr
|
144
|
+
def op
|
145
|
+
:mod
|
146
|
+
end
|
147
|
+
|
148
|
+
def calculate(a,b)
|
149
|
+
return nil if a.nil? || b.nil?
|
150
|
+
a % b
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class RangeExpr < BinExpr
|
155
|
+
def op
|
156
|
+
:range
|
157
|
+
end
|
158
|
+
|
159
|
+
def expr_type(context)
|
160
|
+
[ FAB_NS, 'numeric' ]
|
161
|
+
end
|
162
|
+
|
163
|
+
def result_type(t)
|
164
|
+
[ FAB_NS, 'numeric' ]
|
165
|
+
end
|
166
|
+
|
167
|
+
def calculate(a,b)
|
168
|
+
return nil if a.nil? || b.nil?
|
169
|
+
if a < b
|
170
|
+
r = (a.to_i .. b.to_i).to_a
|
171
|
+
else
|
172
|
+
r = (b.to_i .. a.to_i).to_a.reverse
|
173
|
+
end
|
174
|
+
return r
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|