fabulator 0.0.7 → 0.0.8

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.
@@ -47,6 +47,7 @@ require 'fabulator/lib/lib'
47
47
  require 'fabulator/lib/structural'
48
48
  require 'fabulator/lib/action'
49
49
  require 'fabulator/lib/attribute'
50
+ require 'fabulator/lib/function'
50
51
 
51
52
  module Fabulator
52
53
  module Lib
@@ -57,10 +58,10 @@ module Fabulator
57
58
  structural :structural, Structural
58
59
  structural :action, Action
59
60
  structural :attribute, Attribute
60
- #structural :function, Function
61
- #structural :mapping, Mapping
62
- #structural :reduction, Reduction
63
- #structural :consolidation, Consolidation
61
+ structural :function, Function
62
+ structural :mapping, Mapping
63
+ structural :reduction, Reduction
64
+ structural :consolidation, Consolidation
64
65
  #structural :type, Type
65
66
  #structural :filter, Filter
66
67
  #structural :constraint, Constraint
@@ -1,13 +1,58 @@
1
+ #
2
+ # Provides functional support -- not quite closures (yet)
3
+ #
1
4
  module Fabulator
2
5
  module Lib
3
6
  class Action < Fabulator::Structural
7
+ attr_accessor :attributes
8
+
4
9
  namespace FAB_LIB_NS
5
10
 
6
11
  attribute :name, :static => true
12
+ attribute 'has-actions', :static => true, :as => :has_actions, :type => :boolean
7
13
 
8
14
  contains :attribute
9
15
 
10
16
  has_actions
17
+
18
+ def compile_action(e, context)
19
+ ret = nil
20
+ context.with(e) do |ctx|
21
+ ret = ActionRef.new(self, ctx, ctx.compile_actions(e))
22
+ end
23
+ ret
24
+ end
25
+ end
26
+
27
+ class ActionRef
28
+ def initialize(defining_action, context, actions = nil)
29
+ @context = context
30
+ @action = defining_action
31
+ @actions = actions
32
+ @static_attributes = { }
33
+ @action.attributes.collect{ |a| a.is_static? }.each do |a|
34
+ @static_attributes[a.path] = a.value(@context)
35
+ end
36
+ end
37
+
38
+ def run(context, autovivify = false)
39
+ ret = [ ]
40
+ @context.with(context) do |ctx|
41
+ @static_attributes.each_pair do |p,v|
42
+ ctx.set_value(p, v)
43
+ end
44
+ # These can be passed to f:eval to get their value
45
+ @action.attributes.collect{ |a| !a.is_static? }.each do |attr|
46
+ ctx.set_value(attr.path, attr.value(ctx))
47
+ end
48
+ # we can f:eval($actions) in whatever current context we have
49
+ if @action.has_actions?
50
+ ctx.set_var('actions', ctx.root.anon_node(@actions, [ FAB_NS, 'expression' ]))
51
+ end
52
+ ret = @action.run(ctx)
53
+ end
54
+ ret
55
+ end
11
56
  end
12
57
  end
13
58
  end
@@ -4,6 +4,17 @@ module Fabulator
4
4
  namespace FAB_LIB_NS
5
5
 
6
6
  attribute :name, :static => true
7
+ attribute :ns, :static => true, :inherited => true
8
+ attribute :static, :static => true, :type => :boolean
9
+ attribute :eval, :static => true, :type => :boolean
10
+
11
+ def is_static?
12
+ @static
13
+ end
14
+
15
+ def value(context)
16
+ context.attribute(@ns, @name, { :static => @static, :eval => @eval })
17
+ end
7
18
  end
8
19
  end
9
20
  end
