graft 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -0
- data/lib/graft/core_ext/hash.rb +9 -0
- data/lib/graft/json.rb +14 -0
- data/lib/graft/json/attribute.rb +18 -0
- data/lib/graft/json/model.rb +28 -0
- data/lib/graft/model.rb +13 -44
- data/lib/graft/version.rb +2 -2
- data/lib/graft/xml.rb +19 -0
- data/lib/graft/xml/attribute.rb +52 -0
- data/lib/graft/xml/model.rb +49 -0
- data/lib/graft/xml/type.rb +91 -0
- data/test/test_helper.rb +4 -3
- data/test/unit/core_ext/hash_test.rb +29 -0
- data/test/unit/json/attribute_test.rb +51 -0
- data/test/unit/json/model_test.rb +86 -0
- data/test/unit/xml/attribute_test.rb +161 -0
- data/test/unit/{model_test.rb → xml/model_test.rb} +65 -47
- data/test/unit/xml/type_test.rb +65 -0
- metadata +26 -9
- data/lib/graft.rb +0 -13
- data/lib/graft/attribute.rb +0 -50
- data/lib/graft/type.rb +0 -89
- data/test/unit/attribute_test.rb +0 -159
- data/test/unit/source_test.rb +0 -16
- data/test/unit/type_test.rb +0 -63
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
module Graft
|
4
|
+
module Json
|
5
|
+
class AttributeTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "An instance of the Graft::Json::Attribute class" do
|
8
|
+
|
9
|
+
should "know its name" do
|
10
|
+
attr = Graft::Json::Attribute.new(:foo)
|
11
|
+
attr.name.should == :foo
|
12
|
+
end
|
13
|
+
|
14
|
+
should "have a default source" do
|
15
|
+
attr = Graft::Json::Attribute.new(:foo)
|
16
|
+
attr.source.should == 'foo'
|
17
|
+
end
|
18
|
+
|
19
|
+
should "be able to extract a value from a hash" do
|
20
|
+
data = {"first_name" => "Richerd"}
|
21
|
+
|
22
|
+
attr = Graft::Json::Attribute.new(:first_name)
|
23
|
+
attr.value_from(data).should == 'Richerd'
|
24
|
+
end
|
25
|
+
|
26
|
+
should "be able to extract a value from a hash when provided with a symbol for the source" do
|
27
|
+
data = {"firstname" => "Richerd"}
|
28
|
+
|
29
|
+
attr = Graft::Json::Attribute.new(:first_name, :firstname)
|
30
|
+
attr.value_from(data).should == 'Richerd'
|
31
|
+
end
|
32
|
+
|
33
|
+
should "be able to extract a nested value from a JSON string" do
|
34
|
+
data = {"user" => {"first_name" => "Richerd"}}
|
35
|
+
|
36
|
+
attr = Graft::Json::Attribute.new(:first_name, 'user/first_name')
|
37
|
+
attr.value_from(data).should == 'Richerd'
|
38
|
+
end
|
39
|
+
|
40
|
+
should "return nil when the value doesn't exist" do
|
41
|
+
data = {"first_name" => "Richerd"}
|
42
|
+
|
43
|
+
attr = Graft::Json::Attribute.new(:last_name, 'last_name')
|
44
|
+
attr.value_from(data).should be(nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
class EmptyJsonModel
|
4
|
+
include Graft::Json::Model
|
5
|
+
end
|
6
|
+
|
7
|
+
class JsonModelWithAttributes
|
8
|
+
include Graft::Json::Model
|
9
|
+
|
10
|
+
attribute :name
|
11
|
+
attribute :description, :from => 'desc'
|
12
|
+
attribute :rating, :from => 'rsp/rating'
|
13
|
+
end
|
14
|
+
|
15
|
+
class JsonModelTest < Test::Unit::TestCase
|
16
|
+
|
17
|
+
context "The EmptyJsonModel class" do
|
18
|
+
should "have an empty list of attributes if none are supplied" do
|
19
|
+
EmptyJsonModel.attributes.should == []
|
20
|
+
end
|
21
|
+
|
22
|
+
should "be able to return a collection of instances" do
|
23
|
+
json_data = '{"results":[{"name":"one"},{"name":"two"}]}'
|
24
|
+
|
25
|
+
EmptyJsonModel.expects(:new).with({'name' => 'one'}).returns('model_1')
|
26
|
+
EmptyJsonModel.expects(:new).with({'name' => 'two'}).returns('model_2')
|
27
|
+
|
28
|
+
collection = EmptyJsonModel.collection_from(json_data, 'results')
|
29
|
+
collection.should == ['model_1', 'model_2']
|
30
|
+
end
|
31
|
+
|
32
|
+
should "be able to retrieve data from the source JSON string" do
|
33
|
+
json_data = '{"name":"Graft"}'
|
34
|
+
EmptyJsonModel.data_from(json_data).should == {'name' => 'Graft'}
|
35
|
+
end
|
36
|
+
|
37
|
+
should "be able to retrieve data from the source hash data" do
|
38
|
+
data = {'name' => 'Graft'}
|
39
|
+
EmptyJsonModel.data_from(data).should == {'name' => 'Graft'}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "The JsonModelWithAttributes class" do
|
44
|
+
should "know the names of all its attributes" do
|
45
|
+
JsonModelWithAttributes.attributes.map {|a| a.name.to_s }.should == %w(name description rating)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "An instance of the JsonModelWithAttributes class" do
|
50
|
+
|
51
|
+
should "assign attributes upon initialization" do
|
52
|
+
json_data = '{"name":"Graft"}'
|
53
|
+
JsonModelWithAttributes.new(json_data).name.should == 'Graft'
|
54
|
+
end
|
55
|
+
|
56
|
+
should "have a reference to the original source data" do
|
57
|
+
json_data = '{"name":"Graft"}'
|
58
|
+
data = JSON.parse(json_data)
|
59
|
+
|
60
|
+
m = JsonModelWithAttributes.new(json_data)
|
61
|
+
m.source_data.should == data
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when populating from JSON data" do
|
65
|
+
setup do
|
66
|
+
json_data = '{"name":"Graft", "desc":"library", "rsp":{"rating":10}}'
|
67
|
+
@model = JsonModelWithAttributes.new
|
68
|
+
@model.populate_from(json_data)
|
69
|
+
end
|
70
|
+
|
71
|
+
should "have a value for :name" do
|
72
|
+
@model.name.should == 'Graft'
|
73
|
+
end
|
74
|
+
|
75
|
+
should "have a value for :description" do
|
76
|
+
@model.description.should == 'library'
|
77
|
+
end
|
78
|
+
|
79
|
+
should "have a value for :rating" do
|
80
|
+
@model.rating.should == 10
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
module Graft
|
4
|
+
module Xml
|
5
|
+
class AttributeTest < Test::Unit::TestCase
|
6
|
+
context "An instance of the Graft::Xml::Attribute class" do
|
7
|
+
|
8
|
+
should "know the name of the attribute" do
|
9
|
+
attr = Graft::Xml::Attribute.new('foo')
|
10
|
+
attr.name.should == :foo
|
11
|
+
end
|
12
|
+
|
13
|
+
should "have a default type class" do
|
14
|
+
attr = Graft::Xml::Attribute.new('foo')
|
15
|
+
attr.type_class.should == Graft::Xml::Type::String
|
16
|
+
end
|
17
|
+
|
18
|
+
should "have a default source" do
|
19
|
+
attr = Graft::Xml::Attribute.new(:foo)
|
20
|
+
attr.sources.should == ['foo']
|
21
|
+
end
|
22
|
+
|
23
|
+
should "be able to assign multiple sources" do
|
24
|
+
attr = Graft::Xml::Attribute.new(:foo, :string, ['foo1', 'foo2'])
|
25
|
+
attr.sources.should == ['foo1', 'foo2']
|
26
|
+
end
|
27
|
+
|
28
|
+
should "pull the location from the source" do
|
29
|
+
attr = Graft::Xml::Attribute.new('foo')
|
30
|
+
attr.location('foo').should == 'foo'
|
31
|
+
end
|
32
|
+
|
33
|
+
should "return the location when splitting" do
|
34
|
+
attr = Graft::Xml::Attribute.new('foo')
|
35
|
+
attr.split('foo').should == ['foo', nil]
|
36
|
+
end
|
37
|
+
|
38
|
+
should "return the name for the location when splitting if the location isn't specified" do
|
39
|
+
attr = Graft::Xml::Attribute.new('foo')
|
40
|
+
attr.split('@bar').should == ['foo', 'bar']
|
41
|
+
end
|
42
|
+
|
43
|
+
should "allow the setting of the location information" do
|
44
|
+
attr = Graft::Xml::Attribute.new('foo', :string, 'bar')
|
45
|
+
attr.sources.should == ['bar']
|
46
|
+
end
|
47
|
+
|
48
|
+
should "allow the setting of the attribute value" do
|
49
|
+
attr = Graft::Xml::Attribute.new('foo')
|
50
|
+
attr.attribute('@bogon').should == 'bogon'
|
51
|
+
end
|
52
|
+
|
53
|
+
should "use the location as the attribute" do
|
54
|
+
attr = Graft::Xml::Attribute.new('foo')
|
55
|
+
attr.attribute('foo').should == 'foo'
|
56
|
+
end
|
57
|
+
|
58
|
+
should "use the attribute for the attribute if specified" do
|
59
|
+
attr = Graft::Xml::Attribute.new(:id, :string, '@nsid')
|
60
|
+
attr.attribute('@nsid').should == 'nsid'
|
61
|
+
end
|
62
|
+
|
63
|
+
should "be able to retrieve the node from the path" do
|
64
|
+
document = Hpricot.XML('<name>Bassdrive</name>')
|
65
|
+
expected = document.at('name')
|
66
|
+
|
67
|
+
attr = Graft::Xml::Attribute.new(:name)
|
68
|
+
attr.node_for(document, 'name').should == expected
|
69
|
+
end
|
70
|
+
|
71
|
+
should "be able to retrieve the node that contains the specified attribute" do
|
72
|
+
document = Hpricot.XML('<user id="1337" />')
|
73
|
+
expected = document.at('user')
|
74
|
+
|
75
|
+
attr = Graft::Xml::Attribute.new(:id)
|
76
|
+
attr.node_for(document, '@id').should == expected
|
77
|
+
end
|
78
|
+
|
79
|
+
should "be able to retrieve the node for the specified attribute" do
|
80
|
+
document = Hpricot.XML('<user nsid="1337" />')
|
81
|
+
expected = document.at('user')
|
82
|
+
|
83
|
+
attr = Graft::Xml::Attribute.new(:id, :string, '@nsid')
|
84
|
+
attr.node_for(document, '@nsid').should == expected
|
85
|
+
end
|
86
|
+
|
87
|
+
should "be able to pull simple values from an XML document" do
|
88
|
+
document = Hpricot.XML('<name>Bassdrive</name>')
|
89
|
+
attr = Graft::Xml::Attribute.new(:name)
|
90
|
+
attr.value_from(document).should == 'Bassdrive'
|
91
|
+
end
|
92
|
+
|
93
|
+
should "be able to pull an attribute value from the current XML node" do
|
94
|
+
document = Hpricot.XML('<user id="1337" />')
|
95
|
+
attr = Graft::Xml::Attribute.new(:id)
|
96
|
+
attr.value_from(document).should == '1337'
|
97
|
+
end
|
98
|
+
|
99
|
+
should "be able to pull a specific attribute value from the current XML node" do
|
100
|
+
document = Hpricot.XML('<user nsid="1337" />')
|
101
|
+
attr = Graft::Xml::Attribute.new(:id, :string, '@nsid')
|
102
|
+
attr.value_from(document).should == '1337'
|
103
|
+
end
|
104
|
+
|
105
|
+
should "be able to pull an attribute value for a node and attribute" do
|
106
|
+
document = Hpricot.XML('<station><genre slug="dnb">Drum & Bass</genre></station>')
|
107
|
+
attr = Graft::Xml::Attribute.new(:slug, :string, 'station/genre@slug')
|
108
|
+
attr.value_from(document).should == 'dnb'
|
109
|
+
end
|
110
|
+
|
111
|
+
should "be able to pull a value from a nested XML node" do
|
112
|
+
document = Hpricot.XML('<rsp><user>blip</user></rsp>')
|
113
|
+
attr = Graft::Xml::Attribute.new(:user)
|
114
|
+
attr.value_from(document).should == 'blip'
|
115
|
+
end
|
116
|
+
|
117
|
+
should "return nil if it cannot find the specified node" do
|
118
|
+
document = Hpricot.XML('<user id="1" />')
|
119
|
+
attr = Graft::Xml::Attribute.new(:photoset, :string, '@nsid')
|
120
|
+
attr.value_from(document).should be(nil)
|
121
|
+
end
|
122
|
+
|
123
|
+
should "be able to try a series of nodes to find a value" do
|
124
|
+
document = Hpricot.XML('<photoid>123</photoid>')
|
125
|
+
|
126
|
+
attr = Graft::Xml::Attribute.new(:id, :string, ['photo@nsid', 'photoid'])
|
127
|
+
attr.value_from(document).should == '123'
|
128
|
+
end
|
129
|
+
|
130
|
+
should "be able to convert an integer value" do
|
131
|
+
document = Hpricot.XML('<id>1</id>')
|
132
|
+
|
133
|
+
attr = Graft::Xml::Attribute.new(:id, :integer)
|
134
|
+
attr.value_from(document).should == 1
|
135
|
+
end
|
136
|
+
|
137
|
+
should "be able to convert a boolean value" do
|
138
|
+
document = Hpricot.XML('<active>true</active>')
|
139
|
+
|
140
|
+
attr = Graft::Xml::Attribute.new(:active, :boolean)
|
141
|
+
attr.value_from(document).should == true
|
142
|
+
end
|
143
|
+
|
144
|
+
should "be able to convert a date value" do
|
145
|
+
document = Hpricot.XML('<due_on>2009-08-01</due_on>')
|
146
|
+
|
147
|
+
attr = Graft::Xml::Attribute.new(:due_on, :date)
|
148
|
+
attr.value_from(document).should == Date.parse('2009-08-01')
|
149
|
+
end
|
150
|
+
|
151
|
+
should "be able to convert a time value" do
|
152
|
+
document = Hpricot.XML('<created_at>2009-08-01 00:00:00</created_at>')
|
153
|
+
|
154
|
+
attr = Graft::Xml::Attribute.new(:created_at, :time)
|
155
|
+
attr.value_from(document).should == Time.parse('2009-08-01 00:00:00')
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
require File.dirname(__FILE__) + '
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
2
|
|
3
|
-
class
|
4
|
-
include Graft::Model
|
3
|
+
class EmptyXmlModel
|
4
|
+
include Graft::Xml::Model
|
5
5
|
end
|
6
6
|
|
7
|
-
class
|
8
|
-
include Graft::Model
|
7
|
+
class XmlModelWithAttributes
|
8
|
+
include Graft::Xml::Model
|
9
9
|
|
10
10
|
attribute :name
|
11
11
|
attribute :description, :from => 'desc'
|
@@ -14,18 +14,17 @@ class ModelWithAttributes
|
|
14
14
|
|
15
15
|
end
|
16
16
|
|
17
|
-
class
|
18
|
-
include Graft::Model
|
17
|
+
class XmlModelWithAttributeType
|
18
|
+
include Graft::Xml::Model
|
19
19
|
|
20
20
|
attribute :id, :type => :integer
|
21
|
-
|
22
21
|
end
|
23
22
|
|
24
|
-
class
|
23
|
+
class XmlModelTest < Test::Unit::TestCase
|
25
24
|
|
26
|
-
context "The
|
25
|
+
context "The EmptyXmlModel class" do
|
27
26
|
should "have an empty list of attributes if none are supplied" do
|
28
|
-
|
27
|
+
EmptyXmlModel.attributes.should == []
|
29
28
|
end
|
30
29
|
|
31
30
|
should "be able to return a collection of XML nodes" do
|
@@ -37,52 +36,46 @@ class ModelTest < Test::Unit::TestCase
|
|
37
36
|
</things>
|
38
37
|
XML
|
39
38
|
|
40
|
-
|
41
|
-
|
39
|
+
document = Hpricot.XML(xml)
|
40
|
+
|
41
|
+
EmptyXmlModel.expects(:data_from).with(xml).returns(document)
|
42
|
+
|
43
|
+
EmptyXmlModel.expects(:new).with((document/'things/thing').first).returns('model_1')
|
44
|
+
EmptyXmlModel.expects(:new).with((document/'things/thing').last).returns('model_2')
|
42
45
|
|
43
|
-
collection =
|
46
|
+
collection = EmptyXmlModel.collection_from(xml, 'things/thing')
|
44
47
|
collection.should == ['model_1', 'model_2']
|
45
48
|
end
|
49
|
+
|
50
|
+
should "be able to retrieve data from the source XML string" do
|
51
|
+
xml = '<name>Graft</name>'
|
52
|
+
Hpricot.expects(:XML).with(xml).returns('document')
|
53
|
+
|
54
|
+
EmptyXmlModel.data_from(xml).should == 'document'
|
55
|
+
end
|
46
56
|
|
47
|
-
should "
|
48
|
-
|
49
|
-
|
57
|
+
should "be able to retrieve data from the source document data" do
|
58
|
+
document = Hpricot.XML('<name>Graft</name>')
|
59
|
+
EmptyXmlModel.data_from(document).should == document
|
50
60
|
end
|
51
|
-
|
61
|
+
|
52
62
|
end
|
53
63
|
|
54
|
-
context "The
|
64
|
+
context "The XmlModelWithAttributes class" do
|
55
65
|
should "know the names of all its attributes" do
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
should "return a hash representation of itself" do
|
60
|
-
m = ModelWithAttributes.new
|
61
|
-
|
62
|
-
m.name = 'name'
|
63
|
-
m.description = 'description'
|
64
|
-
m.rating = '5'
|
65
|
-
m.size = 'large'
|
66
|
-
|
67
|
-
m.to_hash.should == {
|
68
|
-
'name' => 'name',
|
69
|
-
'description' => 'description',
|
70
|
-
'rating' => '5',
|
71
|
-
'size' => 'large'
|
72
|
-
}
|
73
|
-
|
66
|
+
XmlModelWithAttributes.attributes.map {|a| a.name.to_s }.should == %w(name description rating size)
|
74
67
|
end
|
75
68
|
end
|
76
69
|
|
77
|
-
context "The
|
70
|
+
context "The XmlModelWithAttributeType class" do
|
78
71
|
should "know that it's attribute is of type :integer" do
|
79
|
-
attribute =
|
80
|
-
attribute.type_class.should == Graft::Type::Integer
|
72
|
+
attribute = XmlModelWithAttributeType.attributes.first
|
73
|
+
attribute.type_class.should == Graft::Xml::Type::Integer
|
81
74
|
end
|
82
75
|
|
83
76
|
should "be able to generate an XML representation of itself" do
|
84
77
|
|
85
|
-
m =
|
78
|
+
m = XmlModelWithAttributeType.new
|
86
79
|
m.id = 1
|
87
80
|
|
88
81
|
xml = String.new
|
@@ -96,26 +89,51 @@ class ModelTest < Test::Unit::TestCase
|
|
96
89
|
end
|
97
90
|
end
|
98
91
|
|
99
|
-
context "An instance of the
|
92
|
+
context "An instance of the EmptyXmlModel class" do
|
93
|
+
|
94
|
+
should "return an empty hash when calling :to_hash" do
|
95
|
+
m = EmptyXmlModel.new
|
96
|
+
m.to_hash.should == {}
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
context "An instance of the XmlModelWithAttributes class" do
|
100
102
|
|
101
103
|
setup { @simple_xml = '<name>Graft</name>' }
|
102
104
|
|
103
105
|
should "have default reader method for :name" do
|
104
|
-
|
106
|
+
XmlModelWithAttributes.new.respond_to?(:name).should be(true)
|
105
107
|
end
|
106
108
|
|
107
109
|
should "be able to populate its data on initialization" do
|
108
110
|
xml = Hpricot.XML(@simple_xml)
|
109
|
-
|
111
|
+
XmlModelWithAttributes.new(xml).name.should == 'Graft'
|
110
112
|
end
|
111
113
|
|
112
114
|
should "have a reference to the original document" do
|
113
115
|
xml = Hpricot.XML(@simple_xml)
|
114
|
-
|
116
|
+
XmlModelWithAttributes.new(xml).source_data.should == xml
|
115
117
|
end
|
116
118
|
|
117
119
|
should "be able to populate from an XML string" do
|
118
|
-
|
120
|
+
XmlModelWithAttributes.new(@simple_xml).name.should == 'Graft'
|
121
|
+
end
|
122
|
+
|
123
|
+
should "return a hash representation of itself" do
|
124
|
+
m = XmlModelWithAttributes.new
|
125
|
+
|
126
|
+
m.name = 'name'
|
127
|
+
m.description = 'description'
|
128
|
+
m.rating = '5'
|
129
|
+
m.size = 'large'
|
130
|
+
|
131
|
+
m.to_hash.should == {
|
132
|
+
'name' => 'name',
|
133
|
+
'description' => 'description',
|
134
|
+
'rating' => '5',
|
135
|
+
'size' => 'large'
|
136
|
+
}
|
119
137
|
end
|
120
138
|
|
121
139
|
context "when populating data from an XML document" do
|
@@ -129,7 +147,7 @@ class ModelTest < Test::Unit::TestCase
|
|
129
147
|
<node type="size" value="large" />
|
130
148
|
XML
|
131
149
|
|
132
|
-
@model =
|
150
|
+
@model = XmlModelWithAttributes.new
|
133
151
|
@model.populate_from(Hpricot.XML(xml))
|
134
152
|
end
|
135
153
|
|