lzell-mapricot 0.0.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 ADDED
@@ -0,0 +1,3 @@
1
+ == 0.0.1 2009-03-06
2
+
3
+ First gem!
data/License.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Louis Zell <lzell11@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,118 @@
1
+ == Mapricot
2
+
3
+ Makes working with XML stupid easy. XML to object mapper with an interface similar to ActiveRecord associations.
4
+
5
+
6
+ == Install
7
+
8
+ Do some stuff...
9
+
10
+ == Usage
11
+
12
+ Your classes should inherit from Mapricot::Base, which provides the class methods
13
+ * has_one(name, type, opts = {})
14
+ * has_many(name, type, opts = {})
15
+ * has_attribute(name)
16
+
17
+ When you instantiate a Mapricot::Base object, you can pass it a string of xml:
18
+ class MapMe < Mapricot::Base
19
+ end
20
+
21
+ MapMe.new :xml => "<some_stuff>...</some_stuff>"
22
+
23
+ Or you can pass it a url:
24
+ class MapMeToo < Mapricot::Base
25
+ end
26
+
27
+ MapMeToo.new :url => "http://some_url"
28
+
29
+ == Examples
30
+
31
+ ==== Super Simple
32
+
33
+ simple_xml = %(
34
+ <user>
35
+ <id>1</name>
36
+ <name>Bob</name>
37
+ <pet>cat</pet>
38
+ <pet>dog</pet>
39
+ </user>
40
+ )
41
+
42
+ class User < Mapricot::Base
43
+ has_one :id, :integer
44
+ has_one :name, :string
45
+ has_many :pets, :string
46
+ end
47
+
48
+ user = User.new(:xml => simple_xml)
49
+ puts user.id # => 1
50
+ puts user.id.class # => Fixnum
51
+ puts user.name # => Bob
52
+ puts user.pets.class # => Array
53
+ puts user.pets.join(", ") # => cat, dog
54
+
55
+
56
+ ==== A little more realistic
57
+
58
+ xml = %(
59
+ <user>
60
+ <id>2</name>
61
+ <name>Sally</name>
62
+ <location code="ny123">
63
+ <city>New York</city>
64
+ <state>NY</state>
65
+ </location>
66
+ <hobby>
67
+ <description>Skiing</description>
68
+ <number_of_years>2</number_of_years>
69
+ </hobby>
70
+ <hobby>
71
+ <description>Hiking</description>
72
+ <number_of_years>3</number_of_years>
73
+ </hobby>
74
+ </user>
75
+ )
76
+
77
+
78
+ class User < Mapricot::Base
79
+ has_one :id, :integer
80
+ has_one :name # Tag type will default to :string
81
+ has_many :pets
82
+ has_one :location, :xml
83
+ has_many :hobbies, :xml
84
+ end
85
+
86
+ class Location < Mapricot::Base
87
+ has_attribute :code
88
+ has_one :city
89
+ has_one :state
90
+ end
91
+
92
+ class Hobby < Mapricot::Base
93
+ has_one :description, :string
94
+ has_one :number_of_years, :integer
95
+ end
96
+
97
+ user = User.new(:xml => xml)
98
+ puts user.name # => Sally
99
+ puts user.pets.inspect # => []
100
+ puts user.location.class # => Location
101
+ puts user.location.city # => New York
102
+ puts user.location.state # => NY
103
+ puts user.location.code # => ny123
104
+ puts user.hobbies.class # => Array
105
+ puts user.hobbies.first.class # => Hobby
106
+
107
+ user.hobbies.each do |hobby|
108
+ puts "#{hobby.description} for #{hobby.number_of_years} years"
109
+ end
110
+ # => Skiing for 2 years
111
+ # => Hiking for 3 years
112
+
113
+ == Credits
114
+
115
+ All to why the luck stiff for Hpricot.
116
+
117
+
118
+ Copyright (c) 2009 Lou Zell, released under the MIT license
@@ -0,0 +1,41 @@
1
+ # Get events in nyc with:
2
+ # http://ws.audioscrobbler.com/2.0/?method=geo.getevents&city=new+york&api_key=YOUR_API_KEY_HERE
3
+
4
+ # The point of this is to demonstrate mapping xml from a real api response.
5
+ # The only difference is you instantiate with:
6
+ # Response.new(:url => "http://someurl")
7
+ # instead of:
8
+ # Response.new(:xml => "some string of xml")
9
+
10
+ # If you do not have an API key, see examples/lastfm_api_no_request.rb
11
+ require '../lib/mapricot'
12
+
13
+ class Response < Mapricot::Base
14
+ has_many :events, :xml
15
+ end
16
+
17
+ class Event < Mapricot::Base
18
+ has_one :title
19
+ has_one :venue, :xml
20
+ end
21
+
22
+ class Venue < Mapricot::Base
23
+ has_one :name
24
+ has_one :location, :xml
25
+ end
26
+
27
+ class Location < Mapricot::Base
28
+ has_one :city
29
+ has_one :country
30
+ has_one :street
31
+ has_one :postalcode, :integer
32
+ end
33
+
34
+ response = Response.new(:url => "http://ws.audioscrobbler.com/2.0/?method=geo.getevents&city=new+york&api_key=#{YOUR_API_KEY_HERE}")
35
+
36
+ response.events.each do |event|
37
+ puts "-------------"
38
+ puts event.title
39
+ puts event.venue.name
40
+ puts event.venue.location.city
41
+ end
@@ -0,0 +1,126 @@
1
+ require '../lib/mapricot'
2
+
3
+
4
+ last_fm_example = %(
5
+ <?xml version="1.0" encoding="utf-8"?>
6
+ <lfm status="ok">
7
+ <events location="New York, United States" page="1" totalpages="92" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" total="917">
8
+ <event>
9
+ <id>895664</id>
10
+ <title>Lydia</title>
11
+ <artists>
12
+ <artist>Lydia</artist>
13
+ <artist>Black Gold</artist>
14
+
15
+ <headliner>Lydia</headliner>
16
+ </artists>
17
+ <venue>
18
+ <name>Mercury Lounge</name>
19
+ <location>
20
+ <city>New York</city>
21
+ <country>United States</country>
22
+
23
+ <street>217 East Houston Street</street>
24
+ <postalcode>10002</postalcode>
25
+ <geo:point>
26
+ <geo:lat>40.722024</geo:lat>
27
+ <geo:long>-73.98682</geo:long>
28
+ </geo:point>
29
+ <timezone>EST</timezone>
30
+
31
+ </location>
32
+ <url>http://www.last.fm/venue/8899833</url>
33
+ </venue>
34
+ <startDate>Thu, 05 Mar 2009</startDate>
35
+ <startTime>18:30</startTime>
36
+ <description><![CDATA[<div class="bbcode">On Sale Fri 1/16 at Noon<br />
37
+ 21+<br />
38
+ $10<br />
39
+ Doors 6:30pm/ Show 7:30pm</div>]]></description>
40
+ <image size="small">http://userserve-ak.last.fm/serve/34/9158303.jpg</image>
41
+
42
+ <image size="medium">http://userserve-ak.last.fm/serve/64/9158303.jpg</image>
43
+ <image size="large">http://userserve-ak.last.fm/serve/126/9158303.jpg</image>
44
+ <attendance>7</attendance>
45
+ <reviews>0</reviews>
46
+ <tag>lastfm:event=895664</tag>
47
+ <url>http://www.last.fm/event/895664</url>
48
+
49
+ </event>
50
+ <event>
51
+ <id>924763</id>
52
+ <title>Stars Like Fleas</title>
53
+ <artists>
54
+ <artist>Stars Like Fleas</artist>
55
+
56
+ <artist>Frances</artist>
57
+ <artist>twi the humble feather</artist>
58
+ <artist>La Strada</artist>
59
+ <headliner>Stars Like Fleas</headliner>
60
+ </artists>
61
+ <venue>
62
+ <name>Music Hall of Williamsburg</name>
63
+
64
+ <location>
65
+ <city>Brooklyn, NY</city>
66
+ <country>United States</country>
67
+ <street>66 North 6th Street</street>
68
+ <postalcode>11211</postalcode>
69
+ <geo:point>
70
+ <geo:lat>40.719308</geo:lat>
71
+
72
+ <geo:long>-73.961607</geo:long>
73
+ </geo:point>
74
+ <timezone>EST</timezone>
75
+ </location>
76
+ <url>http://www.last.fm/venue/8851989</url>
77
+ </venue>
78
+ <startDate>Thu, 05 Mar 2009</startDate>
79
+
80
+ <startTime>19:00</startTime>
81
+ <description><![CDATA[<div class="bbcode">Doors 7 p.m. / Show 8 p.m.<br />
82
+ $10 advance / $12 day of show<br />
83
+ 18+<br />
84
+ <br />
85
+ On sale Wed. 2/4 at noon</div>]]></description>
86
+ <image size="small">http://userserve-ak.last.fm/serve/34/3598785.jpg</image>
87
+ <image size="medium">http://userserve-ak.last.fm/serve/64/3598785.jpg</image>
88
+ <image size="large">http://userserve-ak.last.fm/serve/126/3598785.jpg</image>
89
+ <attendance>1</attendance>
90
+
91
+ <reviews>0</reviews>
92
+ <tag>lastfm:event=924763</tag>
93
+ <url>http://www.last.fm/event/924763</url>
94
+ </event>
95
+ </events></lfm>
96
+
97
+ )
98
+
99
+
100
+ class Response < Mapricot::Base
101
+ has_many :events, :xml
102
+ end
103
+
104
+ class Event < Mapricot::Base
105
+ has_one :id, :integer
106
+ has_one :title, :string
107
+ has_one :artist_group, :xml, :tag_name => "artists"
108
+ has_one :venue, :xml
109
+ end
110
+
111
+ class ArtistGroup < Mapricot::Base
112
+ has_many :artists, :string
113
+ has_one :headliner, :string
114
+ end
115
+
116
+ class Venue < Mapricot::Base
117
+ has_one :name, :string
118
+ end
119
+
120
+ lfm = Response.new(:xml => last_fm_example)
121
+ lfm.events.each do |event|
122
+ puts "-------------------------------"
123
+ puts event.title
124
+ puts event.artist_group.artists.inspect
125
+ puts event.venue.name
126
+ end
@@ -0,0 +1,22 @@
1
+ # Coming soon!
2
+ # class NaturalInputs < Mapricot
3
+ # has_one :message, :string
4
+ # has_many :occurrences, :xml
5
+ # end
6
+ #
7
+ #
8
+ # class Occurrence < Mapricot::Base
9
+ # has_one :start_date
10
+ # has_one :end_date
11
+ # has_one :interval
12
+ # has_one :day_of_week
13
+ # has_one :week_of_month
14
+ # has_one :start_time
15
+ # has_one :end_time
16
+ # has_one :date_of_month
17
+ # end
18
+ #
19
+ #
20
+ # n = NaturalInputs.new("http://localhost:3000/query?q=lunch+this+friday+with+maria")
21
+ # puts n.message # => "lunch with maria"
22
+ # puts n.occurrences.first.start_date # => "2009-01-16"
@@ -0,0 +1,82 @@
1
+ require '../lib/mapricot'
2
+
3
+ # super simple
4
+ simple_xml = %(
5
+ <user>
6
+ <id>1</name>
7
+ <name>Bob</name>
8
+ <pet>cat</pet>
9
+ <pet>dog</pet>
10
+ </user>
11
+ )
12
+
13
+ class User < Mapricot::Base
14
+ has_one :id, :integer
15
+ has_one :name, :string
16
+ has_many :pets, :string
17
+ end
18
+
19
+ user = User.new(:xml => simple_xml)
20
+ puts user.id # => 1
21
+ puts user.id.class # => Fixnum
22
+ puts user.name # => Bob
23
+ puts user.pets.class # => Array
24
+ puts user.pets.join(", ") # => cat, dog
25
+
26
+ puts "-------------------"
27
+
28
+ # A little more realistic
29
+ xml = %(
30
+ <user>
31
+ <id>2</name>
32
+ <name>Sally</name>
33
+ <location code="ny123">
34
+ <city>New York</city>
35
+ <state>NY</state>
36
+ </location>
37
+ <hobby>
38
+ <description>Skiing</description>
39
+ <number_of_years>2</number_of_years>
40
+ </hobby>
41
+ <hobby>
42
+ <description>Hiking</description>
43
+ <number_of_years>3</number_of_years>
44
+ </hobby>
45
+ </user>
46
+ )
47
+
48
+
49
+ class User < Mapricot::Base
50
+ has_one :id, :integer
51
+ has_one :name # Tag type will default to :string
52
+ has_many :pets
53
+ has_one :location, :xml
54
+ has_many :hobbies, :xml
55
+ end
56
+
57
+ class Location < Mapricot::Base
58
+ has_attribute :code
59
+ has_one :city
60
+ has_one :state
61
+ end
62
+
63
+ class Hobby < Mapricot::Base
64
+ has_one :description, :string
65
+ has_one :number_of_years, :integer
66
+ end
67
+
68
+ user = User.new(:xml => xml)
69
+ puts user.name # => Sally
70
+ puts user.pets.inspect # => []
71
+ puts user.location.class # => Location
72
+ puts user.location.city # => New York
73
+ puts user.location.state # => NY
74
+ puts user.location.code # => ny123
75
+ puts user.hobbies.class # => Array
76
+ puts user.hobbies.first.class # => Hobby
77
+
78
+ user.hobbies.each do |hobby|
79
+ puts "#{hobby.description} for #{hobby.number_of_years} years"
80
+ end
81
+ # => Skiing for 2 years
82
+ # => Hiking for 3 years
data/lib/mapricot.rb ADDED
@@ -0,0 +1,174 @@
1
+ require 'open-uri'
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
9
+ require 'active_support/inflector'
10
+
11
+ module Mapricot
12
+
13
+ # Inherit from base, e.g. class Animal < Mapricot::Base
14
+ # Use either a string of xml or a url to initialize
15
+ class Base
16
+ class << self
17
+ # @associations is used to initialize instance variables
18
+ # creates a new HasOneAssociation and appends it to the @associations list
19
+ def has_one(name, type = :string, opts = {})
20
+ ass = HasOneAssociation.new(name, type, opts)
21
+ self.name.match(/::/) && ass.namespace = self.name.match(/(.*)::[^:]+$/)[1]
22
+ associations << ass
23
+ class_eval "attr_reader :#{name}", __FILE__, __LINE__
24
+ end
25
+ # creates a new HasManyAssociation and appends it to the @associations list
26
+ def has_many(name, type = :string, opts = {})
27
+ ass = HasManyAssociation.new(name, type, opts)
28
+ self.name.match(/::/) && ass.namespace = self.name.match(/(.*)::[^:]+$/)[1]
29
+ associations << ass
30
+ class_eval "attr_reader :#{name}", __FILE__, __LINE__
31
+ end
32
+ def has_attribute(name)
33
+ attributes << name
34
+ class_eval "attr_reader :#{name}", __FILE__, __LINE__
35
+ end
36
+ def associations
37
+ @associations ||= []
38
+ end
39
+ def attributes
40
+ @attributes ||= []
41
+ end
42
+ end
43
+
44
+ # class SomeClass < Mapricot::Base; end;
45
+ # SomeClass.new :url => "http://some_url"
46
+ # SomeClass.new :xml => %(<hi></hi>)
47
+ def initialize(opts)
48
+ @xml = Hpricot::XML(open(opts[:url])) if opts[:url]
49
+ @xml = Hpricot::XML(opts[:xml]) if opts[:xml]
50
+ load_associations
51
+ load_attributes
52
+ end
53
+
54
+ # searches xml for a tag with association.name, sets association.value to the inner html of this tag and typecasts it
55
+ def load_has_one(has_one_association)
56
+ has_one_association.search(@xml)
57
+ end
58
+
59
+ def load_has_many(has_many_association)
60
+ has_many_association.search(@xml)
61
+ end
62
+
63
+ def load_associations
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)
71
+ end
72
+ end
73
+
74
+ def load_attributes
75
+ attr_list = self.class.instance_variable_get(:@attributes)
76
+ attr_list && attr_list.each do |att|
77
+ val = (@xml/self.class.name.downcase.match(/[^:]+$/)[0]).first.attributes[att.to_s]
78
+ instance_variable_set("@#{att}", val)
79
+ end
80
+ end
81
+ end
82
+
83
+ # Abstract class; used to subclass HasOneAssociation and HasManyAssociation
84
+ class Association
85
+ VALID_TYPES = [:integer, :time, :xml, :string]
86
+
87
+ attr_accessor :name, :type, :value
88
+ attr_accessor :namespace
89
+ def initialize(name, type, opts = {})
90
+ raise "Don't instantiate me" if abstract_class?
91
+ @name, @type, @opts = name, type, opts
92
+ @namespace = nil
93
+ end
94
+
95
+ def typecast
96
+ raise "association type is invalid" unless VALID_TYPES.include?(@type)
97
+ if [:integer, :time].include?(@type)
98
+ @value = self.send("typecast_#{@type}")
99
+ end
100
+ end
101
+
102
+ def typecast_integer
103
+ @value.is_a?(Array) ? @value.collect {|v| v.to_i} : @value.to_i
104
+ end
105
+
106
+ def typecast_time
107
+ if @value.is_a?(Array)
108
+ @value.collect {|v| Time.parse(v) }
109
+ else
110
+ Time.parse(@value)
111
+ end
112
+ end
113
+
114
+ private
115
+ def abstract_class?
116
+ self.class == Association
117
+ end
118
+
119
+ def singular_name
120
+ @name.to_s
121
+ end
122
+
123
+ def class_from_name
124
+ # ok, first we have to find how the class that inherited from Mapricot::Base is namespaced
125
+ # the class will an @associations class instance var, that will hold an instance of
126
+ if @namespace
127
+ "#{@namespace}::#{singular_name.classify}".constantize
128
+ else
129
+ singular_name.classify.constantize
130
+ end
131
+ end
132
+ end
133
+
134
+
135
+ class HasOneAssociation < Association
136
+ # searches xml for tag name, sets the inner xml as association value and typecasts it
137
+ def search(xml)
138
+ # if tag_name option was passed, use it:
139
+ element = (xml/"#{ @opts[:tag_name] || @name }").first # class Hpricot::Elements
140
+ if element
141
+ if @type == :xml
142
+ @value = class_from_name.new(:xml => element.to_s) # we want to include the tag, not just the inner_html
143
+ else
144
+ @value = element.inner_html
145
+ end
146
+ self.typecast
147
+ end
148
+ end
149
+ end
150
+
151
+
152
+ class HasManyAssociation < Association
153
+
154
+ def singular_name
155
+ # @name.to_s[0..-2]
156
+ "#{@name}".singularize
157
+ end
158
+
159
+ # searches xml for all occurrences of self.singular_name, the inner xml from each tag is stored in an array and set as the association value
160
+ # finally, each element in the array is typecast
161
+ def search(xml)
162
+ @value = []
163
+ (xml/"#{@opts[:tag_name] || self.singular_name}").each do |tag|
164
+ if @type == :xml
165
+ @value << class_from_name.new(:xml => tag.to_s) # a bit of recursion if the inner xml is more xml
166
+ else
167
+ @value << tag.inner_html # in the case of a string, integer, etc.
168
+ end
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ end
data/mapricot.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "mapricot"
3
+ s.version = "0.0.1"
4
+ s.date = "2009-03-06"
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.summary = "XML to object mapper"
7
+ s.email = "lzell11@gmail.com"
8
+ s.homepage = ""
9
+ s.description = "Makes working with XML stupid easy. XML to object mapper with an interface similar to ActiveRecord associations."
10
+ s.has_rdoc = true
11
+ s.authors = ["Lou Zell"]
12
+ s.files = ["README.rdoc",
13
+ "History.txt",
14
+ "License.txt",
15
+ "mapricot.gemspec",
16
+ "examples/lastfm_api.rb",
17
+ "examples/lastfm_api_no_request.rb",
18
+ "examples/natural_inputs.rb",
19
+ "examples/readme_examples.rb",
20
+ "test/mapricot_tests.rb",
21
+ "test/mapricot_spec.rb",
22
+ "lib/mapricot.rb"]
23
+ s.require_paths = ["lib"]
24
+ s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--title", "Mapricot"]
25
+ s.extra_rdoc_files = ["README.rdoc"]
26
+ s.add_dependency("hpricot")
27
+ end
28
+
@@ -0,0 +1,118 @@
1
+ require '../lib/mapricot'
2
+ require 'spec'
3
+
4
+ # Using a Facebook example:
5
+ XML = %(
6
+ <?xml version="1.0" encoding="UTF-8"?>
7
+ <users_getInfo_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
8
+ <user>
9
+ <uid>8055</uid>
10
+ <about_me>This field perpetuates the glorification of the ego. Also, it has a character limit.</about_me>
11
+ <activities>Here: facebook, etc. There: Glee Club, a capella, teaching.</activities>
12
+ <affiliations list="true">
13
+ <affiliation>
14
+ <nid>50453093</nid>
15
+ <name>Facebook Developers</name>
16
+ <type>work</type>
17
+ <status/>
18
+ <year/>
19
+ </affiliation>
20
+ </affiliations>
21
+ <birthday>November 3</birthday>
22
+ <books>The Brothers K, GEB, Ken Wilber, Zen and the Art, Fitzgerald, The Emporer's New Mind, The Wonderful Story of Henry Sugar</books>
23
+ <current_location>
24
+ <city>Palo Alto</city>
25
+ <state>CA</state>
26
+ <country>United States</country>
27
+ <zip>94303</zip>
28
+ </current_location>
29
+ </user>
30
+ </users_getInfo_reponse>
31
+ )
32
+
33
+
34
+ class UsersGetInfoResponse < Mapricot::Base
35
+ has_many :users, :xml
36
+ end
37
+
38
+ class User < Mapricot::Base
39
+ has_one :uid, :integer
40
+ has_one :about_me, :string
41
+ has_one :activities, :string
42
+ has_one :affiliation_list, :xml, :tag_name => "affiliations" # this is cumbersome, do something about this
43
+ has_one :birthday, :string
44
+ has_one :current_location, :xml
45
+ end
46
+
47
+ class AffiliationList < Mapricot::Base
48
+ has_many :affiliations, :xml
49
+ end
50
+
51
+ class Affiliation < Mapricot::Base
52
+ has_one :nid, :integer
53
+ has_one :name, :string
54
+ has_one :type, :string
55
+ has_one :status, :string
56
+ has_one :year, :integer
57
+ end
58
+
59
+ class CurrentLocation < Mapricot::Base
60
+ has_one :city, :string
61
+ has_one :state, :string
62
+ has_one :country, :string
63
+ has_one :zip, :integer
64
+ end
65
+
66
+
67
+ describe UsersGetInfoResponse do
68
+ before(:all) { @response = UsersGetInfoResponse.new(:xml => XML) }
69
+
70
+ it "should respond to users" do
71
+ @response.should respond_to(:users)
72
+ end
73
+
74
+ it "should return an array of size 1 when sent users" do
75
+ @response.users.class.should equal(Array)
76
+ @response.users.size.should equal(1)
77
+ end
78
+ end
79
+
80
+ describe "response.users.first" do
81
+ before(:all) do
82
+ response = UsersGetInfoResponse.new(:xml => XML)
83
+ @first_user = response.users.first
84
+ end
85
+
86
+ it "should be of class User" do
87
+ @first_user.class.should equal(User)
88
+ end
89
+
90
+ it "should respond to activities" do
91
+ @first_user.should respond_to(:activities)
92
+ @first_user.activities.should == "Here: facebook, etc. There: Glee Club, a capella, teaching."
93
+ end
94
+
95
+ it "should respond to current_location" do
96
+ @first_user.should respond_to(:current_location)
97
+ end
98
+ end
99
+
100
+
101
+ describe "response.users.first.current_location" do
102
+ before(:all) do
103
+ response = UsersGetInfoResponse.new(:xml => XML)
104
+ @current_location = response.users.first.current_location
105
+ end
106
+
107
+ it "should have class CurrentLocation" do
108
+ @current_location.class.should equal(CurrentLocation)
109
+ end
110
+
111
+ it "should respond to city, state, country, and zip" do
112
+ @current_location.city.should == 'Palo Alto'
113
+ @current_location.state.should == 'CA'
114
+ @current_location.country.should == 'United States'
115
+ @current_location.zip.should == 94303
116
+ end
117
+ end
118
+
@@ -0,0 +1,109 @@
1
+ require '../lib/mapricot'
2
+ require 'test/unit'
3
+
4
+
5
+ # -------------------------- Test Example 1 of README.txt ------------------ #
6
+ SIMPLE_USER_XML = %(
7
+ <user>
8
+ <id>1</name>
9
+ <name>Bob</name>
10
+ <pet>cat</pet>
11
+ <pet>dog</pet>
12
+ </user>
13
+ )
14
+
15
+ class SimpleUser < Mapricot::Base
16
+ has_one :id, :integer
17
+ has_one :name, :string
18
+ has_many :pets, :string
19
+ end
20
+
21
+
22
+ class TestSimpleUser < Test::Unit::TestCase
23
+ def setup
24
+ @simple_user = SimpleUser.new(:xml => SIMPLE_USER_XML)
25
+ end
26
+
27
+ def test_everything
28
+ assert_equal @simple_user.id, 1
29
+ assert_equal @simple_user.name, "Bob"
30
+ assert_equal @simple_user.pets, ["cat", "dog"]
31
+ end
32
+ end
33
+ # -------------------------------------------------------------------------- #
34
+
35
+
36
+
37
+
38
+
39
+ # -------------------------- Test Example 2 of README.txt ------------------ #
40
+ USER_XML = %(
41
+ <user>
42
+ <id>2</name>
43
+ <name>Sally</name>
44
+ <location code="ny123">
45
+ <city>New York</city>
46
+ <state>NY</state>
47
+ </location>
48
+ <hobby>
49
+ <description>Skiing</description>
50
+ <number_of_years>2</number_of_years>
51
+ </hobby>
52
+ <hobby>
53
+ <description>Hiking</description>
54
+ <number_of_years>3</number_of_years>
55
+ </hobby>
56
+ </user>
57
+ )
58
+
59
+
60
+ class User < Mapricot::Base
61
+ has_one :id, :integer
62
+ has_one :name # Tag type will default to :string
63
+ has_many :pets
64
+ has_one :location, :xml
65
+ has_many :hobbies, :xml
66
+ end
67
+
68
+ class Location < Mapricot::Base
69
+ has_attribute :code
70
+ has_one :city
71
+ has_one :state
72
+ end
73
+
74
+ class Hobby < Mapricot::Base
75
+ has_one :description, :string
76
+ has_one :number_of_years, :integer
77
+ end
78
+
79
+ class TestUser < Test::Unit::TestCase
80
+ def setup
81
+ @user = User.new(:xml => USER_XML)
82
+ end
83
+
84
+ def test_id_and_name
85
+ assert_equal @user.id, 2
86
+ assert_equal @user.name, "Sally"
87
+ end
88
+
89
+ def test_location
90
+ assert @user.location.is_a?(Location)
91
+ assert_equal @user.location.city, "New York"
92
+ assert_equal @user.location.state, "NY"
93
+ assert_equal @user.location.code, "ny123"
94
+ end
95
+
96
+ def test_hobbies
97
+ assert @user.hobbies.is_a?(Array)
98
+ assert_equal @user.hobbies.size, 2
99
+ assert_equal @user.hobbies[0].description, "Skiing"
100
+ assert_equal @user.hobbies[0].number_of_years, 2
101
+ assert_equal @user.hobbies[1].description, "Hiking"
102
+ assert_equal @user.hobbies[1].number_of_years, 3
103
+ end
104
+
105
+ def test_pets
106
+ assert(@user.pets.empty?) # Sally has no pets
107
+ end
108
+ end
109
+ # -------------------------------------------------------------------------- #
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lzell-mapricot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Lou Zell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-06 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Makes working with XML stupid easy. XML to object mapper with an interface similar to ActiveRecord associations.
26
+ email: lzell11@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - README.rdoc
35
+ - History.txt
36
+ - License.txt
37
+ - mapricot.gemspec
38
+ - examples/lastfm_api.rb
39
+ - examples/lastfm_api_no_request.rb
40
+ - examples/natural_inputs.rb
41
+ - examples/readme_examples.rb
42
+ - test/mapricot_tests.rb
43
+ - test/mapricot_spec.rb
44
+ - lib/mapricot.rb
45
+ has_rdoc: true
46
+ homepage: ""
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --main
50
+ - README.rdoc
51
+ - --inline-source
52
+ - --title
53
+ - Mapricot
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: XML to object mapper
75
+ test_files: []
76
+