bmo 0.8.10 → 0.8.11

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,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: