grocer 0.3.1 → 0.3.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.3.2
4
+
5
+ * Validate the size of the payload before sending a notification
6
+
3
7
  ## 0.3.1
4
8
 
5
9
  * Move repo to the Grocer organization.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://api.travis-ci.org/grocer/grocer.png?branch=master)](https://travis-ci.org/grocer/grocer)
4
4
  [![Dependency Status](https://gemnasium.com/grocer/grocer.png)](https://gemnasium.com/grocer/grocer)
5
- [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/grocer/grocer)
5
+ [![Code Climate](https://codeclimate.com/github/grocer/grocer.png)](https://codeclimate.com/github/grocer/grocer)
6
6
 
7
7
  **grocer** interfaces with the [Apple Push Notification
8
8
  Service](http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html)
@@ -118,11 +118,22 @@ send any payload for a Passbook notification. If you do, it will be ignored.
118
118
 
119
119
  ```ruby
120
120
  notification = Grocer::PassbookNotification.new(device_token: "...")
121
-
122
121
  # Generates a JSON payload like:
123
122
  # {"aps": {}}
124
123
  ```
125
124
 
125
+ #### Newsstand Notifications
126
+
127
+ Grocer also supports the special Newsstand 'content-available' notification. `Grocer::NewsstandNotification` can be
128
+ used for this. Like `Grocer::PassbookNotification`, it is a specialized kind of notification which does not require
129
+ any payload. Likewise, anything you add to it will be ignored.
130
+
131
+ ```ruby
132
+ notification = Grocer::NewsstandNotification.new(device_token: "...")
133
+ # Generates a JSON payload like:
134
+ # {"aps": {"content-available":1}}
135
+ ````
136
+
126
137
  ### Feedback
127
138
 
128
139
  ```ruby
@@ -137,7 +148,7 @@ feedback = Grocer.feedback(
137
148
  )
138
149
 
139
150
  feedback.each do |attempt|
140
- puts "Device #{attempt.device_token} failed at #{attempt.timestamp}
151
+ puts "Device #{attempt.device_token} failed at #{attempt.timestamp}"
141
152
  end
142
153
  ```
143
154
 
@@ -1,7 +1,4 @@
1
1
  require 'grocer'
2
- require 'grocer/no_gateway_error'
3
- require 'grocer/no_port_error'
4
- require 'grocer/certificate_expired_error'
5
2
  require 'grocer/ssl_connection'
6
3
 
7
4
  module Grocer
@@ -1,5 +1,3 @@
1
- require 'grocer/invalid_format_error'
2
-
3
1
  module Grocer
4
2
  class FailedDeliveryAttempt
5
3
  LENGTH = 38
@@ -0,0 +1,24 @@
1
+ require 'grocer/notification'
2
+
3
+ module Grocer
4
+ # Public: A specialized form of a Grocer::Notification which requires neither
5
+ # an alert nor badge to be present in the payload. It requires only the
6
+ # `device_token` to be set.
7
+ #
8
+ # Examples
9
+ #
10
+ # Grocer::NewsstandNotification.new(device_token: '...')
11
+ class NewsstandNotification < Notification
12
+
13
+ private
14
+
15
+ def validate_payload
16
+ true
17
+ end
18
+
19
+ def payload_hash
20
+ { "content-available" => 1 }
21
+ end
22
+
23
+ end
24
+ end
@@ -1,9 +1,10 @@
1
1
  require 'json'
2
- require 'grocer/no_payload_error'
3
2
 
4
3
  module Grocer
5
4
  # Public: An object used to send notifications to APNS.
6
5
  class Notification
6
+ MAX_PAYLOAD_SIZE = 256
7
+
7
8
  attr_accessor :identifier, :expiry, :device_token, :alert, :badge, :sound,
8
9
  :custom
9
10
 
@@ -41,8 +42,13 @@ module Grocer
41
42
 
42
43
  private
43
44
 
45
+ def payload_too_large?
46
+ encoded_payload.bytesize > MAX_PAYLOAD_SIZE
47
+ end
48
+
44
49
  def validate_payload
45
50
  fail NoPayloadError unless alert || badge
51
+ fail PayloadTooLargeError if payload_too_large?
46
52
  end
47
53
 
48
54
  def encoded_payload
@@ -1,3 +1,3 @@
1
1
  module Grocer
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.2'
3
3
  end
data/lib/grocer.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'grocer/feedback'
2
2
  require 'grocer/notification'
3
3
  require 'grocer/passbook_notification'
4
+ require 'grocer/newsstand_notification'
4
5
  require 'grocer/feedback_connection'
5
6
  require 'grocer/push_connection'
6
7
  require 'grocer/pusher'
@@ -8,6 +9,13 @@ require 'grocer/version'
8
9
  require 'grocer/server'
9
10
 
10
11
  module Grocer
12
+ Error = Class.new(::StandardError)
13
+ InvalidFormatError = Class.new(Error)
14
+ NoGatewayError = Class.new(Error)
15
+ NoPayloadError = Class.new(Error)
16
+ NoPortError = Class.new(Error)
17
+ PayloadTooLargeError = Class.new(Error)
18
+ CertificateExpiredError = Module.new
11
19
 
12
20
  def self.env
13
21
  ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'grocer/newsstand_notification'
3
+ require 'grocer/shared_examples_for_notifications'
4
+
5
+ describe Grocer::NewsstandNotification do
6
+ describe 'binary format' do
7
+ let(:payload_options) { Hash.new }
8
+ let(:payload_from_bytes) { notification.to_bytes[45..-1] }
9
+ let(:payload_dictionary_from_bytes) { JSON.parse(payload_from_bytes, symbolize_names: true) }
10
+
11
+ include_examples 'a notification'
12
+
13
+ it 'does require a payload' do
14
+ expect(payload_dictionary_from_bytes[:'content-available']).to_not be_nil
15
+ end
16
+
17
+ it 'has a content-available hash' do
18
+ expect(payload_dictionary_from_bytes[:'content-available']).to eq(1)
19
+ end
20
+
21
+ end
22
+ end
@@ -46,12 +46,20 @@ describe Grocer::Notification do
46
46
  expect(bytes[43...45]).to eq([payload_from_bytes.bytesize].pack('n'))
47
47
  end
48
48
 
49
- context 'invalid payload' do
49
+ context 'missing payload' do
50
50
  let(:payload_options) { Hash.new }
51
51
 
52
52
  it 'raises an error when neither alert nor badge is specified' do
53
53
  -> { notification.to_bytes }.should raise_error(Grocer::NoPayloadError)
54
54
  end
55
55
  end
56
+
57
+ context 'oversized payload' do
58
+ let(:payload_options) { { alert: 'a' * (Grocer::Notification::MAX_PAYLOAD_SIZE + 1) } }
59
+
60
+ it 'raises an error when the size of the payload in bytes is too large' do
61
+ -> { notification.to_bytes }.should raise_error(Grocer::PayloadTooLargeError)
62
+ end
63
+ end
56
64
  end
57
65
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grocer
3
3
  version: !ruby/object:Gem::Version
4
+ version: 0.3.2
4
5
  prerelease:
5
- version: 0.3.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Andy Lindeman
@@ -11,88 +11,88 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-01-05 00:00:00.000000000 Z
14
+ date: 2013-02-28 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
- version_requirements: !ruby/object:Gem::Requirement
17
+ name: rspec
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
18
20
  requirements:
19
21
  - - ~>
20
22
  - !ruby/object:Gem::Version
21
23
  version: '2.11'
22
- none: false
23
- name: rspec
24
24
  type: :development
25
25
  prerelease: false
26
- requirement: !ruby/object:Gem::Requirement
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
27
28
  requirements:
28
29
  - - ~>
29
30
  - !ruby/object:Gem::Version
30
31
  version: '2.11'
31
- none: false
32
32
  - !ruby/object:Gem::Dependency
33
- version_requirements: !ruby/object:Gem::Requirement
33
+ name: pry
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
34
36
  requirements:
35
37
  - - ~>
36
38
  - !ruby/object:Gem::Version
37
39
  version: 0.9.8
38
- none: false
39
- name: pry
40
40
  type: :development
41
41
  prerelease: false
42
- requirement: !ruby/object:Gem::Requirement
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
43
44
  requirements:
44
45
  - - ~>
45
46
  - !ruby/object:Gem::Version
46
47
  version: 0.9.8
47
- none: false
48
48
  - !ruby/object:Gem::Dependency
49
- version_requirements: !ruby/object:Gem::Requirement
49
+ name: mocha
50
+ requirement: !ruby/object:Gem::Requirement
51
+ none: false
50
52
  requirements:
51
53
  - - ! '>='
52
54
  - !ruby/object:Gem::Version
53
55
  version: '0'
54
- none: false
55
- name: mocha
56
56
  type: :development
57
57
  prerelease: false
58
- requirement: !ruby/object:Gem::Requirement
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ none: false
59
60
  requirements:
60
61
  - - ! '>='
61
62
  - !ruby/object:Gem::Version
62
63
  version: '0'
63
- none: false
64
64
  - !ruby/object:Gem::Dependency
65
- version_requirements: !ruby/object:Gem::Requirement
65
+ name: bourne
66
+ requirement: !ruby/object:Gem::Requirement
67
+ none: false
66
68
  requirements:
67
69
  - - ! '>='
68
70
  - !ruby/object:Gem::Version
69
71
  version: '0'
70
- none: false
71
- name: bourne
72
72
  type: :development
73
73
  prerelease: false
74
- requirement: !ruby/object:Gem::Requirement
74
+ version_requirements: !ruby/object:Gem::Requirement
75
+ none: false
75
76
  requirements:
76
77
  - - ! '>='
77
78
  - !ruby/object:Gem::Version
78
79
  version: '0'
79
- none: false
80
80
  - !ruby/object:Gem::Dependency
81
- version_requirements: !ruby/object:Gem::Requirement
81
+ name: rake
82
+ requirement: !ruby/object:Gem::Requirement
83
+ none: false
82
84
  requirements:
83
85
  - - ! '>='
84
86
  - !ruby/object:Gem::Version
85
87
  version: '0'
86
- none: false
87
- name: rake
88
88
  type: :development
89
89
  prerelease: false
90
- requirement: !ruby/object:Gem::Requirement
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ none: false
91
92
  requirements:
92
93
  - - ! '>='
93
94
  - !ruby/object:Gem::Version
94
95
  version: '0'
95
- none: false
96
96
  description: ! " Grocer interfaces with the Apple Push\n
97
97
  \ Notification Service to send push\n notifications
98
98
  to iOS devices and collect\n notification feedback via
@@ -117,16 +117,12 @@ files:
117
117
  - Rakefile
118
118
  - grocer.gemspec
119
119
  - lib/grocer.rb
120
- - lib/grocer/certificate_expired_error.rb
121
120
  - lib/grocer/connection.rb
122
121
  - lib/grocer/extensions/deep_symbolize_keys.rb
123
122
  - lib/grocer/failed_delivery_attempt.rb
124
123
  - lib/grocer/feedback.rb
125
124
  - lib/grocer/feedback_connection.rb
126
- - lib/grocer/invalid_format_error.rb
127
- - lib/grocer/no_gateway_error.rb
128
- - lib/grocer/no_payload_error.rb
129
- - lib/grocer/no_port_error.rb
125
+ - lib/grocer/newsstand_notification.rb
130
126
  - lib/grocer/notification.rb
131
127
  - lib/grocer/notification_reader.rb
132
128
  - lib/grocer/passbook_notification.rb
@@ -147,6 +143,7 @@ files:
147
143
  - spec/grocer/failed_delivery_attempt_spec.rb
148
144
  - spec/grocer/feedback_connection_spec.rb
149
145
  - spec/grocer/feedback_spec.rb
146
+ - spec/grocer/newsstand_notification_spec.rb
150
147
  - spec/grocer/notification_reader_spec.rb
151
148
  - spec/grocer/notification_spec.rb
152
149
  - spec/grocer/passbook_notification_spec.rb
@@ -166,17 +163,23 @@ rdoc_options: []
166
163
  require_paths:
167
164
  - lib
168
165
  required_ruby_version: !ruby/object:Gem::Requirement
166
+ none: false
169
167
  requirements:
170
168
  - - ! '>='
171
169
  - !ruby/object:Gem::Version
172
170
  version: '0'
173
- none: false
171
+ segments:
172
+ - 0
173
+ hash: -399715243168588084
174
174
  required_rubygems_version: !ruby/object:Gem::Requirement
175
+ none: false
175
176
  requirements:
176
177
  - - ! '>='
177
178
  - !ruby/object:Gem::Version
178
179
  version: '0'
179
- none: false
180
+ segments:
181
+ - 0
182
+ hash: -399715243168588084
180
183
  requirements: []
181
184
  rubyforge_project:
182
185
  rubygems_version: 1.8.23
@@ -192,6 +195,7 @@ test_files:
192
195
  - spec/grocer/failed_delivery_attempt_spec.rb
193
196
  - spec/grocer/feedback_connection_spec.rb
194
197
  - spec/grocer/feedback_spec.rb
198
+ - spec/grocer/newsstand_notification_spec.rb
195
199
  - spec/grocer/notification_reader_spec.rb
196
200
  - spec/grocer/notification_spec.rb
197
201
  - spec/grocer/passbook_notification_spec.rb
@@ -203,4 +207,3 @@ test_files:
203
207
  - spec/grocer/ssl_server_spec.rb
204
208
  - spec/grocer_spec.rb
205
209
  - spec/spec_helper.rb
206
- has_rdoc:
@@ -1,3 +0,0 @@
1
- module Grocer
2
- CertificateExpiredError = Module.new
3
- end
@@ -1,4 +0,0 @@
1
- module Grocer
2
- class InvalidFormatError < StandardError
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module Grocer
2
- class NoGatewayError < StandardError
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module Grocer
2
- class NoPayloadError < StandardError
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module Grocer
2
- class NoPortError < StandardError
3
- end
4
- end