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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NjY1MWQ5Nzk5Yjg0ZWRkZjJmOTA2MTQwMjA0NWU0NjI5NjhhOGQ0Mw==
4
+ YWVjNzg2YTQ0NmNkMWNkYjI5NTYyZjZkNzg2NGM1NjE5NGI4OGY3Zg==
5
5
  data.tar.gz: !binary |-
6
- OWY3Mjg3YzZhOWE2OTA3MDgxMWQwYzMyOWVmNTc0YTdhMDEzOWIyYg==
6
+ ZjdmZjgxZDNkYTgzZmE5Yzc0MjY4ZTg1M2E0MDQzYTI3ZmQzOTY1YQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YTRjMjZkZjE3ZmIxYmRkNzJjNmY1Njc3ZDhiMmE5MjhlMTY0ZDI2NzdlNWFm
10
- ODU2OWIwNTM5NjI5Y2M2NjIzOGVjNDEwYTMxNjI4YmE0Y2YwMGM3OWE1N2I0
11
- YjcyNjUyM2VkYTZkOTBiYjEzYzYxNmU3NjUzNjNjNzg3MzcxZmE=
9
+ ZTI5ZmYwOTBlYTRmNWMyNWEwMjAzNWY4MWFjNWEwNDc4MjFiN2RlMjQ4MGI2
10
+ ZmE5ODA2MzVhOTU5NzY1OGIwODk0NTdkZjFkN2RmNzk1MDI0M2E0YTMxMDY1
11
+ NDA4OWU0ZWZlODc2YjlkYjNmZWE0Y2UxM2Y4ODQwZTg1OGQwNDg=
12
12
  data.tar.gz: !binary |-
13
- ZTgzZGI1Y2ZjZDBjZjhjYjIyYjgzY2M3Y2U3M2Y4MDA5YjBjMmQzYWU3MmNh
14
- ZjU3M2EzNmYyZDhiMDQxYTlmNzU5OTY0YTZmY2YwYmEzZjMzMTk4ZjQ5MDdi
15
- N2U2ZjU3ZTg2ZTk2MGU1Nzc2Nzg3NmE4ODY4ZDAyMTU2ZTdhM2I=
13
+ ZmI0NWNhZGI0MGFlYjczZmI5ZGI4YmRlNjFiZTFjZTQ3MmVhZGY0OTA2ZTFk
14
+ ZjhiNWZlNzg2NWI2MmNiMDdjNjg0OGFkNGM1ZmEyMDBlMmUzZGE5NzVkNzVj
15
+ NGVhNTlhMjhkNTMwZWY0NWQ0MGZmNjBhYzVkYjAxYmNlNTBhM2Q=
data/Gemfile.lock CHANGED
@@ -26,7 +26,7 @@ GIT
26
26
  PATH
27
27
  remote: .
28
28
  specs:
29
- bmo (0.8.8)
29
+ bmo (0.8.7)
30
30
  equalizer (~> 0.0.0)
31
31
  faraday (> 0.8.0)
32
32
 
@@ -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 = Utils.coerce_to_symbols(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
- data.to_json.bytes.to_a.pack('C*')
52
+ truncate_field! if truncable_field && !valid?
53
+ validate!
54
+ package
51
55
  end
52
56
 
53
57
  def validate!
54
- if to_package.bytesize > MAX_BYTE_SIZE
55
- str = "Payload byte size (#{to_package.bytesize})" \
56
- " should be less than #{Payload::MAX_BYTE_SIZE} bytes"
57
- fail PayloadTooLarge, str
58
- end
59
- true
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
 
@@ -37,7 +37,7 @@ module BMO
37
37
  attr_reader :data
38
38
 
39
39
  def initialize(data)
40
- @data = Utils.coerce_to_symbols(data)
40
+ @data = data
41
41
  end
42
42
 
43
43
  def to_package
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
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
  # Main BMO module, version get right here
3
3
  module BMO
4
- VERSION = '0.8.10'.freeze
4
+ VERSION = '0.8.11'.freeze
5
5
  end
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
- notification = APNS::Notification.new(device_token, data)
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.10
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-10 00:00:00.000000000 Z
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: