lzell-mapricot 0.0.1 → 0.0.2.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.
- data/History.txt +13 -1
- data/README.rdoc +9 -8
- data/benchmark/benchmarks.rb +127 -0
- data/{test/mapricot_spec.rb → examples/facebook_api.rb} +23 -56
- data/examples/lastfm_api.rb +1 -1
- data/examples/lastfm_api_no_request.rb +1 -1
- data/examples/readme_examples.rb +1 -1
- data/examples/xml_with_attributes.rb +26 -0
- data/lib/abstract_doc.rb +121 -0
- data/lib/mapricot.rb +102 -66
- data/mapricot.gemspec +19 -6
- data/test/abstract_doc_spec.rb +79 -0
- data/test/has_attribute/has_attribute_spec.rb +57 -0
- data/test/has_many/has_many_ids_spec.rb +73 -0
- data/test/has_many/has_many_nested_spec.rb +116 -0
- data/test/has_one/has_one_id_spec.rb +64 -0
- data/test/has_one/has_one_nested_spec.rb +97 -0
- data/test/has_one/has_one_user_spec.rb +67 -0
- data/test/suite.rb +8 -0
- data/test/test_mapricot.rb +86 -0
- data/test/{mapricot_tests.rb → test_mapricot_readme.rb} +6 -6
- metadata +36 -4
data/lib/mapricot.rb
CHANGED
@@ -1,97 +1,110 @@
|
|
1
|
-
require '
|
2
|
-
begin
|
3
|
-
require 'hpricot'
|
4
|
-
rescue LoadError
|
5
|
-
require 'rubygems'
|
6
|
-
require 'hpricot'
|
7
|
-
end
|
8
|
-
# singularize, constantize, camelize, classify; doc here: http://api.rubyonrails.com/classes/Inflector.html
|
1
|
+
require 'rubygems'
|
9
2
|
require 'active_support/inflector'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/abstract_doc")
|
10
4
|
|
11
5
|
module Mapricot
|
12
|
-
|
6
|
+
|
7
|
+
|
13
8
|
# Inherit from base, e.g. class Animal < Mapricot::Base
|
14
9
|
# Use either a string of xml or a url to initialize
|
15
10
|
class Base
|
11
|
+
|
16
12
|
class << self
|
17
13
|
# @associations is used to initialize instance variables
|
18
|
-
# creates a new HasOneAssociation and appends it to the @
|
14
|
+
# creates a new HasOneAssociation and appends it to the @association_list
|
19
15
|
def has_one(name, type = :string, opts = {})
|
20
|
-
|
21
|
-
self.name.match(/::/)
|
22
|
-
|
16
|
+
association = HasOneAssociation.new(name, type, opts)
|
17
|
+
if self.name.match(/::/)
|
18
|
+
association.namespace = self.name.match(/(.*)::[^:]+$/)[1]
|
19
|
+
end
|
20
|
+
association_list << association
|
23
21
|
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
24
22
|
end
|
25
|
-
|
23
|
+
|
24
|
+
# creates a new HasManyAssociation and appends it to the @association_list
|
26
25
|
def has_many(name, type = :string, opts = {})
|
27
|
-
|
28
|
-
self.name.match(/::/)
|
29
|
-
|
26
|
+
association = HasManyAssociation.new(name, type, opts)
|
27
|
+
if self.name.match(/::/)
|
28
|
+
association.namespace = self.name.match(/(.*)::[^:]+$/)[1]
|
29
|
+
end
|
30
|
+
association_list << association
|
30
31
|
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
31
32
|
end
|
32
|
-
|
33
|
-
|
33
|
+
|
34
|
+
def has_attribute(name, type = :string)
|
35
|
+
attribute_list << Attribute.new(name, type)
|
34
36
|
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
35
37
|
end
|
36
|
-
|
37
|
-
|
38
|
+
|
39
|
+
def association_list
|
40
|
+
@association_list ||= []
|
38
41
|
end
|
39
|
-
|
40
|
-
|
42
|
+
|
43
|
+
def attribute_list
|
44
|
+
@attribute_list ||= []
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
48
|
# class SomeClass < Mapricot::Base; end;
|
45
49
|
# SomeClass.new :url => "http://some_url"
|
46
50
|
# SomeClass.new :xml => %(<hi></hi>)
|
51
|
+
# the class instance variable @association_list is duplicated in every instance of Feed, as the instance variable @associations.
|
52
|
+
# i.e. Feed.association_list is the template for feed.associations
|
47
53
|
def initialize(opts)
|
48
|
-
@
|
49
|
-
@
|
50
|
-
|
51
|
-
|
54
|
+
@doc = AbstractDoc.from_url(opts[:url]) if opts[:url]
|
55
|
+
@doc = AbstractDoc.from_string(opts[:xml]) if opts[:xml]
|
56
|
+
dup_associations_and_attributes
|
57
|
+
map_associations
|
58
|
+
map_attributes
|
52
59
|
end
|
53
60
|
|
54
|
-
|
55
|
-
|
56
|
-
|
61
|
+
def dup_associations_and_attributes
|
62
|
+
@associations = self.class.association_list.collect {|x| x.dup} # do not do this: self.class.association_list.dup
|
63
|
+
@attributes = self.class.attribute_list.collect {|x| x.dup}
|
57
64
|
end
|
58
65
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# loop through the class's instance variable @attributes, which holds all of our associations
|
65
|
-
association_list = self.class.instance_variable_get(:@associations)
|
66
|
-
association_list && association_list.each do |ass|
|
67
|
-
load_has_one(ass) if ass.is_a?(HasOneAssociation)
|
68
|
-
load_has_many(ass) if ass.is_a?(HasManyAssociation)
|
69
|
-
# set instance variables and create accessors for each
|
70
|
-
instance_variable_set("@#{ass.name}", ass.value)
|
66
|
+
def map_associations
|
67
|
+
@associations.each do |association|
|
68
|
+
node_list = @doc.find(association.tag_name)
|
69
|
+
association.set_value_from_node_list(node_list)
|
70
|
+
instance_variable_set("@#{association.name}", association.value)
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
def
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
instance_variable_set("@#{
|
74
|
+
def map_attributes
|
75
|
+
@attributes.each do |attribute|
|
76
|
+
node = @doc.find(tag_name).first
|
77
|
+
attribute.set_value_from_node(node)
|
78
|
+
instance_variable_set("@#{attribute.name}", attribute.value)
|
79
79
|
end
|
80
80
|
end
|
81
|
+
|
82
|
+
# associations and base classes both have tag_name method
|
83
|
+
def tag_name
|
84
|
+
self.class.name.downcase.match(/[^:]+$/)[0]
|
85
|
+
end
|
81
86
|
end
|
82
87
|
|
88
|
+
|
89
|
+
|
83
90
|
# Abstract class; used to subclass HasOneAssociation and HasManyAssociation
|
84
91
|
class Association
|
85
92
|
VALID_TYPES = [:integer, :time, :xml, :string]
|
86
93
|
|
87
94
|
attr_accessor :name, :type, :value
|
88
95
|
attr_accessor :namespace
|
96
|
+
|
89
97
|
def initialize(name, type, opts = {})
|
90
98
|
raise "Don't instantiate me" if abstract_class?
|
91
99
|
@name, @type, @opts = name, type, opts
|
92
100
|
@namespace = nil
|
93
101
|
end
|
102
|
+
|
103
|
+
def tag_name
|
104
|
+
@opts[:tag_name] || singular_name
|
105
|
+
end
|
94
106
|
|
107
|
+
private
|
95
108
|
def typecast
|
96
109
|
raise "association type is invalid" unless VALID_TYPES.include?(@type)
|
97
110
|
if [:integer, :time].include?(@type)
|
@@ -103,6 +116,7 @@ module Mapricot
|
|
103
116
|
@value.is_a?(Array) ? @value.collect {|v| v.to_i} : @value.to_i
|
104
117
|
end
|
105
118
|
|
119
|
+
# oh, forgot about this, need to add to readme
|
106
120
|
def typecast_time
|
107
121
|
if @value.is_a?(Array)
|
108
122
|
@value.collect {|v| Time.parse(v) }
|
@@ -110,8 +124,7 @@ module Mapricot
|
|
110
124
|
Time.parse(@value)
|
111
125
|
end
|
112
126
|
end
|
113
|
-
|
114
|
-
private
|
127
|
+
|
115
128
|
def abstract_class?
|
116
129
|
self.class == Association
|
117
130
|
end
|
@@ -129,46 +142,69 @@ module Mapricot
|
|
129
142
|
singular_name.classify.constantize
|
130
143
|
end
|
131
144
|
end
|
145
|
+
|
146
|
+
def set_value_from_node_list(node_list)
|
147
|
+
end
|
148
|
+
|
132
149
|
end
|
133
150
|
|
134
151
|
|
135
152
|
class HasOneAssociation < Association
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
153
|
+
|
154
|
+
# pass a node list, depending on the type of association
|
155
|
+
def set_value_from_node_list(node_list)
|
156
|
+
if node_list.empty?
|
157
|
+
@value = nil
|
158
|
+
else
|
141
159
|
if @type == :xml
|
142
|
-
|
160
|
+
@value = class_from_name.new(:xml => node_list.first.to_s)
|
143
161
|
else
|
144
|
-
@value =
|
162
|
+
@value = node_list.first.contents
|
163
|
+
typecast
|
145
164
|
end
|
146
|
-
self.typecast
|
147
165
|
end
|
148
166
|
end
|
149
167
|
end
|
150
168
|
|
151
|
-
|
169
|
+
|
152
170
|
class HasManyAssociation < Association
|
153
171
|
|
154
172
|
def singular_name
|
155
|
-
# @name.to_s[0..-2]
|
156
173
|
"#{@name}".singularize
|
157
174
|
end
|
158
175
|
|
159
|
-
|
160
|
-
# finally, each element in the array is typecast
|
161
|
-
def search(xml)
|
176
|
+
def set_value_from_node_list(node_list)
|
162
177
|
@value = []
|
163
|
-
|
178
|
+
node_list.each do |node|
|
164
179
|
if @type == :xml
|
165
|
-
@value << class_from_name.new(:xml =>
|
180
|
+
@value << class_from_name.new(:xml => node.to_s)
|
166
181
|
else
|
167
|
-
@value <<
|
182
|
+
@value << node.contents
|
168
183
|
end
|
169
184
|
end
|
185
|
+
typecast
|
170
186
|
end
|
171
|
-
|
172
187
|
end
|
188
|
+
|
189
|
+
|
190
|
+
class Attribute
|
191
|
+
attr_accessor :name, :type, :value
|
173
192
|
|
193
|
+
def initialize(name, type)
|
194
|
+
@name = name
|
195
|
+
@type = type
|
196
|
+
end
|
197
|
+
|
198
|
+
def set_value_from_node(node)
|
199
|
+
@value = node.attributes[name.to_s]
|
200
|
+
typecast
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
def typecast
|
205
|
+
if !@value.nil? && !@value.empty? && @type == :integer
|
206
|
+
@value = @value.to_i
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
174
210
|
end
|
data/mapricot.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "mapricot"
|
3
|
-
s.version = "0.0.1"
|
4
|
-
s.date = "2009-03-
|
3
|
+
s.version = "0.0.2.1"
|
4
|
+
s.date = "2009-03-17"
|
5
5
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
6
|
s.summary = "XML to object mapper"
|
7
7
|
s.email = "lzell11@gmail.com"
|
@@ -15,14 +15,27 @@ Gem::Specification.new do |s|
|
|
15
15
|
"mapricot.gemspec",
|
16
16
|
"examples/lastfm_api.rb",
|
17
17
|
"examples/lastfm_api_no_request.rb",
|
18
|
+
"examples/facebook_api.rb",
|
18
19
|
"examples/natural_inputs.rb",
|
19
20
|
"examples/readme_examples.rb",
|
20
|
-
"
|
21
|
-
"test/
|
22
|
-
"
|
21
|
+
"examples/xml_with_attributes.rb",
|
22
|
+
"test/suite.rb",
|
23
|
+
"test/abstract_doc_spec.rb",
|
24
|
+
"test/test_mapricot.rb",
|
25
|
+
"test/test_mapricot_readme.rb",
|
26
|
+
"test/has_attribute/has_attribute_spec.rb",
|
27
|
+
"test/has_many/has_many_ids_spec.rb",
|
28
|
+
"test/has_many/has_many_nested_spec.rb",
|
29
|
+
"test/has_one/has_one_id_spec.rb",
|
30
|
+
"test/has_one/has_one_user_spec.rb",
|
31
|
+
"test/has_one/has_one_nested_spec.rb",
|
32
|
+
"lib/mapricot.rb",
|
33
|
+
"lib/abstract_doc.rb",
|
34
|
+
"benchmark/benchmarks.rb"]
|
23
35
|
s.require_paths = ["lib"]
|
24
36
|
s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--title", "Mapricot"]
|
25
37
|
s.extra_rdoc_files = ["README.rdoc"]
|
26
38
|
s.add_dependency("hpricot")
|
39
|
+
s.add_dependency("nokogiri")
|
40
|
+
s.add_dependency("libxml-ruby")
|
27
41
|
end
|
28
|
-
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/abstract_doc")
|
4
|
+
|
5
|
+
|
6
|
+
include Mapricot
|
7
|
+
|
8
|
+
|
9
|
+
share_examples_for "an abstract xml parser" do
|
10
|
+
|
11
|
+
it "should initialize from a url or a string" do
|
12
|
+
AbstractDoc.should respond_to(:from_string)
|
13
|
+
AbstractDoc.should respond_to(:from_url)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be using libxml or hpricot or nokogiri" do
|
17
|
+
puts "using #{Mapricot.parser}..."
|
18
|
+
[:libxml, :hpricot, :nokogiri].include?(Mapricot.parser).should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "creating a document from a string of xml" do
|
22
|
+
before(:all) do
|
23
|
+
@doc = AbstractDoc.from_string %(<user>bob</user>)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be able to find all the <user> nodes" do
|
27
|
+
@doc.find(:user).should_not be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "the list of user nodes" do
|
31
|
+
|
32
|
+
before(:all) do
|
33
|
+
@user_nodes = @doc.find(:user)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should be an abstract node list" do
|
37
|
+
@user_nodes.should be_a(AbstractNodeList)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should be able to iterate over" do
|
41
|
+
@user_nodes.should respond_to(:each)
|
42
|
+
@user_nodes.should respond_to(:first)
|
43
|
+
@user_nodes.should respond_to(:[])
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "the first user node" do
|
47
|
+
|
48
|
+
before(:all) do
|
49
|
+
@user = @user_nodes.first
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should be a abstract node" do
|
53
|
+
@user.should be_a(AbstractNode)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be able to get the node contents" do
|
57
|
+
@user.contents.should == "bob"
|
58
|
+
@user.to_s.should == "<user>bob</user>"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "AbstractDoc using libxml" do
|
66
|
+
before(:all) { Mapricot.parser = :libxml }
|
67
|
+
it_should_behave_like "an abstract xml parser"
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "AbstractDoc useing hpricot" do
|
71
|
+
before(:all) { Mapricot.parser = :hpricot }
|
72
|
+
it_should_behave_like "an abstract xml parser"
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "AbstractDoc useing hpricot" do
|
76
|
+
before(:all) { Mapricot.parser = :nokogiri }
|
77
|
+
it_should_behave_like "an abstract xml parser"
|
78
|
+
end
|
79
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../lib/mapricot")
|
4
|
+
|
5
|
+
include Mapricot
|
6
|
+
|
7
|
+
class Response < Mapricot::Base
|
8
|
+
has_one :location, :xml
|
9
|
+
end
|
10
|
+
|
11
|
+
class Location < Mapricot::Base
|
12
|
+
has_one :city
|
13
|
+
has_one :state
|
14
|
+
has_attribute :code
|
15
|
+
has_attribute :id, :integer
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
share_as :HasAttribute do
|
20
|
+
|
21
|
+
describe "; response with location city, state, and code" do
|
22
|
+
|
23
|
+
before(:all) do
|
24
|
+
@response = Response.new(:xml => %(
|
25
|
+
<response>
|
26
|
+
<location code='nyc' id='100'>
|
27
|
+
<city>New York</city>
|
28
|
+
<state>NY</state>
|
29
|
+
</location>
|
30
|
+
</response>
|
31
|
+
))
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should have location code 'nyc'" do
|
35
|
+
@response.location.city.should == "New York"
|
36
|
+
@response.location.state.should == "NY"
|
37
|
+
@response.location.code.should == 'nyc'
|
38
|
+
@response.location.id.should == 100
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
describe "has attribute, parsing with hpricot" do
|
45
|
+
before(:all) { Mapricot.parser = :hpricot }
|
46
|
+
it_should_behave_like HasAttribute
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "has many id, parsing with libxml" do
|
50
|
+
before(:all) { Mapricot.parser = :libxml }
|
51
|
+
it_should_behave_like HasAttribute
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "has many id, parsing with nokogiri" do
|
55
|
+
before(:all) { Mapricot.parser = :nokogiri }
|
56
|
+
it_should_behave_like HasAttribute
|
57
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../lib/mapricot")
|
4
|
+
|
5
|
+
include Mapricot
|
6
|
+
|
7
|
+
class ResponseWithManyIds < Mapricot::Base
|
8
|
+
has_many :ids, :integer
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
share_as :HasManyIds do
|
13
|
+
|
14
|
+
before(:all) do
|
15
|
+
@response = ResponseWithManyIds.new(:xml => %(
|
16
|
+
<response>
|
17
|
+
<id>10</id>
|
18
|
+
<id>20</id>
|
19
|
+
<id>30</id>
|
20
|
+
</response>
|
21
|
+
))
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "Interface" do
|
25
|
+
|
26
|
+
it "should have an array of ids" do
|
27
|
+
@response.ids.should be_a(Array)
|
28
|
+
@response.ids[0].should == 10
|
29
|
+
@response.ids[1].should == 20
|
30
|
+
@response.ids[2].should == 30
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
describe "Internals" do
|
36
|
+
|
37
|
+
it "should have an accessor on ids" do
|
38
|
+
@response.should respond_to(:ids)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should have a class instance variable @association_list" do
|
42
|
+
ass_template = @response.class.association_list.first
|
43
|
+
ass_template.name.should == :ids
|
44
|
+
ass_template.type.should == :integer
|
45
|
+
ass_template.namespace.should be_nil
|
46
|
+
ass_template.value.should be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should have an instance variable @associations, duplicated from class ivar @association_list, with value now set" do
|
50
|
+
ass = @response.instance_variable_get(:@associations).first
|
51
|
+
ass.name.should == :ids
|
52
|
+
ass.type.should == :integer
|
53
|
+
ass.namespace.should be_nil
|
54
|
+
ass.value.should == [10,20,30]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
describe "has many ids, parsing with hpricot" do
|
61
|
+
before(:all) { Mapricot.parser = :hpricot }
|
62
|
+
it_should_behave_like HasManyIds
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "has many id, parsing with libxml" do
|
66
|
+
before(:all) { Mapricot.parser = :libxml }
|
67
|
+
it_should_behave_like HasManyIds
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "has many id, parsing with nokogiri" do
|
71
|
+
before(:all) { Mapricot.parser = :nokogiri }
|
72
|
+
it_should_behave_like HasManyIds
|
73
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../lib/mapricot")
|
4
|
+
|
5
|
+
include Mapricot
|
6
|
+
|
7
|
+
class ResponseWithNesting < Mapricot::Base
|
8
|
+
has_many :users, :xml
|
9
|
+
end
|
10
|
+
|
11
|
+
class User < Mapricot::Base
|
12
|
+
has_one :id, :integer
|
13
|
+
has_one :name
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
share_as :HasManyNested do
|
18
|
+
|
19
|
+
before(:all) do
|
20
|
+
@response = ResponseWithNesting.new(:xml => %(
|
21
|
+
<response>
|
22
|
+
<user>
|
23
|
+
<id>10</id>
|
24
|
+
<name>bob</name>
|
25
|
+
</user>
|
26
|
+
<user>
|
27
|
+
<id>20</id>
|
28
|
+
<name>sally</name>
|
29
|
+
</user>
|
30
|
+
</response>
|
31
|
+
))
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "Interface" do
|
35
|
+
|
36
|
+
it "should have bob as the first user" do
|
37
|
+
@response.users.first.id.should == 10
|
38
|
+
@response.users.first.name.should == "bob"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should have sally as the second user" do
|
42
|
+
@response.users.last.id.should == 20
|
43
|
+
@response.users.last.name.should == "sally"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
describe "Internals" do
|
49
|
+
|
50
|
+
it "should have an accessor on users" do
|
51
|
+
@response.should respond_to(:users)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should have a class instance variable @association_list" do
|
55
|
+
ass_template = @response.class.association_list.first
|
56
|
+
ass_template.name.should == :users
|
57
|
+
ass_template.type.should == :xml
|
58
|
+
ass_template.namespace.should be_nil
|
59
|
+
ass_template.value.should be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should have an instance variable @associations, duplicated from class ivar @association_list, with value now set" do
|
63
|
+
ass = @response.instance_variable_get(:@associations).first
|
64
|
+
ass.name.should == :users
|
65
|
+
ass.type.should == :xml
|
66
|
+
ass.namespace.should be_nil
|
67
|
+
ass.value.should_not be_nil # should not
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "its users" do
|
71
|
+
|
72
|
+
before(:all) do
|
73
|
+
@users = @response.users
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should be a an array of User objects, a subclass of Mapricot::Base" do
|
77
|
+
@users.should be_a(Array)
|
78
|
+
@users.first.should be_a(User)
|
79
|
+
@users.first.should be_a(Mapricot::Base)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should have a class instance variable @association_list, an array of HasMany and HasOne *instances*" do
|
83
|
+
ass_template = @users.first.class.association_list.first
|
84
|
+
ass_template.should be_a(HasOneAssociation)
|
85
|
+
ass_template.name.should == :id
|
86
|
+
ass_template.type.should == :integer
|
87
|
+
ass_template.namespace.should be_nil
|
88
|
+
ass_template.value.should be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should have an instance variable @associations, duplicated from class ivar @association_list, with value now set" do
|
92
|
+
ass = @users.first.instance_variable_get(:@associations).first
|
93
|
+
ass.name.should == :id
|
94
|
+
ass.type.should == :integer
|
95
|
+
ass.namespace.should be_nil
|
96
|
+
ass.value.should == 10
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
describe "has many ids, parsing with hpricot" do
|
104
|
+
before(:all) { Mapricot.parser = :hpricot }
|
105
|
+
it_should_behave_like HasManyNested
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "has many id, parsing with libxml" do
|
109
|
+
before(:all) { Mapricot.parser = :libxml }
|
110
|
+
it_should_behave_like HasManyNested
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "has many id, parsing with nokogiri" do
|
114
|
+
before(:all) { Mapricot.parser = :nokogiri }
|
115
|
+
it_should_behave_like HasManyNested
|
116
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../lib/mapricot")
|
4
|
+
|
5
|
+
include Mapricot
|
6
|
+
|
7
|
+
class FeedWithOneId < Mapricot::Base
|
8
|
+
has_one :id, :integer
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
share_as :HasOneId do
|
13
|
+
|
14
|
+
before(:all) do
|
15
|
+
@feed = FeedWithOneId.new(:xml => "<id>10</id>")
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "Interface" do
|
19
|
+
|
20
|
+
it "should have an id of 10" do
|
21
|
+
@feed.id.should == 10
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
describe "Internals" do
|
27
|
+
|
28
|
+
it "should have an accessor on id" do
|
29
|
+
@feed.should respond_to(:id)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have a class instance variable @association_list" do
|
33
|
+
ass_template = @feed.class.association_list.first
|
34
|
+
ass_template.name.should == :id
|
35
|
+
ass_template.type.should == :integer
|
36
|
+
ass_template.namespace.should be_nil
|
37
|
+
ass_template.value.should be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should have an instance variable @associations, duplicated from class ivar @association_list, with value now set" do
|
41
|
+
ass = @feed.instance_variable_get(:@associations).first
|
42
|
+
ass.name.should == :id
|
43
|
+
ass.type.should == :integer
|
44
|
+
ass.namespace.should be_nil
|
45
|
+
ass.value.should == 10
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
describe "has one id, parsing with hpricot" do
|
52
|
+
before(:all) { Mapricot.parser = :hpricot }
|
53
|
+
it_should_behave_like HasOneId
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "has one id, parsing with libxml" do
|
57
|
+
before(:all) { Mapricot.parser = :libxml }
|
58
|
+
it_should_behave_like HasOneId
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "has one id, parsing with nokogiri" do
|
62
|
+
before(:all) { Mapricot.parser = :nokogiri }
|
63
|
+
it_should_behave_like HasOneId
|
64
|
+
end
|