@@ -0,0 +1,36 @@
1
+ module Fabulator
2
+ module Lib
3
+ class Function < Fabulator::Structural
4
+ namespace FAB_LIB_NS
5
+
6
+ attribute :name, :static => true
7
+
8
+ has_actions
9
+ end
10
+
11
+ class Mapping < Fabulator::Structural
12
+ namespace FAB_LIB_NS
13
+
14
+ attribute :name, :static => true
15
+
16
+ has_actions
17
+ end
18
+
19
+ class Reduction < Fabulator::Structural
20
+ namespace FAB_LIB_NS
21
+
22
+ attribute :name, :static => true
23
+
24
+ has_actions
25
+ end
26
+
27
+ class Consolidation < Fabulator::Structural
28
+ namespace FAB_LIB_NS
29
+
30
+ attribute :name, :static => true
31
+
32
+ has_actions
33
+ end
34
+ end
35
+ end
36
+
@@ -3,6 +3,8 @@ module Fabulator
3
3
  class Lib < Fabulator::Structural
4
4
 
5
5
  namespace FAB_LIB_NS
6
+
7
+ element :library
6
8
 
7
9
  attribute :ns, :static => true
8
10
 
@@ -17,16 +19,75 @@ module Fabulator
17
19
  contains :constraint, :storage => :hash, :key => :name
18
20
 
19
21
  def register_library
20
- Fabulator::TagLib.namespaces[@ns] = self
21
- @attributes.each do |attr|
22
- Fabulator::TagLib.attributes << [ @ns, attr[:name], attr[:options] ]
23
- end
22
+ Fabulator::TagLib.namespaces[self.ns] = self
24
23
  end
25
24
 
26
- def compile_action(e, c_attrs)
25
+ def compile_action(e, context)
26
+ name = e.name
27
+ return nil unless @actions.has_key?(name)
28
+ @actions[name].compile_action(e, context)
27
29
  end
28
30
 
29
31
  def run_function(context, nom, args)
32
+ # look for a function/mapping/consolidation
33
+ # then pass along to any objects in @contained
34
+
35
+ fctn = nil
36
+ fctn_type = nil
37
+
38
+ if nom =~ /^(.*)\*$/
39
+ cnom = $1
40
+ if !@consolidations[cnom].nil?
41
+ fctn = @consolidations[cnom]
42
+ fctn_type = :reduction
43
+ end
44
+ else
45
+ if @consolidations.has_key?(nom)
46
+ fctn = @reductions[nom]
47
+ fctn_type = :reduction
48
+ end
49
+ if fctn.nil?
50
+ fctn = @mappings[nom]
51
+ fctn_type = :mapping
52
+ end
53
+ if fctn.nil?
54
+ fctn = @functions[nom]
55
+ fctn_type = :function
56
+ end
57
+ if fctn.nil?
58
+ fctn = @reductions[nom]
59
+ fctn_type = :reduction
60
+ end
61
+ end
62
+
63
+ if !fctn.nil?
64
+ res = [ ]
65
+ context.in_context do |ctx|
66
+ args = args.flatten
67
+ case fctn_type
68
+ when :function:
69
+ args.size.times do |i|
70
+ ctx.set_var((i+1).to_s, args[i])
71
+ end
72
+ ctx.set_var('0', args)
73
+ res = fctn.run(ctx)
74
+ when :mapping:
75
+ res = args.collect{ |a| fctn.run(ctx.with_root(a)) }.flatten
76
+ when :reduction:
77
+ ctx.set_var('0', args.flatten)
78
+ res = fctn.run(ctx)
79
+ end
80
+ end
81
+ return res
82
+ end
83
+
84
+ return [] if @contained.nil?
85
+
86
+ @contained.each do |c|
87
+ ret = c.run_function(context, nom, args)
88
+ return ret unless ret.nil? || ret.empty?
89
+ end
90
+ []
30
91
  end
31
92
 
32
93
  def function_return_type(name)
@@ -38,9 +99,21 @@ module Fabulator
38
99
  end
39
100
 
40
101
  def run_filter(context, nom)
102
+ return if @contained.nil?
103
+ @contained.each do |c|
104
+ ret = c.run_filter(context, nom)
105
+ return ret unless ret.nil?
106
+ end
107
+ nil
41
108
  end
42
109
 
43
110
  def run_constraint(context, nom)
111
+ return if @contained.nil?
112
+ @contained.each do |c|
113
+ ret = c.run_constraint(context, nom)
114
+ return ret unless ret.nil?
115
+ end
116
+ false
44
117
  end
45
118
  end
46
119
  end
@@ -1,7 +1,11 @@
1
1
  module Fabulator
2
2
  class Structural < Action
3
3
 
4
- def compile_xml(xml, context)
4
+ def initialize
5
+ @context = Fabulator::Expr::Context.new
6
+ end
7
+
8
+ def compile_xml(xml, context = nil)
5
9
  XML.default_line_numbers = true
6
10
  if xml.is_a?(String)
7
11
  xml = LibXML::XML::Document.string xml
@@ -17,12 +21,12 @@ module Fabulator
17
21
  end
18
22
 
19
23
  self.setup(xml)
20
-
21
- self
22
24
  end
23
25
 
24
- def self.element(nom)
25
- @@elements[self.name] = nom
26
+ def self.element(nom = nil)
27
+ @@elements ||= { }
28
+ @@elements[self.name] = nom unless nom.nil?
29
+ @@elements[self.name]
26
30
  end
27
31
 
28
32
  def self.contains(nom, opts = { })
@@ -33,16 +37,40 @@ module Fabulator
33
37
  @@structurals[self.name][ns][nom.to_sym] = opts
34
38
  end
35
39
 
40
+ def self.contained_in(ns, nom, h = {})
41
+ @@contained_in ||= { }
42
+
43
+ @@contained_in[ns] ||= { }
44
+ @@contained_in[ns][nom.to_sym] ||= { }
45
+ @@contained_in[ns][nom.to_sym][self.namespace] ||= { }
46
+ @@contained_in[ns][nom.to_sym][self.namespace][self.element.to_sym] = h.update({ :as => :contained})
47
+ end
48
+
36
49
  def self.structurals
37
- return @@structurals[self.name]
50
+ ret = @@structurals[self.name]
51
+ els = self.element
52
+ els = [ els ] unless els.is_a?(Array)
53
+
54
+ return ret if self.element.nil?
55
+
56
+ @@contained_in ||= { }
57
+
58
+ return ret if @@contained_in[self.namespace].nil?
59
+
60
+ pot = @@contained_in[self.namespace][self.element.to_sym]
61
+ return ret if pot.nil? || pot.empty?
62
+
63
+ pot.each_pair do |ns, noms|
64
+ ret[ns] ||= { }
65
+ ret[ns] = ret[ns].update(noms)
66
+ end
67
+ ret
38
68
  end
39
69
 
40
70
  def self.accepts_structural?(ns, nom)
41
- return false if @@structurals.nil?
42
- return false if @@structurals[self.name].nil?
43
- return false if @@structurals[self.name][ns].nil?
44
- return false if @@structurals[self.name][ns][nom.to_sym].nil?
45
- return true
71
+ s = self.structurals
72
+ in_s = (s[ns][nom.to_sym] rescue nil)
73
+ return !in_s.nil?
46
74
  end
47
75
 
48
76
  def accepts_structural?(ns, nom)
@@ -74,7 +74,7 @@ module Fabulator
74
74
  end
75
75
 
76
76
  def structural_class(nom)
77
- Fabulator::TagLib.structural_classes[self.class.name][nom]
77
+ Fabulator::TagLib.structural_classes[self.class.name][nom.to_sym]
78
78
  end
79
79
 
80
80
  def self.inherited(base)
@@ -418,14 +418,10 @@ module Fabulator
418
418
  r
419
419
  }
420
420
  Fabulator::TagLib.structural_classes[self.name] ||= {}
421
- Fabulator::TagLib.structural_classes[self.name][name] = klass
421
+ Fabulator::TagLib.structural_classes[self.name][name.to_sym] = klass
422
422
  end
423
423
  end
424
424
 
425
- def structural_class(nom)
426
- (Fabulator::TagLib.structural_classes[self.class.name][nom] rescue nil)
427
- end
428
-
429
425
  def function(name, returns = nil, takes = nil, &block)
430
426
  self.function_descriptions[name] = { :returns => returns, :takes => takes }
431
427
  self.function_descriptions[name][:description] = Fabulator::TagLib.last_description if Fabulator::TagLib.last_description
@@ -1,9 +1,11 @@
1
1
  class Fabulator::Expr::Parser
2
+ #--
2
3
  # based on XSM expression grammer from
