zeppelin 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -8,8 +8,6 @@ lib/bundler/man
8
8
  pkg
9
9
  rdoc
10
10
  spec/reports
11
- test/tmp
12
- test/version_tmp
13
11
  tmp
14
12
 
15
13
  # YARD artifacts
@@ -18,4 +16,5 @@ _yardoc
18
16
  doc/
19
17
 
20
18
  # Gem-specific
21
- Gemfile.lock
19
+ Gemfile.lock
20
+ bin/
@@ -1,6 +1,7 @@
1
- script: 'rake test'
1
+ script: 'rake spec'
2
2
  rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
+ - 1.9.3
5
6
  - ree
6
7
  - jruby
data/.yardopts CHANGED
@@ -3,4 +3,7 @@
3
3
  --markup-provider maruku
4
4
  --default-return ""
5
5
  --title "Zeppelin Documentation"
6
- --hide-void-return
6
+ --hide-void-return
7
+ -
8
+ Changelog.md
9
+ LICENSE
@@ -0,0 +1,28 @@
1
+ # 0.6.0
2
+
3
+ ## Enhancements
4
+
5
+ * [MultiJson](https://github.com/intridea/multi_json) used to handle JSON
6
+ encoding/decoding. Using the JSON engine of your choice is as simple
7
+ as: `MultiJson.engine = :your_choice`
8
+
9
+ ## Breaking Changes
10
+
11
+ * Instead of having an invalid request return false, exceptions will be raised
12
+ with messages containing details about the fail. This allows for
13
+ better error handling. Should the desired resource not be found,
14
+ `Zeppelin::ResourceNotFound` will be raised, for other errors,
15
+ `Zeppelin::ClientError` will be raised. Successful responses will still
16
+ return `true`.
17
+
18
+ ## Changes
19
+
20
+ * Now using RSpec as the test harness
21
+ * CI covers Ruby 1.9.3
22
+ * [James Herdman](https://github.com/jherdman) added as a contributor
23
+
24
+ # 0.5.0
25
+
26
+ ## Changes
27
+
28
+ * Refactored handling of responses
data/Gemfile CHANGED
@@ -1,2 +1,10 @@
1
1
  source :rubygems
2
- gemspec
2
+ gemspec
3
+
4
+ group :development do
5
+ gem 'rb-fsevent', :require => RUBY_PLATFORM.include?('darwin') && 'rb-fsevent'
6
+ gem 'growl', :require => RUBY_PLATFORM.include?('darwin') && 'growl'
7
+ gem 'guard'
8
+ gem 'guard-bundler'
9
+ gem 'guard-rspec'
10
+ end
@@ -0,0 +1,10 @@
1
+ guard 'rspec', :version => 2 do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
7
+ guard 'bundler' do
8
+ watch('Gemfile')
9
+ watch(/^.+\.gemspec/)
10
+ end
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
- task :default => 'test'
4
+ require 'rspec/core/rake_task'
5
5
 
6
- require 'rake/testtask'
7
- Rake::TestTask.new do |t|
8
- t.ruby_opts += ['-rubygems']
9
- t.libs << 'test'
10
- t.pattern = 'test/**/*_test.rb'
11
- end
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ end
10
+
11
+ task :default => :spec
@@ -13,6 +13,8 @@ class Zeppelin
13
13
  BROADCAST_URI = '/api/push/broadcast/'
14
14
  JSON_HEADERS = { 'Content-Type' => 'application/json' }
15
15
 
16
+ attr_reader :application_key, :application_master_secret, :options
17
+
16
18
  # @param [String] application_key your Urban Airship Application Key
17
19
  #
18
20
  # @param [String] application_master_secret your Urban Airship Application
@@ -33,97 +35,107 @@ class Zeppelin
33
35
  #
34
36
  # @param [String] device_token
35
37
  # @param [Hash] payload the payload to send during registration
38
+ #
36
39
  # @return [Boolean] whether or not the registration was successful
40
+ #
41
+ # @raise [Zeppelin::ClientError] malformed request
37
42
  def register_device_token(device_token, payload = {})
38
43
  uri = device_token_uri(device_token)
39
-
40
- if payload.empty?
41
- response = connection.put(uri)
42
- else
43
- response = connection.put(uri, payload, JSON_HEADERS)
44
- end
45
-
46
- response.success?
44
+ put_request(uri, payload)
47
45
  end
48
46
 
49
47
  # Retrieves information on a device token.
50
48
  #
51
49
  # @param [String] device_token
52
50
  # @return [Hash, nil]
51
+ #
52
+ # @raise [Zeppelin::ResourceNotFound] invalid device token provided
53
53
  def device_token(device_token)
54
- response = connection.get(device_token_uri(device_token))
55
- response.success? ? response.body : nil
54
+ uri = device_token_uri(device_token)
55
+ get_request(uri)
56
56
  end
57
57
 
58
58
  # Deletes a device token.
59
59
  #
60
60
  # @param [String] device_token
61
+ #
61
62
  # @return [Boolean] whether or not the deletion was successful
63
+ #
64
+ # @raise [Zeppelin::ResourceNotFound] invalid device token provided
62
65
  def delete_device_token(device_token)
63
- response = connection.delete(device_token_uri(device_token))
64
- response.success?
66
+ uri = device_token_uri(device_token)
67
+ delete_request(uri)
65
68
  end
66
69
 
67
70
  # Registers an APID.
68
71
  #
69
72
  # @param [String] apid
73
+ #
70
74
  # @param [Hash] payload the payload to send during registration
75
+ #
71
76
  # @return [Boolean] whether or not the registration was successful
77
+ #
78
+ # @raise [Zeppelin::ClientError] invalid payload format
72
79
  def register_apid(apid, payload = {})
73
80
  uri = apid_uri(apid)
74
-
75
- if payload.empty?
76
- response = connection.put(uri)
77
- else
78
- response = connection.put(uri, payload, JSON_HEADERS)
79
- end
80
-
81
- response.success?
81
+ put_request(uri, payload)
82
82
  end
83
83
 
84
84
  # Retrieves information on an APID.
85
85
  #
86
86
  # @param [String] apid
87
+ #
87
88
  # @return [Hash, nil]
89
+ #
90
+ # @raise [Zeppelin::ResourceNotFound] invalid APID provided
88
91
  def apid(apid)
89
- response = connection.get(apid_uri(apid))
90
- response.success? ? response.body : nil
92
+ uri = apid_uri(apid)
93
+ get_request(uri)
91
94
  end
92
95
 
93
96
  # Deletes an APID.
94
97
  #
95
98
  # @param [String] apid
99
+ #
96
100
  # @return [Boolean] whether or not the deletion was successful
101
+ #
102
+ # @raise [Zeppelin::ResourceNotFound] invalid APID provided
97
103
  def delete_apid(apid)
98
- response = connection.delete(apid_uri(apid))
99
- response.success?
104
+ uri = apid_uri(apid)
105
+ delete_request(uri)
100
106
  end
101
107
 
102
108
  # Pushes a message.
103
109
  #
104
110
  # @param [Hash] payload the payload of the message
111
+ #
105
112
  # @return [Boolean] whether or not pushing the message was successful
113
+ #
114
+ # @raise [Zeppelin::ClientError] invalid payload format
106
115
  def push(payload)
107
- response = connection.post(PUSH_URI, payload, JSON_HEADERS)
108
- response.success?
116
+ post_request(PUSH_URI, payload)
109
117
  end
110
118
 
111
119
  # Batch pushes multiple messages.
112
120
  #
113
121
  # @param [<Hash>] payload the payloads of each message
122
+ #
114
123
  # @return [Boolean] whether or not pushing the messages was successful
124
+ #
125
+ # @raise [Zeppelin::ClientError] invalid payload format
115
126
  def batch_push(*payload)
116
- response = connection.post(BATCH_PUSH_URI, payload, JSON_HEADERS)
117
- response.success?
127
+ post_request(BATCH_PUSH_URI, payload)
118
128
  end
119
129
 
120
130
  # Broadcasts a message.
121
131
  #
122
132
  # @param [Hash] payload the payload of the message
133
+ #
123
134
  # @return [Boolean] whether or not broadcasting the message was successful
135
+ #
136
+ # @raise [Zeppelin::ClientError] invalid payload format
124
137
  def broadcast(payload)
125
- response = connection.post(BROADCAST_URI, payload, JSON_HEADERS)
126
- response.success?
138
+ post_request(BROADCAST_URI, payload)
127
139
  end
128
140
 
129
141
  # Retrieves feedback on device tokens.
@@ -131,18 +143,21 @@ class Zeppelin
131
143
  # This is useful for removing inactive device tokens for the database.
132
144
  #
133
145
  # @param [Time] since the time to retrieve inactive tokens from
146
+ #
134
147
  # @return [Hash, nil]
148
+ #
149
+ # @raise [Zeppelin::ClientError] invalid time param
135
150
  def feedback(since)
136
- response = connection.get(feedback_uri(since))
137
- response.success? ? response.body : nil
151
+ uri = feedback_uri(since)
152
+ get_request(uri)
138
153
  end
139
154
 
140
155
  # Retrieve all tags on the service
141
156
  #
142
157
  # @return [Hash, nil]
143
158
  def tags
144
- response = connection.get(tag_uri(nil))
145
- response.success? ? response.body : nil
159
+ uri = tag_uri(nil)
160
+ get_request(uri)
146
161
  end
147
162
 
148
163
  # Modifies device tokens associated with a tag.
@@ -153,7 +168,8 @@ class Zeppelin
153
168
  #
154
169
  # @see http://urbanairship.com/docs/tags.html#modifying-device-tokens-on-a-tag
155
170
  def modify_device_tokens_on_tag(tag_name, payload = {})
156
- connection.post(tag_uri(tag_name), payload, JSON_HEADERS)
171
+ uri = tag_uri(tag_name)
172
+ post_request(uri, payload)
157
173
  end
158
174
 
159
175
  # Creates a tag that is not associated with any device
@@ -162,8 +178,8 @@ class Zeppelin
162
178
  #
163
179
  # @return [Boolean] whether or not the request was successful
164
180
  def add_tag(name)
165
- response = connection.put(tag_uri(name))
166
- response.success?
181
+ uri = tag_uri(name)
182
+ put_request(uri)
167
183
  end
168
184
 
169
185
  # Removes a tag from the service
@@ -172,17 +188,21 @@ class Zeppelin
172
188
  #
173
189
  # @return [Boolean] true when the request was successful. Note that this
174
190
  # method will return false if the tag has already been removed.
191
+ #
192
+ # @raise [Zeppelin::ResourceNotFound] tag already removed
175
193
  def remove_tag(name)
176
- response = connection.delete(tag_uri(name))
177
- response.success?
194
+ uri = tag_uri(name)
195
+ delete_request(uri)
178
196
  end
179
197
 
180
198
  # @param [String] device_token
181
199
  #
182
200
  # @return [Hash, nil]
201
+ #
202
+ # @raise [Zeppelin::ResourceNotFound] device does not exist
183
203
  def device_tags(device_token)
184
- response = connection.get(device_tag_uri(device_token, nil))
185
- response.success? ? response.body : nil
204
+ uri = device_tag_uri(device_token, nil)
205
+ get_request(uri)
186
206
  end
187
207
 
188
208
  # @param [String] device_token
@@ -191,9 +211,11 @@ class Zeppelin
191
211
  #
192
212
  # @return [Boolean] whether or not a tag was successfully associated with
193
213
  # a device
214
+ #
215
+ # @raise [Zeppelin::ResourceNotFound] device does not exist
194
216
  def add_tag_to_device(device_token, tag_name)
195
- response = connection.put(device_tag_uri(device_token, tag_name))
196
- response.success?
217
+ uri = device_tag_uri(device_token, tag_name)
218
+ put_request(uri)
197
219
  end
198
220
 
199
221
  # @param [String] device_token
@@ -202,18 +224,23 @@ class Zeppelin
202
224
  #
203
225
  # @return [Boolean] whether or not a tag was successfully dissociated from
204
226
  # a device
227
+ #
228
+ # @raise [Zeppelin::ResourceNotFound] device does not exist
205
229
  def remove_tag_from_device(device_token, tag_name)
206
- response = connection.delete(device_tag_uri(device_token, tag_name))
207
- response.success?
230
+ uri = device_tag_uri(device_token, tag_name)
231
+ delete_request(uri)
208
232
  end
209
233
 
210
234
  private
211
235
 
212
236
  def initialize_connection
237
+ Faraday::Request::JSON.adapter = MultiJson
238
+
213
239
  conn = Faraday::Connection.new(BASE_URI, @options) do |builder|
214
240
  builder.request :json
215
241
 
216
- builder.use Zeppelin::JsonParserMiddleware
242
+ builder.use Zeppelin::Middleware::JsonParser
243
+ builder.use Zeppelin::Middleware::ResponseRaiseError
217
244
 
218
245
  builder.adapter :net_http
219
246
  end
@@ -223,6 +250,29 @@ class Zeppelin
223
250
  conn
224
251
  end
225
252
 
253
+ def put_request(uri, payload={})
254
+ if !(payload.nil? || payload.empty?)
255
+ response =connection.put(uri, payload, JSON_HEADERS)
256
+ else
257
+ response = connection.put(uri)
258
+ end
259
+
260
+ response.success?
261
+ end
262
+
263
+ def delete_request(uri)
264
+ connection.delete(uri).success?
265
+ end
266
+
267
+ def get_request(uri)
268
+ response = connection.get(uri)
269
+ response.body if response.success?
270
+ end
271
+
272
+ def post_request(uri, payload)
273
+ connection.post(uri, payload, JSON_HEADERS).success?
274
+ end
275
+
226
276
  def device_token_uri(device_token)
227
277
  "/api/device_tokens/#{device_token}"
228
278
  end
@@ -244,5 +294,5 @@ class Zeppelin
244
294
  end
245
295
  end
246
296
 
247
- require 'zeppelin/json_parser_middleware'
297
+ require 'zeppelin/middleware'
248
298
  require 'zeppelin/version'
@@ -0,0 +1,7 @@
1
+ class Zeppelin
2
+ module Middlware
3
+ end
4
+ end
5
+
6
+ require 'zeppelin/middleware/json_parser'
7
+ require 'zeppelin/middleware/response_raise_error'
@@ -0,0 +1,37 @@
1
+ require 'multi_json'
2
+
3
+ class Zeppelin
4
+ module Middleware
5
+ # Middleware for Faraday that parses JSON response bodies. Based on code in
6
+ # the FaradayMiddleware project.
7
+ #
8
+ # @private
9
+ class JsonParser < Faraday::Middleware
10
+ CONTENT_TYPE = 'Content-Type'
11
+
12
+ def initialize(app=nil)
13
+ @app = app
14
+ end
15
+
16
+ def call(env)
17
+ @app.call(env).on_complete do
18
+ parse_response(env) if process_content_type?(env) && parse_response?(env)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def parse_response(env)
25
+ env[:body] = MultiJson.decode(env[:body])
26
+ end
27
+
28
+ def process_content_type?(env)
29
+ env[:response_headers][CONTENT_TYPE].to_s =~ /\bjson$/
30
+ end
31
+
32
+ def parse_response?(env)
33
+ env[:body].respond_to? :to_str
34
+ end
35
+ end
36
+ end
37
+ end