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,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,9 @@
1
+ module Fabulator
2
+ module Template
3
+ require 'fabulator/template/taggable'
4
+ require 'fabulator/template/standard_tags'
5
+ require 'fabulator/template/context'
6
+ require 'fabulator/template/parse_result'
7
+ require 'fabulator/template/parser'
8
+ end
9
+ 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