lzell-mapricot 0.0.3.2 → 0.0.3.8
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/lib/mapricot.rb +6 -203
- data/lib/{abstract_doc.rb → mapricot/abstract_doc.rb} +1 -1
- data/lib/mapricot/associations.rb +100 -0
- data/lib/mapricot/attribute.rb +22 -0
- data/lib/mapricot/base.rb +81 -0
- data/mapricot.gemspec +13 -11
- data/test/has_attribute/test_has_attribute.rb +42 -0
- data/test/has_many/test_has_many_ids.rb +55 -0
- data/test/has_many/test_has_many_nested.rb +81 -0
- data/test/has_one/test_has_one_id.rb +25 -0
- data/test/has_one/test_has_one_nested.rb +31 -0
- data/test/suite.rb +15 -3
- data/test/test_abstract_doc.rb +41 -0
- data/test/test_mapricot.rb +4 -1
- data/test/test_mapricot_readme.rb +36 -40
- metadata +13 -11
- data/test/abstract_doc_spec.rb +0 -79
- data/test/has_attribute/has_attribute_spec.rb +0 -57
- data/test/has_many/has_many_ids_spec.rb +0 -73
- data/test/has_many/has_many_nested_spec.rb +0 -116
- data/test/has_one/has_one_id_spec.rb +0 -64
- data/test/has_one/has_one_nested_spec.rb +0 -97
- data/test/has_one/has_one_user_spec.rb +0 -67
data/lib/mapricot.rb
CHANGED
@@ -1,210 +1,13 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'active_support/inflector'
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + "/abstract_doc")
|
4
3
|
|
5
4
|
module Mapricot
|
6
5
|
VERSION = "0.0.3.2"
|
7
|
-
|
8
|
-
# Inherit from base, e.g. class Animal < Mapricot::Base
|
9
|
-
# Use either a string of xml or a url to initialize
|
10
|
-
class Base
|
11
|
-
|
12
|
-
class << self
|
13
|
-
# @associations is used to initialize instance variables
|
14
|
-
# creates a new HasOneAssociation and appends it to the @association_list
|
15
|
-
def has_one(name, type = :string, opts = {})
|
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
|
21
|
-
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
22
|
-
end
|
23
|
-
|
24
|
-
# creates a new HasManyAssociation and appends it to the @association_list
|
25
|
-
def has_many(name, type = :string, opts = {})
|
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
|
31
|
-
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
32
|
-
end
|
33
|
-
|
34
|
-
def has_attribute(name, type = :string)
|
35
|
-
attribute_list << Attribute.new(name, type)
|
36
|
-
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
37
|
-
end
|
38
|
-
|
39
|
-
def association_list
|
40
|
-
@association_list ||= []
|
41
|
-
end
|
42
|
-
|
43
|
-
def attribute_list
|
44
|
-
@attribute_list ||= []
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# class SomeClass < Mapricot::Base; end;
|
49
|
-
# SomeClass.new :url => "http://some_url"
|
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
|
53
|
-
def initialize(opts)
|
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
|
59
|
-
end
|
60
|
-
|
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}
|
64
|
-
end
|
65
|
-
|
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
|
-
end
|
72
|
-
end
|
73
|
-
|
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
|
-
end
|
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
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
# Abstract class; used to subclass HasOneAssociation and HasManyAssociation
|
91
|
-
class Association
|
92
|
-
VALID_TYPES = [:integer, :time, :xml, :string]
|
93
|
-
|
94
|
-
attr_accessor :name, :type, :value
|
95
|
-
attr_accessor :namespace
|
96
|
-
|
97
|
-
def initialize(name, type, opts = {})
|
98
|
-
raise "Don't instantiate me" if abstract_class?
|
99
|
-
@name, @type, @opts = name, type, opts
|
100
|
-
@namespace = nil
|
101
|
-
end
|
102
|
-
|
103
|
-
def tag_name
|
104
|
-
@opts[:tag_name] || singular_name
|
105
|
-
end
|
106
|
-
|
107
|
-
private
|
108
|
-
def typecast
|
109
|
-
raise "association type is invalid" unless VALID_TYPES.include?(@type)
|
110
|
-
if [:integer, :time].include?(@type)
|
111
|
-
@value = self.send("typecast_#{@type}")
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def typecast_integer
|
116
|
-
@value.is_a?(Array) ? @value.collect {|v| v.to_i} : @value.to_i
|
117
|
-
end
|
118
|
-
|
119
|
-
# oh, forgot about this, need to add to readme
|
120
|
-
def typecast_time
|
121
|
-
if @value.is_a?(Array)
|
122
|
-
@value.collect {|v| Time.parse(v) }
|
123
|
-
else
|
124
|
-
Time.parse(@value)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def abstract_class?
|
129
|
-
self.class == Association
|
130
|
-
end
|
131
|
-
|
132
|
-
def singular_name
|
133
|
-
@name.to_s
|
134
|
-
end
|
135
|
-
|
136
|
-
def class_from_name
|
137
|
-
# ok, first we have to find how the class that inherited from Mapricot::Base is namespaced
|
138
|
-
# the class will an @associations class instance var, that will hold an instance of
|
139
|
-
if @namespace
|
140
|
-
"#{@namespace}::#{singular_name.classify}".constantize
|
141
|
-
else
|
142
|
-
singular_name.classify.constantize
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
def set_value_from_node_list(node_list)
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
|
152
|
-
class HasOneAssociation < Association
|
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
|
159
|
-
if @type == :xml
|
160
|
-
@value = class_from_name.new(:xml => node_list.first.to_s)
|
161
|
-
else
|
162
|
-
@value = node_list.first.contents
|
163
|
-
typecast
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
|
170
|
-
class HasManyAssociation < Association
|
6
|
+
end
|
171
7
|
|
172
|
-
|
173
|
-
"#{@name}".singularize
|
174
|
-
end
|
175
|
-
|
176
|
-
def set_value_from_node_list(node_list)
|
177
|
-
@value = []
|
178
|
-
node_list.each do |node|
|
179
|
-
if @type == :xml
|
180
|
-
@value << class_from_name.new(:xml => node.to_s)
|
181
|
-
else
|
182
|
-
@value << node.contents
|
183
|
-
end
|
184
|
-
end
|
185
|
-
typecast
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
|
190
|
-
class Attribute
|
191
|
-
attr_accessor :name, :type, :value
|
8
|
+
path = File.expand_path(File.join(File.dirname(__FILE__), 'mapricot'))
|
192
9
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
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
|
210
|
-
end
|
10
|
+
require File.join(path, 'base')
|
11
|
+
require File.join(path, 'abstract_doc')
|
12
|
+
require File.join(path, 'associations')
|
13
|
+
require File.join(path, 'attribute')
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Mapricot
|
2
|
+
# Abstract class; used to subclass HasOneAssociation and HasManyAssociation
|
3
|
+
class Association
|
4
|
+
VALID_TYPES = [:integer, :time, :xml, :string]
|
5
|
+
|
6
|
+
attr_accessor :name, :type, :value
|
7
|
+
attr_accessor :namespace
|
8
|
+
|
9
|
+
def initialize(name, type, opts = {})
|
10
|
+
raise "Don't instantiate me" if abstract_class?
|
11
|
+
@name, @type, @opts = name, type, opts
|
12
|
+
@namespace = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def tag_name
|
16
|
+
@opts[:tag_name] || singular_name
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def typecast
|
21
|
+
raise "association type is invalid" unless VALID_TYPES.include?(@type)
|
22
|
+
if [:integer, :time].include?(@type)
|
23
|
+
@value = self.send("typecast_#{@type}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def typecast_integer
|
28
|
+
@value.is_a?(Array) ? @value.collect {|v| v.to_i} : @value.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
# oh, forgot about this, need to add to readme
|
32
|
+
def typecast_time
|
33
|
+
if @value.is_a?(Array)
|
34
|
+
@value.collect {|v| Time.parse(v) }
|
35
|
+
else
|
36
|
+
Time.parse(@value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def abstract_class?
|
41
|
+
self.class == Association
|
42
|
+
end
|
43
|
+
|
44
|
+
def singular_name
|
45
|
+
@name.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def class_from_name
|
49
|
+
# ok, first we have to find how the class that inherited from Mapricot::Base is namespaced
|
50
|
+
# the class will an @associations class instance var, that will hold an instance of
|
51
|
+
if @namespace
|
52
|
+
"#{@namespace}::#{singular_name.classify}".constantize
|
53
|
+
else
|
54
|
+
singular_name.classify.constantize
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_value_from_node_list(node_list)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
class HasOneAssociation < Association
|
64
|
+
|
65
|
+
# pass a node list, depending on the type of association
|
66
|
+
def set_value_from_node_list(node_list)
|
67
|
+
if node_list.empty?
|
68
|
+
@value = nil
|
69
|
+
else
|
70
|
+
if @type == :xml
|
71
|
+
@value = class_from_name.new(:xml => node_list.first.to_s)
|
72
|
+
else
|
73
|
+
@value = node_list.first.contents
|
74
|
+
typecast
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
class HasManyAssociation < Association
|
82
|
+
|
83
|
+
def singular_name
|
84
|
+
"#{@name}".singularize
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_value_from_node_list(node_list)
|
88
|
+
@value = []
|
89
|
+
node_list.each do |node|
|
90
|
+
if @type == :xml
|
91
|
+
@value << class_from_name.new(:xml => node.to_s)
|
92
|
+
else
|
93
|
+
@value << node.contents
|
94
|
+
end
|
95
|
+
end
|
96
|
+
typecast
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Mapricot
|
2
|
+
class Attribute
|
3
|
+
attr_accessor :name, :type, :value
|
4
|
+
|
5
|
+
def initialize(name, type)
|
6
|
+
@name = name
|
7
|
+
@type = type
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_value_from_node(node)
|
11
|
+
@value = node.attributes[name.to_s]
|
12
|
+
typecast
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def typecast
|
17
|
+
if !@value.nil? && !@value.empty? && @type == :integer
|
18
|
+
@value = @value.to_i
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Mapricot
|
2
|
+
# Inherit from base, e.g. class Animal < Mapricot::Base
|
3
|
+
# Use either a string of xml or a url to initialize
|
4
|
+
class Base
|
5
|
+
|
6
|
+
class << self
|
7
|
+
# @associations is used to initialize instance variables
|
8
|
+
# creates a new HasOneAssociation and appends it to the @association_list
|
9
|
+
def has_one(name, type = :string, opts = {})
|
10
|
+
association = HasOneAssociation.new(name, type, opts)
|
11
|
+
if self.name.match(/::/)
|
12
|
+
association.namespace = self.name.match(/(.*)::[^:]+$/)[1]
|
13
|
+
end
|
14
|
+
association_list << association
|
15
|
+
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
16
|
+
end
|
17
|
+
|
18
|
+
# creates a new HasManyAssociation and appends it to the @association_list
|
19
|
+
def has_many(name, type = :string, opts = {})
|
20
|
+
association = HasManyAssociation.new(name, type, opts)
|
21
|
+
if self.name.match(/::/)
|
22
|
+
association.namespace = self.name.match(/(.*)::[^:]+$/)[1]
|
23
|
+
end
|
24
|
+
association_list << association
|
25
|
+
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_attribute(name, type = :string)
|
29
|
+
attribute_list << Attribute.new(name, type)
|
30
|
+
class_eval "attr_reader :#{name}", __FILE__, __LINE__
|
31
|
+
end
|
32
|
+
|
33
|
+
def association_list
|
34
|
+
@association_list ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
def attribute_list
|
38
|
+
@attribute_list ||= []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# class SomeClass < Mapricot::Base; end;
|
43
|
+
# SomeClass.new :url => "http://some_url"
|
44
|
+
# SomeClass.new :xml => %(<hi></hi>)
|
45
|
+
# the class instance variable @association_list is duplicated in every instance of Feed, as the instance variable @associations.
|
46
|
+
# i.e. Feed.association_list is the template for feed.associations
|
47
|
+
def initialize(opts)
|
48
|
+
@doc = AbstractDoc.from_url(opts[:url]) if opts[:url]
|
49
|
+
@doc = AbstractDoc.from_string(opts[:xml]) if opts[:xml]
|
50
|
+
dup_associations_and_attributes
|
51
|
+
map_associations
|
52
|
+
map_attributes
|
53
|
+
end
|
54
|
+
|
55
|
+
def dup_associations_and_attributes
|
56
|
+
@associations = self.class.association_list.collect {|x| x.dup} # do not do this: self.class.association_list.dup
|
57
|
+
@attributes = self.class.attribute_list.collect {|x| x.dup}
|
58
|
+
end
|
59
|
+
|
60
|
+
def map_associations
|
61
|
+
@associations.each do |association|
|
62
|
+
node_list = @doc.find(association.tag_name)
|
63
|
+
association.set_value_from_node_list(node_list)
|
64
|
+
instance_variable_set("@#{association.name}", association.value)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def map_attributes
|
69
|
+
@attributes.each do |attribute|
|
70
|
+
node = @doc.find(tag_name).first
|
71
|
+
attribute.set_value_from_node(node)
|
72
|
+
instance_variable_set("@#{attribute.name}", attribute.value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# associations and base classes both have tag_name method
|
77
|
+
def tag_name
|
78
|
+
self.class.name.downcase.match(/[^:]+$/)[0]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
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.3.
|
4
|
-
s.date = "2009-
|
3
|
+
s.version = "0.0.3.8"
|
4
|
+
s.date = "2009-05-27"
|
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"
|
@@ -13,24 +13,26 @@ Gem::Specification.new do |s|
|
|
13
13
|
"History.txt",
|
14
14
|
"License.txt",
|
15
15
|
"mapricot.gemspec",
|
16
|
+
"examples/facebook_api.rb",
|
16
17
|
"examples/lastfm_api.rb",
|
17
18
|
"examples/lastfm_api_no_request.rb",
|
18
|
-
"examples/facebook_api.rb",
|
19
19
|
"examples/natural_inputs.rb",
|
20
20
|
"examples/readme_examples.rb",
|
21
21
|
"examples/xml_with_attributes.rb",
|
22
22
|
"test/suite.rb",
|
23
|
-
"test/
|
23
|
+
"test/test_abstract_doc.rb",
|
24
24
|
"test/test_mapricot.rb",
|
25
25
|
"test/test_mapricot_readme.rb",
|
26
|
-
"test/has_attribute/
|
27
|
-
"test/has_many/
|
28
|
-
"test/has_many/
|
29
|
-
"test/has_one/
|
30
|
-
"test/has_one/
|
31
|
-
"test/has_one/has_one_nested_spec.rb",
|
26
|
+
"test/has_attribute/test_has_attribute.rb",
|
27
|
+
"test/has_many/test_has_many_ids.rb",
|
28
|
+
"test/has_many/test_has_many_nested.rb",
|
29
|
+
"test/has_one/test_has_one_id.rb",
|
30
|
+
"test/has_one/test_has_one_nested.rb",
|
32
31
|
"lib/mapricot.rb",
|
33
|
-
"lib/abstract_doc.rb",
|
32
|
+
"lib/mapricot/abstract_doc.rb",
|
33
|
+
"lib/mapricot/associations.rb",
|
34
|
+
"lib/mapricot/attribute.rb",
|
35
|
+
"lib/mapricot/base.rb",
|
34
36
|
"benchmark/benchmarks.rb"]
|
35
37
|
s.require_paths = ["lib"]
|
36
38
|
s.rdoc_options = ["--main", "README.rdoc", "--title", "Mapricot"]
|