grocer 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c6555a705340dbf836a1e108191917cb6e070cd4
4
- data.tar.gz: ff071fb2ba59d97b416843adfd3242482628cb0a
3
+ metadata.gz: 22fd48d5c9119fdaf4ebe30482265fd29b42dcda
4
+ data.tar.gz: e4d34ea7dd2625b96e17a1e373b6d7172b8752c6
5
5
  SHA512:
6
- metadata.gz: 18b17445045304ce0dca3673e8f56188fea6c94df2870a6c56dce035dc79af6c8c6dab48900d3aac37b6a5e687dd5e7486dc6285f4c90b3274ba6292ba90f4c7
7
- data.tar.gz: 99874e8769c23afd6a8f5401fae5f276cc6f17b1b65e920d2ed3cfbbbe60bc5ce3a7aeb451de1d08a5cdf97cec368217cd861ed6c309e325fbdc572509cf6619
6
+ metadata.gz: 378b66ae89f8a80446f4b5c36a10894a0f4674e69f8ca041608a162e0030d9d44ec8daecd636119774150391e2c63c17f2dc08c91167899095e2aca5fcecf363
7
+ data.tar.gz: f2498ef365ec5e89fad9d57f79e1dd173fea1742bd6e3b106177383f03d221a3d43d0c915ada43cc11d1f42c67b3112628f60b584627e0c0becade524a57c606
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.5.0
6
+
7
+ * Add `Grocer::SafariNotification` for sending Safari notifications in OS X
8
+ Mavericks. ([Ben Ubois](https://github.com/benubois) and [Adam
9
+ Duke](adamvduke))
10
+
5
11
  ## 0.4.1
6
12
 
7
13
  * Fix `Grocer::NotificationReader`, ensuring it sanitizes incoming `aps`
data/README.md CHANGED
@@ -125,9 +125,10 @@ notification = Grocer::PassbookNotification.new(device_token: "...")
125
125
 
126
126
  #### Newsstand Notifications
127
127
 
128
- Grocer also supports the special Newsstand 'content-available' notification. `Grocer::NewsstandNotification` can be
129
- used for this. Like `Grocer::PassbookNotification`, it is a specialized kind of notification which does not require
130
- any payload. Likewise, anything you add to it will be ignored.
128
+ Grocer also supports the special Newsstand 'content-available' notification.
129
+ `Grocer::NewsstandNotification` can be used for this. Like
130
+ `Grocer::PassbookNotification`, it is a specialized kind of notification which
131
+ does not require any payload. Likewise, anything you add to it will be ignored.
131
132
 
132
133
  ```ruby
133
134
  notification = Grocer::NewsstandNotification.new(device_token: "...")
@@ -135,6 +136,38 @@ notification = Grocer::NewsstandNotification.new(device_token: "...")
135
136
  # {"aps": {"content-available":1}}
136
137
  ````
137
138
 
139
+ #### Safari Notifications
140
+
141
+ Grocer can be used for [Safari Push
142
+ Notifications](https://developer.apple.com/notifications/safari-push-notifications/)
143
+ introduced in Mavericks.
144
+
145
+ ```ruby
146
+ notification = Grocer::SafariNotification.new(
147
+ device_token: '...', # required
148
+ title: 'Hello from Grocer', # required
149
+ body: 'Hi', # required
150
+ action: 'Read', # optional; the label of the action button
151
+ url_args: ['arg1'] # required (array); values that are paired with the placeholders inside the urlFormatString.
152
+ # Apple's documention lists url-args as optional, but in testing it was found to be required
153
+ )
154
+ ```
155
+
156
+ Generates a JSON payload like:
157
+
158
+ ```json
159
+ {
160
+ "aps": {
161
+ "alert": {
162
+ "title": "Hello from Grocer",
163
+ "body": "Hi",
164
+ "action": "Read"
165
+ },
166
+ "url-args": [ "arg1" ]
167
+ }
168
+ }
169
+ ```
170
+
138
171
  ### Feedback
139
172
 
140
173
  ```ruby
data/lib/grocer.rb CHANGED
@@ -5,6 +5,7 @@ require 'grocer/mobile_device_management_notification'
5
5
  require 'grocer/newsstand_notification'
6
6
  require 'grocer/notification'
7
7
  require 'grocer/passbook_notification'
8
+ require 'grocer/safari_notification'
8
9
  require 'grocer/push_connection'
9
10
  require 'grocer/pusher'
10
11
  require 'grocer/server'
@@ -69,8 +69,12 @@ module Grocer
69
69
  def validate_payload
70
70
  fail NoPayloadError unless alert || badge || custom
71
71
  fail PayloadTooLargeError if payload_too_large?
72
+ true
73
+ end
74
+
75
+ def valid?
76
+ validate_payload rescue false
72
77
  end
73
- alias_method :valid?, :validate_payload
74
78
 
75
79
  private
76
80
 
@@ -39,14 +39,10 @@ module Grocer
39
39
  end
