bmo 0.8.10 → 0.8.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/Gemfile.lock +1 -1
- data/lib/bmo/apns/notification.rb +31 -12
- data/lib/bmo/gcm/notification.rb +1 -1
- data/lib/bmo/utils.rb +28 -0
- data/lib/bmo/version.rb +1 -1
- data/lib/bmo.rb +8 -2
- data/spec/bmo/apns/notification_spec.rb +37 -15
- data/spec/bmo/utils_spec.rb +59 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWVjNzg2YTQ0NmNkMWNkYjI5NTYyZjZkNzg2NGM1NjE5NGI4OGY3Zg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZjdmZjgxZDNkYTgzZmE5Yzc0MjY4ZTg1M2E0MDQzYTI3ZmQzOTY1YQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZTI5ZmYwOTBlYTRmNWMyNWEwMjAzNWY4MWFjNWEwNDc4MjFiN2RlMjQ4MGI2
|
10
|
+
ZmE5ODA2MzVhOTU5NzY1OGIwODk0NTdkZjFkN2RmNzk1MDI0M2E0YTMxMDY1
|
11
|
+
NDA4OWU0ZWZlODc2YjlkYjNmZWE0Y2UxM2Y4ODQwZTg1OGQwNDg=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZmI0NWNhZGI0MGFlYjczZmI5ZGI4YmRlNjFiZTFjZTQ3MmVhZGY0OTA2ZTFk
|
14
|
+
ZjhiNWZlNzg2NWI2MmNiMDdjNjg0OGFkNGM1ZmEyMDBlMmUzZGE5NzVkNzVj
|
15
|
+
NGVhNTlhMjhkNTMwZWY0NWQ0MGZmNjBhYzVkYjAxYmNlNTBhM2Q=
|
data/Gemfile.lock
CHANGED
@@ -8,9 +8,9 @@ module BMO
|
|
8
8
|
|
9
9
|
attr_reader :device_token, :payload
|
10
10
|
|
11
|
-
def initialize(device_token, payload)
|
11
|
+
def initialize(device_token, payload, options = {})
|
12
12
|
@device_token = DeviceToken.new(device_token)
|
13
|
-
@payload = Payload.new(payload)
|
13
|
+
@payload = Payload.new(payload, options)
|
14
14
|
end
|
15
15
|
|
16
16
|
def to_package
|
@@ -40,23 +40,42 @@ module BMO
|
|
40
40
|
# Define ==
|
41
41
|
include Equalizer.new(:data)
|
42
42
|
|
43
|
-
attr_reader :data
|
43
|
+
attr_reader :data, :truncable_field, :options
|
44
44
|
|
45
|
-
def initialize(data)
|
46
|
-
@data
|
45
|
+
def initialize(data, options = {})
|
46
|
+
@data = data
|
47
|
+
@truncable_field = options[:truncable_field]
|
48
|
+
@options = options
|
47
49
|
end
|
48
50
|
|
49
51
|
def to_package
|
50
|
-
|
52
|
+
truncate_field! if truncable_field && !valid?
|
53
|
+
validate!
|
54
|
+
package
|
51
55
|
end
|
52
56
|
|
53
57
|
def validate!
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
return true if valid?
|
59
|
+
str = "Payload byte size (#{package.bytesize})" \
|
60
|
+
" should be less than #{Payload::MAX_BYTE_SIZE} bytes"
|
61
|
+
fail PayloadTooLarge, str
|
62
|
+
end
|
63
|
+
|
64
|
+
def package
|
65
|
+
data.to_json.bytes.to_a.pack('C*')
|
66
|
+
end
|
67
|
+
|
68
|
+
def truncate_field!
|
69
|
+
return unless data[:apns] && data[:apns][truncable_field]
|
70
|
+
string = data[:apns][truncable_field]
|
71
|
+
diff_bytesize = package.bytesize - MAX_BYTE_SIZE
|
72
|
+
desirable_bytesize = (string.bytesize - diff_bytesize) - 1
|
73
|
+
data[:apns][truncable_field] = Utils
|
74
|
+
.bytesize_force_truncate(string, desirable_bytesize, options)
|
75
|
+
end
|
76
|
+
|
77
|
+
def valid?
|
78
|
+
package.bytesize < MAX_BYTE_SIZE
|
60
79
|
end
|
61
80
|
end # class Payload
|
62
81
|
|
data/lib/bmo/gcm/notification.rb
CHANGED
data/lib/bmo/utils.rb
CHANGED
@@ -11,5 +11,33 @@ module BMO
|
|
11
11
|
end
|
12
12
|
hash_symbolized
|
13
13
|
end
|
14
|
+
|
15
|
+
# Byte aware truncation
|
16
|
+
def self.bytesize_force_truncate(string, bytesize, options = {})
|
17
|
+
if bytesize <= 0
|
18
|
+
return ''
|
19
|
+
elsif bytesize > string.bytesize
|
20
|
+
return string.dup
|
21
|
+
end
|
22
|
+
|
23
|
+
options[:omission] ||= '...'
|
24
|
+
computed_bytesize = bytesize - options[:omission].bytesize
|
25
|
+
return bytesize_force_truncate(options[:omission],
|
26
|
+
bytesize,
|
27
|
+
omission: '') if computed_bytesize <= 0
|
28
|
+
new_string = ''
|
29
|
+
|
30
|
+
string.chars.each_with_index do |char, i|
|
31
|
+
break if (new_string + char).bytesize > computed_bytesize
|
32
|
+
new_string << char
|
33
|
+
end
|
34
|
+
|
35
|
+
stop = if options[:separator]
|
36
|
+
new_string.rindex(options[:separator]) || new_string.length
|
37
|
+
else
|
38
|
+
new_string.length
|
39
|
+
end
|
40
|
+
(new_string[0...stop] + options[:omission]).to_s
|
41
|
+
end
|
14
42
|
end
|
15
43
|
end
|
data/lib/bmo/version.rb
CHANGED
data/lib/bmo.rb
CHANGED
@@ -25,14 +25,19 @@ module BMO
|
|
25
25
|
#
|
26
26
|
# @param device_token [String]
|
27
27
|
# @param data [Hash] The data you want to send
|
28
|
+
# @option options :truncable_field If the payload is too large
|
29
|
+
# this field will be truncated, it must be in a apns hash
|
30
|
+
# @option options :omission ('...') The omission in truncate
|
31
|
+
# @option options :separator The separator use in truncation
|
28
32
|
#
|
29
33
|
# @return The Socket#write return
|
30
34
|
#
|
31
35
|
# @see https://developer.apple.com/library/ios/documentation/
|
32
36
|
# NetworkingInternet/Conceptual/RemoteNotificationsPG/
|
33
37
|
# Chapters/ApplePushService.html
|
34
|
-
def self.send_ios_notification(device_token, data)
|
35
|
-
|
38
|
+
def self.send_ios_notification(device_token, data, options = {})
|
39
|
+
data = Utils.coerce_to_symbols(data)
|
40
|
+
notification = APNS::Notification.new(device_token, data, options)
|
36
41
|
notification.validate!
|
37
42
|
apns_client.send_notification(notification)
|
38
43
|
end
|
@@ -55,6 +60,7 @@ module BMO
|
|
55
60
|
#
|
56
61
|
# @see http://developer.android.com/google/gcm/server.html]
|
57
62
|
def self.send_android_notification(device_token, data)
|
63
|
+
data = Utils.coerce_to_symbols(data)
|
58
64
|
notification = GCM::Notification.new(device_token, data)
|
59
65
|
notification.validate!
|
60
66
|
gcm_client.send_notification(notification)
|
@@ -31,21 +31,6 @@ describe BMO::APNS::Notification::DeviceToken do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
describe BMO::APNS::Notification::Payload do
|
34
|
-
it 'coerce hash keys to symbols' do
|
35
|
-
payload = described_class.new('Finn' => 'The Human')
|
36
|
-
expect(payload.data).to eq(Finn: 'The Human')
|
37
|
-
end
|
38
|
-
|
39
|
-
it "doesn't coerce incompatible types" do
|
40
|
-
payload = described_class.new(1 => 'For Money')
|
41
|
-
expect(payload.data).to eq(1 => 'For Money')
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'returns true for equality between coerced hash and symbolized hash ' do
|
45
|
-
payload = described_class.new('Jake' => 'The Dog')
|
46
|
-
expect(payload).to eq(described_class.new(Jake: 'The Dog'))
|
47
|
-
end
|
48
|
-
|
49
34
|
describe '#validate!' do
|
50
35
|
it 'returns true if the payload is valid' do
|
51
36
|
payload = described_class.new(apns: 'a' * 200)
|
@@ -57,4 +42,41 @@ describe BMO::APNS::Notification::Payload do
|
|
57
42
|
BMO::APNS::Notification::Payload::PayloadTooLarge)
|
58
43
|
end
|
59
44
|
end
|
45
|
+
|
46
|
+
describe '#to_package' do
|
47
|
+
it 'truncates if there is a truncable field and this is not valid' do
|
48
|
+
options = { truncable_field: :message }
|
49
|
+
payload = described_class.new({ apns: { message: 'a' * 256 } }, options)
|
50
|
+
expect(payload.to_package).to eq("{\"apns\":{\"message\":\"#{'a' * 229}...\"}}")
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'truncates to respect the MAX_BYTE_SIZE' do
|
54
|
+
options = { truncable_field: :message }
|
55
|
+
payload = described_class.new({ apns: { message: 'a' * 256 } }, options)
|
56
|
+
expect(payload.to_package.bytesize).to be < BMO::APNS::Notification::Payload::MAX_BYTE_SIZE
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#truncable_field!' do
|
61
|
+
it 'truncates the corresponding field in apns' do
|
62
|
+
options = { truncable_field: :message }
|
63
|
+
payload = described_class.new({ apns: { message: 'a' * 256 } }, options)
|
64
|
+
payload.truncate_field!
|
65
|
+
expect(payload.data[:apns][:message]).to eq(('a' * 229) + '...')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'truncates with omission' do
|
69
|
+
options = { truncable_field: :message, omission: '[more]' }
|
70
|
+
payload = described_class.new({ apns: { message: 'a' * 256 } }, options)
|
71
|
+
payload.truncate_field!
|
72
|
+
expect(payload.data[:apns][:message]).to eq(('a' * 226) + '[more]')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'truncates with separator' do
|
76
|
+
options = { truncable_field: :message, separator: ' ' }
|
77
|
+
payload = described_class.new({ apns: { message: 'test ' + ('a' * 255) } }, options)
|
78
|
+
payload.truncate_field!
|
79
|
+
expect(payload.data[:apns][:message]).to eq('test...')
|
80
|
+
end
|
81
|
+
end
|
60
82
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe BMO::Utils do
|
5
|
+
describe '#bytesize_force_truncate' do
|
6
|
+
|
7
|
+
it 'truncates the string' do
|
8
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', 10, omission: ''))
|
9
|
+
.to eq('Ça a déb')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'adds a default omission' do
|
13
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', 10))
|
14
|
+
.to eq('Ça a d...')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'adds accepts an optional omission params' do
|
18
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', 10, omission: '[more]'))
|
19
|
+
.to eq('Ça [more]')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'forces the returned string to be less or equal to the length' do
|
23
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', 10, omission: '[more]').bytesize)
|
24
|
+
.to be 10
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'does not mutate the string' do
|
28
|
+
string = 'Ça a débuté comme ça.'
|
29
|
+
BMO::Utils.bytesize_force_truncate(string, 10)
|
30
|
+
expect(string.bytesize)
|
31
|
+
.to be > 10
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns an empty string if the length if less than 1' do
|
35
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', -2))
|
36
|
+
.to eq('')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns the whole string if the length is more than the string length' do
|
40
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', 100000))
|
41
|
+
.to eq('Ça a débuté comme ça.')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'accepts a separator param' do
|
45
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', 20, separator: ' '))
|
46
|
+
.to eq('Ça a débuté...')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns an empty string if the length if less than 1' do
|
50
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', -2))
|
51
|
+
.to eq('')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'truncates the omission too' do
|
55
|
+
expect(BMO::Utils.bytesize_force_truncate('Ça a débuté comme ça.', 2))
|
56
|
+
.to eq('..')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bmo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Antoine Lyset
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: equalizer
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- lib/bmo/utils.rb
|
96
96
|
- lib/bmo/version.rb
|
97
97
|
- spec/bmo/apns/notification_spec.rb
|
98
|
+
- spec/bmo/utils_spec.rb
|
98
99
|
- spec/spec_helper.rb
|
99
100
|
homepage: https://github.com/antoinelyset/bmo
|
100
101
|
licenses:
|
@@ -122,5 +123,6 @@ specification_version: 4
|
|
122
123
|
summary: Push notifications to iOS and Android devices
|
123
124
|
test_files:
|
124
125
|
- spec/bmo/apns/notification_spec.rb
|
126
|
+
- spec/bmo/utils_spec.rb
|
125
127
|
- spec/spec_helper.rb
|
126
128
|
has_rdoc:
|