zeppelin 0.5.0 → 0.6.0

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/.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