dozuki 0.0.1

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.
@@ -0,0 +1,43 @@
1
+ Feature: Getting integers from the document
2
+ In order to provide simpler way of getting integers from a node
3
+ As a traverser
4
+ I want to access nodes using the int method and an xpath
5
+
6
+ Scenario: getting the int of a single node
7
+ When I parse the XML:
8
+ """
9
+ <root>
10
+ <name>St. George's Arms</name>
11
+ <average_price>20.32</average_price>
12
+ <number_of_beers>2</number_of_beers>
13
+ </root>
14
+ """
15
+ And I call "int('/root/number_of_beers')" on the document
16
+ Then the result should be 2
17
+
18
+ Scenario: getting the int of a single node with whitespace
19
+ When I parse the XML:
20
+ """
21
+ <root>
22
+ <name>St. George's Arms</name>
23
+ <average_price>20.32</average_price>
24
+ <number_of_beers>
25
+ 2
26
+ </number_of_beers>
27
+ </root>
28
+ """
29
+ And I call "int('/root/number_of_beers')" on the document
30
+ Then the result should be 2
31
+
32
+ Scenario: getting the int of a non-existent node
33
+ When I parse the XML:
34
+ """
35
+ <root>
36
+ <name>St. George's Arms</name>
37
+ <average_price>20.32</average_price>
38
+ <number_of_beers>2</number_of_beers>
39
+ </root>
40
+ """
41
+ Then calling "int('//something/missing')" on the document should raise a "NotFound" error
42
+ And the error should have the xpath "//something/missing"
43
+ And the error should have a stored node
@@ -0,0 +1,84 @@
1
+ When /^I parse the XML:$/ do |string|
2
+ @doc = Dozuki::XML.parse(string)
3
+ end
4
+
5
+ Then /^the float result should be (\d+\.\d+)$/ do |float|
6
+ @result.should == float.to_f
7
+ end
8
+
9
+ Then /^the error should have the xpath "([^"]*)"$/ do |xpath|
10
+ @error.xpath.should == xpath
11
+ end
12
+
13
+ Then /^the error should have a stored node$/ do
14
+ @error.node.should_not be_nil
15
+ end
16
+
17
+ Then /^calling "([^"]*)" on the document should raise a "([^"]*)" error$/ do |code, error|
18
+ begin
19
+ @doc.instance_eval(code)
20
+ fail "Expected error #{error}, nothing raised"
21
+ rescue Dozuki::XML.const_get(error) => e
22
+ @error = e
23
+ end
24
+ end
25
+
26
+ When /^I call "([^"]*)" on the document$/ do |code|
27
+ @result = @doc.instance_eval(code)
28
+ end
29
+
30
+ When /^I call "([^"]*)" on the document with a block$/ do |code|
31
+ @result = @doc.instance_eval(code + "{|res| res}") # returns the variable passed to the block
32
+ end
33
+
34
+ When /^I call "([^"]*)" on the document and collect the results$/ do |code|
35
+ @results = @doc.instance_eval("results = [];" + code + "{|res| results << res}; results;")
36
+ end
37
+
38
+ Then /^the result should be (\d+)$/ do |int|
39
+ @result.should == int.to_i
40
+ end
41
+
42
+ Then /^the result should be "([^"]*)"$/ do |string|
43
+ @result.should == string
44
+ end
45
+
46
+ Then /^the result should be (\d+\.\d+)$/ do |float|
47
+ @result.should == float.to_f
48
+ end
49
+
50
+ Then /^the (?:result|block parameter) should be a "([^"]*)"$/ do |type|
51
+ @result.class.to_s.should == type
52
+ end
53
+
54
+ Then /^the result should be true$/ do
55
+ @result.should be_true
56
+ end
57
+
58
+ Then /^the result should be false$/ do
59
+ @result.should be_false
60
+ end
61
+
62
+ Then /^the (?:result|parameter) should have (\d+) elements$/ do |count|
63
+ @result.children.select{|e| e.is_a?(Nokogiri::XML::Element)}.count.should == count.to_i
64
+ end
65
+
66
+ Then /^the result should have the (.*) "([^"]*)"$/ do |method, value|
67
+ @result.send(method).should == value
68
+ end
69
+
70
+ Then /^the results should contain a node with the text "([^"]*)"$/ do |text|
71
+ @results.any?{|n| n.text == text}.should be_true
72
+ end
73
+
74
+ Then /^the results should contain "([^"]*)"$/ do |string|
75
+ @results.should include(string)
76
+ end
77
+
78
+ Then /^the results should contain (\d+)$/ do |int|
79
+ @results.should include(int.to_i)
80
+ end
81
+
82
+ Then /^the results should contain (\d+\.\d+)$/ do |float|
83
+ @results.should include(float.to_f)
84
+ end
@@ -0,0 +1,41 @@
1
+ Feature: Getting strings from the document
2
+ In order to provide simpler way of getting strings from a node
3
+ As a traverser
4
+ I want to access nodes using the string method and an xpath
5
+
6
+ Scenario: getting the string of a single node
7
+ When I parse the XML:
8
+ """
9
+ <root>
10
+ <name>St. George's Arms</name>
11
+ <average_cost>20.32</average_cost>
12
+ <number_of_beers>2</number_of_beers>
13
+ </root>
14
+ """
15
+ And I call "string('/root/name')" on the document
16
+ Then the result should be "St. George's Arms"
17
+
18
+ Scenario: getting the text of a single node with whitespace
19
+ When I parse the XML:
20
+ """
21
+ <root>
22
+ <name>St. George's Arms</name>
23
+ <average_cost>20.32</average_cost>
24
+ <number_of_beers>2</number_of_beers>
25
+ </root>
26
+ """
27
+ And I call "string('/root/name')" on the document
28
+ Then the result should be "St. George's Arms"
29
+
30
+ Scenario: getting a non-existent node
31
+ When I parse the XML:
32
+ """
33
+ <root>
34
+ <name>St. George's Arms</name>
35
+ <average_cost>20.32</average_cost>
36
+ <number_of_beers>2</number_of_beers>
37
+ </root>
38
+ """
39
+ Then calling "string('//something/missing')" on the document should raise a "NotFound" error
40
+ And the error should have the xpath "//something/missing"
41
+ And the error should have a stored node
@@ -0,0 +1 @@
1
+ require 'dozuki'
@@ -0,0 +1,3 @@
1
+ require 'nokogiri'
2
+
3
+ require 'dozuki/xml'
@@ -0,0 +1,3 @@
1
+ module Dozuki
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,12 @@
1
+ require 'dozuki/xml/node'
2
+ require 'dozuki/xml/node_collection'
3
+ require 'dozuki/xml/parser'
4
+ require 'dozuki/xml/exceptions'
5
+
6
+ module Dozuki
7
+ module XML
8
+ def self.parse(string)
9
+ Node.new(Nokogiri::XML.parse(string))
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ module Dozuki
2
+ module XML
3
+
4
+ class NotFound < StandardError
5
+ attr_accessor :xpath, :node
6
+
7
+ def initialize(msg=nil, opts={})
8
+ super msg
9
+ self.xpath = opts[:xpath]
10
+ self.node = opts[:node]
11
+ end
12
+
13
+ end
14
+
15
+ class InvalidFormat < StandardError
16
+ attr_accessor :format, :node, :value
17
+
18
+ def initialize(msg=nil, opts={})
19
+ super msg
20
+ self.format = opts[:format]
21
+ self.node = opts[:node]
22
+ self.value = opts[:value]
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ module Dozuki
2
+ module XML
3
+ class Node
4
+ attr_accessor :nokogiri_node
5
+
6
+ def initialize(nokogiri_node)
7
+ self.nokogiri_node = nokogiri_node
8
+ end
9
+
10
+ def method_missing(method, *args, &blk)
11
+ nokogiri_node.send(method, *args, &blk)
12
+ end
13
+
14
+ def respond_to?(method)
15
+ nokogiri_node.respond_to?(method) ? true : super
16
+ end
17
+
18
+ def each(xpath, &blk)
19
+ collection = NodeCollection.new(nokogiri_node.xpath(xpath))
20
+ block_given? ? collection.as_node(&blk) : collection
21
+ end
22
+
23
+ def string(xpath)
24
+ Parser.to_string(get_first_node(xpath))
25
+ end
26
+
27
+ def int(xpath)
28
+ Parser.to_int(get_first_node(xpath))
29
+ end
30
+
31
+ def float(xpath)
32
+ Parser.to_float(get_first_node(xpath))
33
+ end
34
+
35
+ def get(xpath)
36
+ node = Node.new(get_first_node(xpath))
37
+ yield node if block_given?
38
+ node
39
+ end
40
+
41
+ def exists?(xpath)
42
+ !nokogiri_node.xpath(xpath).empty?
43
+ end
44
+
45
+ private
46
+ def get_first_node(xpath)
47
+ node = nokogiri_node.xpath(xpath)
48
+ raise NotFound.new("Node not found", :xpath => xpath, :node => nokogiri_node) if node.empty?
49
+ node.first
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,27 @@
1
+ module Dozuki
2
+ module XML
3
+ class NodeCollection
4
+ attr_accessor :collection
5
+
6
+ def initialize(collection)
7
+ self.collection = collection
8
+ end
9
+
10
+ def as_node(&blk)
11
+ collection.each{|item| blk.call(Node.new(item))}
12
+ end
13
+
14
+ def as_string(&blk)
15
+ collection.each{|item| blk.call(Parser.to_string(item))}
16
+ end
17
+
18
+ def as_int(&blk)
19
+ collection.each{|item| blk.call(Parser.to_int(item))}
20
+ end
21
+
22
+ def as_float(&blk)
23
+ collection.each{|item| blk.call(Parser.to_float(item))}
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Dozuki
2
+ module XML
3
+ module Parser
4
+
5
+ def self.to_string(node)
6
+ node.text.strip
7
+ end
8
+
9
+ def self.to_int(node)
10
+ string = to_string(node)
11
+ raise InvalidFormat.new("Parsing error", :node => node, :value => string, :format => "int") unless string =~ /^-?[0-9]+$/
12
+ string.to_i
13
+ end
14
+
15
+ def self.to_float(node)
16
+ string = to_string(node)
17
+ raise InvalidFormat.new("Parsing error", :node => node, :value => string, :format => "float") unless string =~ /^-?[0-9]+(\.[0-9]+)?$/
18
+ string.to_f
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+ module Dozuki
3
+ module XML
4
+ describe NodeCollection do
5
+
6
+ describe "as_node" do
7
+ let(:collection){mock "some_nodes"}
8
+ let(:blk){Proc.new{}}
9
+ let(:node_collection){NodeCollection.new(collection)}
10
+ let(:collection_item){mock "collection item"}
11
+ let(:new_node){mock "new node"}
12
+ before(:each) do
13
+ collection.stub(:each).and_yield(collection_item)
14
+ Node.stub(:new).and_return(new_node)
15
+ end
16
+
17
+ subject{node_collection.as_node(&blk)}
18
+
19
+ it "should iterate through the collection" do
20
+ collection.should_receive(:each)
21
+ subject
22
+ end
23
+ it "should create a new Node with the yielded collection item" do
24
+ Node.should_receive(:new).with(collection_item)
25
+ subject
26
+ end
27
+ it "should call the bloc with the node" do
28
+ blk.should_receive(:call).with(new_node)
29
+ subject
30
+ end
31
+ end
32
+
33
+ describe "as_string" do
34
+ let(:collection){mock "some_nodes"}
35
+ let(:blk){Proc.new{}}
36
+ let(:node_collection){NodeCollection.new(collection)}
37
+ let(:collection_item){mock "collection item"}
38
+ let(:string){"string"}
39
+ before(:each) do
40
+ collection.stub(:each).and_yield(collection_item)
41
+ Parser.stub(:to_string).and_return(string)
42
+ end
43
+
44
+ subject{node_collection.as_string(&blk)}
45
+
46
+ it "should iterate through the collection" do
47
+ collection.should_receive(:each)
48
+ subject
49
+ end
50
+ it "should create a new Node with the yielded collection item" do
51
+ Parser.should_receive(:to_string).with(collection_item)
52
+ subject
53
+ end
54
+ it "should call the bloc with the node" do
55
+ blk.should_receive(:call).with("string")
56
+ subject
57
+ end
58
+ end
59
+
60
+ describe "as_int" do
61
+ let(:collection){mock "some_nodes"}
62
+ let(:blk){Proc.new{}}
63
+ let(:node_collection){NodeCollection.new(collection)}
64
+ let(:collection_item){mock "collection item"}
65
+ let(:int){39}
66
+ before(:each) do
67
+ collection.stub(:each).and_yield(collection_item)
68
+ Parser.stub(:to_int).and_return(int)
69
+ end
70
+
71
+ subject{node_collection.as_int(&blk)}
72
+
73
+ it "should iterate through the collection" do
74
+ collection.should_receive(:each)
75
+ subject
76
+ end
77
+ it "should create a new Node with the yielded collection item" do
78
+ Parser.should_receive(:to_int).with(collection_item)
79
+ subject
80
+ end
81
+ it "should call the bloc with the node" do
82
+ blk.should_receive(:call).with(int)
83
+ subject
84
+ end
85
+ end
86
+
87
+ describe "as_float" do
88
+ let(:collection){mock "some_nodes"}
89
+ let(:blk){Proc.new{}}
90
+ let(:node_collection){NodeCollection.new(collection)}
91
+ let(:collection_item){mock "collection item"}
92
+ let(:float){39.50}
93
+ before(:each) do
94
+ collection.stub(:each).and_yield(collection_item)
95
+ Parser.stub(:to_float).and_return(float)
96
+ end
97
+
98
+ subject{node_collection.as_float(&blk)}
99
+
100
+ it "should iterate through the collection" do
101
+ collection.should_receive(:each)
102
+ subject
103
+ end
104
+ it "should create a new Node with the yielded collection item" do
105
+ Parser.should_receive(:to_float).with(collection_item)
106
+ subject
107
+ end
108
+ it "should call the bloc with the node" do
109
+ blk.should_receive(:call).with(float)
110
+ subject
111
+ end
112
+ end
113
+
114
+
115
+ end
116
+ end
117
+ end