kerryb-httparty 0.3.3 → 0.4.3

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.
@@ -1,4 +0,0 @@
1
- Dir[File.dirname(__FILE__) + "/parsers/*.rb"].sort.each do |path|
2
- filename = File.basename(path)
3
- require "httparty/parsers/#{filename}"
4
- end
@@ -1,74 +0,0 @@
1
- # Copyright (c) 2004-2008 David Heinemeier Hansson
2
- # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
- # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
4
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5
-
6
- require 'yaml'
7
- require 'strscan'
8
-
9
- module HTTParty
10
- module Parsers #:nodoc:
11
- module JSON #:nodoc:
12
- class ParseError < StandardError #:nodoc:
13
- end
14
-
15
- def self.decode(json)
16
- YAML.load(unescape(convert_json_to_yaml(json)))
17
- rescue ArgumentError => e
18
- raise ParseError, "Invalid JSON string"
19
- end
20
-
21
- protected
22
-
23
- def self.unescape(str)
24
- str.gsub(/\\u([0-9a-f]{4})/) {
25
- [$1.hex].pack("U")
26
- }
27
- end
28
-
29
- # matches YAML-formatted dates
30
- DATE_REGEX = /^\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[ \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?$/
31
-
32
- # Ensure that ":" and "," are always followed by a space
33
- def self.convert_json_to_yaml(json) #:nodoc:
34
- scanner, quoting, marks, pos, times = StringScanner.new(json), false, [], nil, []
35
- while scanner.scan_until(/(\\['"]|['":,\\]|\\.)/)
36
- case char = scanner[1]
37
- when '"', "'"
38
- if !quoting
39
- quoting = char
40
- pos = scanner.pos
41
- elsif quoting == char
42
- if json[pos..scanner.pos-2] =~ DATE_REGEX
43
- # found a date, track the exact positions of the quotes so we can remove them later.
44
- # oh, and increment them for each current mark, each one is an extra padded space that bumps
45
- # the position in the final YAML output
46
- total_marks = marks.size
47
- times << pos+total_marks << scanner.pos+total_marks
48
- end
49
- quoting = false
50
- end
51
- when ":",","
52
- marks << scanner.pos - 1 unless quoting
53
- end
54
- end
55
-
56
- if marks.empty?
57
- json.gsub(/\\\//, '/')
58
- else
59
- left_pos = [-1].push(*marks)
60
- right_pos = marks << json.length
61
- output = []
62
- left_pos.each_with_index do |left, i|
63
- output << json[left.succ..right_pos[i]]
64
- end
65
- output = output * " "
66
-
67
- times.each { |i| output[i-1] = ' ' }
68
- output.gsub!(/\\\//, '/')
69
- output
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,209 +0,0 @@
1
- require 'rexml/parsers/streamparser'
2
- require 'rexml/parsers/baseparser'
3
- require 'rexml/light/node'
4
-
5
- # This is a slighly modified version of the XMLUtilityNode from
6
- # http://merb.devjavu.com/projects/merb/ticket/95 (has.sox@gmail.com)
7
- # It's mainly just adding vowels, as I ht cd wth n vwls :)
8
- # This represents the hard part of the work, all I did was change the
9
- # underlying parser.
10
- class REXMLUtilityNode #:nodoc:
11
- attr_accessor :name, :attributes, :children, :type
12
-
13
- def self.typecasts
14
- @@typecasts
15
- end
16
-
17
- def self.typecasts=(obj)
18
- @@typecasts = obj
19
- end
20
-
21
- def self.available_typecasts
22
- @@available_typecasts
23
- end
24
-
25
- def self.available_typecasts=(obj)
26
- @@available_typecasts = obj
27
- end
28
-
29
- self.typecasts = {}
30
- self.typecasts["integer"] = lambda{|v| v.nil? ? nil : v.to_i}
31
- self.typecasts["boolean"] = lambda{|v| v.nil? ? nil : (v.strip != "false")}
32
- self.typecasts["datetime"] = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
33
- self.typecasts["date"] = lambda{|v| v.nil? ? nil : Date.parse(v)}
34
- self.typecasts["dateTime"] = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
35
- self.typecasts["decimal"] = lambda{|v| v.nil? ? nil : BigDecimal(v.to_s)}
36
- self.typecasts["double"] = lambda{|v| v.nil? ? nil : v.to_f}
37
- self.typecasts["float"] = lambda{|v| v.nil? ? nil : v.to_f}
38
- self.typecasts["symbol"] = lambda{|v| v.nil? ? nil : v.to_sym}
39
- self.typecasts["string"] = lambda{|v| v.to_s}
40
- self.typecasts["yaml"] = lambda{|v| v.nil? ? nil : YAML.load(v)}
41
- self.typecasts["base64Binary"] = lambda{|v| v.unpack('m').first }
42
-
43
- self.available_typecasts = self.typecasts.keys
44
-
45
- def initialize(name, attributes = {})
46
- @name = name.tr("-", "_")
47
- # leave the type alone if we don't know what it is
48
- @type = self.class.available_typecasts.include?(attributes["type"]) ? attributes.delete("type") : attributes["type"]
49
-
50
- @nil_element = attributes.delete("nil") == "true"
51
- @attributes = undasherize_keys(attributes)
52
- @children = []
53
- @text = false
54
- end
55
-
56
- def add_node(node)
57
- @text = true if node.is_a? String
58
- @children << node
59
- end
60
-
61
- def to_hash
62
- if @type == "file"
63
- f = StringIO.new((@children.first || '').unpack('m').first)
64
- class << f
65
- attr_accessor :original_filename, :content_type
66
- end
67
- f.original_filename = attributes['name'] || 'untitled'
68
- f.content_type = attributes['content_type'] || 'application/octet-stream'
69
- return {name => f}
70
- end
71
-
72
- if @text
73
- return { name => typecast_value( translate_xml_entities( inner_html ) ) }
74
- else
75
- #change repeating groups into an array
76
- groups = @children.inject({}) { |s,e| (s[e.name] ||= []) << e; s }
77
-
78
- out = nil
79
- if @type == "array"
80
- out = []
81
- groups.each do |k, v|
82
- if v.size == 1
83
- out << v.first.to_hash.entries.first.last
84
- else
85
- out << v.map{|e| e.to_hash[k]}
86
- end
87
- end
88
- out = out.flatten
89
-
90
- else # If Hash
91
- out = {}
92
- groups.each do |k,v|
93
- if v.size == 1
94
- out.merge!(v.first)
95
- else
96
- out.merge!( k => v.map{|e| e.to_hash[k]})
97
- end
98
- end
99
- out.merge! attributes unless attributes.empty?
100
- out = out.empty? ? nil : out
101
- end
102
-
103
- if @type && out.nil?
104
- { name => typecast_value(out) }
105
- else
106
- { name => out }
107
- end
108
- end
109
- end
110
-
111
- # Typecasts a value based upon its type. For instance, if
112
- # +node+ has #type == "integer",
113
- # {{[node.typecast_value("12") #=> 12]}}
114
- #
115
- # @param value<String> The value that is being typecast.
116
- #
117
- # @details [:type options]
118
- # "integer"::
119
- # converts +value+ to an integer with #to_i
120
- # "boolean"::
121
- # checks whether +value+, after removing spaces, is the literal
122
- # "true"
123
- # "datetime"::
124
- # Parses +value+ using Time.parse, and returns a UTC Time
125
- # "date"::
126
- # Parses +value+ using Date.parse
127
- #
128
- # @return <Integer, TrueClass, FalseClass, Time, Date, Object>
129
- # The result of typecasting +value+.
130
- #
131
- # @note
132
- # If +self+ does not have a "type" key, or if it's not one of the
133
- # options specified above, the raw +value+ will be returned.
134
- def typecast_value(value)
135
- return value unless @type
136
- proc = self.class.typecasts[@type]
137
- proc.nil? ? value : proc.call(value)
138
- end
139
-
140
- # Convert basic XML entities into their literal values.
141
- #
142
- # @param value<#gsub> An XML fragment.
143
- #
144
- # @return <#gsub> The XML fragment after converting entities.
145
- def translate_xml_entities(value)
146
- value.gsub(/&lt;/, "<").
147
- gsub(/&gt;/, ">").
148
- gsub(/&quot;/, '"').
149
- gsub(/&apos;/, "'").
150
- gsub(/&amp;/, "&")
151
- end
152
-
153
- # Take keys of the form foo-bar and convert them to foo_bar
154
- def undasherize_keys(params)
155
- params.keys.each do |key, value|
156
- params[key.tr("-", "_")] = params.delete(key)
157
- end
158
- params
159
- end
160
-
161
- # Get the inner_html of the REXML node.
162
- def inner_html
163
- @children.join
164
- end
165
-
166
- # Converts the node into a readable HTML node.
167
- #
168
- # @return <String> The HTML node in text form.
169
- def to_html
170
- attributes.merge!(:type => @type ) if @type
171
- "<#{name}#{attributes.to_xml_attributes}>#{@nil_element ? '' : inner_html}</#{name}>"
172
- end
173
-
174
- # @alias #to_html #to_s
175
- def to_s
176
- to_html
177
- end
178
- end
179
-
180
- module HTTParty
181
- module Parsers #:nodoc:
182
- module XML #:nodoc:
183
- def self.parse(xml)
184
- stack = []
185
- parser = REXML::Parsers::BaseParser.new(xml)
186
-
187
- while true
188
- event = parser.pull
189
- case event[0]
190
- when :end_document
191
- break
192
- when :end_doctype, :start_doctype
193
- # do nothing
194
- when :start_element
195
- stack.push REXMLUtilityNode.new(event[1], event[2])
196
- when :end_element
197
- if stack.size > 1
198
- temp = stack.pop
199
- stack.last.add_node(temp)
200
- end
201
- when :text, :cdata
202
- stack.last.add_node(event[1]) unless event[1].strip.length == 0 || stack.empty?
203
- end
204
- end
205
- stack.pop.to_hash
206
- end
207
- end
208
- end
209
- end
@@ -1,42 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
-
3
- describe HTTParty::Parsers::JSON do
4
- TESTS = {
5
- %q({"data": "G\u00fcnter"}) => {"data" => "Günter"},
6
- %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
7
- %q({returnTo:{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
8
- %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}},
9
- %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}},
10
- %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
11
- %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
12
- %({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
13
- %({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
14
- %({a: "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
15
- %({a: "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
16
- # no time zone
17
- %({a: "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
18
- %([]) => [],
19
- %({}) => {},
20
- %(1) => 1,
21
- %("") => "",
22
- %("\\"") => "\"",
23
- %(null) => nil,
24
- %(true) => true,
25
- %(false) => false,
26
- %q("http:\/\/test.host\/posts\/1") => "http://test.host/posts/1"
27
- }
28
-
29
- TESTS.each do |json, expected|
30
- it "should decode json (#{json})" do
31
- lambda {
32
- HTTParty::Parsers::JSON.decode(json).should == expected
33
- }.should_not raise_error
34
- end
35
- end
36
-
37
- it "should raise error for failed decoding" do
38
- lambda {
39
- HTTParty::Parsers::JSON.decode(%({: 1}))
40
- }.should raise_error(HTTParty::Parsers::JSON::ParseError)
41
- end
42
- end
@@ -1,445 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
-
3
- require "date"
4
- require 'bigdecimal'
5
-
6
- describe HTTParty::Parsers::XML, "#parse" do
7
- it "should transform a simple tag with content" do
8
- xml = "<tag>This is the contents</tag>"
9
- HTTParty::Parsers::XML.parse(xml).should == { 'tag' => 'This is the contents' }
10
- end
11
-
12
- it "should work with cdata tags" do
13
- xml = <<-END
14
- <tag>
15
- <![CDATA[
16
- text inside cdata
17
- ]]>
18
- </tag>
19
- END
20
- HTTParty::Parsers::XML.parse(xml)["tag"].strip.should == "text inside cdata"
21
- end
22
-
23
- it "should transform a simple tag with attributes" do
24
- xml = "<tag attr1='1' attr2='2'></tag>"
25
- hash = { 'tag' => { 'attr1' => '1', 'attr2' => '2' } }
26
- HTTParty::Parsers::XML.parse(xml).should == hash
27
- end
28
-
29
- it "should transform repeating siblings into an array" do
30
- xml =<<-XML
31
- <opt>
32
- <user login="grep" fullname="Gary R Epstein" />
33
- <user login="stty" fullname="Simon T Tyson" />
34
- </opt>
35
- XML
36
-
37
- HTTParty::Parsers::XML.parse(xml)['opt']['user'].should be_an_instance_of(Array)
38
-
39
- hash = {
40
- 'opt' => {
41
- 'user' => [{
42
- 'login' => 'grep',
43
- 'fullname' => 'Gary R Epstein'
44
- },{
45
- 'login' => 'stty',
46
- 'fullname' => 'Simon T Tyson'
47
- }]
48
- }
49
- }
50
-
51
- HTTParty::Parsers::XML.parse(xml).should == hash
52
- end
53
-
54
- it "should not transform non-repeating siblings into an array" do
55
- xml =<<-XML
56
- <opt>
57
- <user login="grep" fullname="Gary R Epstein" />
58
- </opt>
59
- XML
60
-
61
- HTTParty::Parsers::XML.parse(xml)['opt']['user'].should be_an_instance_of(Hash)
62
-
63
- hash = {
64
- 'opt' => {
65
- 'user' => {
66
- 'login' => 'grep',
67
- 'fullname' => 'Gary R Epstein'
68
- }
69
- }
70
- }
71
-
72
- HTTParty::Parsers::XML.parse(xml).should == hash
73
- end
74
-
75
- it "should typecast an integer" do
76
- xml = "<tag type='integer'>10</tag>"
77
- HTTParty::Parsers::XML.parse(xml)['tag'].should == 10
78
- end
79
-
80
- it "should typecast a true boolean" do
81
- xml = "<tag type='boolean'>true</tag>"
82
- HTTParty::Parsers::XML.parse(xml)['tag'].should be_true
83
- end
84
-
85
- it "should typecast a false boolean" do
86
- ["false"].each do |w|
87
- HTTParty::Parsers::XML.parse("<tag type='boolean'>#{w}</tag>")['tag'].should be_false
88
- end
89
- end
90
-
91
- it "should typecast a datetime" do
92
- xml = "<tag type='datetime'>2007-12-31 10:32</tag>"
93
- HTTParty::Parsers::XML.parse(xml)['tag'].should == Time.parse( '2007-12-31 10:32' ).utc
94
- end
95
-
96
- it "should typecast a date" do
97
- xml = "<tag type='date'>2007-12-31</tag>"
98
- HTTParty::Parsers::XML.parse(xml)['tag'].should == Date.parse('2007-12-31')
99
- end
100
-
101
- it "should unescape html entities" do
102
- values = {
103
- "<" => "&lt;",
104
- ">" => "&gt;",
105
- '"' => "&quot;",
106
- "'" => "&apos;",
107
- "&" => "&amp;"
108
- }
109
- values.each do |k,v|
110
- xml = "<tag>Some content #{v}</tag>"
111
- HTTParty::Parsers::XML.parse(xml)['tag'].should match(Regexp.new(k))
112
- end
113
- end
114
-
115
- it "should undasherize keys as tags" do
116
- xml = "<tag-1>Stuff</tag-1>"
117
- HTTParty::Parsers::XML.parse(xml).keys.should include( 'tag_1' )
118
- end
119
-
120
- it "should undasherize keys as attributes" do
121
- xml = "<tag1 attr-1='1'></tag1>"
122
- HTTParty::Parsers::XML.parse(xml)['tag1'].keys.should include( 'attr_1')
123
- end
124
-
125
- it "should undasherize keys as tags and attributes" do
126
- xml = "<tag-1 attr-1='1'></tag-1>"
127
- HTTParty::Parsers::XML.parse(xml).keys.should include( 'tag_1' )
128
- HTTParty::Parsers::XML.parse(xml)['tag_1'].keys.should include( 'attr_1')
129
- end
130
-
131
- it "should render nested content correctly" do
132
- xml = "<root><tag1>Tag1 Content <em><strong>This is strong</strong></em></tag1></root>"
133
- HTTParty::Parsers::XML.parse(xml)['root']['tag1'].should == "Tag1 Content <em><strong>This is strong</strong></em>"
134
- end
135
-
136
- it "should render nested content with split text nodes correctly" do
137
- xml = "<root>Tag1 Content<em>Stuff</em> Hi There</root>"
138
- HTTParty::Parsers::XML.parse(xml)['root'].should == "Tag1 Content<em>Stuff</em> Hi There"
139
- end
140
-
141
- it "should ignore attributes when a child is a text node" do
142
- xml = "<root attr1='1'>Stuff</root>"
143
- HTTParty::Parsers::XML.parse(xml).should == { "root" => "Stuff" }
144
- end
145
-
146
- it "should ignore attributes when any child is a text node" do
147
- xml = "<root attr1='1'>Stuff <em>in italics</em></root>"
148
- HTTParty::Parsers::XML.parse(xml).should == { "root" => "Stuff <em>in italics</em>" }
149
- end
150
-
151
- it "should correctly transform multiple children" do
152
- xml = <<-XML
153
- <user gender='m'>
154
- <age type='integer'>35</age>
155
- <name>Home Simpson</name>
156
- <dob type='date'>1988-01-01</dob>
157
- <joined-at type='datetime'>2000-04-28 23:01</joined-at>
158
- <is-cool type='boolean'>true</is-cool>
159
- </user>
160
- XML
161
-
162
- hash = {
163
- "user" => {
164
- "gender" => "m",
165
- "age" => 35,
166
- "name" => "Home Simpson",
167
- "dob" => Date.parse('1988-01-01'),
168
- "joined_at" => Time.parse("2000-04-28 23:01"),
169
- "is_cool" => true
170
- }
171
- }
172
-
173
- HTTParty::Parsers::XML.parse(xml).should == hash
174
- end
175
-
176
- it "should properly handle nil values (ActiveSupport Compatible)" do
177
- topic_xml = <<-EOT
178
- <topic>
179
- <title></title>
180
- <id type="integer"></id>
181
- <approved type="boolean"></approved>
182
- <written-on type="date"></written-on>
183
- <viewed-at type="datetime"></viewed-at>
184
- <content type="yaml"></content>
185
- <parent-id></parent-id>
186
- </topic>
187
- EOT
188
-
189
- expected_topic_hash = {
190
- 'title' => nil,
191
- 'id' => nil,
192
- 'approved' => nil,
193
- 'written_on' => nil,
194
- 'viewed_at' => nil,
195
- 'content' => nil,
196
- 'parent_id' => nil
197
- }
198
- HTTParty::Parsers::XML.parse(topic_xml)["topic"].should == expected_topic_hash
199
- end
200
-
201
- it "should handle a single record from xml (ActiveSupport Compatible)" do
202
- topic_xml = <<-EOT
203
- <topic>
204
- <title>The First Topic</title>
205
- <author-name>David</author-name>
206
- <id type="integer">1</id>
207
- <approved type="boolean"> true </approved>
208
- <replies-count type="integer">0</replies-count>
209
- <replies-close-in type="integer">2592000000</replies-close-in>
210
- <written-on type="date">2003-07-16</written-on>
211
- <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
212
- <content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
213
- <author-email-address>david@loudthinking.com</author-email-address>
214
- <parent-id></parent-id>
215
- <ad-revenue type="decimal">1.5</ad-revenue>
216
- <optimum-viewing-angle type="float">135</optimum-viewing-angle>
217
- <resident type="symbol">yes</resident>
218
- </topic>
219
- EOT
220
-
221
- expected_topic_hash = {
222
- 'title' => "The First Topic",
223
- 'author_name' => "David",
224
- 'id' => 1,
225
- 'approved' => true,
226
- 'replies_count' => 0,
227
- 'replies_close_in' => 2592000000,
228
- 'written_on' => Date.new(2003, 7, 16),
229
- 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
230
- # Changed this line where the key is :message. The yaml specifies this as a symbol, and who am I to change what you specify
231
- # The line in ActiveSupport is
232
- # 'content' => { 'message' => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
233
- 'content' => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
234
- 'author_email_address' => "david@loudthinking.com",
235
- 'parent_id' => nil,
236
- 'ad_revenue' => BigDecimal("1.50"),
237
- 'optimum_viewing_angle' => 135.0,
238
- 'resident' => :yes
239
- }
240
-
241
- HTTParty::Parsers::XML.parse(topic_xml)["topic"].each do |k,v|
242
- v.should == expected_topic_hash[k]
243
- end
244
- end
245
-
246
- it "should handle multiple records (ActiveSupport Compatible)" do
247
- topics_xml = <<-EOT
248
- <topics type="array">
249
- <topic>
250
- <title>The First Topic</title>
251
- <author-name>David</author-name>
252
- <id type="integer">1</id>
253
- <approved type="boolean">false</approved>
254
- <replies-count type="integer">0</replies-count>
255
- <replies-close-in type="integer">2592000000</replies-close-in>
256
- <written-on type="date">2003-07-16</written-on>
257
- <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
258
- <content>Have a nice day</content>
259
- <author-email-address>david@loudthinking.com</author-email-address>
260
- <parent-id nil="true"></parent-id>
261
- </topic>
262
- <topic>
263
- <title>The Second Topic</title>
264
- <author-name>Jason</author-name>
265
- <id type="integer">1</id>
266
- <approved type="boolean">false</approved>
267
- <replies-count type="integer">0</replies-count>
268
- <replies-close-in type="integer">2592000000</replies-close-in>
269
- <written-on type="date">2003-07-16</written-on>
270
- <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
271
- <content>Have a nice day</content>
272
- <author-email-address>david@loudthinking.com</author-email-address>
273
- <parent-id></parent-id>
274
- </topic>
275
- </topics>
276
- EOT
277
-
278
- expected_topic_hash = {
279
- 'title' => "The First Topic",
280
- 'author_name' => "David",
281
- 'id' => 1,
282
- 'approved' => false,
283
- 'replies_count' => 0,
284
- 'replies_close_in' => 2592000000,
285
- 'written_on' => Date.new(2003, 7, 16),
286
- 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
287
- 'content' => "Have a nice day",
288
- 'author_email_address' => "david@loudthinking.com",
289
- 'parent_id' => nil
290
- }
291
- # puts HTTParty::Parsers::XML.parse(topics_xml)['topics'].first.inspect
292
- HTTParty::Parsers::XML.parse(topics_xml)["topics"].first.each do |k,v|
293
- v.should == expected_topic_hash[k]
294
- end
295
- end
296
-
297
- it "should handle a single record from_xml with attributes other than type (ActiveSupport Compatible)" do
298
- topic_xml = <<-EOT
299
- <rsp stat="ok">
300
- <photos page="1" pages="1" perpage="100" total="16">
301
- <photo id="175756086" owner="55569174@N00" secret="0279bf37a1" server="76" title="Colored Pencil PhotoBooth Fun" ispublic="1" isfriend="0" isfamily="0"/>
302
- </photos>
303
- </rsp>
304
- EOT
305
-
306
- expected_topic_hash = {
307
- 'id' => "175756086",
308
- 'owner' => "55569174@N00",
309
- 'secret' => "0279bf37a1",
310
- 'server' => "76",
311
- 'title' => "Colored Pencil PhotoBooth Fun",
312
- 'ispublic' => "1",
313
- 'isfriend' => "0",
314
- 'isfamily' => "0",
315
- }
316
- HTTParty::Parsers::XML.parse(topic_xml)["rsp"]["photos"]["photo"].each do |k,v|
317
- v.should == expected_topic_hash[k]
318
- end
319
- end
320
-
321
- it "should handle an emtpy array (ActiveSupport Compatible)" do
322
- blog_xml = <<-XML
323
- <blog>
324
- <posts type="array"></posts>
325
- </blog>
326
- XML
327
- expected_blog_hash = {"blog" => {"posts" => []}}
328
- HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
329
- end
330
-
331
- it "should handle empty array with whitespace from xml (ActiveSupport Compatible)" do
332
- blog_xml = <<-XML
333
- <blog>
334
- <posts type="array">
335
- </posts>
336
- </blog>
337
- XML
338
- expected_blog_hash = {"blog" => {"posts" => []}}
339
- HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
340
- end
341
-
342
- it "should handle array with one entry from_xml (ActiveSupport Compatible)" do
343
- blog_xml = <<-XML
344
- <blog>
345
- <posts type="array">
346
- <post>a post</post>
347
- </posts>
348
- </blog>
349
- XML
350
- expected_blog_hash = {"blog" => {"posts" => ["a post"]}}
351
- HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
352
- end
353
-
354
- it "should handle array with multiple entries from xml (ActiveSupport Compatible)" do
355
- blog_xml = <<-XML
356
- <blog>
357
- <posts type="array">
358
- <post>a post</post>
359
- <post>another post</post>
360
- </posts>
361
- </blog>
362
- XML
363
- expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}}
364
- HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
365
- end
366
-
367
- it "should handle file types (ActiveSupport Compatible)" do
368
- blog_xml = <<-XML
369
- <blog>
370
- <logo type="file" name="logo.png" content_type="image/png">
371
- </logo>
372
- </blog>
373
- XML
374
- hash = HTTParty::Parsers::XML.parse(blog_xml)
375
- hash.should have_key('blog')
376
- hash['blog'].should have_key('logo')
377
-
378
- file = hash['blog']['logo']
379
- file.original_filename.should == 'logo.png'
380
- file.content_type.should == 'image/png'
381
- end
382
-
383
- it "should handle file from xml with defaults (ActiveSupport Compatible)" do
384
- blog_xml = <<-XML
385
- <blog>
386
- <logo type="file">
387
- </logo>
388
- </blog>
389
- XML
390
- file = HTTParty::Parsers::XML.parse(blog_xml)['blog']['logo']
391
- file.original_filename.should == 'untitled'
392
- file.content_type.should == 'application/octet-stream'
393
- end
394
-
395
- it "should handle xsd like types from xml (ActiveSupport Compatible)" do
396
- bacon_xml = <<-EOT
397
- <bacon>
398
- <weight type="double">0.5</weight>
399
- <price type="decimal">12.50</price>
400
- <chunky type="boolean"> 1 </chunky>
401
- <expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at>
402
- <notes type="string"></notes>
403
- <illustration type="base64Binary">YmFiZS5wbmc=</illustration>
404
- </bacon>
405
- EOT
406
-
407
- expected_bacon_hash = {
408
- 'weight' => 0.5,
409
- 'chunky' => true,
410
- 'price' => BigDecimal("12.50"),
411
- 'expires_at' => Time.utc(2007,12,25,12,34,56),
412
- 'notes' => "",
413
- 'illustration' => "babe.png"
414
- }
415
-
416
- HTTParty::Parsers::XML.parse(bacon_xml)["bacon"].should == expected_bacon_hash
417
- end
418
-
419
- it "should let type trickle through when unknown (ActiveSupport Compatible)" do
420
- product_xml = <<-EOT
421
- <product>
422
- <weight type="double">0.5</weight>
423
- <image type="ProductImage"><filename>image.gif</filename></image>
424
-
425
- </product>
426
- EOT
427
-
428
- expected_product_hash = {
429
- 'weight' => 0.5,
430
- 'image' => {'type' => 'ProductImage', 'filename' => 'image.gif' },
431
- }
432
-
433
- HTTParty::Parsers::XML.parse(product_xml)["product"].should == expected_product_hash
434
- end
435
-
436
- it "should handle unescaping from xml (ActiveResource Compatible)" do
437
- xml_string = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
438
- expected_hash = {
439
- 'bare_string' => 'First & Last Name',
440
- 'pre_escaped_string' => 'First &amp; Last Name'
441
- }
442
-
443
- HTTParty::Parsers::XML.parse(xml_string)['person'].should == expected_hash
444
- end
445
- end