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