xmlparsable 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/xmlparsable/elements/array.rb +36 -0
- data/lib/xmlparsable/elements/record.rb +6 -3
- data/lib/xmlparsable/elements.rb +1 -1
- data/lib/xmlparsable.rb +38 -30
- data/spec/examples/accessors.example +89 -0
- data/spec/examples/elements/array.example +110 -0
- data/spec/examples/elements/date.example +44 -0
- data/spec/examples/elements/numeric.example +60 -0
- data/spec/examples/elements/record.example +84 -0
- data/spec/examples/elements/string.example +44 -0
- data/spec/examples/elements/text.example +38 -0
- data/spec/examples/elements/time.example +36 -0
- data/spec/examples/elements/xml.example +1 -0
- data/spec/examples/inheritance.example +100 -124
- metadata +20 -4
- data/lib/xmlparsable/elements/list.rb +0 -31
- data/spec/examples/record.example +0 -260
@@ -0,0 +1,36 @@
|
|
1
|
+
module XmlParsable
|
2
|
+
module Elements
|
3
|
+
|
4
|
+
class ArrayElement < AbstractElement
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
class Array < ::Array
|
8
|
+
attr_reader :xmlattrs
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(name, attributes, parent, arguments)
|
12
|
+
@name, @parent, @elements = name, parent, Array.new
|
13
|
+
|
14
|
+
@item_name = arguments[:item_name].to_s
|
15
|
+
@item_type = arguments[:class]
|
16
|
+
@item_args = arguments[:item]
|
17
|
+
@elements.instance_variable_set(:@xmlattrs, attributes)
|
18
|
+
end
|
19
|
+
|
20
|
+
def open(name, attributes)
|
21
|
+
if name == @item_name
|
22
|
+
@item_type.parsable.new(name, attributes, self, @item_args)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def close(element, value)
|
27
|
+
@elements << value
|
28
|
+
end
|
29
|
+
|
30
|
+
def finalize
|
31
|
+
@parent.close(self, @elements)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -10,10 +10,12 @@ module XmlParsable
|
|
10
10
|
@target = target
|
11
11
|
@parsers = parsers
|
12
12
|
@elements = Hash.new
|
13
|
+
@target.instance_variable_set(:@xmlattrs, @attributes)
|
13
14
|
end
|
14
15
|
|
15
16
|
def open(name, attributes)
|
16
17
|
parser, *arguments = @parsers[name]
|
18
|
+
|
17
19
|
if parser
|
18
20
|
parser.new(name, attributes, self, *arguments)
|
19
21
|
end
|
@@ -21,15 +23,16 @@ module XmlParsable
|
|
21
23
|
|
22
24
|
def close(element, value)
|
23
25
|
parser, *arguments = @parsers[element.name]
|
26
|
+
|
24
27
|
if arguments.include?(:repeated)
|
25
|
-
(@elements[element.name] ||= []) << value
|
28
|
+
(@elements[element.name.to_sym] ||= []) << value
|
26
29
|
else
|
27
|
-
@elements[element.name] = value
|
30
|
+
@elements[element.name.to_sym] = value
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
34
|
def finalize
|
32
|
-
@
|
35
|
+
@target.instance_variable_set(:@xmlelems, @elements)
|
33
36
|
@parent.close(self, @target) if @parent
|
34
37
|
end
|
35
38
|
|
data/lib/xmlparsable/elements.rb
CHANGED
@@ -2,7 +2,7 @@ module XmlParsable
|
|
2
2
|
module Elements
|
3
3
|
autoload :AbstractElement, "xmlparsable/elements/abstract"
|
4
4
|
autoload :DateElement, "xmlparsable/elements/date"
|
5
|
-
autoload :
|
5
|
+
autoload :ArrayElement, "xmlparsable/elements/array"
|
6
6
|
autoload :NumericElement, "xmlparsable/elements/numeric"
|
7
7
|
autoload :RecordElement, "xmlparsable/elements/record"
|
8
8
|
autoload :StringElement, "xmlparsable/elements/string"
|
data/lib/xmlparsable.rb
CHANGED
@@ -20,50 +20,58 @@ module XmlParsable
|
|
20
20
|
end
|
21
21
|
|
22
22
|
module ClassMethods
|
23
|
-
def element(name, *arguments)
|
24
|
-
element ||= arguments.pop.delete(:class) if arguments.last.is_a?(Hash)
|
25
|
-
element ||= arguments.shift if arguments.first.is_a?(Class)
|
26
|
-
element ||= Elements::StringElement
|
27
23
|
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
# element :name, StringElement, {options...}
|
25
|
+
# element :name, {:class => StringElement, options...}
|
26
|
+
def element(elem_name, *extras)
|
27
|
+
arguments = extras.pop if extras.last.is_a?(Hash)
|
28
|
+
arguments ||= Hash.new
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
def repeated(name, *arguments)
|
39
|
-
element ||= arguments.pop.delete(:class) if arguments.last.is_a?(Hash)
|
40
|
-
element ||= arguments.shift if arguments.first.is_a?(Class)
|
41
|
-
element ||= Elements::StringElement
|
30
|
+
elem_type = extras.shift if extras.first.is_a?(Class)
|
31
|
+
elem_type ||= arguments.delete(:class)
|
32
|
+
elem_type ||= Elements::StringElement
|
33
|
+
raise ArgumentError, "extra arguments" unless extras.empty?
|
42
34
|
|
43
35
|
# Look up the inheritance hierarchy to map element name to parser
|
44
36
|
parent = superclass < XmlParsable ?
|
45
37
|
superclass.instance_variable_get(:@parsers) : Hash.new
|
46
38
|
|
47
39
|
@parsers ||= Hash.new{|h,k| parent[k] }
|
48
|
-
@parsers[
|
40
|
+
@parsers[elem_name.to_s] = [elem_type.parsable, arguments]
|
41
|
+
|
42
|
+
# Define accessor method (or don't, see if I care!)
|
43
|
+
attr_name = arguments.fetch(:accessor, elem_name)
|
49
44
|
|
50
|
-
|
45
|
+
if attr_name and not method_defined?(attr_name)
|
46
|
+
define_method(attr_name) { instance_variable_get(:@xmlelems)[elem_name] }
|
47
|
+
end
|
51
48
|
end
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
50
|
+
# collection :hive, BeeElement, {:item_name => :bee, array-options..., :item => {item-options...}}
|
51
|
+
# collection :hive, :bee, BeeElement, {array-options..., :item => {item-options...}}
|
52
|
+
# collection :hive, {array-options..., :item => {:class => BeeElement, item-options...}}
|
53
|
+
def collection(elem_name, *extras)
|
54
|
+
arguments = extras.pop if extras.last.is_a?(Hash)
|
55
|
+
arguments ||= Hash.new
|
56
|
+
|
57
|
+
arguments[:item] ||= Hash.new
|
58
|
+
arguments[:item_name] ||= extras.shift unless extras.first.is_a?(Class)
|
59
|
+
arguments[:item_name] ||= elem_name.to_s.singularize
|
60
|
+
arguments[:class] ||= extras.shift if extras.first.is_a?(Class)
|
61
|
+
arguments[:class] ||= Elements::StringElement
|
62
|
+
raise ArgumentError, "extra arguments" unless extras.empty?
|
63
|
+
|
64
|
+
element(elem_name, Elements::ArrayElement, arguments)
|
65
|
+
end
|
57
66
|
|
58
|
-
|
59
|
-
|
60
|
-
|
67
|
+
def repeated(elem_name, *extras)
|
68
|
+
if extras.last.is_a?(Hash)
|
69
|
+
extras.last[:repeated] = true
|
70
|
+
element(elem_name, *extras)
|
61
71
|
else
|
62
|
-
|
63
|
-
|
72
|
+
extras.push(Hash[:repeated => true])
|
73
|
+
element(elem_name, *extras)
|
64
74
|
end
|
65
|
-
|
66
|
-
element(plural, Elements::ListElement, single, item)
|
67
75
|
end
|
68
76
|
|
69
77
|
def parse(input)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable, "accessors" do
|
4
|
+
|
5
|
+
let(:input) do
|
6
|
+
<<-XML
|
7
|
+
<root lang="en" charset="utf-8">
|
8
|
+
<size>500</size>
|
9
|
+
<wise>none</wise>
|
10
|
+
<secret>Ovaltine</secret>
|
11
|
+
</root>
|
12
|
+
XML
|
13
|
+
end
|
14
|
+
|
15
|
+
context "default" do
|
16
|
+
let(:parser) do
|
17
|
+
Class.new do
|
18
|
+
class Inner
|
19
|
+
attr_reader :xmlattrs
|
20
|
+
attr_reader :xmlelems
|
21
|
+
|
22
|
+
include XmlParsable
|
23
|
+
element :size
|
24
|
+
element :wise
|
25
|
+
end
|
26
|
+
|
27
|
+
include XmlParsable
|
28
|
+
element :root, Inner
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "stores attributes in `xmlattrs`" do
|
33
|
+
xml = parser.parse(input)
|
34
|
+
xml.root.xmlattrs.should == Hash["lang" => "en", "charset" => "utf-8"]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "stores elements in `xmlelems`" do
|
38
|
+
xml = parser.parse(input)
|
39
|
+
xml.root.xmlelems[:size] = "500"
|
40
|
+
xml.root.xmlelems[:wise] = "none"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "creates accessors for elements" do
|
44
|
+
xml = parser.parse(input)
|
45
|
+
xml.root.xmlelems[:size].should eql(xml.root.size)
|
46
|
+
xml.root.xmlelems[:wise].should eql(xml.root.wise)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "overridden" do
|
51
|
+
let(:parser) do
|
52
|
+
Class.new do
|
53
|
+
class Inner
|
54
|
+
attr_reader :xmlelems
|
55
|
+
|
56
|
+
def size
|
57
|
+
"junk junk"
|
58
|
+
end
|
59
|
+
|
60
|
+
include XmlParsable
|
61
|
+
element :size
|
62
|
+
element :wise, accessor: :wisdom
|
63
|
+
element :secret, accessor: false
|
64
|
+
end
|
65
|
+
|
66
|
+
include XmlParsable
|
67
|
+
element :root, Inner
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "stores elements in `xmlelems`" do
|
72
|
+
xml = parser.parse(input)
|
73
|
+
xml.root.xmlelems[:size] == "500"
|
74
|
+
xml.root.xmlelems[:wise] == "none"
|
75
|
+
xml.root.xmlelems[:secret] == "Ovaltine"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "doesn't create accessors for hidden elements" do
|
79
|
+
xml = parser.parse(input)
|
80
|
+
xml.root.should_not respond_to(:secret)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "creates accessors for renamed elements" do
|
84
|
+
xml = parser.parse(input)
|
85
|
+
xml.root.xmlelems[:wise].should eql(xml.root.wisdom)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable::Elements::ArrayElement do
|
4
|
+
|
5
|
+
describe "declaration" do
|
6
|
+
|
7
|
+
it "fully specified" do
|
8
|
+
parser = Class.new do
|
9
|
+
sheep = Class.new do
|
10
|
+
include XmlParsable
|
11
|
+
element :name
|
12
|
+
element :bahh
|
13
|
+
end
|
14
|
+
|
15
|
+
include XmlParsable
|
16
|
+
collection :flock, :sheep, sheep
|
17
|
+
end
|
18
|
+
|
19
|
+
xml = parser.parse(<<-XML)
|
20
|
+
<flock>
|
21
|
+
<sheep><bahh>H*</bahh></sheep>
|
22
|
+
<sheep><bahh>HH</bahh></sheep>
|
23
|
+
<sheep><bahh>*H</bahh></sheep>
|
24
|
+
</flock>
|
25
|
+
XML
|
26
|
+
|
27
|
+
xml.flock[0].bahh.should == "H*"
|
28
|
+
xml.flock[1].bahh.should == "HH"
|
29
|
+
xml.flock[2].bahh.should == "*H"
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "default child type is StringElement" do
|
33
|
+
parser = Class.new do
|
34
|
+
include XmlParsable
|
35
|
+
collection :contacts, :name
|
36
|
+
end
|
37
|
+
|
38
|
+
xml = parser.parse("<contacts><name>Green</name><name>White</name></contacts>")
|
39
|
+
xml.contacts.should == %w(Green White)
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "default child name is singular collection name" do
|
43
|
+
parser = Class.new do
|
44
|
+
include XmlParsable
|
45
|
+
collection :bees, XmlParsable::Elements::NumericElement
|
46
|
+
end
|
47
|
+
|
48
|
+
xml = parser.parse("<bees><bee>1000</bee><bee>1001</bee></bees>")
|
49
|
+
xml.bees.should == [1000, 1001]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "parser" do
|
54
|
+
let(:parser) do
|
55
|
+
Class.new do
|
56
|
+
include XmlParsable
|
57
|
+
collection :list, :item
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "parses empty list into an empty Array" do
|
62
|
+
input = "<list/>"
|
63
|
+
expected = []
|
64
|
+
|
65
|
+
parser.parse(input).list.should == expected
|
66
|
+
end
|
67
|
+
|
68
|
+
it "parses attributes" do
|
69
|
+
input = '<list thang="yarn" milk="yawn"/>'
|
70
|
+
expected = Hash["thang" => "yarn", "milk" => "yawn"]
|
71
|
+
|
72
|
+
parser.parse(input).list.xmlattrs.should == expected
|
73
|
+
end
|
74
|
+
|
75
|
+
it "parses non-empty list into an Array" do
|
76
|
+
input = "<list><item>a</item><item>b</item></list>"
|
77
|
+
expected = ["a", "b"]
|
78
|
+
|
79
|
+
parser.parse(input).list.should == expected
|
80
|
+
end
|
81
|
+
|
82
|
+
it "ignores non-matching children" do
|
83
|
+
input = "<list><fail/><item/><boat/><item/><item/></list>"
|
84
|
+
expected = ["", "", ""]
|
85
|
+
|
86
|
+
parser.parse(input).list.should == expected
|
87
|
+
end
|
88
|
+
|
89
|
+
it "ignores comments" do
|
90
|
+
input = "<list><!-- <item>x</item> --><item><!-- y --></item></list>"
|
91
|
+
expected = [""]
|
92
|
+
|
93
|
+
parser.parse(input).list.should == expected
|
94
|
+
end
|
95
|
+
|
96
|
+
it "ignores whitespace between children" do
|
97
|
+
input = <<-XML
|
98
|
+
<list>
|
99
|
+
<item>a</item>
|
100
|
+
<item>b</item>
|
101
|
+
<item>c</item>
|
102
|
+
</list>
|
103
|
+
XML
|
104
|
+
|
105
|
+
expected = ["a", "b", "c"]
|
106
|
+
parser.parse(input).list.should == expected
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable::Elements::DateElement do
|
4
|
+
|
5
|
+
describe "parser" do
|
6
|
+
let(:parser) do
|
7
|
+
Class.new do
|
8
|
+
include XmlParsable
|
9
|
+
element :date, XmlParsable::Elements::DateElement
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "parses date into a ruby Date" do
|
14
|
+
expected = Date.today
|
15
|
+
input = "<date>#{expected}</date>"
|
16
|
+
parser.parse(input).date.should == expected
|
17
|
+
end
|
18
|
+
|
19
|
+
it "parses missing date as nil" do
|
20
|
+
expected = nil
|
21
|
+
input = "<date><!-- nope --></date>"
|
22
|
+
parser.parse(input).date.should == expected
|
23
|
+
end
|
24
|
+
|
25
|
+
it "ignores children" do
|
26
|
+
expected = nil
|
27
|
+
input = "<date><x>2010-01-01</x></date>"
|
28
|
+
parser.parse(input).date.should == expected
|
29
|
+
end
|
30
|
+
|
31
|
+
it "ignores comments" do
|
32
|
+
expected = Date.today
|
33
|
+
input = "<date>#{expected} <!-- that's today --></date>"
|
34
|
+
parser.parse(input).date.should == expected
|
35
|
+
end
|
36
|
+
|
37
|
+
it "ignores whitespace" do
|
38
|
+
expected = Date.today
|
39
|
+
input = "<date>\n #{Date.today}\n </date>"
|
40
|
+
parser.parse(input).date.should == expected
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable::Elements::StringElement do
|
4
|
+
|
5
|
+
describe "parser" do
|
6
|
+
let(:parser) do
|
7
|
+
Class.new do
|
8
|
+
include XmlParsable
|
9
|
+
element :number, XmlParsable::Elements::NumericElement
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "parses integers" do
|
14
|
+
expected = rand(1_000)
|
15
|
+
input = "<number>#{expected}</number>"
|
16
|
+
parser.parse(input).number.should == expected
|
17
|
+
end
|
18
|
+
|
19
|
+
it "parses hexadecimal" do
|
20
|
+
expected = rand(1_000)
|
21
|
+
input = "<number>0x#{expected.to_s(16)}</number>"
|
22
|
+
parser.parse(input).number.should == expected
|
23
|
+
end
|
24
|
+
|
25
|
+
it "parser octal" do
|
26
|
+
expected = rand(1_000)
|
27
|
+
input = "<number>0#{expected.to_s(8)}</number>"
|
28
|
+
parser.parse(input).number.should == expected
|
29
|
+
end
|
30
|
+
|
31
|
+
it "parses binary" do
|
32
|
+
expected = rand(1_000)
|
33
|
+
input = "<number>0b#{expected.to_s(2)}</number>"
|
34
|
+
parser.parse(input).number.should == expected
|
35
|
+
end
|
36
|
+
|
37
|
+
it "parses rationals" do
|
38
|
+
expected = rand(1_000) + rand
|
39
|
+
input = "<number>#{expected}</number>"
|
40
|
+
parser.parse(input).number.should == BigDecimal(expected.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "ignores comments" do
|
44
|
+
input = "<time><!-- 65432 --></time>"
|
45
|
+
parser.parse(input).number.should be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "ignores children" do
|
49
|
+
input = "<time><b>#{rand}</b></time>"
|
50
|
+
parser.parse(input).number.should be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it "ignores whitespace" do
|
54
|
+
expected = rand(1_000)
|
55
|
+
input = "<number> #{expected} </number>"
|
56
|
+
parser.parse(input).number.should == expected
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable::Elements::RecordElement do
|
4
|
+
|
5
|
+
let(:parser) do
|
6
|
+
Class.new do
|
7
|
+
include XmlParsable
|
8
|
+
|
9
|
+
element :date, XmlParsable::Elements::DateElement
|
10
|
+
element :string, XmlParsable::Elements::StringElement
|
11
|
+
element :text, XmlParsable::Elements::TextElement
|
12
|
+
element :time, XmlParsable::Elements::TimeElement
|
13
|
+
element :xml, XmlParsable::Elements::XmlElement
|
14
|
+
element :number, XmlParsable::Elements::NumericElement
|
15
|
+
element :record, self
|
16
|
+
|
17
|
+
collection :kids, self
|
18
|
+
collection :list, :item
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "parser" do
|
23
|
+
it "parses multiple elements" do
|
24
|
+
time = Time.now
|
25
|
+
date = Date.today
|
26
|
+
|
27
|
+
xml = parser.parse <<-XML
|
28
|
+
<record>
|
29
|
+
<date>#{date}</date>
|
30
|
+
<time>#{time}</time>
|
31
|
+
<list>
|
32
|
+
<item>a</item>
|
33
|
+
<item>b</item>
|
34
|
+
<item>c</item>
|
35
|
+
</list>
|
36
|
+
<string>xyz</string>
|
37
|
+
<number>888</number>
|
38
|
+
<text>
|
39
|
+
<ul>
|
40
|
+
<li>vim</li>
|
41
|
+
<li>emacs</li>
|
42
|
+
<li>ctags</li>
|
43
|
+
<li>lint</li>
|
44
|
+
<li>gdb</li>
|
45
|
+
</ul>
|
46
|
+
</text>
|
47
|
+
</record>
|
48
|
+
XML
|
49
|
+
|
50
|
+
xml.record.list.should == ["a","b","c"]
|
51
|
+
xml.record.string.should == "xyz"
|
52
|
+
xml.record.number.should == 888
|
53
|
+
xml.record.date.should == date
|
54
|
+
xml.record.time.to_i.should == time.to_i
|
55
|
+
xml.record.text.strip.should == <<-DOC.strip
|
56
|
+
vim
|
57
|
+
emacs
|
58
|
+
ctags
|
59
|
+
lint
|
60
|
+
gdb
|
61
|
+
DOC
|
62
|
+
end
|
63
|
+
|
64
|
+
it "parses recursive records" do
|
65
|
+
xml = parser.parse(<<-XML)
|
66
|
+
<record>
|
67
|
+
<string>root</string>
|
68
|
+
<record>
|
69
|
+
<string>child</string>
|
70
|
+
<record>
|
71
|
+
<string>grand child</string>
|
72
|
+
</record>
|
73
|
+
</record>
|
74
|
+
</record>
|
75
|
+
XML
|
76
|
+
|
77
|
+
xml.string.should be_nil
|
78
|
+
xml.record.string.should == "root"
|
79
|
+
xml.record.record.string.should == "child"
|
80
|
+
xml.record.record.record.string.should == "grand child"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable::Elements::StringElement do
|
4
|
+
|
5
|
+
describe "parser" do
|
6
|
+
let(:parser) do
|
7
|
+
Class.new do
|
8
|
+
include XmlParsable
|
9
|
+
element :string, XmlParsable::Elements::StringElement
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "parses empty string" do
|
14
|
+
expected = ""
|
15
|
+
input = "<string></string>"
|
16
|
+
parser.parse(input).string.should == expected
|
17
|
+
end
|
18
|
+
|
19
|
+
it "parses non-empty string" do
|
20
|
+
expected = "lo and behold"
|
21
|
+
input = "<string>lo and behold</string>"
|
22
|
+
parser.parse(input).string.should == expected
|
23
|
+
end
|
24
|
+
|
25
|
+
it "ignores comments" do
|
26
|
+
expected = "hi"
|
27
|
+
input = "<string>hi<!-- secret message --></string>"
|
28
|
+
parser.parse(input).string.should == expected
|
29
|
+
end
|
30
|
+
|
31
|
+
it "ignores children" do
|
32
|
+
expected = ", , plain"
|
33
|
+
input = "<string><b>bold</b>, <i>italic</i>, plain</string>"
|
34
|
+
parser.parse(input).string.should == expected
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not ignore whitespace" do
|
38
|
+
expected = " foob ar"
|
39
|
+
input = "<string> foob ar</string>"
|
40
|
+
parser.parse(input).string.should == expected
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable::Elements::StringElement do
|
4
|
+
|
5
|
+
describe "parser" do
|
6
|
+
let(:parser) do
|
7
|
+
Class.new do
|
8
|
+
include XmlParsable
|
9
|
+
element :text, XmlParsable::Elements::TextElement
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "parses text" do
|
14
|
+
expected = "lo and behold"
|
15
|
+
input = "<text>lo and behold</text>"
|
16
|
+
parser.parse(input).text.should == expected
|
17
|
+
end
|
18
|
+
|
19
|
+
it "ignores comments" do
|
20
|
+
expected = "lo behold"
|
21
|
+
input = "<text>lo <!--and--> behold</text>"
|
22
|
+
parser.parse(input).text.should == expected
|
23
|
+
end
|
24
|
+
|
25
|
+
it "strips away markup" do
|
26
|
+
expected = "lo and behold"
|
27
|
+
input = "<text>lo <span class='x'><i>and</i> behold</span></text>"
|
28
|
+
parser.parse(input).text.should == expected
|
29
|
+
end
|
30
|
+
|
31
|
+
it "does not ignore whitespace" do
|
32
|
+
expected = " foob ar"
|
33
|
+
input = "<text> foob ar</text>"
|
34
|
+
parser.parse(input).text.should == expected
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe XmlParsable::Elements::StringElement do
|
4
|
+
|
5
|
+
describe "parser" do
|
6
|
+
let(:parser) do
|
7
|
+
Class.new do
|
8
|
+
include XmlParsable
|
9
|
+
element :time, XmlParsable::Elements::TimeElement
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "parses time" do
|
14
|
+
expected = Time.now
|
15
|
+
input = "<time>#{expected}</time>"
|
16
|
+
parser.parse(input).time.to_i.should == expected.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
it "ignores comments" do
|
20
|
+
input = "<time><!-- #{Time.now} --></time>"
|
21
|
+
parser.parse(input).time.should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "ignores children" do
|
25
|
+
input = "<time><b>#{Time.now}</b></time>"
|
26
|
+
parser.parse(input).time.should be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "ignores whitespace" do
|
30
|
+
expected = Time.now
|
31
|
+
input = "<time> #{expected} </time>"
|
32
|
+
parser.parse(input).time.to_i.should == expected.to_i
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "spec_helper"
|
@@ -1,154 +1,130 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe XmlParsable
|
3
|
+
describe XmlParsable, "inheritance" do
|
4
|
+
|
5
|
+
let(:input) do
|
6
|
+
<<-XML
|
7
|
+
<root>
|
8
|
+
<!-- This is parsed as a Date, Integer, or String -->
|
9
|
+
<id>20120531</id>
|
10
|
+
<inherited>11235</inherited>
|
11
|
+
|
12
|
+
<a>some a-data</a>
|
13
|
+
<b>some b-data</b>
|
14
|
+
<c>
|
15
|
+
<id>IDENTIFIER</id>
|
16
|
+
<inherited></inherited>
|
17
|
+
</c>
|
18
|
+
</root>
|
19
|
+
XML
|
20
|
+
end
|
4
21
|
|
5
|
-
|
6
|
-
|
22
|
+
let(:common) do
|
23
|
+
Class.new do
|
24
|
+
attr_reader :xmlelems
|
7
25
|
|
8
|
-
class Record
|
9
26
|
include XmlParsable
|
10
|
-
element :id
|
11
|
-
element :
|
27
|
+
element :id
|
28
|
+
element :inherited, XmlParsable::Elements::NumericElement
|
12
29
|
end
|
13
|
-
|
14
|
-
element :record, Record
|
15
30
|
end
|
16
31
|
|
17
|
-
|
18
|
-
|
32
|
+
let(:base) do
|
33
|
+
root = common
|
34
|
+
Class.new do
|
35
|
+
include XmlParsable
|
36
|
+
element :root, root
|
37
|
+
end
|
38
|
+
end
|
19
39
|
|
20
|
-
|
21
|
-
|
22
|
-
|
40
|
+
# Override the parent's id element
|
41
|
+
let(:a) do
|
42
|
+
parent = common
|
43
|
+
Class.new do
|
44
|
+
inner = Class.new(parent) do
|
45
|
+
element :id, XmlParsable::Elements::TimeElement
|
46
|
+
element :a
|
47
|
+
end
|
48
|
+
include XmlParsable
|
49
|
+
element :root, inner
|
23
50
|
end
|
51
|
+
end
|
24
52
|
|
25
|
-
|
53
|
+
# Override the parent's id element
|
54
|
+
let(:b) do
|
55
|
+
parent = common
|
56
|
+
Class.new do
|
57
|
+
inner = Class.new(parent) do
|
58
|
+
element :id, XmlParsable::Elements::NumericElement
|
59
|
+
element :b
|
60
|
+
end
|
61
|
+
include XmlParsable
|
62
|
+
element :root, inner
|
63
|
+
end
|
26
64
|
end
|
27
65
|
|
28
|
-
|
29
|
-
|
66
|
+
let(:c) do
|
67
|
+
parent = common
|
30
68
|
|
31
|
-
|
32
|
-
|
33
|
-
|
69
|
+
Class.new do
|
70
|
+
inner = Class.new(parent) do
|
71
|
+
element :c, self
|
72
|
+
end
|
34
73
|
|
35
|
-
|
74
|
+
include XmlParsable
|
75
|
+
element :root, inner
|
76
|
+
end
|
36
77
|
end
|
37
78
|
|
38
|
-
|
39
|
-
|
79
|
+
describe "base parser" do
|
80
|
+
it "is separate from derived parsers" do
|
81
|
+
xml = base.parse(input)
|
82
|
+
xml.root.id.should == "20120531"
|
83
|
+
xml.root.inherited.should == 11235
|
40
84
|
|
41
|
-
|
42
|
-
|
43
|
-
|
85
|
+
xml.root.xmlelems.should_not have_key(:a)
|
86
|
+
xml.root.xmlelems.should_not have_key(:b)
|
87
|
+
xml.root.xmlelems.should_not have_key(:c)
|
44
88
|
|
45
|
-
|
89
|
+
xml.root.should_not respond_to(:a)
|
90
|
+
xml.root.should_not respond_to(:b)
|
91
|
+
xml.root.should_not respond_to(:c)
|
92
|
+
end
|
46
93
|
end
|
47
94
|
|
48
|
-
describe "
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
specify { should_not respond_to(:parent) }
|
54
|
-
|
55
|
-
it "parses attributes" do
|
56
|
-
data = BaseRecord.parse(<<-XML.strip)
|
57
|
-
<record>
|
58
|
-
<id>0xCAFE</id>
|
59
|
-
<size>0xFE</size>
|
60
|
-
</record>
|
61
|
-
XML
|
62
|
-
|
63
|
-
data.record.should be_a(BaseRecord::Record)
|
64
|
-
data.record.id.should == "0xCAFE"
|
65
|
-
data.record.size.should == 0xFE
|
95
|
+
describe "derived parsers" do
|
96
|
+
it "inherit elements from base parser" do
|
97
|
+
a.parse(input).root.inherited.should == 11235
|
98
|
+
b.parse(input).root.inherited.should == 11235
|
99
|
+
c.parse(input).root.inherited.should == 11235
|
66
100
|
end
|
67
|
-
end
|
68
101
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
it "parses attributes" do
|
77
|
-
data = FirstRecord.parse(<<-XML.strip)
|
78
|
-
<record>
|
79
|
-
<id>20120530T154500</id>
|
80
|
-
<size>0xCA7</size>
|
81
|
-
<name>Sabji</name>
|
82
|
-
</record>
|
83
|
-
XML
|
84
|
-
|
85
|
-
data.record.should be_a(FirstRecord::Record)
|
86
|
-
data.record.id.should == Time.local(2012, 5, 30, 15, 45)
|
87
|
-
data.record.size.should == 0xCA7
|
88
|
-
data.record.name.should == "Sabji"
|
102
|
+
it "can specify additional elements" do
|
103
|
+
a.parse(input).root.a.should == "some a-data"
|
104
|
+
b.parse(input).root.b.should == "some b-data"
|
105
|
+
|
106
|
+
c.parse(input).root.c.should_not be_nil
|
107
|
+
c.parse(input).root.c.id.should == "IDENTIFIER"
|
108
|
+
c.parse(input).root.c.inherited.should be_nil
|
89
109
|
end
|
90
|
-
end
|
91
110
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
specify { should respond_to(:size) }
|
96
|
-
specify { should_not respond_to(:name) }
|
97
|
-
specify { should_not respond_to(:parent) }
|
98
|
-
|
99
|
-
it "parses attributes" do
|
100
|
-
data = SecondRecord.parse(<<-XML)
|
101
|
-
<record>
|
102
|
-
<id>0.314</id>
|
103
|
-
<size>3.014</size>
|
104
|
-
</record>
|
105
|
-
XML
|
106
|
-
|
107
|
-
data.record.should be_a(SecondRecord::Record)
|
108
|
-
data.record.id.should == 0.314
|
109
|
-
data.record.size.should == 3.014
|
111
|
+
it "can override an inherited element" do
|
112
|
+
a.parse(input).root.id.should be_a(Time)
|
113
|
+
b.parse(input).root.id.should be_a(Integer)
|
110
114
|
end
|
111
|
-
end
|
112
115
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
<parent>
|
126
|
-
<id>X039-P99-THX1138</id>
|
127
|
-
<size>112358</size>
|
128
|
-
<parent>
|
129
|
-
<id>X039-P99</id>
|
130
|
-
<size>11235</size>
|
131
|
-
<parent>
|
132
|
-
<id>X039</id>
|
133
|
-
<size>1123</size>
|
134
|
-
</parent>
|
135
|
-
</parent>
|
136
|
-
</parent>
|
137
|
-
</record>
|
138
|
-
XML
|
139
|
-
|
140
|
-
data.record.should be_a(ThirdRecord::Record)
|
141
|
-
data.record.id.should == "X039-P99-THX1138-U"
|
142
|
-
data.record.size.should == 11235813
|
143
|
-
|
144
|
-
data.record.parent.id.should == "X039-P99-THX1138"
|
145
|
-
data.record.parent.size.should == 112358
|
146
|
-
|
147
|
-
data.record.parent.parent.id.should == "X039-P99"
|
148
|
-
data.record.parent.parent.size.should == 11235
|
149
|
-
|
150
|
-
data.record.parent.parent.parent.id.should == "X039"
|
151
|
-
data.record.parent.parent.parent.size.should == 1123
|
116
|
+
specify "are independent from one another" do
|
117
|
+
xml = a.parse(input).root
|
118
|
+
xml.should_not respond_to(:b)
|
119
|
+
xml.should_not respond_to(:c)
|
120
|
+
|
121
|
+
xml = b.parse(input).root
|
122
|
+
xml.should_not respond_to(:a)
|
123
|
+
xml.should_not respond_to(:c)
|
124
|
+
|
125
|
+
xml = c.parse(input).root
|
126
|
+
xml.should_not respond_to(:a)
|
127
|
+
xml.should_not respond_to(:b)
|
152
128
|
end
|
153
129
|
end
|
154
130
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xmlparsable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -36,8 +36,8 @@ files:
|
|
36
36
|
- README.md
|
37
37
|
- Rakefile
|
38
38
|
- lib/xmlparsable/elements/abstract.rb
|
39
|
+
- lib/xmlparsable/elements/array.rb
|
39
40
|
- lib/xmlparsable/elements/date.rb
|
40
|
-
- lib/xmlparsable/elements/list.rb
|
41
41
|
- lib/xmlparsable/elements/numeric.rb
|
42
42
|
- lib/xmlparsable/elements/record.rb
|
43
43
|
- lib/xmlparsable/elements/string.rb
|
@@ -47,8 +47,16 @@ files:
|
|
47
47
|
- lib/xmlparsable/elements.rb
|
48
48
|
- lib/xmlparsable/parser.rb
|
49
49
|
- lib/xmlparsable.rb
|
50
|
+
- spec/examples/accessors.example
|
51
|
+
- spec/examples/elements/array.example
|
52
|
+
- spec/examples/elements/date.example
|
53
|
+
- spec/examples/elements/numeric.example
|
54
|
+
- spec/examples/elements/record.example
|
55
|
+
- spec/examples/elements/string.example
|
56
|
+
- spec/examples/elements/text.example
|
57
|
+
- spec/examples/elements/time.example
|
58
|
+
- spec/examples/elements/xml.example
|
50
59
|
- spec/examples/inheritance.example
|
51
|
-
- spec/examples/record.example
|
52
60
|
- spec/spec_helper.rb
|
53
61
|
homepage: https://github.com/kputnam/xmlparsable
|
54
62
|
licenses: []
|
@@ -75,5 +83,13 @@ signing_key:
|
|
75
83
|
specification_version: 3
|
76
84
|
summary: Simple declarative XML parsing
|
77
85
|
test_files:
|
86
|
+
- spec/examples/accessors.example
|
87
|
+
- spec/examples/elements/array.example
|
88
|
+
- spec/examples/elements/date.example
|
89
|
+
- spec/examples/elements/numeric.example
|
90
|
+
- spec/examples/elements/record.example
|
91
|
+
- spec/examples/elements/string.example
|
92
|
+
- spec/examples/elements/text.example
|
93
|
+
- spec/examples/elements/time.example
|
94
|
+
- spec/examples/elements/xml.example
|
78
95
|
- spec/examples/inheritance.example
|
79
|
-
- spec/examples/record.example
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module XmlParsable
|
2
|
-
module Elements
|
3
|
-
|
4
|
-
class ListElement < AbstractElement
|
5
|
-
attr_reader :name
|
6
|
-
|
7
|
-
def initialize(name, attributes, parent, *arguments)
|
8
|
-
@name, @parent, @elements = name, parent, []
|
9
|
-
|
10
|
-
@cname = arguments.shift.to_s
|
11
|
-
@cparser = arguments.shift
|
12
|
-
@cargs = arguments
|
13
|
-
end
|
14
|
-
|
15
|
-
def open(name, attributes)
|
16
|
-
if name == @cname
|
17
|
-
@cparser.parsable.new(name, attributes, self, *@cargs)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def close(element, value)
|
22
|
-
@elements << value
|
23
|
-
end
|
24
|
-
|
25
|
-
def finalize
|
26
|
-
@parent.close(self, @elements)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
@@ -1,260 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe XmlParsable::Elements::RecordElement do
|
4
|
-
|
5
|
-
class Record
|
6
|
-
include XmlParsable
|
7
|
-
|
8
|
-
element :date, DateElement
|
9
|
-
element :string, StringElement
|
10
|
-
element :text, TextElement
|
11
|
-
element :time, TimeElement
|
12
|
-
element :xml, XmlElement
|
13
|
-
element :number, NumericElement
|
14
|
-
element :record, self
|
15
|
-
|
16
|
-
collection :kids, self
|
17
|
-
collection :list, :item
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "date" do
|
21
|
-
it "parses date into a ruby Date" do
|
22
|
-
Record.parse("<date>#{Date.today}</date>").date.should == Date.today
|
23
|
-
end
|
24
|
-
|
25
|
-
it "parses missing date as nil" do
|
26
|
-
Record.parse("<date><!-- nope --></date>").date.should == nil
|
27
|
-
end
|
28
|
-
|
29
|
-
it "ignores children" do
|
30
|
-
Record.parse("<date><x>2010-01-01</x></date>").date.should == nil
|
31
|
-
end
|
32
|
-
|
33
|
-
it "ignores comments" do
|
34
|
-
Record.parse("<date>#{Date.today} <!-- that's today --></date>").date.should == Date.today
|
35
|
-
end
|
36
|
-
|
37
|
-
it "ignores whitespace" do
|
38
|
-
Record.parse("<date>\n #{Date.today}\n </date>").date.should == Date.today
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "list of strings" do
|
43
|
-
it "parses empty list into an empty Array" do
|
44
|
-
Record.parse("<list/>").list.should == []
|
45
|
-
end
|
46
|
-
|
47
|
-
it "parses non-empty list into an Array" do
|
48
|
-
Record.parse("<list><item>a</item><item>b</item></list>").list.should == ["a", "b"]
|
49
|
-
end
|
50
|
-
|
51
|
-
it "ignores non-matching children" do
|
52
|
-
Record.parse("<list><fail/><item/><boat/><item/><item/></list>").list.should == ["", "", ""]
|
53
|
-
end
|
54
|
-
|
55
|
-
it "ignores comments" do
|
56
|
-
Record.parse("<list><!-- <item>x</item> --><item><!-- y --></item></list>").list.should == [""]
|
57
|
-
end
|
58
|
-
|
59
|
-
it "ignores whitespace between children" do
|
60
|
-
Record.parse(<<-XML).list.should == ["a", "b", "c"]
|
61
|
-
<list>
|
62
|
-
<item>a</item>
|
63
|
-
<item>b</item>
|
64
|
-
<item>c</item>
|
65
|
-
</list>
|
66
|
-
XML
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "list of records" do
|
71
|
-
it "parses empty list into an empty Array" do
|
72
|
-
Record.parse("<kids/>").kids.should == []
|
73
|
-
end
|
74
|
-
|
75
|
-
it "parses non-empty list into an array" do
|
76
|
-
x = Record.parse(<<-XML)
|
77
|
-
<kids>
|
78
|
-
<kid><text>first</text></kid>
|
79
|
-
<kid><text>second</text></kid>
|
80
|
-
<kid><text>third</text></kid>
|
81
|
-
</kids>
|
82
|
-
XML
|
83
|
-
|
84
|
-
x.kids.should have(3).items
|
85
|
-
x.kids[0].text.should == "first"
|
86
|
-
x.kids[1].text.should == "second"
|
87
|
-
x.kids[2].text.should == "third"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
describe "string" do
|
92
|
-
it "parses empty string" do
|
93
|
-
Record.parse("<string></string>").string.should == ""
|
94
|
-
end
|
95
|
-
|
96
|
-
it "parses non-empty string" do
|
97
|
-
Record.parse("<string>lo and behold</string>").string.should == "lo and behold"
|
98
|
-
end
|
99
|
-
|
100
|
-
it "ignores comments" do
|
101
|
-
Record.parse("<string>hi<!-- secret message --></string>").string.should == "hi"
|
102
|
-
end
|
103
|
-
|
104
|
-
it "ignores children" do
|
105
|
-
Record.parse("<string><b>bold</b>, <i>italic</i>, plain</string>").string.should == ", , plain"
|
106
|
-
end
|
107
|
-
|
108
|
-
it "does not ignore whitespace" do
|
109
|
-
Record.parse("<string> foob ar</string>").string.should == " foob ar"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
describe "text" do
|
114
|
-
it "parses text" do
|
115
|
-
Record.parse("<text>lo and behold</text>").text.should == "lo and behold"
|
116
|
-
end
|
117
|
-
|
118
|
-
it "ignores comments" do
|
119
|
-
Record.parse("<text>lo <!--and--> behold</text>").text.should == "lo behold"
|
120
|
-
end
|
121
|
-
|
122
|
-
it "strips away markup" do
|
123
|
-
Record.parse("<text>lo <span class='x'><i>and</i> behold</span></text>").text.should == "lo and behold"
|
124
|
-
end
|
125
|
-
|
126
|
-
it "does not ignore whitespace" do
|
127
|
-
Record.parse("<text> foob ar</text>").text.should == " foob ar"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
describe "time" do
|
132
|
-
it "parses time" do
|
133
|
-
time = Time.now
|
134
|
-
Record.parse("<time>#{time}</time>").time.to_i.should == time.to_i
|
135
|
-
end
|
136
|
-
|
137
|
-
it "ignores comments" do
|
138
|
-
Record.parse("<time><!-- #{Time.now} --></time>").time.should be_nil
|
139
|
-
end
|
140
|
-
|
141
|
-
it "ignores children" do
|
142
|
-
Record.parse("<time><b>#{Time.now}</b></time>").time.should be_nil
|
143
|
-
end
|
144
|
-
|
145
|
-
it "ignores whitespace" do
|
146
|
-
time = Time.now
|
147
|
-
Record.parse("<time> #{time} </time>").time.to_i.should == time.to_i
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe "number" do
|
152
|
-
it "parses integers" do
|
153
|
-
number = rand(1_000)
|
154
|
-
Record.parse("<number>#{number}</number>").number.should == number
|
155
|
-
end
|
156
|
-
|
157
|
-
it "parses rationals" do
|
158
|
-
number = rand(1_000) + rand
|
159
|
-
Record.parse("<number>#{number}</number>").number.should == BigDecimal(number.to_s)
|
160
|
-
end
|
161
|
-
|
162
|
-
it "ignores comments" do
|
163
|
-
Record.parse("<time><!-- 65432 --></time>").number.should be_nil
|
164
|
-
end
|
165
|
-
|
166
|
-
it "ignores children" do
|
167
|
-
Record.parse("<time><b>#{rand}</b></time>").number.should be_nil
|
168
|
-
end
|
169
|
-
|
170
|
-
it "ignores whitespace" do
|
171
|
-
number = rand(1_000)
|
172
|
-
Record.parse("<number> #{number} </number>").number.should == number
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
describe "record" do
|
177
|
-
it "parses date" do
|
178
|
-
x = Record.parse("<record><date>#{Date.today}</date></record>")
|
179
|
-
x.date.should be_nil
|
180
|
-
x.record.date.should == Date.today
|
181
|
-
end
|
182
|
-
|
183
|
-
it "parses list" do
|
184
|
-
x = Record.parse("<record><list/></record>")
|
185
|
-
x.list.should be_nil
|
186
|
-
x.record.list.should == []
|
187
|
-
end
|
188
|
-
|
189
|
-
it "parses string" do
|
190
|
-
x = Record.parse("<record><string>abc</string></record>")
|
191
|
-
x.string.should be_nil
|
192
|
-
x.record.string.should == "abc"
|
193
|
-
end
|
194
|
-
|
195
|
-
it "parses text" do
|
196
|
-
x = Record.parse("<record><text><b>big</b><i>little</i></text></record>")
|
197
|
-
x.text.should be_nil
|
198
|
-
x.record.text.should == "biglittle"
|
199
|
-
end
|
200
|
-
|
201
|
-
it "parses time" do
|
202
|
-
time = Time.now
|
203
|
-
Record.parse("<record><time>#{time}</time></record>").record.time.to_i.should == time.to_i
|
204
|
-
end
|
205
|
-
|
206
|
-
it "parses number" do
|
207
|
-
number = rand(1_000) + rand
|
208
|
-
Record.parse("<record><number>#{number}</number></record>").record.number.should == BigDecimal(number.to_s)
|
209
|
-
end
|
210
|
-
|
211
|
-
it "parses multiple elements" do
|
212
|
-
time = Time.now
|
213
|
-
x = Record.parse <<-XML
|
214
|
-
<record>
|
215
|
-
<date>#{Date.today}</date>
|
216
|
-
<list>
|
217
|
-
<item>a</item>
|
218
|
-
<item>b</item>
|
219
|
-
<item>c</item>
|
220
|
-
</list>
|
221
|
-
<string>xyz</string>
|
222
|
-
<text>
|
223
|
-
<ul>
|
224
|
-
<li>vim</li>
|
225
|
-
<li>emacs</li>
|
226
|
-
<li>ctags</li>
|
227
|
-
<li>lint</li>
|
228
|
-
<li>gdb</li>
|
229
|
-
</ul>
|
230
|
-
</text>
|
231
|
-
<time>#{time}</time>
|
232
|
-
</record>
|
233
|
-
XML
|
234
|
-
|
235
|
-
x.record.date.should == Date.today
|
236
|
-
x.record.list.should == ["a","b","c"]
|
237
|
-
x.record.string.should == "xyz"
|
238
|
-
x.record.text.strip.should == <<-DOC.strip
|
239
|
-
vim
|
240
|
-
emacs
|
241
|
-
ctags
|
242
|
-
lint
|
243
|
-
gdb
|
244
|
-
DOC
|
245
|
-
|
246
|
-
x.record.time.to_i.should == time.to_i
|
247
|
-
end
|
248
|
-
|
249
|
-
it "parses recursive records" do
|
250
|
-
x = Record.parse("<record><record><record><record></record></record></record></record>")
|
251
|
-
x.should be_a(Record)
|
252
|
-
x.record.should be_a(Record)
|
253
|
-
x.record.record.should be_a(Record)
|
254
|
-
x.record.record.record.should be_a(Record)
|
255
|
-
x.record.record.record.record.should be_a(Record)
|
256
|
-
x.record.record.record.record.record.should be_nil
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
end
|