nom-xml 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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