nom-xml 0.1.2 → 0.2.0

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/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ rvm:
2
+ - "1.9.3"
3
+ - jruby-19mode
4
+ - rbx-19mode
5
+ - jruby-18mode
6
+ - "1.8.7"
data/Gemfile CHANGED
@@ -4,3 +4,7 @@ gemspec
4
4
 
5
5
  gem 'simplecov', :platform => :ruby_19
6
6
  gem 'rcov', :platform => :ruby_18
7
+ gem 'debugger', :platform => :mri_19
8
+ gem "redcarpet", :platform => :ruby_19
9
+
10
+ gem 'nokogiri', '1.5.6.rc2'
data/Rakefile CHANGED
@@ -30,5 +30,5 @@ end
30
30
  desc "Continuous Integration build"
31
31
  task :ci do
32
32
  Rake::Task['spec'].invoke
33
- Rake::Task['yard'].invoke
33
+ # Rake::Task['yard'].invoke
34
34
  end
@@ -1,4 +1,9 @@
1
1
  module Nom::XML::Decorators::NodeSet
2
+
3
+ ##
4
+ # Add a #method_missing handler to NodeSets. If all of the elements in the Nodeset
5
+ # respond to a method (e.g. if it is a term accessor), call that method on all the
6
+ # elements in the node
2
7
  def method_missing sym, *args, &block
3
8
  if self.all? { |node| node.respond_to? sym }
4
9
  result = self.collect { |node| node.send(sym, *args, &block) }.flatten
@@ -7,4 +12,12 @@ module Nom::XML::Decorators::NodeSet
7
12
  super
8
13
  end
9
14
  end
15
+
16
+ def respond_to? sym
17
+ if self.all? { |node| node.respond_to? sym }
18
+ true
19
+ else
20
+ super
21
+ end
22
+ end
10
23
  end
@@ -1,91 +1,60 @@
1
1
  module Nom::XML::Decorators::Terminology