40
40
 
41
41
  def sanitize_keys(hash)
42
- hash ||= {}
43
-
44
- clean_hash = hash.map { |k, v|
45
- new_key = k.to_s.gsub(/-/i, '_').to_sym
46
- [new_key, v]
47
- }
48
-
49
- Hash[clean_hash]
42
+ hash.each_with_object({}) do |(k,v), h|
43
+ new_key = k.to_s.gsub(/-/,'_').to_sym
44
+ h[new_key] = v
45
+ end
50
46
  end
51
47
  end
52
48
  end
@@ -0,0 +1,85 @@
1
+ require 'grocer/notification'
2
+
3
+ module Grocer
4
+ # Public: A specialized form of a Grocer::Notification for sending
5
+ # Safari push notifications
6
+ #
7
+ # Examples
8
+ #
9
+ # Grocer::SafariNotification.new(
10
+ # device_token: '...',
11
+ # title: '...',
12
+ # body: '...',
13
+ # action: '...',
14
+ # url_args: ['...']
15
+ # )
16
+ #
17
+ # #=>
18
+ # {
19
+ # "aps": {
20
+ # "alert": {
21
+ # "title": "...",
22
+ # "body": "...",
23
+ # "action": "..."
24
+ # },
25
+ # "url-args": ["..."]
26
+ # }
27
+ # }
28
+ class SafariNotification < Notification
29
+
30
+ def initialize(payload = {})
31
+ self.alert = {}
32
+ super(payload)
33
+ end
34
+
35
+ def title
36
+ alert[:title]
37
+ end
38
+
39
+ def title=(title)
40
+ alert[:title] = title
41
+ @encoded_payload = nil
42
+ end
43
+
44
+ def body
45
+ alert[:body]
46
+ end
47
+
48
+ def body=(body)
49
+ alert[:body] = body
50
+ @encoded_payload = nil
51
+ end
52
+
53
+ def action
54
+ alert[:action]
55
+ end
56
+
57
+ def action=(action)
58
+ alert[:action] = action
59
+ @encoded_payload = nil
60
+ end
61
+
62
+ def url_args
63
+ Array(@url_args)
64
+ end
65
+
66
+ def url_args=(args)
67
+ @url_args = args.dup
68
+ @encoded_payload = nil
69
+ end
70
+
71
+ private
72
+
73
+ def validate_payload
74
+ fail ArgumentError.new('missing title') unless title
75
+ fail ArgumentError.new('missing body') unless body
76
+ super
77
+ end
78
+
79
+ def payload_hash
80
+ aps_hash = { alert: alert }
81
+ aps_hash[:'url-args'] = url_args
82
+ { aps: aps_hash }
83
+ end
84
+ end
85
+ end
@@ -1,3 +1,3 @@
1
1
  module Grocer
2
- VERSION = '0.4.1'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -55,6 +55,10 @@ describe Grocer::Notification do
55
55
  expect(payload[:aps]).to_not have_key(:'content-available')
56
56
  end
57
57
 
58
+ it "is valid" do
59
+ expect(notification.valid?).to be_true
60
+ end
61
+
58
62
  context 'missing payload' do
59
63
  let(:payload_options) { Hash.new }
60
64
 
@@ -62,6 +66,10 @@ describe Grocer::Notification do
62
66
  -> { notification.to_bytes }.should raise_error(Grocer::NoPayloadError)
63
67
  end
64
68
 
69
+ it 'is not valid' do
70
+ expect(notification.valid?).to be_false
71
+ end
72
+
65
73
  [{alert: 'hi'}, {badge: 1}, {custom: {a: 'b'}}].each do |payload|
66
74
  context "when #{payload.keys.first} exists, but not any other payload keys" do
67
75
  let(:payload_options) { payload }
@@ -79,6 +87,10 @@ describe Grocer::Notification do
79
87
  it 'raises an error when the size of the payload in bytes is too large' do
80
88
  -> { notification.to_bytes }.should raise_error(Grocer::PayloadTooLargeError)
81
89
  end
90
+
91
+ it 'is not valid' do
92
+ expect(notification.valid?).to be_false
93
+ end
82
94
  end
83
95
  end
84
96
  end
