grocer 0.4.1 → 0.5.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.
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: