nom-xml 0.0.3 → 0.0.4

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/lib/nom/xml.rb CHANGED
@@ -3,7 +3,9 @@ require 'nokogiri'
3
3
  module Nom
4
4
  module XML
5
5
  require 'nom/xml/version'
6
+ require 'nom/xml/term'
6
7
  require 'nom/xml/terminology'
8
+ require 'nom/xml/template_registry'
7
9
  require 'nom/xml/decorators'
8
10
 
9
11
  require 'nom/xml/nokogiri_extension'
@@ -2,5 +2,6 @@ module Nom::XML
2
2
  module Decorators
3
3
  require 'nom/xml/decorators/terminology'
4
4
  require 'nom/xml/decorators/nodeset'
5
+ require 'nom/xml/decorators/template_registry'
5
6
  end
6
7
  end
@@ -0,0 +1,7 @@
1
+ module Nom::XML::Decorators
2
+ module TemplateRegistry
3
+ def template(node_type, *args)
4
+ template_registry.instantiate(node_type, *args)
5
+ end
6
+ end
7
+ end
@@ -4,44 +4,89 @@ module Nom::XML::Decorators::Terminology
4
4
  klass.add_terminology_methods!
5
5
  end
6
6
 
7
+ ##
8
+ # Add terminology accessors for querying child terms
7
9
  def add_terminology_methods!