@@ -0,0 +1,111 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+ require 'grocer/safari_notification'
4
+ require 'grocer/shared_examples_for_notifications'
5
+
6
+ describe Grocer::SafariNotification do
7
+ describe 'binary format' do
8
+ let(:payload_options) {
9
+ {
10
+ title: 'Grocer Update!',
11
+ body: 'Grocer now supports Safari Notifications',
12
+ action: 'View',
13
+ url_args: ['message_id', '124234']
14
+ }
15
+ }
16
+ let(:payload) { payload_hash(notification) }
17
+
18
+ include_examples 'a notification'
19
+
20
+ it 'encodes title as part of the payload' do
21
+ notification.title = 'Hello World!'
22
+ expect(payload[:aps][:alert][:title]).to eq('Hello World!')
23
+ end
24
+
25
+ it 'encodes body as part of the payload' do
26
+ notification.body = 'In the body'
27
+ expect(payload[:aps][:alert][:body]).to eq('In the body')
28
+ end
29
+
30
+ it 'encodes action as part of the payload' do
31
+ notification.action = 'Launch'
32
+ expect(payload[:aps][:alert][:action]).to eq('Launch')
33
+ end
34
+
35
+ it 'encodes url-args payload attributes' do
36
+ notification.url_args = ['hello', 'world']
37
+ expect(payload[:aps][:'url-args']).to eq(['hello','world'])
38
+ end
39
+
40
+ it 'is valid' do
41
+ expect(notification.valid?).to be_true
42
+ end
43
+
44
+ context 'missing parameters' do
45
+ context 'title' do
46
+ let(:payload_options) { { alert: { body: 'This is a body' } } }
47
+
48
+ it 'raises an error when title is missing' do
49
+ -> { notification.to_bytes }.should raise_error(ArgumentError)
50
+ end
51
+
52
+ it 'is not valid' do
53
+ expect(notification.valid?).to be_false
54
+ end
55
+ end
56
+
57
+ context 'body' do
58
+ let(:payload_options) { { alert: { title: 'This is a title' } } }
59
+
60
+ it 'raises an error when body is missing' do
61
+ -> { notification.to_bytes }.should raise_error(ArgumentError)
62
+ end
63
+
64
+ it 'is not valid' do
65
+ expect(notification.valid?).to be_false
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'oversized payload' do
71
+ let(:payload_options) { { alert: { title: 'Test', body: 'a' * (Grocer::Notification::MAX_PAYLOAD_SIZE + 1) } } }
72
+
73
+ it 'raises an error when the size of the payload in bytes is too large' do
74
+ -> { notification.to_bytes }.should raise_error(Grocer::PayloadTooLargeError)
75
+ end
76
+
77
+ it 'is not valid' do
78
+ expect(notification.valid?).to be_false
79
+ end
80
+ end
81
+
82
+ context 'with a complete alert hash passed to the initializer' do
83
+ let(:payload_options) {
84
+ {
85
+ alert: {
86
+ title: 'Title',
87
+ body: 'Body',
88
+ action: 'View'
89
+ },
90
+ url_args: ['hello', 'world']
91
+ }
92
+ }
93
+
94
+ it 'has the correct title' do
95
+ expect(notification.title).to eq('Title')
96
+ end
97
+
98
+ it 'has the correct body' do
99
+ expect(notification.body).to eq('Body')
100
+ end
101
+
102
+ it 'has the correct action' do
103
+ expect(notification.action).to eq('View')
104
+ end
105
+
106
+ it 'has the correct url-args' do
107
+ expect(notification.url_args).to eq(['hello','world'])
108
+ end
109
+ end
110
+ end
111
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grocer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Lindeman
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-06-20 00:00:00.000000000 Z
13
+ date: 2013-11-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -123,6 +123,7 @@ files:
123
123
  - lib/grocer/passbook_notification.rb
124
124
  - lib/grocer/push_connection.rb
125
125
  - lib/grocer/pusher.rb
126
+ - lib/grocer/safari_notification.rb
126
127
  - lib/grocer/server.rb
127
128
  - lib/grocer/ssl_connection.rb
128
129
  - lib/grocer/ssl_server.rb
@@ -146,6 +147,7 @@ files:
146
147
  - spec/grocer/passbook_notification_spec.rb
147
148
  - spec/grocer/push_connection_spec.rb
148
149
  - spec/grocer/pusher_spec.rb
150
+ - spec/grocer/safari_notification_spec.rb
149
151
  - spec/grocer/server_spec.rb
150
152
  - spec/grocer/shared_examples_for_notifications.rb
151
153
  - spec/grocer/ssl_connection_spec.rb
@@ -173,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
175
  version: '0'
174
176
  requirements: []
175
177
  rubyforge_project:
176
- rubygems_version: 2.0.2
178
+ rubygems_version: 2.1.10
177
179
  signing_key:
178
180
  specification_version: 4
179
181
  summary: Pushing Apple notifications since 2012.
@@ -194,6 +196,7 @@ test_files:
194
196
  - spec/grocer/passbook_notification_spec.rb
195
197
  - spec/grocer/push_connection_spec.rb
196
198
  - spec/grocer/pusher_spec.rb
199
+ - spec/grocer/safari_notification_spec.rb
197
200
  - spec/grocer/server_spec.rb
198
201
  - spec/grocer/shared_examples_for_notifications.rb
199
202
  - spec/grocer/ssl_connection_spec.rb
@@ -201,3 +204,4 @@ test_files:
201
204
  - spec/grocer_spec.rb
202
205
  - spec/spec_helper.rb
203
206
  - spec/support/notification_helpers.rb
207
+ has_rdoc: