graft 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|
|