nom-xml 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +6 -0
- data/LICENSE +11 -0
- data/README.md +71 -0
- data/Rakefile +34 -0
- data/lib/nom.rb +1 -0
- data/lib/nom/xml.rb +14 -0
- data/lib/nom/xml/decorators.rb +6 -0
- data/lib/nom/xml/decorators/nodeset.rb +10 -0
- data/lib/nom/xml/decorators/terminology.rb +18 -0
- data/lib/nom/xml/nokogiri_extension.rb +84 -0
- data/lib/nom/xml/terminology.rb +129 -0
- data/lib/nom/xml/version.rb +5 -0
- data/nom.gemspec +30 -0
- data/spec/examples/nutrition_example_spec.rb +42 -0
- data/spec/fixtures/nutrition.xml +236 -0
- data/spec/lib/nodeset_decorator_spec.rb +0 -0
- data/spec/lib/nokogiri_extension_spec.rb +26 -0
- data/spec/lib/terminology_decorator_spec.rb +6 -0
- data/spec/lib/terminology_spec.rb +0 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test_spec.rb +80 -0
- metadata +162 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Copyright © 2012 by The Board of Trustees of the Leland Stanford Junior University. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use of this distribution in source and binary forms, with or without modification, are permitted provided that:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice appear in all copies and supporting documentation.
|
6
|
+
|
7
|
+
The name, identifiers, and trademarks of The Board of Trustees of the Leland Stanford Junior University are not used in advertising or publicity without the express prior written permission of The Board of Trustees of the Leland Stanford Junior University.
|
8
|
+
|
9
|
+
Recipients acknowledge that this distribution is made available as a research courtesy, “as is”, potentially with defects, without any obligation on the part of The Board of Trustees of the Leland Stanford Junior University to provide support, services, or repair.
|
10
|
+
|
11
|
+
THE BOARD OF TRUSTEES OF THE LELAND STANFORD JUNIOR UNIVERSITY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE BOARD OF TRUSTEES OF THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# NOM
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/cbeer/nom.png)](http://travis-ci.org/cbeer/nom)
|
4
|
+
|
5
|
+
A library to help you tame sprawling XML schemas
|
6
|
+
|
7
|
+
NOM allows you to define a “terminology” to ease translation between XML and ruby objects – you can query the xml for Nodes or node values without ever writing a line of XPath.
|
8
|
+
|
9
|
+
|
10
|
+
Some Handy Links
|
11
|
+
----------------
|
12
|
+
[API](http://rubydoc.info/github/cbeer/nom) - A reference to NOM's classes
|
13
|
+
[#projecthydra](http://webchat.freenode.net/?channels=#projecthydra) on irc.freenode.net
|
14
|
+
[Project Hydra Google Group](http://groups.google.com/group/hydra-tech) - community mailing list and forum
|
15
|
+
|
16
|
+
An Example
|
17
|
+
---------------
|
18
|
+
|
19
|
+
```xml
|
20
|
+
<?xml version="1.0"?>
|
21
|
+
<!-- from http://www.alistapart.com/d/usingxml/xml_uses_a.html -->
|
22
|
+
<nutrition>
|
23
|
+
<food>
|
24
|
+
<name>Avocado Dip</name>
|
25
|
+
<mfr>Sunnydale</mfr>
|
26
|
+
<serving units="g">29</serving>
|
27
|
+
<calories total="110" fat="100"/>
|
28
|
+
<total-fat>11</total-fat>
|
29
|
+
<saturated-fat>3</saturated-fat>
|
30
|
+
<cholesterol>5</cholesterol>
|
31
|
+
<sodium>210</sodium>
|
32
|
+
<carb>2</carb>
|
33
|
+
<fiber>0</fiber>
|
34
|
+
<protein>1</protein>
|
35
|
+
<vitamins>
|
36
|
+
<a>0</a>
|
37
|
+
<c>0</c>
|
38
|
+
</vitamins>
|
39
|
+
<minerals>
|
40
|
+
<ca>0</ca>
|
41
|
+
<fe>0</fe>
|
42
|
+
</minerals>
|
43
|
+
</food>
|
44
|
+
</nutrition>
|
45
|
+
```
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
doc = Nokogiri::XML my_source_document
|
49
|
+
|
50
|
+
doc.set_terminology do |t|
|
51
|
+
t.name
|
52
|
+
|
53
|
+
t.vitamins do |v|
|
54
|
+
v.a
|
55
|
+
v.c
|
56
|
+
end
|
57
|
+
|
58
|
+
t.minerals do |m|
|
59
|
+
m.calcium :path => 'ca'
|
60
|
+
m.iron :path => 'fe'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
doc.nom!
|
65
|
+
|
66
|
+
doc.name.text == 'Avocado Dip'
|
67
|
+
doc.minerals.calcium.text == '0'
|
68
|
+
```
|
69
|
+
|
70
|
+
|
71
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :ci
|
14
|
+
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
desc "Run specs"
|
17
|
+
RSpec::Core::RakeTask.new do |t|
|
18
|
+
|
19
|
+
if ENV['COVERAGE'] and RUBY_VERSION =~ /^1.8/
|
20
|
+
t.rcov = true
|
21
|
+
t.rcov_opts = %w{--exclude spec\/*,gems\/*,ruby\/* --aggregate coverage.data}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'yard'
|
26
|
+
YARD::Rake::YardocTask.new do |t|
|
27
|
+
t.options = ["--readme", "README.md"]
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Continuous Integration build"
|
31
|
+
task :ci do
|
32
|
+
Rake::Task['spec'].invoke
|
33
|
+
Rake::Task['yard'].invoke
|
34
|
+
end
|
data/lib/nom.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'nom/xml'
|
data/lib/nom/xml.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Nom
|
4
|
+
module XML
|
5
|
+
require 'nom/xml/version'
|
6
|
+
require 'nom/xml/terminology'
|
7
|
+
require 'nom/xml/decorators'
|
8
|
+
|
9
|
+
require 'nom/xml/nokogiri_extension'
|
10
|
+
|
11
|
+
Nokogiri::XML::Document.send(:include, NokogiriExtension)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Nom::XML::Decorators::NodeSet
|
2
|
+
def method_missing sym, *args, &block
|
3
|
+
if self.all? { |node| node.respond_to? sym }
|
4
|
+
result = self.collect { |node| node.send(sym, *args, &block) }.flatten
|
5
|
+
self.class.new(self.document, result) rescue result
|
6
|
+
else
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Nom::XML::Decorators::Terminology
|
2
|
+
def self.extended klass
|
3
|
+
|
4
|
+
klass.add_terminology_methods!
|
5
|
+
end
|
6
|
+
|
7
|
+
def terms
|
8
|
+
@terms ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def terms= terms
|
12
|
+
@terms = terms
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_terminology_methods!
|
16
|
+
document.add_terminology_methods(self)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Nom::XML
|
2
|
+
module NokogiriExtension
|
3
|
+
|
4
|
+
def nom!
|
5
|
+
unless decorators(Nokogiri::XML::Node).include? Nom::XML::Decorators::Terminology
|
6
|
+
decorators(Nokogiri::XML::Node) << Nom::XML::Decorators::Terminology
|
7
|
+
decorate!
|
8
|
+
end
|
9
|
+
|
10
|
+
unless decorators(Nokogiri::XML::NodeSet).include? Nom::XML::Decorators::NodeSet
|
11
|
+
decorators(Nokogiri::XML::NodeSet) << Nom::XML::Decorators::NodeSet
|
12
|
+
decorate!
|
13
|
+
end
|
14
|
+
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_terminology &block
|
19
|
+
@terminology = Nom::XML::Terminology.new &block
|
20
|
+
end
|
21
|
+
|
22
|
+
def terminology
|
23
|
+
@terminology ||= Nom::XML::Terminology.new
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Add terminology accessors for querying child terms
|
28
|
+
# @param [Nokogiri::XML::Node] node
|
29
|
+
def add_terminology_methods node
|
30
|
+
if node == node.document.root or node.is_a? Nokogiri::XML::Document
|
31
|
+
node.terms = root_terms(node)
|
32
|
+
elsif not node.parent.terms.empty?
|
33
|
+
node.terms = child_terms(node)
|
34
|
+
end
|
35
|
+
|
36
|
+
node.terms.each do |k, t|
|
37
|
+
(class << node; self; end).send(:define_method, k.to_sym) do
|
38
|
+
if self.is_a? Nokogiri::XML::Document
|
39
|
+
result = self.root.xpath(t.local_xpath)
|
40
|
+
else
|
41
|
+
result = self.xpath(t.local_xpath)
|
42
|
+
end
|
43
|
+
m = t.options[:accessor]
|
44
|
+
case
|
45
|
+
when m.nil?
|
46
|
+
result
|
47
|
+
when m.is_a?(Symbol)
|
48
|
+
result.collect { |r| r.send(m) }
|
49
|
+
when m.is_a?(Proc)
|
50
|
+
result.collect { |r| m.call(r) }
|
51
|
+
else
|
52
|
+
raise "Unknown accessor class: #{m.class}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def root_terms node
|
61
|
+
node.document.terminology.terms
|
62
|
+
end
|
63
|
+
|
64
|
+
def child_terms node
|
65
|
+
h = {}
|
66
|
+
|
67
|
+
terms_for_node(node).each do |k,v|
|
68
|
+
v.terms.each do |k1, v1|
|
69
|
+
h[k1] = v1
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
h
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
#find this node in the terminology
|
78
|
+
def terms_for_node node
|
79
|
+
node.parent.terms.select do |k,term|
|
80
|
+
node.parent.xpath(term.local_xpath).include? node
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,129 @@
|
|
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
|
+
(options[:path] || name).to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing method, *args, &block
|
53
|
+
if in_edit_context?
|
54
|
+
add_term(method, *args, &block)
|
55
|
+
elsif key?(method)
|
56
|
+
term(method)
|
57
|
+
# else if options[:ref]
|
58
|
+
# resolve_ref_and_return_term(method, *args, &block)
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
#terms[method]
|
63
|
+
end
|
64
|
+
|
65
|
+
def key? term
|
66
|
+
terms.key? term
|
67
|
+
end
|
68
|
+
|
69
|
+
def substitute_parent p
|
70
|
+
obj = self.dup
|
71
|
+
|
72
|
+
obj.parent = p
|
73
|
+
obj.clear_parent_cache
|
74
|
+
|
75
|
+
obj
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
def add_term method, options = {}, *args, &block
|
80
|
+
terms[method] = if options[:ref]
|
81
|
+
TermRef.new(self, method, options, *args, &block)
|
82
|
+
else
|
83
|
+
Term.new(self, method, options, *args, &block)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def term method, *args, &block
|
88
|
+
terms[method]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class TermRef < Term
|
93
|
+
def ref
|
94
|
+
elements = Array(options[:ref])
|
95
|
+
|
96
|
+
elements.inject(parent) { |memo, mtd| memo.send(mtd) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def key? term
|
100
|
+
ref.key? term
|
101
|
+
end
|
102
|
+
|
103
|
+
def local_xpath
|
104
|
+
(options[:path] || ref.local_xpath).to_s
|
105
|
+
end
|
106
|
+
|
107
|
+
def method_missing *args, &block
|
108
|
+
if in_edit_context?
|
109
|
+
super
|
110
|
+
else
|
111
|
+
ref.method_missing(*args, &block).substitute_parent(self)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class Terminology < Term
|
117
|
+
def initialize *args, &block
|
118
|
+
@terms = {}
|
119
|
+
in_edit_context do
|
120
|
+
yield(self) if block_given?
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
def xpath
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/nom.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "nom/xml/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "nom-xml"
|
7
|
+
s.version = Nom::XML::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Chris Beer"]
|
10
|
+
s.email = %q{cabeer@stanford.edu}
|
11
|
+
s.homepage = %q{http://github.com/cbeer/nom}
|
12
|
+
s.summary = %q{ asdf }
|
13
|
+
s.description = %q{ asdfgh }
|
14
|
+
|
15
|
+
s.add_dependency 'nokogiri'
|
16
|
+
|
17
|
+
s.add_development_dependency "rspec"
|
18
|
+
s.add_development_dependency "rake"
|
19
|
+
s.add_development_dependency "yard"
|
20
|
+
s.add_development_dependency "redcarpet"
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
s.extra_rdoc_files = [
|
26
|
+
"LICENSE",
|
27
|
+
"README.md"
|
28
|
+
]
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Nutrition" do
|
4
|
+
let(:file) { File.open(File.join(File.dirname(__FILE__), '..', 'fixtures', 'nutrition.xml'), 'r') }
|
5
|
+
let(:xml) { Nokogiri::XML(file) }
|
6
|
+
|
7
|
+
subject {
|
8
|
+
xml.set_terminology do |t|
|
9
|
+
t.daily_values :path => 'daily-values' do |dv|
|
10
|
+
dv.total_fat :path => 'total-fat' do |tf|
|
11
|
+
tf.value :path => '.', :accessor => lambda { |node| node.text.to_i }
|
12
|
+
tf.units :path => '@units'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
t.foods :path => 'food' do |food|
|
17
|
+
food._name :path => 'name'
|
18
|
+
food.mfr
|
19
|
+
|
20
|
+
food.total_fat :path => 'total-fat' do |tf|
|
21
|
+
tf.value :path => '.', :accessor => lambda { |node| node.text.to_i }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
xml.nom!
|
27
|
+
|
28
|
+
xml
|
29
|
+
}
|
30
|
+
|
31
|
+
it "should have total fat information" do
|
32
|
+
subject.daily_values.total_fat.text.should == "65"
|
33
|
+
subject.daily_values.total_fat.value.should include(65)
|
34
|
+
subject.daily_values.total_fat.units.text.should =='g'
|
35
|
+
|
36
|
+
subject.foods.total_fat.value.inject(:+).should == 117
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have food names" do
|
40
|
+
subject.foods._name.text.should include("Avocado Dip")
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<?xml-stylesheet type="text/css" href="nutrition.css"?>
|
3
|
+
<nutrition>
|
4
|
+
<!-- sample from http://www.alistapart.com/d/usingxml/xml_uses_a.html -->
|
5
|
+
|
6
|
+
<daily-values>
|
7
|
+
<total-fat units="g">65</total-fat>
|
8
|
+
<saturated-fat units="g">20</saturated-fat>
|
9
|
+
<cholesterol units="mg">300</cholesterol>
|
10
|
+
<sodium units="mg">2400</sodium>
|
11
|
+
<carb units="g">300</carb>
|
12
|
+
<fiber units="g">25</fiber>
|
13
|
+
<protein units="g">50</protein>
|
14
|
+
</daily-values>
|
15
|
+
|
16
|
+
<food>
|
17
|
+
<name>Avocado Dip</name>
|
18
|
+
<mfr>Sunnydale</mfr>
|
19
|
+
<serving units="g">29</serving>
|
20
|
+
<calories total="110" fat="100"/>
|
21
|
+
<total-fat>11</total-fat>
|
22
|
+
<saturated-fat>3</saturated-fat>
|
23
|
+
<cholesterol>5</cholesterol>
|
24
|
+
<sodium>210</sodium>
|
25
|
+
<carb>2</carb>
|
26
|
+
<fiber>0</fiber>
|
27
|
+
<protein>1</protein>
|
28
|
+
<vitamins>
|
29
|
+
<a>0</a>
|
30
|
+
<c>0</c>
|
31
|
+
</vitamins>
|
32
|
+
<minerals>
|
33
|
+
<ca>0</ca>
|
34
|
+
<fe>0</fe>
|
35
|
+
</minerals>
|
36
|
+
</food>
|
37
|
+
|
38
|
+
<food>
|
39
|
+
<name>Bagels, New York Style </name>
|
40
|
+
<mfr>Thompson</mfr>
|
41
|
+
<serving units="g">104</serving>
|
42
|
+
<calories total="300" fat="35"/>
|
43
|
+
<total-fat>4</total-fat>
|
44
|
+
<saturated-fat>1</saturated-fat>
|
45
|
+
<cholesterol>0</cholesterol>
|
46
|
+
<sodium>510</sodium>
|
47
|
+
<carb>54</carb>
|
48
|
+
<fiber>3</fiber>
|
49
|
+
<protein>11</protein>
|
50
|
+
<vitamins>
|
51
|
+
<a>0</a>
|
52
|
+
<c>0</c>
|
53
|
+
</vitamins>
|
54
|
+
<minerals>
|
55
|
+
<ca>8</ca>
|
56
|
+
<fe>20</fe>
|
57
|
+
</minerals>
|
58
|
+
</food>
|
59
|
+
|
60
|
+
<food>
|
61
|
+
<name>Beef Frankfurter, Quarter Pound </name>
|
62
|
+
<mfr>Armitage</mfr>
|
63
|
+
<serving units="g">115</serving>
|
64
|
+
<calories total="370" fat="290"/>
|
65
|
+
<total-fat>32</total-fat>
|
66
|
+
<saturated-fat>15</saturated-fat>
|
67
|
+
<cholesterol>65</cholesterol>
|
68
|
+
<sodium>1100</sodium>
|
69
|
+
<carb>8</carb>
|
70
|
+
<fiber>0</fiber>
|
71
|
+
<protein>13</protein>
|
72
|
+
<vitamins>
|
73
|
+
<a>0</a>
|
74
|
+
<c>2</c>
|
75
|
+
</vitamins>
|
76
|
+
<minerals>
|
77
|
+
<ca>1</ca>
|
78
|
+
<fe>6</fe>
|
79
|
+
</minerals>
|
80
|
+
</food>
|
81
|
+
|
82
|
+
<food>
|
83
|
+
<name>Chicken Pot Pie</name>
|
84
|
+
<mfr>Lakeson</mfr>
|
85
|
+
<serving units="g">198</serving>
|
86
|
+
<calories total="410" fat="200"/>
|
87
|
+
<total-fat>22</total-fat>
|
88
|
+
<saturated-fat>9</saturated-fat>
|
89
|
+
<cholesterol>25</cholesterol>
|
90
|
+
<sodium>810</sodium>
|
91
|
+
<carb>42</carb>
|
92
|
+
<fiber>2</fiber>
|
93
|
+
<protein>10</protein>
|
94
|
+
<vitamins>
|
95
|
+
<a>20</a>
|
96
|
+
<c>2</c>
|
97
|
+
</vitamins>
|
98
|
+
<minerals>
|
99
|
+
<ca>2</ca>
|
100
|
+
<fe>10</fe>
|
101
|
+
</minerals>
|
102
|
+
</food>
|
103
|
+
|
104
|
+
<food>
|
105
|
+
<name>Cole Slaw</name>
|
106
|
+
<mfr>Fresh Quick</mfr>
|
107
|
+
<serving units=" cup">1.5</serving>
|
108
|
+
<calories total="20" fat="0"/>
|
109
|
+
<total-fat>0</total-fat>
|
110
|
+
<saturated-fat>0</saturated-fat>
|
111
|
+
<cholesterol>0</cholesterol>
|
112
|
+
<sodium>15</sodium>
|
113
|
+
<carb>5</carb>
|
114
|
+
<fiber>2</fiber>
|
115
|
+
<protein>1</protein>
|
116
|
+
<vitamins>
|
117
|
+
<a>30</a>
|
118
|
+
<c>45</c>
|
119
|
+
</vitamins>
|
120
|
+
<minerals>
|
121
|
+
<ca>4</ca>
|
122
|
+
<fe>2</fe>
|
123
|
+
</minerals>
|
124
|
+
</food>
|
125
|
+
|
126
|
+
<food>
|
127
|
+
<name>Eggs</name>
|
128
|
+
<mfr>Goodpath</mfr>
|
129
|
+
<serving units="g">50</serving>
|
130
|
+
<calories total="70" fat="40"/>
|
131
|
+
<total-fat>4.5</total-fat>
|
132
|
+
<saturated-fat>1.5</saturated-fat>
|
133
|
+
<cholesterol>215</cholesterol>
|
134
|
+
<sodium>65</sodium>
|
135
|
+
<carb>1</carb>
|
136
|
+
<fiber>0</fiber>
|
137
|
+
<protein>6</protein>
|
138
|
+
<vitamins>
|
139
|
+
<a>6</a>
|
140
|
+
<c>0</c>
|
141
|
+
</vitamins>
|
142
|
+
<minerals>
|
143
|
+
<ca>2</ca>
|
144
|
+
<fe>4</fe>
|
145
|
+
</minerals>
|
146
|
+
</food>
|
147
|
+
|
148
|
+
<food>
|
149
|
+
<name>Hazelnut Spread</name>
|
150
|
+
<mfr>Ferreira</mfr>
|
151
|
+
<serving units="tbsp">2</serving>
|
152
|
+
<calories total="200" fat="90"/>
|
153
|
+
<total-fat>10</total-fat>
|
154
|
+
<saturated-fat>2</saturated-fat>
|
155
|
+
<cholesterol>0</cholesterol>
|
156
|
+
<sodium>20</sodium>
|
157
|
+
<carb>23</carb>
|
158
|
+
<fiber>2</fiber>
|
159
|
+
<protein>3</protein>
|
160
|
+
<vitamins>
|
161
|
+
<a>0</a>
|
162
|
+
<c>0</c>
|
163
|
+
</vitamins>
|
164
|
+
<minerals>
|
165
|
+
<ca>6</ca>
|
166
|
+
<fe>4</fe>
|
167
|
+
</minerals>
|
168
|
+
</food>
|
169
|
+
|
170
|
+
<food>
|
171
|
+
<name>Potato Chips</name>
|
172
|
+
<mfr>Lees</mfr>
|
173
|
+
<serving units="g">28</serving>
|
174
|
+
<calories total="150" fat="90"/>
|
175
|
+
<total-fat>10</total-fat>
|
176
|
+
<saturated-fat>3</saturated-fat>
|
177
|
+
<cholesterol>0</cholesterol>
|
178
|
+
<sodium>180</sodium>
|
179
|
+
<carb>15</carb>
|
180
|
+
<fiber>1</fiber>
|
181
|
+
<protein>2</protein>
|
182
|
+
<vitamins>
|
183
|
+
<a>0</a>
|
184
|
+
<c>10</c>
|
185
|
+
</vitamins>
|
186
|
+
<minerals>
|
187
|
+
<ca>0</ca>
|
188
|
+
<fe>0</fe>
|
189
|
+
</minerals>
|
190
|
+
</food>
|
191
|
+
|
192
|
+
<food>
|
193
|
+
<name>Soy Patties, Grilled</name>
|
194
|
+
<mfr>Gardenproducts</mfr>
|
195
|
+
<serving units="g">96</serving>
|
196
|
+
<calories total="160" fat="45"/>
|
197
|
+
<total-fat>5</total-fat>
|
198
|
+
<saturated-fat>0</saturated-fat>
|
199
|
+
<cholesterol>0</cholesterol>
|
200
|
+
<sodium>420</sodium>
|
201
|
+
<carb>10</carb>
|
202
|
+
<fiber>4</fiber>
|
203
|
+
<protein>9</protein>
|
204
|
+
<vitamins>
|
205
|
+
<a>0</a>
|
206
|
+
<c>0</c>
|
207
|
+
</vitamins>
|
208
|
+
<minerals>
|
209
|
+
<ca>0</ca>
|
210
|
+
<fe>0</fe>
|
211
|
+
</minerals>
|
212
|
+
</food>
|
213
|
+
|
214
|
+
<food>
|
215
|
+
<name>Truffles, Dark Chocolate</name>
|
216
|
+
<mfr>Lyndon's</mfr>
|
217
|
+
<serving units="g">39</serving>
|
218
|
+
<calories total="220" fat="170"/>
|
219
|
+
<total-fat>19</total-fat>
|
220
|
+
<saturated-fat>14</saturated-fat>
|
221
|
+
<cholesterol>25</cholesterol>
|
222
|
+
<sodium>10</sodium>
|
223
|
+
<carb>16</carb>
|
224
|
+
<fiber>1</fiber>
|
225
|
+
<protein>1</protein>
|
226
|
+
<vitamins>
|
227
|
+
<a>0</a>
|
228
|
+
<c>0</c>
|
229
|
+
</vitamins>
|
230
|
+
<minerals>
|
231
|
+
<ca>0</ca>
|
232
|
+
<fe>0</fe>
|
233
|
+
</minerals>
|
234
|
+
</food>
|
235
|
+
|
236
|
+
</nutrition>
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nom::XML::NokogiriExtension do
|
4
|
+
let(:doc) {
|
5
|
+
Nokogiri::XML(<<-eoxml)
|
6
|
+
<item>
|
7
|
+
<title>foo</title>
|
8
|
+
<description>this is the foo thing</description>
|
9
|
+
<nested>
|
10
|
+
<second_level>value</second_level>
|
11
|
+
|
12
|
+
<further_nesting>
|
13
|
+
<third_level>3rd</third_level>
|
14
|
+
</further_nesting>
|
15
|
+
</nested>
|
16
|
+
</item>
|
17
|
+
eoxml
|
18
|
+
}
|
19
|
+
describe "#add_terminology_methods" do
|
20
|
+
context "root node" do
|
21
|
+
it "should add terminology methods to the root node" do
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
File without changes
|
data/spec/spec_helper.rb
ADDED
data/spec/test_spec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nom::XML do
|
4
|
+
|
5
|
+
it "should do stuff with terminologies" do
|
6
|
+
doc = Nokogiri::XML <<-eos
|
7
|
+
<root>
|
8
|
+
<element_a>a value</element_a>
|
9
|
+
<element_b>
|
10
|
+
<element_c>c value</element_c>
|
11
|
+
</element_b>
|
12
|
+
<element_d>
|
13
|
+
<element_e>
|
14
|
+
<element_f foo="bar">f value</element_f>
|
15
|
+
</element_e>
|
16
|
+
</element_d>
|
17
|
+
<element_g>
|
18
|
+
<element_h>h value 1</element_h>
|
19
|
+
<element_h>h value 2</element_h>
|
20
|
+
</element_g>
|
21
|
+
<element_g>
|
22
|
+
<element_h>h value 3</element_h>
|
23
|
+
</element_g>
|
24
|
+
</root>
|
25
|
+
eos
|
26
|
+
|
27
|
+
doc.set_terminology do |t|
|
28
|
+
t.element_a
|
29
|
+
t.element_b do |n|
|
30
|
+
n.element_c
|
31
|
+
end
|
32
|
+
t.element_d do |n|
|
33
|
+
n.element_e do |e|
|
34
|
+
e.element_f
|
35
|
+
e.foo :path => 'element_f/@foo'
|
36
|
+
e.foo_text :path => 'element_f/@foo', :accessor => :text
|
37
|
+
end
|
38
|
+
end
|
39
|
+
t.element_g do |n|
|
40
|
+
n.element_h :accessor => :text
|
41
|
+
n.whatever :path => "*", :accessor => lambda { |node| [node.name,node.text].join(':') }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
doc.nom!
|
46
|
+
|
47
|
+
doc.root.element_a.text.should == 'a value'
|
48
|
+
doc.root.element_b.element_c.text.should == 'c value'
|
49
|
+
doc.root.element_d.element_e.element_f.text.strip.should == 'f value'
|
50
|
+
doc.root.element_d.element_e.foo.collect(&:text).should == ['bar']
|
51
|
+
doc.root.element_d.element_e.foo_text.should == ['bar']
|
52
|
+
doc.root.element_g.first.element_h.should == ['h value 1','h value 2']
|
53
|
+
doc.root.element_g.element_h.should == ['h value 1','h value 2','h value 3']
|
54
|
+
doc.root.element_g.whatever.should == ['element_h:h value 1','element_h:h value 2','element_h:h value 3']
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe Nom do
|
59
|
+
### High level goals
|
60
|
+
#Given a tree like:
|
61
|
+
# <level1>
|
62
|
+
# <level2 id="parent1">
|
63
|
+
# <level3 id="target1"/>
|
64
|
+
# <level3 id="target1"/>
|
65
|
+
# </level2>
|
66
|
+
# <level2 id="parent2">
|
67
|
+
# <level3 id="target3"/>
|
68
|
+
# </level2>
|
69
|
+
# </level1>
|
70
|
+
|
71
|
+
it "Should be able to query for all the 'level3' nodes (leafs with different parents)"
|
72
|
+
it "Should be able to query for all the 'level3' nodes that are children of parent1 (leafs with same parent)"
|
73
|
+
it "Should be able to query for the nth child of a specific node"
|
74
|
+
it "Should be able to update the inner text of a specific target node"
|
75
|
+
it "Should be able to update the inner texts of a bunch of nodes????? (e.g. find('level2 > level3').innerText=['one', 'two', 'three']"
|
76
|
+
it "Should be able to add a subtree at a specific point in the graph"
|
77
|
+
it "Should be able to remove a subtree from the graph"
|
78
|
+
it "should be able to set the text content of a node to nil"
|
79
|
+
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nom-xml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Beer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: yard
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: redcarpet
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: ! ' asdfgh '
|
95
|
+
email: cabeer@stanford.edu
|
96
|
+
executables: []
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files:
|
99
|
+
- LICENSE
|
100
|
+
- README.md
|
101
|
+
files:
|
102
|
+
- Gemfile
|
103
|
+
- LICENSE
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- lib/nom.rb
|
107
|
+
- lib/nom/xml.rb
|
108
|
+
- lib/nom/xml/decorators.rb
|
109
|
+
- lib/nom/xml/decorators/nodeset.rb
|
110
|
+
- lib/nom/xml/decorators/terminology.rb
|
111
|
+
- lib/nom/xml/nokogiri_extension.rb
|
112
|
+
- lib/nom/xml/terminology.rb
|
113
|
+
- lib/nom/xml/version.rb
|
114
|
+
- nom.gemspec
|
115
|
+
- spec/examples/nutrition_example_spec.rb
|
116
|
+
- spec/fixtures/nutrition.xml
|
117
|
+
- spec/lib/nodeset_decorator_spec.rb
|
118
|
+
- spec/lib/nokogiri_extension_spec.rb
|
119
|
+
- spec/lib/terminology_decorator_spec.rb
|
120
|
+
- spec/lib/terminology_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
122
|
+
- spec/test_spec.rb
|
123
|
+
homepage: http://github.com/cbeer/nom
|
124
|
+
licenses: []
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
segments:
|
136
|
+
- 0
|
137
|
+
hash: 1208570413108466077
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
segments:
|
145
|
+
- 0
|
146
|
+
hash: 1208570413108466077
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 1.8.23
|
150
|
+
signing_key:
|
151
|
+
specification_version: 3
|
152
|
+
summary: asdf
|
153
|
+
test_files:
|
154
|
+
- spec/examples/nutrition_example_spec.rb
|
155
|
+
- spec/fixtures/nutrition.xml
|
156
|
+
- spec/lib/nodeset_decorator_spec.rb
|
157
|
+
- spec/lib/nokogiri_extension_spec.rb
|
158
|
+
- spec/lib/terminology_decorator_spec.rb
|
159
|
+
- spec/lib/terminology_spec.rb
|
160
|
+
- spec/spec_helper.rb
|
161
|
+
- spec/test_spec.rb
|
162
|
+
has_rdoc:
|