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,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
|