purzelrakete-boomloop 0.0.5 → 0.0.9
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 +4 -1
- data/bin/boomloop +2 -2
- data/lib/boomloop.rb +12 -3
- data/lib/{authentication → boomloop/authentication}/client.rb +2 -2
- data/lib/{authentication → boomloop/authentication}/credentials.rb +0 -0
- data/lib/{authentication → boomloop/authentication}/store/base.rb +0 -0
- data/lib/{authentication → boomloop/authentication}/store/yaml_store.rb +0 -0
- data/lib/{resources → boomloop/resources}/base.rb +47 -32
- data/lib/{resources → boomloop/resources}/event.rb +0 -0
- data/lib/{resources → boomloop/resources}/event_series.rb +0 -0
- data/lib/{resources → boomloop/resources}/place.rb +0 -0
- data/lib/{resources → boomloop/resources}/ticket_category.rb +0 -0
- data/lib/{version.rb → boomloop/version.rb} +0 -0
- data/test/boomloop_resource_test.rb +124 -11
- data/test/mocks/monster.rb +2 -0
- data/test/test_helper.rb +2 -1
- metadata +12 -12
data/History.txt
CHANGED
data/bin/boomloop
CHANGED
@@ -33,8 +33,8 @@ error(parser) unless options.secret && options.key
|
|
33
33
|
|
34
34
|
# negotiate the tokens
|
35
35
|
client = Boomloop::Authentication::Client.new("api", Boomloop::Authentication::Store::YAMLStore.new)
|
36
|
-
request_token = client.consume(options.key, options.secret) rescue error("Invalid. Check your credentials at #{ Boomloop::Resources::Base.
|
37
|
-
puts "\nalmost ready! go to #{ request_token.authorize_url
|
36
|
+
request_token = client.consume(options.key, options.secret) rescue error("Invalid. Check your credentials at #{ Boomloop::Resources::Base.boomloop_base }/oauth/applications.")
|
37
|
+
puts "\nalmost ready! go to #{ request_token.authorize_url }\n\n press enter when you're done... <waiting>\n"
|
38
38
|
|
39
39
|
while !@access_token && gets
|
40
40
|
@access_token = client.activate rescue nil
|
data/lib/boomloop.rb
CHANGED
@@ -9,8 +9,17 @@ module Boomloop
|
|
9
9
|
class ApiError < ::StandardError; end
|
10
10
|
class AuthorizationError < ApiError; end
|
11
11
|
class ValidationError < ApiError; end
|
12
|
+
class RedirectError < ApiError; end
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
$:.unshift File.dirname(__FILE__)
|
16
|
+
|
17
|
+
require 'boomloop/authentication/client'
|
18
|
+
require 'boomloop/authentication/credentials'
|
19
|
+
require 'boomloop/authentication/store/base'
|
20
|
+
require 'boomloop/authentication/store/yaml_store'
|
21
|
+
require 'boomloop/resources/base'
|
22
|
+
require 'boomloop/resources/event'
|
23
|
+
require 'boomloop/resources/event_series'
|
24
|
+
require 'boomloop/resources/place'
|
25
|
+
require 'boomloop/resources/ticket_category'
|
@@ -63,8 +63,8 @@ module Boomloop
|
|
63
63
|
connection.get(url, options.merge({ "X-Consumer-Key" => self.consumer.key }))
|
64
64
|
end
|
65
65
|
|
66
|
-
def post(url, params = "")
|
67
|
-
connection.post(url, params, { "X-Consumer-Key" => self.consumer.key })
|
66
|
+
def post(url, params = "", headers = {})
|
67
|
+
connection.post(url, params, { "X-Consumer-Key" => self.consumer.key, 'Accept'=>'application/xml', 'Content-Type' => 'application/xml' }.merge(headers))
|
68
68
|
end
|
69
69
|
|
70
70
|
def raise_error_if_not_authenticated(credentials)
|
File without changes
|
File without changes
|
File without changes
|
@@ -5,19 +5,6 @@ module Boomloop
|
|
5
5
|
attr_accessor :client
|
6
6
|
end
|
7
7
|
|
8
|
-
def self.api_base
|
9
|
-
@@api_base ||= (ENV["BOOMLOOP_API_URL"] ? ENV["BOOMLOOP_API_URL"].gsub(/\/$/, "") : 'http://api.boomloop.com' )
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.client
|
13
|
-
@@client ||= init
|
14
|
-
end
|
15
|
-
|
16
|
-
# get oauth token
|
17
|
-
def self.init
|
18
|
-
self.client = Boomloop::Authentication::Client.new("api", Boomloop::Authentication::Store::YAMLStore.new)
|
19
|
-
end
|
20
|
-
|
21
8
|
def save
|
22
9
|
returned = self.class.create(self)
|
23
10
|
self.instance_variable_set("@table", returned.to_hash)
|
@@ -28,12 +15,33 @@ module Boomloop
|
|
28
15
|
links = to_hash.keys.select { |key| key =~ /resource-url$/ }
|
29
16
|
end
|
30
17
|
|
18
|
+
def valid?
|
19
|
+
self.errors.blank?
|
20
|
+
end
|
21
|
+
|
31
22
|
def to_hash
|
32
23
|
instance_variable_get("@table")
|
33
24
|
end
|
34
25
|
|
35
|
-
def to_xml
|
36
|
-
self.to_hash.to_xml
|
26
|
+
def to_xml(options = {})
|
27
|
+
self.to_hash.to_xml(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.api_base
|
31
|
+
@@api_base ||= (ENV["BOOMLOOP_API_URL"] ? ENV["BOOMLOOP_API_URL"].gsub(/\/$/, "") : 'http://api.boomloop.com' )
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.boomloop_base
|
35
|
+
@@boomloop_base ||= self.api_base.gsub /(^http:\/\/)(api.)(.*)/, '\1' + '\3'
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.client
|
39
|
+
@@client ||= init
|
40
|
+
end
|
41
|
+
|
42
|
+
# get oauth token
|
43
|
+
def self.init
|
44
|
+
self.client = Boomloop::Authentication::Client.new("api", Boomloop::Authentication::Store::YAMLStore.new)
|
37
45
|
end
|
38
46
|
|
39
47
|
def self.singular
|
@@ -45,6 +53,12 @@ module Boomloop
|
|
45
53
|
end
|
46
54
|
|
47
55
|
# REST methods
|
56
|
+
def self.show(url)
|
57
|
+
res = client.get(url)
|
58
|
+
attrs = from_response(res)
|
59
|
+
self.new(attrs[self.singular])
|
60
|
+
end
|
61
|
+
|
48
62
|
def self.index(params = {})
|
49
63
|
url = "#{ api_base }/#{ self.plural }"
|
50
64
|
url += "?#{ params.to_query }" unless params.empty?
|
@@ -53,24 +67,33 @@ module Boomloop
|
|
53
67
|
construct_resource_collection(attrs)
|
54
68
|
end
|
55
69
|
|
56
|
-
def self.
|
57
|
-
|
70
|
+
def self.create(resource)
|
71
|
+
resource = resource.kind_of?(self) ? resource : self.new(resource)
|
72
|
+
|
73
|
+
url = "#{ api_base }/#{ self.plural }"
|
74
|
+
res = client.post(url, resource.to_xml(:root => singular.to_sym))
|
58
75
|
attrs = from_response(res)
|
59
76
|
self.new(attrs[self.singular])
|
60
77
|
end
|
61
78
|
|
62
|
-
def self.
|
63
|
-
|
64
|
-
res
|
65
|
-
self.new(from_response(res)[self.singular])
|
79
|
+
def self.follow_redirect(response)
|
80
|
+
res = client.get(response.location)
|
81
|
+
from_response(res, response)
|
66
82
|
end
|
67
83
|
|
68
|
-
def self.from_response(response)
|
84
|
+
def self.from_response(response, old_response=nil)
|
69
85
|
xml = response.body
|
70
86
|
|
71
87
|
case response.code.to_i
|
88
|
+
when 422
|
89
|
+
@result = { self.singular => Hash.from_xml(xml) }
|
72
90
|
when 401
|
73
91
|
raise Boomloop::AuthorizationError.new
|
92
|
+
when 301
|
93
|
+
raise Boomloop::RedirectError.new("Redirect URL seem to be the same as the original. I do not follow!") if
|
94
|
+
old_response and old_response.location and response.location and response.location == old_response.location
|
95
|
+
|
96
|
+
follow_redirect(response)
|
74
97
|
when 200...299
|
75
98
|
begin
|
76
99
|
@result = Hash.from_xml(xml)
|
@@ -81,8 +104,8 @@ module Boomloop
|
|
81
104
|
raise Boomloop::ValidationError.new("There was a problem with your request: \n\n #{ response }") if @result["errors"]
|
82
105
|
else
|
83
106
|
raise Boomloop::ApiError.new("boomloop responded with #{ response.class } (#{ response.code }): #{ response.body }")
|
84
|
-
end
|
85
|
-
|
107
|
+
end
|
108
|
+
|
86
109
|
@result
|
87
110
|
end
|
88
111
|
|
@@ -94,14 +117,6 @@ module Boomloop
|
|
94
117
|
when Hash : self.new(collection[self.singular])
|
95
118
|
end
|
96
119
|
end
|
97
|
-
|
98
|
-
def self.transitive_create(resource)
|
99
|
-
if resource.child_resources
|
100
|
-
child_resources.each { |child| transitive_create(child) }
|
101
|
-
else
|
102
|
-
create(resource)
|
103
|
-
end
|
104
|
-
end
|
105
120
|
end
|
106
121
|
end
|
107
122
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
2
|
|
3
|
-
context "
|
3
|
+
context "A boomloop resource" do
|
4
4
|
|
5
5
|
setup do
|
6
6
|
Boomloop::Authentication::Client.class_eval { def raise_error_if_not_authenticated(*args); end }
|
@@ -101,19 +101,32 @@ context "a boomloop resource" do
|
|
101
101
|
|
102
102
|
specify "should be savable when calling .save on a Monster instance" do
|
103
103
|
intended_resource_url = "#{ Boomloop::Resources::Base.api_base }/monsters/samuel"
|
104
|
-
intended_attributes = { :
|
104
|
+
intended_attributes = { :affect => :mordant, :name => "samuel", :size => :laughable }
|
105
|
+
intended_ingoing_xml = <<-XML
|
106
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
107
|
+
<monster>
|
108
|
+
<name>samuel</name>
|
109
|
+
<size type="symbol">laughable</size>
|
110
|
+
<affect type="symbol">mordant</affect>
|
111
|
+
</monster>
|
112
|
+
XML
|
113
|
+
|
114
|
+
intended_return_xml = <<-XML
|
115
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
116
|
+
<monster>
|
117
|
+
<name>samuel</name>
|
118
|
+
<affect type="symbol">mordant</affect>
|
119
|
+
<size type="symbol">laughable</size>
|
120
|
+
<resource-url>#{ Boomloop::Resources::Base.api_base }/monsters/samuel</resource-url>
|
121
|
+
</monster>
|
122
|
+
XML
|
123
|
+
|
105
124
|
response = mock()
|
106
125
|
response.expects(:code).returns 201
|
107
|
-
response.expects(:body).returns(
|
108
|
-
|
109
|
-
|
110
|
-
<size>laughable</size>
|
111
|
-
<affect>mordant</affect>
|
112
|
-
<name>samuel</name>
|
113
|
-
</monster>
|
114
|
-
XML
|
126
|
+
response.expects(:body).returns(intended_return_xml)
|
127
|
+
|
128
|
+
@client.expects(:post).with("#{ Boomloop::Resources::Base.api_base }/monsters", intended_ingoing_xml).at_least_once.returns(response)
|
115
129
|
|
116
|
-
@client.expects(:post).with("#{ Boomloop::Resources::Base.api_base }/monsters", intended_attributes.to_query).at_least_once.returns(response)
|
117
130
|
monster = Boomloop::Resources::Monster.new(intended_attributes)
|
118
131
|
monster.save
|
119
132
|
monster.resource_url.should.equal intended_resource_url
|
@@ -146,4 +159,104 @@ context "a boomloop resource" do
|
|
146
159
|
Boomloop::Resources::Monster.show("#{ Boomloop::Resources::Base.api_base }/monsters/fred")
|
147
160
|
end
|
148
161
|
end
|
162
|
+
|
163
|
+
specify "should follow and return the new resource XML if redirected via 301 on create and resource is a duplicate" do
|
164
|
+
intended_resource_url = "#{ Boomloop::Resources::Base.api_base }/monsters/samuel"
|
165
|
+
intended_attributes = { :size => :huge, :affect => :sanguine, :name => "samuel" }
|
166
|
+
|
167
|
+
response = mock()
|
168
|
+
response.expects(:code).returns 301
|
169
|
+
response.expects(:location).returns intended_resource_url
|
170
|
+
response.expects(:body).returns(<<-XML)
|
171
|
+
<duplicates>
|
172
|
+
<resource_url>#{ intended_resource_url }</resource_url>
|
173
|
+
</duplicates>
|
174
|
+
XML
|
175
|
+
|
176
|
+
intended_response = mock()
|
177
|
+
intended_response.expects(:code).returns 200
|
178
|
+
intended_response.expects(:body).returns(<<-XML)
|
179
|
+
<monster>
|
180
|
+
<resource_url>#{ intended_resource_url }</resource_url>
|
181
|
+
<size>huge</size>
|
182
|
+
<affect>sanguine</affect>
|
183
|
+
<name>samuel</name>
|
184
|
+
</monster>
|
185
|
+
XML
|
186
|
+
|
187
|
+
@client.expects(:post).with("#{ Boomloop::Resources::Base.api_base }/monsters", intended_attributes.to_xml(:root => :monster)).at_least_once.returns(response)
|
188
|
+
@client.expects(:get).with(intended_resource_url).at_least_once.returns(intended_response)
|
189
|
+
|
190
|
+
monster = Boomloop::Resources::Monster.new(intended_attributes)
|
191
|
+
monster.save
|
192
|
+
monster.resource_url.should.equal intended_resource_url
|
193
|
+
end
|
194
|
+
|
195
|
+
specify "should follow and return the new resource XML if redirected via 301 on show" do
|
196
|
+
called_resource_url = "#{ Boomloop::Resources::Base.api_base }/monsters/fred"
|
197
|
+
intended_resource_url = "#{ Boomloop::Resources::Base.api_base }/monsters/samuel"
|
198
|
+
|
199
|
+
response = mock()
|
200
|
+
response.expects(:code).returns 301
|
201
|
+
response.expects(:location).returns intended_resource_url
|
202
|
+
response.expects(:body).returns(<<-XML)
|
203
|
+
<duplicates>
|
204
|
+
<resource_url>#{ intended_resource_url }</resource_url>
|
205
|
+
</duplicates>
|
206
|
+
XML
|
207
|
+
|
208
|
+
second_response = mock()
|
209
|
+
second_response.expects(:code).returns 200
|
210
|
+
second_response.expects(:body).returns(<<-XML)
|
211
|
+
<monster>
|
212
|
+
<resource_url>#{ intended_resource_url }</resource_url>
|
213
|
+
<size>huge</size>
|
214
|
+
<affect>sanguine</affect>
|
215
|
+
<name>samuel</name>
|
216
|
+
</monster>
|
217
|
+
XML
|
218
|
+
|
219
|
+
@client.expects(:get).with(any_of(equals(called_resource_url), equals(intended_resource_url))).at_least_once.returns(response, second_response)
|
220
|
+
monster = Boomloop::Resources::Monster.show(called_resource_url)
|
221
|
+
end
|
222
|
+
|
223
|
+
specify "should raise an exception if response redirects to own resource_url" do
|
224
|
+
intended_resource_url = "#{ Boomloop::Resources::Base.api_base }/monsters/samuel"
|
225
|
+
|
226
|
+
response = mock()
|
227
|
+
response.expects(:code).at_least_once.returns 301
|
228
|
+
response.expects(:location).at_least_once.returns intended_resource_url
|
229
|
+
response.expects(:body).at_least_once.returns(<<-XML)
|
230
|
+
<duplicates>
|
231
|
+
<resource_url>#{ intended_resource_url }</resource_url>
|
232
|
+
</duplicates>
|
233
|
+
XML
|
234
|
+
|
235
|
+
@client.expects(:get).with(intended_resource_url).times(2).returns(response)
|
236
|
+
should.raise Boomloop::RedirectError do
|
237
|
+
Boomloop::Resources::Monster.show(intended_resource_url)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
specify "should have errors if boomloop API returns errors" do
|
242
|
+
monster_attributes = { :title => "Foo" }
|
243
|
+
|
244
|
+
response = mock
|
245
|
+
response.expects(:code).returns 422
|
246
|
+
response.expects(:body).returns(<<-XML)
|
247
|
+
<errors>
|
248
|
+
<error>Location boomloop braucht eine Location.</error>
|
249
|
+
<error>Start date trying to parse nil date, bad stuff.</error>
|
250
|
+
<error>Location boomloop braucht eine Location.</error>
|
251
|
+
<error>Start hour Zeit bitte in HH:MM Format.</error>
|
252
|
+
<error>Beschreibung Hast Du keine Informationen zu diesem Event?</error>
|
253
|
+
<error>trying to parse nil date, bad stuff.</error>
|
254
|
+
</errors>
|
255
|
+
XML
|
256
|
+
|
257
|
+
@client.expects(:post).with("#{ Boomloop::Resources::Base.api_base }/monsters", monster_attributes.to_xml(:root => :monster)).returns(response)
|
258
|
+
|
259
|
+
monster = Boomloop::Resources::Monster.create(monster_attributes)
|
260
|
+
monster.should.not.be.valid
|
261
|
+
end
|
149
262
|
end
|
data/test/mocks/monster.rb
CHANGED
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: purzelrakete-boomloop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rany Keddo
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-06-18 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -31,17 +31,17 @@ extra_rdoc_files:
|
|
31
31
|
- History.txt
|
32
32
|
- README.txt
|
33
33
|
files:
|
34
|
-
- lib/authentication/client.rb
|
35
|
-
- lib/authentication/credentials.rb
|
36
|
-
- lib/authentication/store/base.rb
|
37
|
-
- lib/authentication/store/yaml_store.rb
|
34
|
+
- lib/boomloop/authentication/client.rb
|
35
|
+
- lib/boomloop/authentication/credentials.rb
|
36
|
+
- lib/boomloop/authentication/store/base.rb
|
37
|
+
- lib/boomloop/authentication/store/yaml_store.rb
|
38
38
|
- lib/boomloop.rb
|
39
|
-
- lib/resources/base.rb
|
40
|
-
- lib/resources/event.rb
|
41
|
-
- lib/resources/event_series.rb
|
42
|
-
- lib/resources/place.rb
|
43
|
-
- lib/resources/ticket_category.rb
|
44
|
-
- lib/version.rb
|
39
|
+
- lib/boomloop/resources/base.rb
|
40
|
+
- lib/boomloop/resources/event.rb
|
41
|
+
- lib/boomloop/resources/event_series.rb
|
42
|
+
- lib/boomloop/resources/place.rb
|
43
|
+
- lib/boomloop/resources/ticket_category.rb
|
44
|
+
- lib/boomloop/version.rb
|
45
45
|
- bin/boomloop
|
46
46
|
- History.txt
|
47
47
|
- README.txt
|