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,49 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class PathExpr
|
4
|
+
def initialize(pe, predicates, segment)
|
5
|
+
@primary_expr = pe
|
6
|
+
@predicates = predicates
|
7
|
+
@segment = (segment.is_a?(Array) ? segment : [ segment ]) - [nil]
|
8
|
+
end
|
9
|
+
|
10
|
+
def expr_type(context)
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(context, autovivify = false)
|
15
|
+
if @primary_expr.nil?
|
16
|
+
possible = [ context.root ]
|
17
|
+
else
|
18
|
+
possible = @primary_expr.run(context,autovivify).uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
final = [ ]
|
22
|
+
|
23
|
+
@segment = [ @segment ] unless @segment.is_a?(Array)
|
24
|
+
|
25
|
+
possible.each do |e|
|
26
|
+
next if e.nil?
|
27
|
+
not_pass = false
|
28
|
+
@predicates.each do |p|
|
29
|
+
if !p.test(context.with_root(e))
|
30
|
+
not_pass = true
|
31
|
+
break
|
32
|
+
end
|
33
|
+
end
|
34
|
+
next if not_pass
|
35
|
+
pos = [ e ]
|
36
|
+
@segment.each do |s|
|
37
|
+
pos = pos.collect{ |p|
|
38
|
+
s.run(context.with_root(p), autovivify)
|
39
|
+
}.flatten - [ nil ]
|
40
|
+
end
|
41
|
+
|
42
|
+
final = final + pos
|
43
|
+
end
|
44
|
+
|
45
|
+
return final
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class Predicates
|
4
|
+
def initialize(axis,p)
|
5
|
+
@axis = axis
|
6
|
+
@predicates = p
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(context, autovivify = false)
|
10
|
+
# we want to run through all of the predicates and return true if
|
11
|
+
# they all return true
|
12
|
+
result = [ ]
|
13
|
+
possible = @axis.run(context, autovivify)
|
14
|
+
return possible if @predicates.nil? || @predicates.empty?
|
15
|
+
@predicates.each do |p|
|
16
|
+
n_p = [ ]
|
17
|
+
if p.is_a?(Fabulator::Expr::IndexPredicate)
|
18
|
+
n_p = p.run(context).collect{ |i| possible[i-1] }
|
19
|
+
else
|
20
|
+
possible.each do |c|
|
21
|
+
res = p.run(context.with_root(c))
|
22
|
+
if res.is_a?(Array)
|
23
|
+
n_p << c if !res.empty? && !!res.first.value
|
24
|
+
else
|
25
|
+
n_p << c if !!res.value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
possible = n_p
|
30
|
+
end
|
31
|
+
return possible
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class IndexPredicate
|
36
|
+
def initialize(l)
|
37
|
+
@indices = l
|
38
|
+
end
|
39
|
+
|
40
|
+
def run(context)
|
41
|
+
@indices.collect { |e| e.run(context).collect{ |i| i.to([FAB_NS, 'numeric']).value.to_i } }.flatten
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class StatementList
|
4
|
+
def initialize
|
5
|
+
@statements = [ ]
|
6
|
+
@ensures = [ ]
|
7
|
+
@catches = [ ]
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_statement(s)
|
11
|
+
@statements << s if !s.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_ensure(s)
|
15
|
+
@ensures << s
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_catch(s)
|
19
|
+
@catches << s
|
20
|
+
end
|
21
|
+
|
22
|
+
def is_noop?
|
23
|
+
@statements.empty? && @ensures.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def run(context, autovivify = false)
|
27
|
+
result = [ ]
|
28
|
+
begin
|
29
|
+
if !@statements.nil?
|
30
|
+
(@statements - [nil]).each do |s|
|
31
|
+
result = s.run(context, autovivify)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
rescue Fabulator::StateChangeException => e
|
35
|
+
raise e
|
36
|
+
rescue => e
|
37
|
+
result = []
|
38
|
+
caught = false
|
39
|
+
ex = nil
|
40
|
+
if e.is_a?(Fabulator::Expr::Exception)
|
41
|
+
ex = e.node
|
42
|
+
else
|
43
|
+
ex = context.root.anon_node(e.to_s, [ FAB_NS, 'string' ])
|
44
|
+
ex.set_attribute('class', 'ruby.' + e.class.to_s.gsub(/::/, '.'))
|
45
|
+
end
|
46
|
+
if !@catches.nil?
|
47
|
+
@catches.each do |s|
|
48
|
+
if !s.nil? && s.run_test(ex)
|
49
|
+
caught = true
|
50
|
+
result = s.run(context.with_root(ex), autovivify)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
raise e unless caught
|
56
|
+
ensure
|
57
|
+
if !@ensures.nil? && !@ensures.empty?
|
58
|
+
@ensures.each do |s|
|
59
|
+
s.run(context, autovivify) unless s.nil?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
return result
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class WithExpr
|
69
|
+
def initialize(e,w)
|
70
|
+
@expr = e
|
71
|
+
@with = w
|
72
|
+
end
|
73
|
+
|
74
|
+
def run(context, autovivify = false)
|
75
|
+
result = @expr.run(context, autovivify)
|
76
|
+
result.each do |r|
|
77
|
+
@with.run(context.with_root(r), true)
|
78
|
+
end
|
79
|
+
result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class DataSet
|
84
|
+
def initialize(p,v)
|
85
|
+
@path = p
|
86
|
+
@value = v
|
87
|
+
end
|
88
|
+
|
89
|
+
def run(context, autovivify = false)
|
90
|
+
context.set_value(@path, @value)
|
91
|
+
[ context.root ]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class Step
|
4
|
+
def initialize(a,n)
|
5
|
+
@axis = a
|
6
|
+
@node_test = n
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(context, autovivify = false)
|
10
|
+
c = context.root
|
11
|
+
if !@axis.nil? && @axis != '' && context.root.roots.has_key?(@axis) &&
|
12
|
+
@axis != context.root.axis
|
13
|
+
c = context.root.roots[@axis]
|
14
|
+
end
|
15
|
+
if @node_test.is_a?(String)
|
16
|
+
n = @node_test
|
17
|
+
else
|
18
|
+
n = (@node_test.run(context).last.value rescue nil)
|
19
|
+
end
|
20
|
+
return [ ] if n.nil?
|
21
|
+
if n == '*'
|
22
|
+
possible = c.children
|
23
|
+
else
|
24
|
+
possible = c.children.select{ |cc| cc.name == n }
|
25
|
+
if possible.empty? && autovivify
|
26
|
+
#Rails.logger.info("Autovivifying #{n}")
|
27
|
+
possible = context.with_root(c).traverse_path([ n ], true)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
return possible
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_node(context)
|
34
|
+
return nil if node_text == '*'
|
35
|
+
|
36
|
+
c = Fabulator::Expr::Node.new(context.root.axis, context.root.roots, nil, [])
|
37
|
+
c.name = @node_test
|
38
|
+
context.root.add_child(c)
|
39
|
+
c
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class UnaryExpr
|
4
|
+
def initialize(e)
|
5
|
+
@expr = e
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(context, autovivify = false)
|
9
|
+
l = @expr.run(context, autovivify)
|
10
|
+
|
11
|
+
l = [ l ] unless l.is_a?(Array)
|
12
|
+
|
13
|
+
l = l.collect { |i| i.value }.uniq - [ nil ]
|
14
|
+
|
15
|
+
return @expr.collect{|e| Fabulator::Expr::Node.new(
|
16
|
+
context.root.axis,
|
17
|
+
context.root.roots,
|
18
|
+
self.calculate(e),
|
19
|
+
[]
|
20
|
+
) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class NegExpr < UnaryExpr
|
25
|
+
def calculate(e)
|
26
|
+
e.nil? ? nil : -e
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Fabulator
|
2
|
+
module Expr
|
3
|
+
class UnionExpr
|
4
|
+
def initialize(es)
|
5
|
+
@exprs = es
|
6
|
+
end
|
7
|
+
|
8
|
+
def expr_type(context)
|
9
|
+
Fabulator::ActionLib.unify_types(@exprs.collect{ |e| e.expr_type(context) })
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(context, autovivify = false)
|
13
|
+
u = [ ]
|
14
|
+
@exprs.each do |e|
|
15
|
+
u = u + e.run(context, autovivify)
|
16
|
+
end
|
17
|
+
return u.uniq
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'radius'
|
2
|
+
|
3
|
+
module Fabulator::Template
|
4
|
+
class Context < Radius::Context
|
5
|
+
|
6
|
+
attr_reader :context
|
7
|
+
|
8
|
+
def initialize(parser)
|
9
|
+
super()
|
10
|
+
@parser = parser
|
11
|
+
globals.context = @context
|
12
|
+
parser.tags.each do |name|
|
13
|
+
define_tag(name) { |tag_binding| parser.render_tag(name, tag_binding) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def raise_errors?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def render_tag(name, attributes = {}, &block)
|
22
|
+
binding = @tag_binding_stack.last
|
23
|
+
locals = binding ? binding.locals : globals
|
24
|
+
set_process_variables(locals.page)
|
25
|
+
super
|
26
|
+
rescue Exception => e
|
27
|
+
raise e if raise_errors?
|
28
|
+
@tag_binding_stack.pop unless @tag_binding_stack.last == binding
|
29
|
+
render_error_message(e.message)
|
30
|
+
end
|
31
|
+
|
32
|
+
def tag_missing(name, attributes = {}, &block)
|
33
|
+
super
|
34
|
+
rescue Radius::UndefinedTagError => e
|
35
|
+
raise StandardTags::TagError.new(e.message)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def render_error_message(message)
|
41
|
+
"<div><strong>#{message}</strong></div>"
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_process_variables(parser)
|
45
|
+
#parser.request ||= @parser.request
|
46
|
+
#parser.response ||= @parser.response
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'xml/libxml'
|
2
|
+
require 'xml/xslt'
|
3
|
+
|
4
|
+
@@fabulator_xslt_file = File.join(File.dirname(__FILE__), "..", "..", "..", "xslt", "form.xsl")
|
5
|
+
|
6
|
+
@@fabulator_xmlt = LibXML::XML::Document.file(@@fabulator_xslt_file)
|
7
|
+
|
8
|
+
|
9
|
+
module Fabulator::Template
|
10
|
+
class ParseResult
|
11
|
+
def initialize(text)
|
12
|
+
@doc = LibXML::XML::Document.string text
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_default_values(context)
|
16
|
+
each_form_element do |el|
|
17
|
+
own_id = el.attributes['id']
|
18
|
+
next if own_id.nil? || own_id.to_s == ''
|
19
|
+
|
20
|
+
default = nil
|
21
|
+
is_grid = false
|
22
|
+
if el.name == 'grid'
|
23
|
+
default = el.find('./default | ./row/default | ./column/default')
|
24
|
+
is_grid = true
|
25
|
+
else
|
26
|
+
default = el.find('./default')
|
27
|
+
end
|
28
|
+
|
29
|
+
id = el_id(el)
|
30
|
+
ids = id.split('/')
|
31
|
+
if !context.nil? && (default.is_a?(Array) && default.empty? || !default)
|
32
|
+
l = context.traverse_path(ids)
|
33
|
+
if !l.nil? && !l.empty?
|
34
|
+
if is_grid
|
35
|
+
count = (el.attributes['count'].to_s rescue '')
|
36
|
+
how_many = 'multiple'
|
37
|
+
direction = 'both'
|
38
|
+
if count =~ %r{^(multiple|single)(-by-(row|column))?$}
|
39
|
+
how_many = $1
|
40
|
+
direction = $3 || 'both'
|
41
|
+
end
|
42
|
+
if direction == 'both'
|
43
|
+
l.collect{|ll| ll.value}.each do |v|
|
44
|
+
el << XML::Node.new('default', v)
|
45
|
+
end
|
46
|
+
elsif direction == 'row' || direction == 'column'
|
47
|
+
el.find("./#{direction}").each do |div|
|
48
|
+
id = (div.attributes['id'].to_s rescue '')
|
49
|
+
next if id == ''
|
50
|
+
l.collect{|c| context.with_root(c).traverse_path(id)}.flatten.collect{|c| c.value}.each do |v|
|
51
|
+
div << XML::Node.new('default', v)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
else
|
56
|
+
l.collect{|ll| ll.value}.each do |v|
|
57
|
+
el << XML::Node.new('default', v)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_missing_values(missing = [ ])
|
66
|
+
each_form_element do |el|
|
67
|
+
id = el_id(el)
|
68
|
+
next if id == ''
|
69
|
+
next unless missing.include?(id)
|
70
|
+
el.attributes["missing"] = "1"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_errors(errors = { })
|
75
|
+
each_form_element do |el|
|
76
|
+
id = el_id(el)
|
77
|
+
next if id == ''
|
78
|
+
next unless errors.has_key?(id)
|
79
|
+
if errors[id].is_a?(Array)
|
80
|
+
errors[id].each do |e|
|
81
|
+
el << XML::Node.new('error', e)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
el << XML::Node.new('error', errors[id])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_captions(captions = { })
|
90
|
+
each_form_element do |el|
|
91
|
+
id = el_id(el)
|
92
|
+
next if id == ''
|
93
|
+
next unless captions.has_key?(id)
|
94
|
+
|
95
|
+
is_grid = false
|
96
|
+
if el.name == 'grid'
|
97
|
+
else
|
98
|
+
caption = el.find_first('./caption')
|
99
|
+
if caption.nil?
|
100
|
+
el << XML::Node.new('caption', captions[id])
|
101
|
+
else
|
102
|
+
caption.content = captions[id]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def to_s
|
109
|
+
@doc.to_s
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_html
|
113
|
+
xslt = XML::XSLT.new
|
114
|
+
xslt.parameters = { }
|
115
|
+
xslt.xml = @doc
|
116
|
+
xslt.xsl = @@fabulator_xslt
|
117
|
+
xslt.serve
|
118
|
+
end
|
119
|
+
|
120
|
+
protected
|
121
|
+
|
122
|
+
def each_form_element(&block)
|
123
|
+
@doc.root.find(%{
|
124
|
+
//text
|
125
|
+
| //textline
|
126
|
+
| //textbox
|
127
|
+
| //editbox
|
128
|
+
| //asset
|
129
|
+
| //password
|
130
|
+
| //selection
|
131
|
+
| //grid
|
132
|
+
| //submit
|
133
|
+
}).each do |el|
|
134
|
+
yield el
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def el_id(el)
|
139
|
+
own_id = el.attributes['id']
|
140
|
+
return '' if own_id.nil? || own_id == ''
|
141
|
+
|
142
|
+
ancestors = el.find(%{
|
143
|
+
ancestor::option[@id != '']
|
144
|
+
| ancestor::group[@id != '']
|
145
|
+
| ancestor::form[@id != '']
|
146
|
+
| ancestor::container[@id != '']
|
147
|
+
})
|
148
|
+
ids = ancestors.collect{|a| a.attributes['id']}.select{|a| !a.nil? }
|
149
|
+
ids << own_id
|
150
|
+
ids.collect{|i| i.to_s}.join('/')
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|