3
4
  # http://cpansearch.perl.org/src/JSMITH/Gestinanna-0.02/parser.PL
4
-
5
+ #
5
6
  # instead of compiling ruby code, we'll instantiate objects to handle the
6
7
  # run-time performance
8
+ #++
7
9
 
8
10
  start statements
9
11
 
@@ -184,15 +186,38 @@ rule
184
186
  end
185
187
 
186
188
  ---- inner
189
+ # == Fabulator Expression Parser
190
+ #
191
+ # <tt>Fabulator::Expr::Parser</tt> provides a parser for Fabulator
192
+ # expressions operating on a DOM-like data model provided by
193
+ # Fabulator::Expr::Context and Fabulator::Expr::Node.
194
+ #
195
+ # The expression language is based on XQuery and XPath.
196
+ #
197
+
187
198
  require 'fabulator/expr'
188
199
  require 'rational'
189
200
  require 'bigdecimal'
190
201
  require 'bigdecimal/util'
191
202
 
192
- def parse(t, ctx)
193
- @source = t
203
+ # Within the context of a Fabulator::Expr::Context object, this will
204
+ # parse the given string and return an object that can be run to return
205
+ # an array if Fabulator::Expr::Node objects.
206
+ #
207
+ # Example:
208
+ #
209
+ # parser = Fabulator::Expr::Parser.new
210
+ # context = Fabulator::Expr::Context.new
211
+ # expr = parser.parse('//foo', context)
212
+ # foos = expr.run(context)
213
+ #
214
+ # Results in 'foos' being an array of all of the nodes in the
215
+ # context that are named 'foo' regardless of their depth in the
216
+ # node tree.
217
+ def parse(text, context)
218
+ @source = text
194
219
  @curpos = 0
195
- @context = ctx
220
+ @context = context
196
221
  @line = 0
197
222
  @col = 0
198
223
 
@@ -203,6 +228,8 @@ end
203
228
  do_parse
204
229
  end
205
230
 
231
+ # Used internally by the parser to raise a Fabulator::Expr::ParserError
232
+ # when the parse fails.
206
233
  def on_error(*args)
207
234
  raise Fabulator::Expr::ParserError.new("unable to parse '#{args[1]}' near line #{@line + 1}, column #{@col}")
208
235
  end
@@ -396,8 +423,8 @@ end
396
423
  if res[1] == 'if'
397
424
  @token = [ :IF, 'if' ]
398
425
  else
399
- if @source[@curpos+res[1].length .. @curpos+res[1].length] == '*'
400
- @token = [ :FUNCTION_NAME, res[1]+'*' ]
426
+ if @source[@curpos+res[1].length .. @curpos+res[1].length + 1] =~ /^(\??\*?)/
427
+ @token = [ :FUNCTION_NAME, res[1]+$1 ]
401
428
  else
402
429
  @token = [ :FUNCTION_NAME, res[1] ]
403
430
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fabulator
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 7
10
- version: 0.0.7
9
+ - 8
10
+ version: 0.0.8
11
11
  platform: ruby
12
12
  authors:
13
13
  - James Smith
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-07 00:00:00 +00:00
18
+ date: 2010-09-11 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -106,6 +106,7 @@ extensions: []
106
106
 
107
107
  extra_rdoc_files:
108
108
  - README.rdoc
109
+ - TODO
109
110
  files:
110
111
  - History.txt
111
112
  - Manifest.txt
@@ -165,6 +166,7 @@ files:
165
166
  - lib/fabulator/lib.rb
166
167
  - lib/fabulator/lib/action.rb
167
168
  - lib/fabulator/lib/attribute.rb
169
+ - lib/fabulator/lib/function.rb
168
170
  - lib/fabulator/lib/lib.rb
169
171
  - lib/fabulator/lib/structural.rb
170
172
  - lib/fabulator/structural.rb
@@ -180,6 +182,7 @@ files:
180
182
  - test/test_helper.rb
181
183
  - xslt/form.xsl
182
184
  - xsm_expression_parser.racc
185
+ - TODO
183
186
  - test/cucumber.rb
184
187
  has_rdoc: true
185
188
  homepage: http://github.com/jgsmith/ruby-fabulator