2
- def self.extended klass
3
-
4
- klass.add_terminology_methods!
5
- end
6
-
7
- ##
8
- # Add terminology accessors for querying child terms
9
- def add_terminology_methods!
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 += "[#{t.options[:if]}]" if t.options[:if] and t.options[:if].is_a? String
19
- xpath += "[not(#{t.options[:unless]})]" if t.options[:unless] and t.options[:unless].is_a? String
20
-
21
- xpath += "[#{args.join('][')}]" unless args.empty?
22
-
23
- result = case self
24
- when Nokogiri::XML::Document
25
- self.root.xpath(xpath, self.document.terminology_namespaces)
26
- else
27
- self.xpath(xpath, self.document.terminology_namespaces)
28
- end
29
-
30
- result = result.select &t.options[:if] if t.options[:if].is_a? Proc
31
- result = result.reject &t.options[:unless] if t.options[:unless].is_a? Proc
32
-
33
- m = t.options[:accessor]
34
- return_value = case
35
- when m.nil?
36
- result
37
- when m.is_a?(Symbol)
38
- result.collect { |r| r.send(m) }.compact
39
- when m.is_a?(Proc)
40
- result.collect { |r| m.call(r) }.compact
41
- else
42
- raise "Unknown accessor class: #{m.class}"
43
- end
44
-
45
-
46
- if return_value and (t.options[:single] or (return_value.length == 1 and return_value.first.is_a? Nokogiri::XML::Attr))
47
- return return_value.first
2
+
3
+ METHODS_WE_NEED_TO_BE_CAREFUL_OF = [:id, :type]
4
+
5
+ METHODS_WE_NEED_TO_BE_CAREFUL_OF.each do |t|
6
+ class_eval <<-eos
7
+ def #{t.to_s} *args, &block
8
+ if self.term_accessors[:#{t}]
9
+ lookup_term(self.term_accessors[:#{t}], *args, &block)
10
+ else
11
+ super
48
12
  end
13
+ end
14
+ eos
15
+ end
49
16
 
50
- return return_value
17
+ def method_missing method, *args, &block
18
+ if self.term_accessors[method.to_sym]
19
+ (class << self; self; end).send(:define_method, method.to_sym) do |*local_args|
20
+ lookup_term(self.term_accessors[method.to_sym], *local_args)
51
21
  end
22
+
23
+ self.send(method, *args, &block)
24
+ else
25
+ super
52
26
  end
27
+ end
53
28
 
54
- self
29
+ def respond_to? method
30
+ super || self.term_accessors[method.to_sym]
55
31
  end
56
32
 
57
33
  ##
58
- # Get the terminology terms associated with this node
34
+ # Get the terms associated with this node
59
35
  def terms
60
- return @terms if @terms
61
- p = self.parent
62
-
63
- t = []
64
-
65
- until p.is_a? Nokogiri::XML::Document
66
- p.term_accessors.each do |k,term|
67
- t << term if term.nodes.include? self
68
- end
69
- p = p.parent
70
- end
71
-
72
- @terms ||= t
36
+ @terms ||= self.ancestors.map { |p| p.term_accessors(self).map { |keys, values| values } }.flatten.compact.uniq
73
37
  end
74
38
 
75
39
  protected
76
40
  ##
77
41
  # Collection of salient terminology accessors for this node
78
- def term_accessors
79
- case
42
+ #
43
+ # The root note or document node should have all the root terms
44
+ def term_accessors matching_node = nil
45
+ terms = case
80
46
  when (self == self.document.root or self.is_a? Nokogiri::XML::Document)
81
47
  root_terms
82
48
  else
83
49
  child_terms
84
50
  end
51
+
52
+ terms &&= terms.select { |key, term| term.nodes.include? matching_node } if matching_node
53
+
54
+ terms
85
55
  end
86
56
 
87
57
  private
88
-
89
58
  ##
90
59
  # Root terms for the document
91
60
  def root_terms
@@ -97,17 +66,60 @@ module Nom::XML::Decorators::Terminology
97
66
  def child_terms
98
67
  h = {}
99
68
 
69
+ # collect the sub-terms of the terms applicable to this node
100
70
  terms.each do |term|
101
-
102
71
  term.terms.each do |k1, v1|
103
72
  h[k1] = v1
104
73
  end
105
74
  end
106
75
 
76
+ # and mix in any global terms of this node's ancestors
107
77
  self.ancestors.each do |a|
108
78
  a.term_accessors.each { |k,t| h[k] ||= t if t.options[:global] }
109
79
  end
110
80
 
111
81
  h
112
82
  end
83
+
84
+ def lookup_term term, *args
85
+ options = args.extract_options!
86
+
87
+ args += options.map { |key, value| %{#{key}="#{value.gsub(/"/, '\\\"') }"} }
88
+
89
+ xpath = term.local_xpath
90
+
91
+ xpath += "[#{term.options[:if]}]" if term.options[:if] and term.options[:if].is_a? String
92
+ xpath += "[not(#{term.options[:unless]})]" if term.options[:unless] and term.options[:unless].is_a? String
93
+
94
+ xpath += "[#{args.join('][')}]" unless args.empty?
95
+
96
+ result = case self
97
+ when Nokogiri::XML::Document
98
+ self.document.root.xpath(xpath, self.document.terminology_namespaces)
99
+ else
100
+ self.xpath(xpath, self.document.terminology_namespaces)
101
+ end
102
+
103
+ result = result.select &(term.options[:if]) if term.options[:if].is_a? Proc
104
+ result = result.reject &(term.options[:unless]) if term.options[:unless].is_a? Proc
105
+
106
+ m = term.options[:accessor]
107
+
108
+ return_value = case
109
+ when m.nil?
110
+ result
111
+ when m.is_a?(Symbol)
112
+ result.collect { |r| r.send(m) }.compact
113
+ when m.is_a?(Proc)
114
+ result.collect { |r| m.call(r) }.compact
115
+ else
116
+ raise "Unknown accessor class: #{m.class}"
117
+ end
118
+
119
+ if return_value and (term.options[:single] or (return_value.length == 1 and return_value.first.is_a? Nokogiri::XML::Attr))
120
+ return return_value.first
121
+ end
122
+
123
+ return return_value
124
+ end
113
125
  end
@@ -3,6 +3,8 @@ require 'active_support/core_ext/array'
3
3
  module Nom::XML
4
4
  module NokogiriExtension
5
5
 
6
+ ##
7
+ # Apply NOM decorators to Nokogiri classes
6
8
  def nom!
7
9
  unless decorators(Nokogiri::XML::Node).include? Nom::XML::Decorators::Terminology
8
10
  decorators(Nokogiri::XML::Node) << Nom::XML::Decorators::Terminology
@@ -20,19 +22,26 @@ module Nom::XML
20
22
  self
21
23
  end
22
24
 
25
+ ##
26
+ # Set the terminology accessors for this document
23
27
  def set_terminology options = {}, &block
24
- @terminology_namespaces = options[:namespaces]
25
28
  @terminology = Nom::XML::Terminology.new(self, options, &block)
29
+
30
+ self
26
31
  end
27
32
 
28
33
  def terminology_namespaces
29
- @terminology_namespaces ||= {}
34
+ @terminology.namespaces
30
35
  end
31
36
 
32
37
  def terminology
33
38
  @terminology ||= Nom::XML::Terminology.new self
34
39
  end
35
40
 
41
+ def terminology= terminology
42
+ @terminology = terminology
43
+ end
44
+
36
45
  def template_registry
37
46
  @template_registry ||= Nom::XML::TemplateRegistry.new
38
47
  end
@@ -1,5 +1,5 @@
1
1
  module Nom
2
2
  module XML
3
- VERSION = '0.1.2'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
data/nom.gemspec CHANGED
@@ -19,8 +19,6 @@ Gem::Specification.new do |s|
19
19
  s.add_development_dependency "rspec"
20
20
  s.add_development_dependency "rake"
21
21
  s.add_development_dependency "yard"
22
- s.add_development_dependency "redcarpet"
23
-
24
22
  s.files = `git ls-files`.split("\n")
25
23
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
24
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe "Namespaces example" do
4
4
 
5
- let(:file) { File.open(File.join(File.dirname(__FILE__), '..', 'fixtures', 'mods_document.xml'), 'r') }
5
+ let(:file) { File.read(File.join(File.dirname(__FILE__), '..', 'fixtures', 'mods_document.xml')) }
6
6
  let(:xml) { Nokogiri::XML(file) }
7
7
 
8
8
  subject {
@@ -17,7 +17,7 @@ describe "Namespaces example" do
17
17
  t.corporate_authors :path => '//mods:name[@type="corporate"]'
18
18
  t.personal_authors :path => 'mods:name[@type="personal"]' do |n|
19
19
  n.roleTerm :path => 'mods:role/mods:roleTerm', :index_as => [:type_1] do |r|
20
- r.type :path => '@type'
20
+ r._type :path => '@type'
21
21
  end
22
22
 
23
23
  n.name_role_pair :path => '.', :accessor => lambda { |node| node.roleTerm.text + ": " + node.namePart.text }
@@ -32,7 +32,6 @@ describe "Namespaces example" do
32
32
  end
33
33
 
34
34
  xml.nom!
35
-
36
35
  xml
37
36
  }
38
37
 
@@ -67,7 +66,7 @@ describe "Namespaces example" do
67
66
  eric.namePart.text.should == "Alterman, Eric"
68
67
  eric.roleTerm.text.should == "creator"
69
68
 
70
- eric.roleTerm.type.text.should == "text"
69
+ eric.roleTerm._type.text.should == "text"
71
70
  end
72
71
 
73
72
  it "should let you mix and match xpaths and nom accessors" do
@@ -6,8 +6,8 @@ describe "Namespaces example" do
6
6
 
7
7
  subject {
8
8
  xml.set_terminology(:namespaces => { 'html4' => 'http://www.w3.org/TR/html4/', 'furniture' => "http://www.w3schools.com/furniture"}) do |t|
9
- t.table :xmlns => 'html4' do |t|
10
- t.tr do |tr|
9
+ t.table :xmlns => 'html4' do |tb|
10
+ tb.tr do |tr|
11
11
  tr.td
12
12
  end
13
13
  end
@@ -37,6 +37,7 @@ describe "Template Registry example" do
37
37
  }
38
38
 
39
39
  it "should work" do
40
+ pending if defined? JRUBY_VERSION
40
41
  subject.root.add_child(subject.template(:a, 'asdf'))
41
42
  subject.a.should have(2).items
42
43
  end
@@ -1,4 +1,3 @@
1
-
2
1
  <?xml version='1.0' encoding='UTF-8' ?>
3
2
  <mods xmlns:xlink="http://www.w3.org/1999/xlink" version="3.4"
4
3
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.loc.gov/mods/v3"
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.1.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -107,22 +107,6 @@ dependencies:
107
107
  - - ! '>='
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
- - !ruby/object:Gem::Dependency
111
- name: redcarpet
112
- requirement: !ruby/object:Gem::Requirement
113
- none: false
114
- requirements:
115
- - - ! '>='
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
- requirements:
123
- - - ! '>='
124
- - !ruby/object:Gem::Version
125
- version: '0'
126
110
  description: ! ' asdfgh '
127
111
  email: cabeer@stanford.edu
128
112
  executables: []
@@ -131,6 +115,7 @@ extra_rdoc_files:
131
115
  - LICENSE
132
116
  - README.md
133
117
  files:
118
+ - .travis.yml
134
119
  - Gemfile
135
120
  - LICENSE
136
121
  - README.md
@@ -174,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
174
159
  version: '0'
175
160
  segments:
176
161
  - 0
177
- hash: -3641921164440724288
162
+ hash: -597609388430309558
178
163
  required_rubygems_version: !ruby/object:Gem::Requirement
179
164
  none: false
180
165
  requirements:
@@ -183,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
168
  version: '0'
184
169
  segments:
185
170
  - 0
186
- hash: -3641921164440724288
171
+ hash: -597609388430309558
187
172
  requirements: []
188
173
  rubyforge_project:
189
174
  rubygems_version: 1.8.23