push_builder 0.0.1
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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/PAYLOAD.md +18 -0
- data/README.md +53 -0
- data/Rakefile +6 -0
- data/lib/push_builder.rb +15 -0
- data/lib/push_builder/aps.rb +25 -0
- data/lib/push_builder/compiler.rb +39 -0
- data/lib/push_builder/payload.rb +40 -0
- data/lib/push_builder/string_cropper.rb +40 -0
- data/lib/push_builder/version.rb +3 -0
- data/push_builder.gemspec +21 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/aps_spec.rb +87 -0
- data/spec/unit/compiler_spec.rb +44 -0
- data/spec/unit/payload_spec.rb +59 -0
- data/spec/unit/push_builder.rb +14 -0
- data/spec/unit/string_cropper_spec.rb +26 -0
- metadata +104 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Philipe Fatio
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/PAYLOAD.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Anatomy of a Payload
|
2
|
+
|
3
|
+
JSON dictionary ([RFC 4627](http://www.rfc-editor.org/rfc/rfc4627.txt)) weighing in at a max of 256 bytes.
|
4
|
+
|
5
|
+
Must contain `aps` dictionary with at least one of the following keys:
|
6
|
+
|
7
|
+
- `alert` (string or dictionary): The message to display or a dictionary which let's you specify further things (see below).
|
8
|
+
- `badge` (number): The number to add to the app icon. If absent, the current badge is not changed. 0 clears the badge.
|
9
|
+
- `sound` (string): The identifier of a sound to play.
|
10
|
+
|
11
|
+
The `alert` dictionary can contain the following keys:
|
12
|
+
|
13
|
+
- `body` (string): The message to display.
|
14
|
+
- `action-loc-key` (string or null): The localization key of the string to use in place of "View" in the right button. Specify null to only show the "OK" button.
|
15
|
+
- `loc-key` (string): The localization key of the string that is used as the message.
|
16
|
+
- `loc-args` (array of strings): The arguments to appear in place of the format specifiers in `low-key`.
|
17
|
+
- `launch-image` (string): The filename of an image file in the application bundle (may omit the extension).
|
18
|
+
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# PushBuilder
|
2
|
+
|
3
|
+
PushBuilder was born with one mission only: construct JSON payloads for Apple's push notification service.
|
4
|
+
|
5
|
+
## What it Does
|
6
|
+
|
7
|
+
- Automatically crops the alert so that the payload does not exceed the allowed 256 bytes.
|
8
|
+
- Supports specifying custom data (data that the iOS app can read from the push notification).
|
9
|
+
- Supports specifying data for a third party (data that is intended for a "man in the middle" such as Urban Airship; this data is assumed to be stripped from the payload by the third party and thus does not count towards the 256 bytes limit).
|
10
|
+
- Performs some basic type checking.
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
PushBuilder.build(alert: 'Hello World!', badge: 3, sound: 'default').to_json
|
16
|
+
# => {"aps":{"badge":3,"alert":"Hello World!","sound":"default"}}
|
17
|
+
|
18
|
+
# Specifying custom data:
|
19
|
+
payload = PushBuilder.build(alert: 'Hello World!')
|
20
|
+
payload.custom_data[:notification_id] = 1234
|
21
|
+
payload.to_json
|
22
|
+
# => {"notification_id":1234,"aps":{"alert":"Hello World!"}}
|
23
|
+
|
24
|
+
# Specifying third party data (such as UrbanAirship aliases):
|
25
|
+
payload = PushBuilder.build(alert: 'Hello World!')
|
26
|
+
payload.third_party_data[:aliases] = %w[ 123 456 789 ]
|
27
|
+
payload.to_json
|
28
|
+
# => {"aliases":["123","456","789"],"aps":{"alert":"Hello World!"}}
|
29
|
+
|
30
|
+
# Auto crops alerts to not exceed max payload size of 256 bytes:
|
31
|
+
PushBuilder.build(alert: 'Hello World ' * 100, badge: 3, sound: 'default').to_json
|
32
|
+
# => {"aps":{"badge":3,"alert":"Hello World [...] H…","sound":"default"}}
|
33
|
+
```
|
34
|
+
|
35
|
+
## Limitations
|
36
|
+
|
37
|
+
The `alert` key of the `aps` dictionary only supports strings at the moment.
|
38
|
+
Technically, the alert can be customized further as described in [PAYLOAD.md](PAYLOAD.md).
|
39
|
+
|
40
|
+
## Additional Information
|
41
|
+
|
42
|
+
### Useful Links
|
43
|
+
|
44
|
+
- [Anatomy of a Payload](PAYLOAD.md)
|
45
|
+
- [Local and Push Notification Programming Guide](http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html)
|
46
|
+
|
47
|
+
### Maintainers
|
48
|
+
|
49
|
+
- Philipe Fatio ([@fphilipe](https://github.com/fphilipe))
|
50
|
+
|
51
|
+
### License
|
52
|
+
|
53
|
+
MIT License. Copyright 2013 Philipe Fatio
|
data/Rakefile
ADDED
data/lib/push_builder.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'push_builder/version'
|
2
|
+
require 'push_builder/payload'
|
3
|
+
require 'push_builder/aps'
|
4
|
+
require 'push_builder/compiler'
|
5
|
+
require 'push_builder/string_cropper'
|
6
|
+
|
7
|
+
module PushBuilder
|
8
|
+
TypeError = Class.new(StandardError)
|
9
|
+
|
10
|
+
def self.build(args={})
|
11
|
+
Payload.new.tap do |payload|
|
12
|
+
args.each { |k, v| payload.aps.send("#{k}=", v) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module PushBuilder
|
2
|
+
class APS
|
3
|
+
attr_reader :alert, :badge, :sound
|
4
|
+
|
5
|
+
def badge=(badge)
|
6
|
+
@badge = badge.nil? ? nil : Integer(badge)
|
7
|
+
rescue ArgumentError
|
8
|
+
fail TypeError, 'Invalid number for badge'
|
9
|
+
end
|
10
|
+
|
11
|
+
def alert=(alert)
|
12
|
+
@alert = alert.nil? ? nil : String(alert)
|
13
|
+
end
|
14
|
+
|
15
|
+
def sound=(sound)
|
16
|
+
@sound = sound.nil? ? nil : String(sound)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash(opts={})
|
20
|
+
{ badge: badge, alert: alert, sound: sound }.reject do |_,v|
|
21
|
+
v.nil?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
|
3
|
+
module PushBuilder
|
4
|
+
class Compiler
|
5
|
+
MAX_PAYLOAD_SIZE = 256
|
6
|
+
|
7
|
+
attr_reader :payload, :third_party_data
|
8
|
+
|
9
|
+
def initialize(payload, third_party_data={})
|
10
|
+
@payload = payload
|
11
|
+
@third_party_data = third_party_data
|
12
|
+
end
|
13
|
+
|
14
|
+
def compile
|
15
|
+
crop_alert_if_necessary!
|
16
|
+
|
17
|
+
to_json(third_party_data.merge(payload))
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def crop_alert_if_necessary!
|
23
|
+
if (alert = payload.fetch(:aps, {})[:alert])
|
24
|
+
payload[:aps][:alert] =
|
25
|
+
StringCropper
|
26
|
+
.new(alert)
|
27
|
+
.crop_bytes(size(payload) - MAX_PAYLOAD_SIZE)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def size(data)
|
32
|
+
to_json(data).bytesize
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_json(data)
|
36
|
+
MultiJson.dump(data)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module PushBuilder
|
2
|
+
class Payload
|
3
|
+
attr_reader :aps, :custom_data, :third_party_data
|
4
|
+
|
5
|
+
def initialize(args={})
|
6
|
+
@aps = APS.new
|
7
|
+
@custom_data = {}
|
8
|
+
@third_party_data = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def aps=(aps)
|
12
|
+
if aps.is_a?(APS)
|
13
|
+
@aps = aps
|
14
|
+
else
|
15
|
+
fail TypeError, 'Trying to set aps to a non APS object.'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def custom_data=(data)
|
20
|
+
if data.is_a?(Hash)
|
21
|
+
@custom_data = data
|
22
|
+
else
|
23
|
+
fail TypeError, 'Trying to set custom_data to something other than Hash.'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def third_party_data=(data)
|
28
|
+
if data.is_a?(Hash)
|
29
|
+
@third_party_data = data
|
30
|
+
else
|
31
|
+
fail TypeError, 'Trying to set third_party_data to something other than Hash.'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_json
|
36
|
+
payload = custom_data.merge(aps: aps.to_hash)
|
37
|
+
Compiler.new(payload, third_party_data).compile
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
module PushBuilder
|
4
|
+
class StringCropper
|
5
|
+
DEFAULT_CROP_INDICATOR = ?…
|
6
|
+
|
7
|
+
attr_reader :string, :indicator
|
8
|
+
|
9
|
+
def initialize(string, indicator=DEFAULT_CROP_INDICATOR)
|
10
|
+
@string = string
|
11
|
+
@indicator = indicator
|
12
|
+
end
|
13
|
+
|
14
|
+
def crop_bytes(bytes_to_crop)
|
15
|
+
return string if bytes_to_crop <= 0
|
16
|
+
|
17
|
+
bytes_to_crop += indicator.bytesize
|
18
|
+
remaining_bytes = string.bytesize - bytes_to_crop
|
19
|
+
|
20
|
+
string_with_bytes(remaining_bytes) + indicator
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def string_with_bytes(bytes)
|
26
|
+
char_count = char_count_fitting_in_bytes(bytes)
|
27
|
+
|
28
|
+
string[0, char_count]
|
29
|
+
end
|
30
|
+
|
31
|
+
def char_count_fitting_in_bytes(bytes)
|
32
|
+
string.each_char.with_index.inject(0) do |byte_sum, (char, char_count)|
|
33
|
+
byte_sum += char.bytesize
|
34
|
+
break char_count if byte_sum > bytes
|
35
|
+
|
36
|
+
byte_sum
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'push_builder/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'push_builder'
|
7
|
+
gem.version = PushBuilder::VERSION
|
8
|
+
gem.authors = ['Philipe Fatio']
|
9
|
+
gem.email = ['me@phili.pe']
|
10
|
+
gem.summary = %q{Easily construct JSON payloads for Apple's push notification service.}
|
11
|
+
gem.description = gem.summary
|
12
|
+
gem.homepage = 'https://github.com/fphilipe/push_builder'
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
|
18
|
+
gem.add_development_dependency 'rspec', '~> 2.12'
|
19
|
+
|
20
|
+
gem.add_dependency 'multi_json', '~> 1.0'
|
21
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PushBuilder::APS do
|
4
|
+
subject(:aps) { described_class.new }
|
5
|
+
|
6
|
+
describe '#badge=' do
|
7
|
+
it 'raises for non numeric values' do
|
8
|
+
expect { aps.badge = 'test' }.to raise_error(PushBuilder::TypeError)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'accepts numeric strings' do
|
12
|
+
aps.badge = '123'
|
13
|
+
aps.badge.should be 123
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'accepts numbers' do
|
17
|
+
aps.badge = 123
|
18
|
+
aps.badge.should be 123
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'accepts nil' do
|
22
|
+
aps.badge = nil
|
23
|
+
aps.badge.should be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#alert=' do
|
28
|
+
it 'accepts strings' do
|
29
|
+
aps.alert = 'foobar'
|
30
|
+
aps.alert.should eq 'foobar'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'accepts values convertable to strings' do
|
34
|
+
aps.alert = 123
|
35
|
+
aps.alert.should eq '123'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'accepts nil' do
|
39
|
+
aps.alert = nil
|
40
|
+
aps.alert.should be_nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#sound=' do
|
45
|
+
it 'accepts strings' do
|
46
|
+
aps.sound = 'foobar'
|
47
|
+
aps.sound.should eq 'foobar'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'accepts values convertable to strings' do
|
51
|
+
aps.sound = 123
|
52
|
+
aps.sound.should eq '123'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'accepts nil' do
|
56
|
+
aps.sound = nil
|
57
|
+
aps.sound.should be_nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#to_hash' do
|
62
|
+
before do
|
63
|
+
aps.badge = 1
|
64
|
+
aps.alert = 'foo'
|
65
|
+
aps.sound = 'bar'
|
66
|
+
end
|
67
|
+
|
68
|
+
let(:expected_hash) do
|
69
|
+
{ badge: 1, alert: 'foo', sound: 'bar' }
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns a hash' do
|
73
|
+
aps.to_hash.should eq expected_hash
|
74
|
+
end
|
75
|
+
|
76
|
+
[:badge, :alert, :sound].each do |key|
|
77
|
+
context "when #{key} is nil" do
|
78
|
+
it 'does not include it' do
|
79
|
+
aps.send("#{key}=", nil)
|
80
|
+
expected_hash.delete(key)
|
81
|
+
|
82
|
+
aps.to_hash.should eq expected_hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe PushBuilder::Compiler do
|
6
|
+
describe '#compile' do
|
7
|
+
it 'crops the alert if necessary' do
|
8
|
+
alert = 50.times.map { 'foobar' }.join
|
9
|
+
payload = { aps: { alert: alert } }
|
10
|
+
|
11
|
+
json = described_class.new(payload).compile
|
12
|
+
json.bytesize.should be 256
|
13
|
+
json.should =~ %r{"alert":"[fobar]+…"}
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'does not crop the alert if not necessary' do
|
17
|
+
payload = { aps: { alert: 'foobar' } }
|
18
|
+
|
19
|
+
json = described_class.new(payload).compile
|
20
|
+
json.bytesize.should be < 256
|
21
|
+
json.should include '"alert":"foobar"'
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when third party data is large' do
|
25
|
+
it 'does not crop the alert if not necessary' do
|
26
|
+
payload = { aps: { alert: 'foobar' } }
|
27
|
+
third_party_data = { test: 50.times.map { 'foobar' }.join }
|
28
|
+
|
29
|
+
json = described_class.new(payload, third_party_data).compile
|
30
|
+
json.bytesize.should be > 256
|
31
|
+
json.should include '"alert":"foobar"'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when no alert present' do
|
36
|
+
it 'does not include an alert key' do
|
37
|
+
payload = { aps: { badge: 4 } }
|
38
|
+
|
39
|
+
json = described_class.new(payload).compile
|
40
|
+
json.should_not include '"alert":'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe PushBuilder::Payload do
|
6
|
+
subject(:payload) { described_class.new }
|
7
|
+
|
8
|
+
describe '#aps' do
|
9
|
+
it 'is an APS' do
|
10
|
+
payload.aps.should be_a(PushBuilder::APS)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#aps=' do
|
15
|
+
it 'accepts an APS object' do
|
16
|
+
aps = PushBuilder::APS.new
|
17
|
+
payload.aps = aps
|
18
|
+
payload.aps.should be aps
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'raises when object is not an APS' do
|
22
|
+
expect { payload.aps = 'foobar' }.
|
23
|
+
to raise_error(PushBuilder::TypeError)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
%w[ custom_data third_party_data ].each do |method|
|
28
|
+
describe "##{method}" do
|
29
|
+
it 'is an emtpy hash by default' do
|
30
|
+
payload.send(method).should == {}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "##{method}=" do
|
35
|
+
it 'accepts a Hash' do
|
36
|
+
payload.send("#{method}=", { foo: 'bar' })
|
37
|
+
payload.send(method)[:foo].should eq 'bar'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'raises when object is not a Hash' do
|
41
|
+
expect { payload.send("#{method}=", 123) }.
|
42
|
+
to raise_error(PushBuilder::TypeError)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#to_json' do
|
48
|
+
it 'returns a JSON string' do
|
49
|
+
payload.aps.stub(to_hash: { foo: 'bar' })
|
50
|
+
payload.custom_data[:abc] = 123
|
51
|
+
payload.third_party_data[:xyz] = true
|
52
|
+
|
53
|
+
json = payload.to_json
|
54
|
+
json.should include '"abc":123'
|
55
|
+
json.should include '"aps":{"foo":"bar"}'
|
56
|
+
json.should include '"xyz":true'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PushBuilder do
|
4
|
+
describe '.build' do
|
5
|
+
it 'returns a Payload' do
|
6
|
+
payload = PushBuilder.build(alert: 'Hello', sound: 'default', badge: 5)
|
7
|
+
|
8
|
+
payload.should be_a described_class::Payload
|
9
|
+
payload.aps.alert.should eq 'Hello'
|
10
|
+
payload.aps.sound.should eq 'default'
|
11
|
+
payload.aps.badge.should eq 5
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe PushBuilder::StringCropper do
|
6
|
+
describe '#crop_bytes' do
|
7
|
+
def crop_bytes(string, bytes, indicator='')
|
8
|
+
PushBuilder::StringCropper.new(string, indicator).crop_bytes(bytes)
|
9
|
+
end
|
10
|
+
|
11
|
+
specify { crop_bytes('abcdefg', -1). should eq 'abcdefg' }
|
12
|
+
specify { crop_bytes('abcdefg', 0). should eq 'abcdefg' }
|
13
|
+
specify { crop_bytes('abcdefg', 1). should eq 'abcdef' }
|
14
|
+
specify { crop_bytes('abcdefg', 1, '…').should eq 'abc…' }
|
15
|
+
specify { crop_bytes('abcdefg', 4, '…').should eq '…' }
|
16
|
+
|
17
|
+
specify { crop_bytes('aäoöuüe', 2). should eq 'aäoöu' }
|
18
|
+
specify { crop_bytes('aäoöuüe', 3). should eq 'aäoöu' }
|
19
|
+
specify { crop_bytes('aäoöuüe', 4). should eq 'aäoö' }
|
20
|
+
specify { crop_bytes('aäoöuüe', 5). should eq 'aäo' }
|
21
|
+
specify { crop_bytes('aäoöuüe', 1, '…').should eq 'aäoö…' }
|
22
|
+
specify { crop_bytes('aäoöuüe', 2, '…').should eq 'aäo…' }
|
23
|
+
specify { crop_bytes('aäoöuüe', 3, '…').should eq 'aäo…' }
|
24
|
+
specify { crop_bytes('aäoöuüe', 4, '…').should eq 'aä…' }
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: push_builder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Philipe Fatio
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.12'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.12'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: multi_json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.0'
|
46
|
+
description: Easily construct JSON payloads for Apple's push notification service.
|
47
|
+
email:
|
48
|
+
- me@phili.pe
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- .rspec
|
55
|
+
- Gemfile
|
56
|
+
- LICENSE.txt
|
57
|
+
- PAYLOAD.md
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- lib/push_builder.rb
|
61
|
+
- lib/push_builder/aps.rb
|
62
|
+
- lib/push_builder/compiler.rb
|
63
|
+
- lib/push_builder/payload.rb
|
64
|
+
- lib/push_builder/string_cropper.rb
|
65
|
+
- lib/push_builder/version.rb
|
66
|
+
- push_builder.gemspec
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
- spec/unit/aps_spec.rb
|
69
|
+
- spec/unit/compiler_spec.rb
|
70
|
+
- spec/unit/payload_spec.rb
|
71
|
+
- spec/unit/push_builder.rb
|
72
|
+
- spec/unit/string_cropper_spec.rb
|
73
|
+
homepage: https://github.com/fphilipe/push_builder
|
74
|
+
licenses: []
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 1.8.23
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: Easily construct JSON payloads for Apple's push notification service.
|
97
|
+
test_files:
|
98
|
+
- spec/spec_helper.rb
|
99
|
+
- spec/unit/aps_spec.rb
|
100
|
+
- spec/unit/compiler_spec.rb
|
101
|
+
- spec/unit/payload_spec.rb
|
102
|
+
- spec/unit/push_builder.rb
|
103
|
+
- spec/unit/string_cropper_spec.rb
|
104
|
+
has_rdoc:
|