8
- document.add_terminology_methods(self)
10
+ self.term_accessors.each do |k, t|
11
+ (class << self; self; end).send(:define_method, k.to_sym) do |*args|
12
+ options = args.extract_options!
13
+
14
+ args += options.map { |key, value| %{#{key}="#{value.gsub(/"/, '\\\"') }"} }
15
+
16
+ xpath = t.local_xpath
17
+
18
+ xpath += "[#{args.join('][')}]" unless args.empty?
19
+
20
+ result = case self
21
+ when Nokogiri::XML::Document
22
+ self.root.xpath(xpath, self.document.terminology_namespaces)
23
+ else
24
+ self.xpath(xpath, self.document.terminology_namespaces)
25
+ end
26
+
27
+ m = t.options[:accessor]
28
+ case
29
+ when m.nil?
30
+ result
31
+ when m.is_a?(Symbol)
32
+ result.collect { |r| r.send(m) }
33
+ when m.is_a?(Proc)
34
+ result.collect { |r| m.call(r) }
35
+ else
36
+ raise "Unknown accessor class: #{m.class}"
37
+ end
38
+ end
39
+ end
40
+
41
+ self
9
42
  end
10
43
 
44
+ ##
45
+ # Get the terminology terms associated with this node
11
46
  def terms
12
- if self == self.document.root or self.is_a? Nokogiri::XML::Document
13
- root_terms
14
- elsif not self.parent.terms.empty?
15
- child_terms
16
- else
17
- []
47
+ return {} unless self.respond_to? :parent and not self.parent.term_accessors.empty?
48
+
49
+ self.parent.term_accessors.select do |k,term|
50
+ self.parent.xpath(term.local_xpath, self.document.terminology_namespaces).include? self
51
+ end
52
+ end
53
+
54
+ protected
55
+ ##
56
+ # Collection of salient terminology accessors for this node
57
+ def term_accessors
58
+ case
59
+ when (self == self.document.root or self.is_a? Nokogiri::XML::Document)
60
+ root_terms
61
+ else
62
+ child_terms
18
63
  end
19
64
  end
20
65
 
21
66
  private
22
67
 
23
- def root_terms
68
+ ##
69
+ # Root terms for the document
70
+ def root_terms
24
71
  self.document.terminology.terms
25
72
  end
26
73
 
27
- def child_terms
74
+ ##
75
+ # Terms that are immediate children of this node, or are globally applicable
76
+ def child_terms
28
77
  h = {}
29
78
 
30
- collect_terms_for_node.each do |k,v|
31
- v.terms.each do |k1, v1|
79
+ terms.each do |k,term|
80
+
81
+ term.terms.each do |k1, v1|
32
82
  h[k1] = v1
33
83
  end
34
84
  end
35
85
 
36
- h
37
- end
38
-
39
- ##
40
- #find this self in the terminology
41
- def collect_terms_for_node
42
- self.parent.terms.select do |k,term|
43
- self.parent.xpath(term.local_xpath, self.document.terminology_namespaces).include? self
86
+ self.ancestors.each do |a|
87
+ a.term_accessors.each { |k,t| h[k] ||= t if t.options[:global] }
44
88
  end
45
- end
46
89
 
90
+ h
91
+ end
47
92
  end
@@ -6,14 +6,17 @@ module Nom::XML
6
6
  def nom!
7
7
  unless decorators(Nokogiri::XML::Node).include? Nom::XML::Decorators::Terminology
8
8
  decorators(Nokogiri::XML::Node) << Nom::XML::Decorators::Terminology
9
- decorate!
10
9
  end
11
10
 
12
11
  unless decorators(Nokogiri::XML::NodeSet).include? Nom::XML::Decorators::NodeSet
13
12
  decorators(Nokogiri::XML::NodeSet) << Nom::XML::Decorators::NodeSet
14
- decorate!
15
13
  end
16
14
 
15
+ unless decorators(Nokogiri::XML::Document).include? Nom::XML::Decorators::TemplateRegistry
16
+ decorators(Nokogiri::XML::Document) << Nom::XML::Decorators::TemplateRegistry
17
+ end
18
+
19
+ decorate!
17
20
  self
18
21
  end
19
22
 
@@ -30,46 +33,18 @@ module Nom::XML
30
33
  @terminology ||= Nom::XML::Terminology.new
31
34
  end
32
35
 
33
- ##
34
- # Add terminology accessors for querying child terms
35
- # @param [Nokogiri::XML::Node] node
36
- def add_terminology_methods node
37
- terms_to_add = node.terms
38
- node.ancestors.each do |a|
39
- a.terms.each { |k,t| terms_to_add[k] ||= t if t.options[:global] }
40
- end
41
-
42
- terms_to_add.each do |k, t|
43
- (class << node; self; end).send(:define_method, k.to_sym) do |*args|
44
- options = args.extract_options!
45
-
46
- args += options.map { |key, value| %{#{key}="#{value.gsub(/"/, '\\\"') }"} }
47
-
48
- xpath = t.local_xpath
49
-
36
+ def template_registry
37
+ @template_registry ||= Nom::XML::TemplateRegistry.new
38
+ end
50
39
 
51
- xpath += "[#{args.join('][')}]" unless args.empty?
40
+ # Define a new node template with the Nom::XML::TemplateRegistry.
41
+ # * +name+ is a Symbol indicating the name of the new template.
42
+ # * The +block+ does the work of creating the new node, and will receive
43
+ # a Nokogiri::XML::Builder and any other args passed to one of the node instantiation methods.
44
+ def define_template name, &block
45
+ self.template_registry.define name, &block
46
+ end
52
47
 
53
- result = case self
54
- when Nokogiri::XML::Document
55
- self.root.xpath(xpath, node.document.terminology_namespaces)
56
- else
57
- self.xpath(xpath, node.document.terminology_namespaces)
58
- end
59
48
 
60
- m = t.options[:accessor]
61
- case
62
- when m.nil?
63
- result
64
- when m.is_a?(Symbol)
65
- result.collect { |r| r.send(m) }
66
- when m.is_a?(Proc)
67
- result.collect { |r| m.call(r) }
68
- else
69
- raise "Unknown accessor class: #{m.class}"
70
- end
71
- end
72
- end
73
- end
74
49
  end
75
50
  end
@@ -0,0 +1,163 @@
1
+ class Nom::XML::TemplateRegistry
2
+
3
+ def initialize
4
+ @templates = {}
5
+ end
6
+
7
+ # Define an XML template
8
+ # @param [Symbol] a node_type key to associate with this template
9
+ # @param [Block] a block that will receive a [Nokogiri::XML::Builder] object and any arbitrary parameters passed to +instantiate+
10
+ # @return the +node_type+ Symbol
11
+ def define(node_type, &block)
12
+ unless node_type.is_a?(Symbol)
13
+ raise TypeError, "Registered node type must be a Symbol (e.g., :person)"
14
+ end
15
+
16
+ @templates[node_type] = block
17
+ node_type
18
+ end
19
+
20
+ # Undefine an XML template
21
+ # @param [Symbol] the node_type key of the template to undefine
22
+ # @return the +node_type+ Symbol
23
+ def undefine(node_type)
24
+ @templates.delete(node_type)
25
+ node_type
26
+ end
27
+
28
+ # Check whether a particular node_type is defined
29
+ # @param [Symbol] the node_type key to check
30
+ # @return [True] or [False]
31
+ def has_node_type?(node_type)
32
+ @templates.has_key?(node_type)
33
+ end
34
+
35
+ # List defined node_types
36
+ # @return [Array] of node_type symbols.
37
+ def node_types
38
+ @templates.keys
39
+ end
40
+
41
+ # Instantiate a detached, standalone node
42
+ # @param [Symbol] the node_type to instantiate
43
+ # @param additional arguments to pass to the template
44
+ def instantiate(node_type, *args)
45
+ result = create_detached_node(nil, node_type, *args)
46
+ # Strip namespaces from text and CDATA nodes. Stupid Nokogiri.
47
+ result.traverse { |node|
48
+ if node.is_a?(Nokogiri::XML::CharacterData)
49
+ node.namespace = nil
50
+ end
51
+ }
52
+ return result
53
+ end
54
+
55
+ # +instantiate+ a node and add it as a child of the [Nokogiri::XML::Node] specified by +target_node+
56
+ # @return the new [Nokogiri::XML::Node]
57
+ def add_child(target_node, node_type, *args, &block)
58
+ attach_node(:add_child, target_node, :self, node_type, *args, &block)
59
+ end
60
+
61
+ # +instantiate+ a node and add it as a following sibling of the [Nokogiri::XML::Node] specified by +target_node+
62
+ # @return the new [Nokogiri::XML::Node]
63
+ def add_next_sibling(target_node, node_type, *args, &block)
64
+ attach_node(:add_next_sibling, target_node, :parent, node_type, *args, &block)
65
+ end
66
+
67
+ # +instantiate+ a node and add it as a preceding sibling of the [Nokogiri::XML::Node] specified by +target_node+
68
+ # @return the new [Nokogiri::XML::Node]
69
+ def add_previous_sibling(target_node, node_type, *args, &block)
70
+ attach_node(:add_previous_sibling, target_node, :parent, node_type, *args, &block)
71
+ end
72
+
73
+ # +instantiate+ a node and add it as a following sibling of the [Nokogiri::XML::Node] specified by +target_node+
74
+ # @return +target_node+
75
+ def after(target_node, node_type, *args, &block)
76
+ attach_node(:after, target_node, :parent, node_type, *args, &block)
77
+ end
78
+
79
+ # +instantiate+ a node and add it as a preceding sibling of the [Nokogiri::XML::Node] specified by +target_node+
80
+ # @return +target_node+
81
+ def before(target_node, node_type, *args, &block)
82
+ attach_node(:before, target_node, :parent, node_type, *args, &block)
83
+ end
84
+
85
+ # +instantiate+ a node replace the [Nokogiri::XML::Node] specified by +target_node+ with it
86
+ # @return the new [Nokogiri::XML::Node]
87
+ def replace(target_node, node_type, *args, &block)
88
+ attach_node(:replace, target_node, :parent, node_type, *args, &block)
89
+ end
90
+
91
+ # +instantiate+ a node replace the [Nokogiri::XML::Node] specified by +target_node+ with it
92
+ # @return +target_node+
93
+ def swap(target_node, node_type, *args, &block)
94
+ attach_node(:swap, target_node, :parent, node_type, *args, &block)
95
+ end
96
+
97
+ def methods
98
+ super + @templates.keys.collect { |k| k.to_s }
99
+ end
100
+
101
+ def method_missing(sym,*args)
102
+ sym = sym.to_s.sub(/_$/,'').to_sym
103
+ if @templates.has_key?(sym)
104
+ instantiate(sym,*args)
105
+ else
106
+ super(sym,*args)
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ # Create a new Nokogiri::XML::Node based on the template for +node_type+
113
+ #
114
+ # @param [Nokogiri::XML::Node] builder_node The node to use as starting point for building the node using Nokogiri::XML::Builder.with(builder_node). This provides namespace info, etc for constructing the new Node object. If nil, defaults to {Nom::XML::TemplateRegistry#empty_root_node}. This is just used to create the new node and will not be included in the response.
115
+ # @param node_type a pointer to the template to use when creating the node
116
+ # @param [Array] args any additional args
117
+ def create_detached_node(builder_node, node_type, *args)
118
+ proc = @templates[node_type]
119
+ if proc.nil?
120
+ raise NameError, "Unknown node type: #{node_type.to_s}"
121
+ end
122
+ if builder_node.nil?
123
+ builder_node = empty_root_node
124
+ end
125
+
126
+ builder = Nokogiri::XML::Builder.with(builder_node) do |xml|
127
+ proc.call(xml,*args)
128
+ end
129
+ builder_node.elements.last.remove
130
+ end
131
+
132
+ # Create a new XML node of type +node_type+ and attach it to +target_node+ using the specified +method+
133
+ #
134
+ # @param [Symbol] method name that should be called on +target_node+, usually a Nokogiri::XML::Node instance method
135
+ # @param [Nokogiri::XML::Node or Nokogiri::XML::NodeSet with only one Node in it] target_node
136
+ # @param [Symbol] builder_node_offset Indicates node to use as the starting point for _constructing_ the new node using {Nom::XML::TemplateRegistry#create_detached_node}. If this is set to :parent, target_node.parent will be used. Otherwise, target_node will be used.
137
+ # @param node_type
138
+ # @param [Array] args any additional arguments for creating the node
139
+ def attach_node(method, target_node, builder_node_offset, node_type, *args, &block)
140
+ if target_node.is_a?(Nokogiri::XML::NodeSet) and target_node.length == 1
141
+ target_node = target_node.first
142
+ end
143
+ builder_node = builder_node_offset == :parent ? target_node.parent : target_node
144
+ new_node = create_detached_node(builder_node, node_type, *args)
145
+ result = target_node.send(method, new_node)
146
+ # Strip namespaces from text and CDATA nodes. Stupid Nokogiri.
147
+ new_node.traverse { |node|
148
+ if node.is_a?(Nokogiri::XML::CharacterData)
149
+ node.namespace = nil
150
+ end
151
+ }
152
+ if block_given?
153
+ yield result
154
+ else
155
+ return result
156
+ end
157
+ end
158
+
159
+ def empty_root_node
160
+ Nokogiri::XML('<root/>').root
161
+ end
162
+
163
+ end
@@ -0,0 +1,74 @@
1
+ module Nom::XML
2
+ class Term
3
+ attr_reader :name
4
+ attr_reader :terms
5
+ attr_reader :parent
6
+ attr_writer :parent
7
+ attr_reader :options
8
+
9
+ def initialize parent, name, options = {}, *args, &block
10
+ @name = name
11
+ @terms = {}
12
+ @parent = parent
13
+ @options = options || {}
14
+
15
+ in_edit_context do
16
+ yield(self) if block_given?
17
+ end
18
+ end
19
+
20
+ def in_edit_context &block
21
+ @edit_context = true
22
+ yield
23
+ @edit_context = false
24
+ end
25
+
26
+ def in_edit_context?
27
+ @edit_context
28
+ end
29
+
30
+ def parent_xpath
31
+ @parent_xpath ||= self.parent.xpath
32
+ end
33
+
34
+ def clear_parent_cache!
35
+ @parent_xpath = nil
36
+ end
37
+
38
+ def xpath
39
+ [parent_xpath, local_xpath].flatten.compact.join("/")
40
+ end
41
+
42
+ def local_xpath
43
+ ("#{xmlns}:" unless xmlns.blank? ).to_s + (options[:path] || name).to_s
44
+ end
45
+
46
+ def xmlns
47
+ (options[:xmlns] if options) || (self.parent.xmlns if self.parent)
48
+ end
49
+
50
+ def method_missing method, *args, &block
51
+ if in_edit_context?
52
+ add_term(method, *args, &block)
53
+ elsif key?(method)
54
+ term(method)
55
+ else
56
+ super
57
+ end
58
+ end
59
+
60
+ def key? term
61
+ terms.key? term
62
+ end
63
+
64
+ protected
65
+ def add_term method, options = {}, *args, &block
66
+ terms[method] = Term.new(self, method, options, *args, &block)
67
+ end
68
+
69
+ def term method, *args, &block
70
+ terms[method]
71
+ end
72
+ end
73
+
74
+ end
@@ -1,94 +1,4 @@
1
1
  module Nom::XML
2
- class Term
3
- attr_reader :name
4
- attr_reader :terms
5
- attr_reader :parent
6
- attr_writer :parent
7
- attr_reader :options
8
-
9
- def initialize parent, name, options = {}, *args, &block
10
- @name = name
11
- @terms = {}
12
- @parent = parent
13
- @options = options || {}
14
-
15
- in_edit_context do
16
- yield(self) if block_given?
17
- end
18
- end
19
-
20
- def in_edit_context &block
21
- @edit_context = true
22
- yield
23
- @edit_context = false
24
- end
25
-
26
- def terms_from_node node
27
- terms.select do |k, term|
28
- node.parent.xpath(term.xpath).include? node
29
- end.flatten
30
- end
31
-
32
- def in_edit_context?
33
- @edit_context
34
- end
35
-
36
- def parent_xpath
37
- @parent_xpath ||= self.parent.xpath
38
- end
39
-
40
- def clear_parent_cache
41
- @parent_xpath = nil
42
- end
43
-
44
- def xpath
45
- [parent_xpath, local_xpath].flatten.compact.join("/")
46
- end
47
-
48
- def local_xpath
49
- ("#{xmlns}:" unless xmlns.blank? ).to_s + (options[:path] || name).to_s
50
- end
51
-
52
- def xmlns
53
- (options[:xmlns] if options) || (self.parent.xmlns if self.parent)
54
- end
55
-
56
- def method_missing method, *args, &block
57
- if in_edit_context?
58
- add_term(method, *args, &block)
59
- elsif key?(method)
60
- term(method)
61
- # else if options[:ref]
62
- # resolve_ref_and_return_term(method, *args, &block)
63
- else
64
- super
65
- end
66
- #terms[method]
67
- end
68
-
69
- def key? term
70
- terms.key? term
71
- end
72
-
73
- def substitute_parent p
74
- obj = self.dup
75
-
76
- obj.parent = p
77
- obj.clear_parent_cache
78
-
79
- obj
80
- end
81
-
82
- protected
83
- def add_term method, options = {}, *args, &block
84
- terms[method] = Term.new(self, method, options, *args, &block)
85
- end
86
-
87
- def term method, *args, &block
88
- terms[method]
89
- end
90
- end
91
-
92
2
  class Terminology < Term
93
3
  def initialize *args, &block
94
4
  @terms = {}
@@ -97,7 +7,6 @@ module Nom::XML
97
7
  end
98
8
  end
99
9
 
100
-
101
10
  def xpath
102
11
  nil
103
12
  end
@@ -1,5 +1,5 @@
1
1
  module Nom
2
2
  module XML
3
- VERSION = '0.0.3'
3
+ VERSION = '0.0.4'
4
4
  end
5
5
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Template Registry example" do
4
+ let(:file) {
5
+ <<-eoxml
6
+ <root>
7
+ <a>1234</a>
8
+
9
+ <b>asdf</b>
10
+
11
+ <c>
12
+ <nested>poiuyt</nested>
13
+ </c>
14
+ </root>
15
+ eoxml
16
+ }
17
+ let(:xml) { Nokogiri::XML(file) }
18
+
19
+ subject {
20
+ xml.define_template :a do |xml, value|
21
+ xml.a { xml.text value }
22
+ end
23
+
24
+ xml.set_terminology do |t|
25
+ t.a
26
+ t.b
27
+ t.b_ref :path => 'b'
28
+
29
+ t.c do |c|
30
+ c.nested
31
+ end
32
+ end
33
+
34
+ xml.nom!
35
+
36
+ xml
37
+ }
38
+
39
+ it "should work" do
40
+ subject.root.add_child(subject.template(:a, 'asdf'))
41
+ subject.a.should have(2).items
42
+ end
43
+ end
@@ -16,11 +16,14 @@ describe Nom::XML::NokogiriExtension do
16
16
  </item>
17
17
  eoxml
18
18
  }
19
- describe "#add_terminology_methods" do
20
- context "root node" do
21
- it "should add terminology methods to the root node" do
22
19
 
23
- end
20
+ describe "#nom!" do
21
+ it "should decorate Nodes and Nodesets with our decorators" do
22
+ doc.nom!
23
+
24
+ doc.root.should be_a_kind_of(Nom::XML::Decorators::Terminology)
25
+
26
+ doc.xpath('//*').should be_a_kind_of(Nom::XML::Decorators::NodeSet)
24
27
  end
25
28
  end
26
29
  end
@@ -1,6 +1,163 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
+
3
+ describe "Nutrition" do
4
+ let(:file) {
5
+ <<-eoxml
6
+ <root>
7
+ <a>1234</a>
8
+
9
+ <b>asdf</b>
10
+
11
+ <c>
12
+ <nested>poiuyt</nested>
13
+ </c>
14
+ </root>
15
+ eoxml
16
+ }
17
+ let(:xml) { Nokogiri::XML(file) }
18
+
19
+ let(:document) {
20
+ xml.set_terminology do |t|
21
+ t.a
22
+ t.b
23
+ t.b_ref :path => 'b'
24
+
25
+ t.c do |c|
26
+ c.nested
27
+ end
28
+ end
29
+
30
+ xml.nom!
31
+
32
+ xml
33
+ }
34
+
35
+ describe "#add_terminology_methods!" do
36
+ subject do
37
+ m = mock()
38
+ m.stub(:document).and_return(mock(:terminology_namespaces => {}))
39
+ m.stub(:term_accessors).and_return(@term_accessors)
40
+ m.extend Nom::XML::Decorators::Terminology
41
+ m
42
+ end
43
+
44
+ it "should define terminology accessors" do
45
+ mock_term = mock
46
+ @term_accessors = { :asdf => mock_term }
47
+
48
+ subject.should respond_to(:asdf)
49
+ end
50
+
51
+ it "should perform basic xpath queries" do
52
+ mock_term = mock(:local_xpath => '//asdf', :options => {})
53
+ @term_accessors = { :asdf => mock_term }
54
+
55
+ subject.should_receive(:xpath).with('//asdf', anything)
56
+
57
+ subject.asdf
58
+ end
59
+
60
+ it "should perform xpath queries with constraints" do
61
+ mock_term = mock(:local_xpath => '//asdf', :options => {})
62
+ @term_accessors = { :asdf => mock_term }
63
+
64
+ subject.should_receive(:xpath).with('//asdf[predicate="value"]', anything)
65
+ subject.should_receive(:xpath).with('//asdf[predicate="\"value\""]', anything)
66
+ subject.should_receive(:xpath).with('//asdf[custom-xpath-predicate()]', anything)
67
+ subject.should_receive(:xpath).with('//asdf[custom-xpath-predicate()][predicate="value"]', anything)
68
+
69
+ subject.asdf(:predicate => 'value')
70
+ subject.asdf(:predicate => '"value"')
71
+ subject.asdf('custom-xpath-predicate()')
72
+ subject.asdf('custom-xpath-predicate()', :predicate => 'value')
73
+ end
74
+
75
+ it "should execute accessors" do
76
+ mock_term = mock(:local_xpath => '//asdf', :options => {:accessor => :text })
77
+ @term_accessors = { :asdf => mock_term }
78
+
79
+ m = mock()
80
+ subject.should_receive(:xpath).with('//asdf', anything).and_return([m])
81
+ m.should_receive(:text)
82
+
83
+ subject.asdf
84
+ end
85
+
86
+ it "should execute proc-based accessors" do
87
+ mock_term = mock(:local_xpath => '//asdf', :options => {:accessor => lambda { |x| x.zxcvb } })
88
+ @term_accessors = { :asdf => mock_term }
89
+
90
+ m = mock()
91
+ subject.should_receive(:xpath).with('//asdf', anything).and_return([m])
92
+ m.should_receive(:zxcvb)
93
+
94
+ subject.asdf
95
+ end
96
+ end
97
+
98
+ describe "#terms" do
99
+
100
+ context "root element" do
101
+ subject { document.root }
102
+
103
+ it "should not have any associated terminology terms" do
104
+ subject.terms.should be_empty
105
+ end
106
+
107
+ end
108
+
109
+ context "node with a single term" do
110
+ subject { document.xpath('//a').first }
111
+
112
+ it "should have a single term" do
113
+ subject.terms.should have(1).item
114
+ end
115
+
116
+ it "should find the right term" do
117
+ subject.terms.keys.should include(:a)
118
+ end
119
+ end
120
+
121
+ context "node with multiple terms" do
122
+ subject { document.xpath('//b').first }
123
+
124
+ it "should have multiple terms" do
125
+ subject.terms.should have(2).items
126
+ end
127
+
128
+ it "should find the right terms" do
129
+ subject.terms.keys.should include(:b, :b_ref)
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "#term_accessors" do
135
+
136
+ context "node" do
137
+ subject { document.xpath('//c').first }
138
+
139
+ it "should have a child accessor" do
140
+ subject.send(:term_accessors).keys.should include(:nested)
141
+ end
142
+ end
143
+
144
+ context "document" do
145
+ subject { document }
146
+
147
+ it "should have all the root terms" do
148
+ subject.send(:term_accessors).keys.should include(:a, :b, :c)
149
+ end
150
+ end
151
+
152
+ context "root node" do
153
+ subject { document.root }
154
+
155
+ it "should have all the root terms" do
156
+ subject.send(:term_accessors).keys.should include(:a, :b, :c)
157
+ end
158
+ end
159
+ end
2
160
 
3
- describe Nom::XML::Decorators::Terminology do
4
161
 
5
162
  end
6
163
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nom-xml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-13 00:00:00.000000000 Z
12
+ date: 2012-09-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -139,13 +139,17 @@ files:
139
139
  - lib/nom/xml.rb
140
140
  - lib/nom/xml/decorators.rb
141
141
  - lib/nom/xml/decorators/nodeset.rb
142
+ - lib/nom/xml/decorators/template_registry.rb
142
143
  - lib/nom/xml/decorators/terminology.rb
143
144
  - lib/nom/xml/nokogiri_extension.rb
145
+ - lib/nom/xml/template_registry.rb
146
+ - lib/nom/xml/term.rb
144
147
  - lib/nom/xml/terminology.rb
145
148
  - lib/nom/xml/version.rb
146
149
  - nom.gemspec
147
150
  - spec/examples/namespaced_example_spec.rb
148
151
  - spec/examples/nutrition_example_spec.rb
152
+ - spec/examples/template_registry_example_spec.rb
149
153
  - spec/fixtures/nutrition.xml
150
154
  - spec/fixtures/xml_namespaces.xml
151
155
  - spec/lib/nodeset_decorator_spec.rb
@@ -168,7 +172,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
168
172
  version: '0'
169
173
  segments:
170
174
  - 0
171
- hash: 3518149504485723530
175
+ hash: 1606554633515477206
172
176
  required_rubygems_version: !ruby/object:Gem::Requirement
173
177
  none: false
174
178
  requirements:
@@ -177,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
181
  version: '0'
178
182
  segments:
179
183
  - 0
180
- hash: 3518149504485723530
184
+ hash: 1606554633515477206
181
185
  requirements: []
182
186
  rubyforge_project:
183
187
  rubygems_version: 1.8.23
@@ -187,6 +191,7 @@ summary: asdf
187
191
  test_files:
188
192
  - spec/examples/namespaced_example_spec.rb
189
193
  - spec/examples/nutrition_example_spec.rb
194
+ - spec/examples/template_registry_example_spec.rb
190
195
  - spec/fixtures/nutrition.xml
191
196
  - spec/fixtures/xml_namespaces.xml
192
197
  - spec/lib/nodeset_decorator_spec.rb