sparqcode-urbanairship 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.markdown +132 -0
- data/Rakefile +8 -0
- data/lib/urbanairship.rb +1 -0
- data/lib/urbanairship/base.rb +28 -0
- data/lib/urbanairship/response.rb +33 -0
- data/lib/urbanairship/service.rb +124 -0
- data/spec/response_spec.rb +77 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/urbanairship_spec.rb +456 -0
- metadata +120 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2011 Groupon, Inc.
|
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 NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
Urbanairship is a Ruby library for interacting with the [Urban Airship API](http://urbanairship.com).
|
2
|
+
|
3
|
+
Installation
|
4
|
+
============
|
5
|
+
gem install urbanairship
|
6
|
+
|
7
|
+
Note: if you are using Ruby 1.8, you should also install the ```system_timer``` gem for more reliable timeout behaviour. See http://ph7spot.com/musings/system-timer for more information.
|
8
|
+
|
9
|
+
Configuration
|
10
|
+
=============
|
11
|
+
```ruby
|
12
|
+
Urbanairship.application_key = 'application-key'
|
13
|
+
Urbanairship.application_secret = 'application-secret'
|
14
|
+
Urbanairship.master_secret = 'master-secret'
|
15
|
+
Urbanairship.logger = Rails.logger
|
16
|
+
Urbanairship.request_timeout = 5 # default
|
17
|
+
```
|
18
|
+
|
19
|
+
Usage
|
20
|
+
=====
|
21
|
+
|
22
|
+
Registering a device token
|
23
|
+
--------------------------
|
24
|
+
```ruby
|
25
|
+
Urbanairship.register_device('DEVICE-TOKEN')
|
26
|
+
```
|
27
|
+
|
28
|
+
Unregistering a device token
|
29
|
+
----------------------------
|
30
|
+
```ruby
|
31
|
+
Urbanairship.unregister_device('DEVICE-TOKEN')
|
32
|
+
```
|
33
|
+
|
34
|
+
Sending a push notification
|
35
|
+
---------------------------
|
36
|
+
```ruby
|
37
|
+
notification = {
|
38
|
+
:schedule_for => [1.hour.from_now],
|
39
|
+
:device_tokens => ['DEVICE-TOKEN-ONE', 'DEVICE-TOKEN-TWO'],
|
40
|
+
:aps => {:alert => 'You have a new message!', :badge => 1}
|
41
|
+
}
|
42
|
+
|
43
|
+
Urbanairship.push(notification) # =>
|
44
|
+
# {
|
45
|
+
# "scheduled_notifications" => ["https://go.urbanairship.com/api/push/scheduled/123456"]
|
46
|
+
# }
|
47
|
+
```
|
48
|
+
|
49
|
+
Batching push notification sends
|
50
|
+
--------------------------------
|
51
|
+
```ruby
|
52
|
+
notifications = [
|
53
|
+
{
|
54
|
+
:schedule_for => [{ :alias => 'deadbeef', :scheduled_time => 1.hour.from_now }],
|
55
|
+
:device_tokens => ['DEVICE-TOKEN-ONE', 'DEVICE-TOKEN-TWO'],
|
56
|
+
:aps => {:alert => 'You have a new message!', :badge => 1}
|
57
|
+
},
|
58
|
+
{
|
59
|
+
:schedule_for => [3.hours.from_now],
|
60
|
+
:device_tokens => ['DEVICE-TOKEN-THREE'],
|
61
|
+
:aps => {:alert => 'You have a new message!', :badge => 1}
|
62
|
+
}
|
63
|
+
]
|
64
|
+
|
65
|
+
Urbanairship.batch_push(notifications)
|
66
|
+
```
|
67
|
+
|
68
|
+
|
69
|
+
Sending broadcast notifications
|
70
|
+
-------------------------------
|
71
|
+
Urban Airship allows you to send a broadcast notification to all active registered device tokens for your app.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
notification = {
|
75
|
+
:schedule_for => [1.hour.from_now],
|
76
|
+
:aps => {:alert => 'Important announcement!', :badge => 1}
|
77
|
+
}
|
78
|
+
|
79
|
+
Urbanairship.broadcast_push(notification)
|
80
|
+
```
|
81
|
+
|
82
|
+
Polling the feedback API
|
83
|
+
------------------------
|
84
|
+
The first time you attempt to send a push notification to a device that has uninstalled your app (or has opted-out of notifications), both Apple and Urban Airship will register that token in their feedback API. Urban Airship will prevent further attempted notification sends to that device, but it's a good practice to periodically poll Urban Airship's feedback API and mark those tokens as inactive in your own system as well.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
# find all device tokens deactivated in the past 24 hours
|
88
|
+
Urbanairship.feedback(24.hours.ago) # =>
|
89
|
+
# [
|
90
|
+
# {
|
91
|
+
# "marked_inactive_on"=>"2011-06-03 22:53:23",
|
92
|
+
# "alias"=>nil,
|
93
|
+
# "device_token"=>"DEVICE-TOKEN-ONE"
|
94
|
+
# },
|
95
|
+
# {
|
96
|
+
# "marked_inactive_on"=>"2011-06-03 22:53:23",
|
97
|
+
# "alias"=>nil,
|
98
|
+
# "device_token"=>"DEVICE-TOKEN-TWO"
|
99
|
+
# }
|
100
|
+
# ]
|
101
|
+
```
|
102
|
+
|
103
|
+
Deleting scheduled notifications
|
104
|
+
--------------------------------
|
105
|
+
|
106
|
+
If you know the alias or id of a scheduled push notification then you can delete it from Urban Airship's queue and it will not be delivered.
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Urbanairship.delete_scheduled_push("123456789")
|
110
|
+
Urbanairship.delete_scheduled_push(123456789)
|
111
|
+
Urbanairship.delete_scheduled_push(:alias => "deadbeef")
|
112
|
+
```
|
113
|
+
|
114
|
+
-----------------------------
|
115
|
+
|
116
|
+
Note: all public library methods will return either an array or a hash, depending on the response from the Urban Airship API. In addition, you can inspect these objects to find out if they were successful or not, and what the http response code from Urban Airship was.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
response = Urbanairship.push(payload)
|
120
|
+
response.success? # => true
|
121
|
+
response.code # => '200'
|
122
|
+
response.inspect # => "{\"scheduled_notifications\"=>[\"https://go.urbanairship.com/api/push/scheduled/123456\"]}"
|
123
|
+
```
|
124
|
+
|
125
|
+
If the call to Urban Airship times out, you'll get a response object with a '503' code.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
response = Urbanairship.feedback(1.year.ago)
|
129
|
+
response.success? # => false
|
130
|
+
response.code # => '503'
|
131
|
+
response.inspect # => "{\"error\"=>\"Request timeout\"}"
|
132
|
+
```
|
data/Rakefile
ADDED
data/lib/urbanairship.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'urbanairship/service')
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'service')
|
2
|
+
|
3
|
+
module Urbanairship
|
4
|
+
class Base
|
5
|
+
include Service
|
6
|
+
|
7
|
+
def initialize(application_key, application_secret, master_secret)
|
8
|
+
self.application_key = application_key
|
9
|
+
self.application_secret = application_secret
|
10
|
+
self.master_secret = master_secret
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
@@applications = { }
|
17
|
+
|
18
|
+
def self.[](application_id)
|
19
|
+
@@applications[application_id]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add_service(application_id, application_key, application_secret, master_secret)
|
23
|
+
new_service = Base.new(application_key, application_secret, master_secret)
|
24
|
+
yield new_service if block_given?
|
25
|
+
@@applications[application_id] = new_service
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Urbanairship
|
2
|
+
module Response
|
3
|
+
module InstanceMethods
|
4
|
+
attr_accessor :ua_response, :ua_options
|
5
|
+
|
6
|
+
def code
|
7
|
+
(ua_options[:code] || ua_response.code).to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def success?
|
11
|
+
!!(code =~ /^2/)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.wrap(response, options = {})
|
16
|
+
if options[:body]
|
17
|
+
output = options[:body]
|
18
|
+
else
|
19
|
+
begin
|
20
|
+
output = JSON.parse(response.body || '{}')
|
21
|
+
rescue JSON::ParserError
|
22
|
+
output = {}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
output.extend(Urbanairship::Response::InstanceMethods)
|
27
|
+
output.ua_response = response
|
28
|
+
output.ua_options = options
|
29
|
+
|
30
|
+
return output
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'net/https'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), 'response')
|
6
|
+
|
7
|
+
module Urbanairship
|
8
|
+
begin
|
9
|
+
require 'system_timer'
|
10
|
+
Timer = SystemTimer
|
11
|
+
rescue LoadError
|
12
|
+
require 'timeout'
|
13
|
+
Timer = Timeout
|
14
|
+
end
|
15
|
+
|
16
|
+
module Service
|
17
|
+
attr_accessor :application_key, :application_secret, :master_secret, :logger, :request_timeout
|
18
|
+
|
19
|
+
def register_device(device_token, options = {})
|
20
|
+
body = parse_register_options(options).to_json
|
21
|
+
do_request(:put, "/api/device_tokens/#{device_token}", :body => body, :authenticate_with => :application_secret)
|
22
|
+
end
|
23
|
+
|
24
|
+
def unregister_device(device_token)
|
25
|
+
do_request(:delete, "/api/device_tokens/#{device_token}", :authenticate_with => :application_secret)
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete_scheduled_push(param)
|
29
|
+
path = param.is_a?(Hash) ? "/api/push/scheduled/alias/#{param[:alias].to_s}" : "/api/push/scheduled/#{param.to_s}"
|
30
|
+
do_request(:delete, path, :authenticate_with => :master_secret)
|
31
|
+
end
|
32
|
+
|
33
|
+
def push(options = {})
|
34
|
+
body = parse_push_options(options).to_json
|
35
|
+
do_request(:post, "/api/push/", :body => body, :authenticate_with => :master_secret)
|
36
|
+
end
|
37
|
+
|
38
|
+
def batch_push(notifications = [])
|
39
|
+
body = notifications.map{|notification| parse_push_options(notification)}.to_json
|
40
|
+
do_request(:post, "/api/push/batch/", :body => body, :authenticate_with => :master_secret)
|
41
|
+
end
|
42
|
+
|
43
|
+
def broadcast_push(options = {})
|
44
|
+
body = parse_push_options(options).to_json
|
45
|
+
do_request(:post, "/api/push/broadcast/", :body => body, :authenticate_with => :master_secret)
|
46
|
+
end
|
47
|
+
|
48
|
+
def feedback(time)
|
49
|
+
do_request(:get, "/api/device_tokens/feedback/?since=#{format_time(time)}", :authenticate_with => :master_secret)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def do_request(http_method, path, options = {})
|
55
|
+
verify_configuration_values(:application_key, options[:authenticate_with])
|
56
|
+
|
57
|
+
klass = Net::HTTP.const_get(http_method.to_s.capitalize)
|
58
|
+
|
59
|
+
request = klass.new(path)
|
60
|
+
request.basic_auth @application_key, instance_variable_get("@#{options[:authenticate_with]}")
|
61
|
+
request.add_field "Content-Type", "application/json"
|
62
|
+
request.body = options[:body] if options[:body]
|
63
|
+
|
64
|
+
Timer.timeout(request_timeout) do
|
65
|
+
start_time = Time.now
|
66
|
+
response = http_client.request(request)
|
67
|
+
log_request_and_response(request, response, Time.now - start_time)
|
68
|
+
Urbanairship::Response.wrap(response)
|
69
|
+
end
|
70
|
+
rescue Timeout::Error
|
71
|
+
logger.error "Urbanairship request timed out after #{request_timeout} seconds: [#{http_method} #{request.path} #{request.body}]"
|
72
|
+
Urbanairship::Response.wrap(nil, :body => {:error => 'Request timeout'}, :code => '503')
|
73
|
+
end
|
74
|
+
|
75
|
+
def verify_configuration_values(*symbols)
|
76
|
+
absent_values = symbols.select{|symbol| instance_variable_get("@#{symbol}").nil? }
|
77
|
+
raise("Must configure #{absent_values.join(", ")} before making this request.") unless absent_values.empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
def http_client
|
81
|
+
Net::HTTP.new("go.urbanairship.com", 443).tap{|http| http.use_ssl = true}
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_register_options(hash = {})
|
85
|
+
hash[:alias] = hash[:alias].to_s unless hash[:alias].nil?
|
86
|
+
hash
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_push_options(hash = {})
|
90
|
+
hash[:schedule_for] = hash[:schedule_for].map{|elem| process_scheduled_elem(elem)} unless hash[:schedule_for].nil?
|
91
|
+
hash
|
92
|
+
end
|
93
|
+
|
94
|
+
def log_request_and_response(request, response, time)
|
95
|
+
return if logger.nil?
|
96
|
+
|
97
|
+
time = (time * 1000).to_i
|
98
|
+
http_method = request.class.to_s.split('::')[-1]
|
99
|
+
logger.info "Urbanairship (#{time}ms): [#{http_method} #{request.path}, #{request.body}], [#{response.code}, #{response.body}]"
|
100
|
+
logger.flush if logger.respond_to?(:flush)
|
101
|
+
end
|
102
|
+
|
103
|
+
def format_time(time)
|
104
|
+
time = Time.parse(time) if time.is_a?(String)
|
105
|
+
time.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
106
|
+
end
|
107
|
+
|
108
|
+
def process_scheduled_elem(elem)
|
109
|
+
if elem.class == Hash
|
110
|
+
elem.merge!(:scheduled_time => format_time(elem[:scheduled_time]))
|
111
|
+
else
|
112
|
+
format_time(elem)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def request_timeout
|
117
|
+
@request_timeout || 5.0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
extend Service
|
122
|
+
|
123
|
+
end
|
124
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
describe Urbanairship::Response do
|
2
|
+
|
3
|
+
before do
|
4
|
+
FakeWeb.allow_net_connect = false
|
5
|
+
end
|
6
|
+
|
7
|
+
context "#code" do
|
8
|
+
subject { Urbanairship.register_device("new_device_token") }
|
9
|
+
|
10
|
+
before do
|
11
|
+
FakeWeb.register_uri(:put, "https://my_app_key:my_app_secret@go.urbanairship.com/api/device_tokens/new_device_token", :status => ["201", "Created"])
|
12
|
+
FakeWeb.register_uri(:put, /bad_key\:my_app_secret\@go\.urbanairship\.com/, :status => ["401", "Unauthorized"])
|
13
|
+
Urbanairship.application_secret = "my_app_secret"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should be set correctly on new registraion token" do
|
17
|
+
Urbanairship.application_key = "my_app_key"
|
18
|
+
subject.code.should eql '201'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should set correctly on unauthhorized" do
|
22
|
+
Urbanairship.application_key = "bad_key"
|
23
|
+
subject.code.should eql '401'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "#success?" do
|
28
|
+
subject { Urbanairship.register_device("new_device_token") }
|
29
|
+
|
30
|
+
before do
|
31
|
+
FakeWeb.register_uri(:put, "https://my_app_key:my_app_secret@go.urbanairship.com/api/device_tokens/new_device_token", :status => ["201", "Created"])
|
32
|
+
FakeWeb.register_uri(:put, /bad_key\:my_app_secret\@go\.urbanairship\.com/, :status => ["401", "Unauthorized"])
|
33
|
+
Urbanairship.application_secret = "my_app_secret"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should be true with good key" do
|
37
|
+
Urbanairship.application_key = "my_app_key"
|
38
|
+
subject.success?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should be false with bad key" do
|
42
|
+
Urbanairship.application_key = "bad_key"
|
43
|
+
subject.success?.should == false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "body array accessor" do
|
48
|
+
subject { Urbanairship.feedback(Time.now) }
|
49
|
+
|
50
|
+
before do
|
51
|
+
FakeWeb.register_uri(:get, /my_app_key\:my_master_secret\@go\.urbanairship.com\/api\/device_tokens\/feedback/, :status => ["200", "OK"], :body => "[{\"device_token\":\"token\",\"marked_inactive_on\":\"2010-10-14T19:15:13Z\",\"alias\":\"my_alias\"},{\"device_token\":\"token2\",\"marked_inactive_on\":\"2010-10-14T19:15:13Z\",\"alias\":\"my_alias\"}]")
|
52
|
+
Urbanairship.application_secret = "my_app_secret"
|
53
|
+
Urbanairship.application_key = "my_app_key"
|
54
|
+
Urbanairship.master_secret = "my_master_secret"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should set up correct indexes" do
|
58
|
+
subject[0]['device_token'].should eql "token"
|
59
|
+
subject[1]['device_token'].should eql "token2"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "non array response" do
|
64
|
+
subject { Urbanairship.feedback(Time.now) }
|
65
|
+
|
66
|
+
before do
|
67
|
+
FakeWeb.register_uri(:get, /my_app_key\:my_master_secret\@go\.urbanairship.com\/api\/device_tokens\/feedback/, :status => ["200", "OK"], :body => "{\"device_token\":\"token\",\"marked_inactive_on\":\"2010-10-14T19:15:13Z\",\"alias\":\"my_alias\"}")
|
68
|
+
Urbanairship.application_secret = "my_app_secret"
|
69
|
+
Urbanairship.application_key = "my_app_key"
|
70
|
+
Urbanairship.master_secret = "my_master_secret"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should set up correct keys" do
|
74
|
+
subject['device_token'].should eql "token"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'fakeweb'
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), '/../lib/urbanairship')
|
5
|
+
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.after(:each) do
|
9
|
+
# reset configuration
|
10
|
+
Urbanairship.application_key = nil
|
11
|
+
Urbanairship.application_secret = nil
|
12
|
+
Urbanairship.master_secret = nil
|
13
|
+
Urbanairship.logger = nil
|
14
|
+
|
15
|
+
FakeWeb.instance_variable_set("@last_request", nil)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,456 @@
|
|
1
|
+
describe Urbanairship do
|
2
|
+
before(:all) do
|
3
|
+
FakeWeb.allow_net_connect = false
|
4
|
+
|
5
|
+
# register_device
|
6
|
+
FakeWeb.register_uri(:put, "https://my_app_key:my_app_secret@go.urbanairship.com/api/device_tokens/new_device_token", :status => ["201", "Created"])
|
7
|
+
FakeWeb.register_uri(:put, "https://my_app_key:my_app_secret@go.urbanairship.com/api/device_tokens/existing_device_token", :status => ["200", "OK"])
|
8
|
+
FakeWeb.register_uri(:put, "https://my_app_key:my_app_secret@go.urbanairship.com/api/device_tokens/device_token_one", :status => ["201", "Created"])
|
9
|
+
FakeWeb.register_uri(:put, /bad_key\:my_app_secret\@go\.urbanairship\.com/, :status => ["401", "Unauthorized"])
|
10
|
+
|
11
|
+
# unregister_device
|
12
|
+
FakeWeb.register_uri(:delete, /my_app_key\:my_app_secret\@go\.urbanairship.com\/api\/device_tokens\/.+/, :status => ["204", "No Content"])
|
13
|
+
FakeWeb.register_uri(:delete, /bad_key\:my_app_secret\@go\.urbanairship.com\/api\/device_tokens\/.+/, :status => ["401", "Unauthorized"])
|
14
|
+
|
15
|
+
# push
|
16
|
+
FakeWeb.register_uri(:post, "https://my_app_key:my_master_secret@go.urbanairship.com/api/push/", :status => ["200", "OK"])
|
17
|
+
FakeWeb.register_uri(:post, "https://my_app_key2:my_master_secret2@go.urbanairship.com/api/push/", :status => ["400", "Bad Request"])
|
18
|
+
FakeWeb.register_uri(:post, /bad_key\:my_master_secret\@go\.urbanairship\.com/, :status => ["401", "Unauthorized"])
|
19
|
+
|
20
|
+
# batch_push
|
21
|
+
FakeWeb.register_uri(:post, "https://my_app_key:my_master_secret@go.urbanairship.com/api/push/batch/", :status => ["200", "OK"])
|
22
|
+
FakeWeb.register_uri(:post, "https://my_app_key2:my_master_secret2@go.urbanairship.com/api/push/batch/", :status => ["400", "Bad Request"])
|
23
|
+
|
24
|
+
# broadcast push
|
25
|
+
FakeWeb.register_uri(:post, "https://my_app_key:my_master_secret@go.urbanairship.com/api/push/broadcast/", :status => ["200", "OK"])
|
26
|
+
FakeWeb.register_uri(:post, "https://my_app_key2:my_master_secret2@go.urbanairship.com/api/push/broadcast/", :status => ["400", "Bad Request"])
|
27
|
+
|
28
|
+
# delete_scheduled_push
|
29
|
+
FakeWeb.register_uri(:delete, /my_app_key\:my_master_secret\@go\.urbanairship.com\/api\/push\/scheduled\/[0-9]+/, :status => ["204", "No Content"])
|
30
|
+
FakeWeb.register_uri(:delete, /my_app_key\:my_master_secret\@go\.urbanairship.com\/api\/push\/scheduled\/alias\/.+/, :status => ["204", "No Content"])
|
31
|
+
FakeWeb.register_uri(:delete, /bad_key\:my_master_secret\@go\.urbanairship.com\/api\/push\/scheduled\/[0-9]+/, :status => ["401", "Unauthorized"])
|
32
|
+
|
33
|
+
# feedback
|
34
|
+
FakeWeb.register_uri(:get, /my_app_key\:my_master_secret\@go\.urbanairship.com\/api\/device_tokens\/feedback/, :status => ["200", "OK"], :body => "[{\"device_token\":\"token\",\"marked_inactive_on\":\"2010-10-14T19:15:13Z\",\"alias\":\"my_alias\"}]")
|
35
|
+
FakeWeb.register_uri(:get, /my_app_key2\:my_master_secret2\@go\.urbanairship.com\/api\/device_tokens\/feedback/, :status => ["500", "Internal Server Error"])
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "configuration" do
|
39
|
+
it "enables you to configure the application key" do
|
40
|
+
Urbanairship.application_key.should be_nil
|
41
|
+
Urbanairship.application_key = "asdf1234"
|
42
|
+
Urbanairship.application_key.should == "asdf1234"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "enables you to configure the application secret" do
|
46
|
+
Urbanairship.application_secret.should be_nil
|
47
|
+
Urbanairship.application_secret = "asdf1234"
|
48
|
+
Urbanairship.application_secret.should == "asdf1234"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "enables you to configure the master secret" do
|
52
|
+
Urbanairship.master_secret.should be_nil
|
53
|
+
Urbanairship.master_secret = "asdf1234"
|
54
|
+
Urbanairship.master_secret.should == "asdf1234"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "::register_device" do
|
59
|
+
before(:each) do
|
60
|
+
@valid_params = {:alias => 'one'}
|
61
|
+
Urbanairship.application_key = "my_app_key"
|
62
|
+
Urbanairship.application_secret = "my_app_secret"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "raises an error if call is made without an app key and secret configured" do
|
66
|
+
Urbanairship.application_key = nil
|
67
|
+
Urbanairship.application_secret = nil
|
68
|
+
|
69
|
+
lambda {
|
70
|
+
Urbanairship.register_device("asdf1234")
|
71
|
+
}.should raise_error(RuntimeError, "Must configure application_key, application_secret before making this request.")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "uses app key and secret to sign the request" do
|
75
|
+
Urbanairship.register_device("new_device_token")
|
76
|
+
FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64('my_app_key:my_app_secret').chomp}"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "takes and sends a device token" do
|
80
|
+
Urbanairship.register_device("new_device_token")
|
81
|
+
FakeWeb.last_request.path.should == "/api/device_tokens/new_device_token"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "returns true when the device is registered for the first time" do
|
85
|
+
Urbanairship.register_device("new_device_token").success?.should == true
|
86
|
+
end
|
87
|
+
|
88
|
+
it "returns true when the device is registered again" do
|
89
|
+
Urbanairship.register_device("existing_device_token").success?.should == true
|
90
|
+
end
|
91
|
+
|
92
|
+
it "returns false when the authorization is invalid" do
|
93
|
+
Urbanairship.application_key = "bad_key"
|
94
|
+
Urbanairship.register_device("new_device_token").success?.should == false
|
95
|
+
end
|
96
|
+
|
97
|
+
it "accepts an alias" do
|
98
|
+
Urbanairship.register_device("device_token_one", @valid_params).success?.should == true
|
99
|
+
end
|
100
|
+
|
101
|
+
it "adds alias to the JSON payload" do
|
102
|
+
Urbanairship.register_device("device_token_one", @valid_params)
|
103
|
+
request_json['alias'].should == "one"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "converts alias param to string" do
|
107
|
+
Urbanairship.register_device("device_token_one", :alias => 11)
|
108
|
+
request_json['alias'].should be_a_kind_of String
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "::unregister_device" do
|
113
|
+
before(:each) do
|
114
|
+
Urbanairship.application_key = "my_app_key"
|
115
|
+
Urbanairship.application_secret = "my_app_secret"
|
116
|
+
end
|
117
|
+
|
118
|
+
it "raises an error if call is made without an app key and secret configured" do
|
119
|
+
Urbanairship.application_key = nil
|
120
|
+
Urbanairship.application_secret = nil
|
121
|
+
|
122
|
+
lambda {
|
123
|
+
Urbanairship.unregister_device("asdf1234")
|
124
|
+
}.should raise_error(RuntimeError, "Must configure application_key, application_secret before making this request.")
|
125
|
+
end
|
126
|
+
|
127
|
+
it "uses app key and secret to sign the request" do
|
128
|
+
Urbanairship.unregister_device("key_to_delete")
|
129
|
+
FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64('my_app_key:my_app_secret').chomp}"
|
130
|
+
end
|
131
|
+
|
132
|
+
it "sends the key that needs to be deleted" do
|
133
|
+
Urbanairship.unregister_device("key_to_delete")
|
134
|
+
FakeWeb.last_request.path.should == "/api/device_tokens/key_to_delete"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns true when the device is successfully unregistered" do
|
138
|
+
Urbanairship.unregister_device("key_to_delete").success?.should == true
|
139
|
+
FakeWeb.last_request.body.should be_nil
|
140
|
+
end
|
141
|
+
|
142
|
+
it "returns false when the authorization is invalid" do
|
143
|
+
Urbanairship.application_key = "bad_key"
|
144
|
+
Urbanairship.unregister_device("key_to_delete").success?.should == false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "::delete_scheduled_push" do
|
149
|
+
before(:each) do
|
150
|
+
Urbanairship.application_key = "my_app_key"
|
151
|
+
Urbanairship.master_secret = "my_master_secret"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "raises an error if call is made without an app key and master secret configured" do
|
155
|
+
Urbanairship.application_key = nil
|
156
|
+
Urbanairship.master_secret = nil
|
157
|
+
|
158
|
+
lambda {
|
159
|
+
Urbanairship.delete_scheduled_push("123456789")
|
160
|
+
}.should raise_error(RuntimeError, "Must configure application_key, master_secret before making this request.")
|
161
|
+
end
|
162
|
+
|
163
|
+
it "uses app key and secret to sign the request" do
|
164
|
+
Urbanairship.delete_scheduled_push("123456789")
|
165
|
+
FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64('my_app_key:my_master_secret').chomp}"
|
166
|
+
end
|
167
|
+
|
168
|
+
it "sends the key that needs to be deleted" do
|
169
|
+
Urbanairship.delete_scheduled_push("123456789")
|
170
|
+
FakeWeb.last_request.path.should == "/api/push/scheduled/123456789"
|
171
|
+
end
|
172
|
+
|
173
|
+
it "sends the key that needs to be deleted" do
|
174
|
+
Urbanairship.delete_scheduled_push(123456789)
|
175
|
+
FakeWeb.last_request.path.should == "/api/push/scheduled/123456789"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "sends the alias that needs to be deleted" do
|
179
|
+
Urbanairship.delete_scheduled_push(:alias => "alias_to_delete")
|
180
|
+
FakeWeb.last_request.path.should == "/api/push/scheduled/alias/alias_to_delete"
|
181
|
+
end
|
182
|
+
|
183
|
+
it "returns true when the push notification is successfully deleted" do
|
184
|
+
Urbanairship.delete_scheduled_push("123456789").success?.should == true
|
185
|
+
FakeWeb.last_request.body.should be_nil
|
186
|
+
end
|
187
|
+
|
188
|
+
it "returns false when the authorization is invalid" do
|
189
|
+
Urbanairship.application_key = "bad_key"
|
190
|
+
Urbanairship.delete_scheduled_push("123456789").success?.should == false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "::push" do
|
195
|
+
before(:each) do
|
196
|
+
@valid_params = {:device_tokens => ['device_token_one', 'device_token_two'], :aps => {:alert => 'foo'}}
|
197
|
+
Urbanairship.application_key = "my_app_key"
|
198
|
+
Urbanairship.master_secret = "my_master_secret"
|
199
|
+
end
|
200
|
+
|
201
|
+
it "raises an error if call is made without an app key and master secret configured" do
|
202
|
+
Urbanairship.application_key = nil
|
203
|
+
Urbanairship.master_secret = nil
|
204
|
+
|
205
|
+
lambda {
|
206
|
+
Urbanairship.push(@valid_params)
|
207
|
+
}.should raise_error(RuntimeError, "Must configure application_key, master_secret before making this request.")
|
208
|
+
end
|
209
|
+
|
210
|
+
it "uses app key and secret to sign the request" do
|
211
|
+
Urbanairship.push(@valid_params)
|
212
|
+
FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64('my_app_key:my_master_secret').chomp}"
|
213
|
+
end
|
214
|
+
|
215
|
+
it "returns true when it successfully pushes a notification" do
|
216
|
+
Urbanairship.push(@valid_params).success?.should == true
|
217
|
+
end
|
218
|
+
|
219
|
+
it "returns false when the authorization is invalid" do
|
220
|
+
Urbanairship.application_key = "bad_key"
|
221
|
+
Urbanairship.push(@valid_params).success?.should == false
|
222
|
+
end
|
223
|
+
|
224
|
+
it "adds schedule_for to the JSON payload" do
|
225
|
+
time = Time.parse("Oct 17th, 2010, 8:00 PM UTC")
|
226
|
+
Urbanairship.push(@valid_params.merge(:schedule_for => [time]))
|
227
|
+
request_json['schedule_for'].should == ['2010-10-17T20:00:00Z']
|
228
|
+
end
|
229
|
+
|
230
|
+
it "only attempts to format schedule_for if it is a time object" do
|
231
|
+
Urbanairship.push(@valid_params.merge(:schedule_for => ["2010-10-10 09:09:09 UTC"]))
|
232
|
+
request_json['schedule_for'].should == ['2010-10-10T09:09:09Z']
|
233
|
+
end
|
234
|
+
|
235
|
+
it "returns false if urbanairship responds with a non-200 response" do
|
236
|
+
Urbanairship.application_key = "my_app_key2"
|
237
|
+
Urbanairship.master_secret = "my_master_secret2"
|
238
|
+
Urbanairship.push.success?.should == false
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "::batch_push" do
|
243
|
+
before(:each) do
|
244
|
+
@valid_params = [
|
245
|
+
{:device_tokens => ['device_token_one', 'device_token_two'], :aps => {:alert => 'foo'}},
|
246
|
+
{:device_tokens => ['device_token_three', 'device_token_four'], :aps => {:alert => 'bar'}}
|
247
|
+
]
|
248
|
+
Urbanairship.application_key = "my_app_key"
|
249
|
+
Urbanairship.master_secret = "my_master_secret"
|
250
|
+
end
|
251
|
+
|
252
|
+
it "raises an error if call is made without an app key and master secret configured" do
|
253
|
+
Urbanairship.application_key = nil
|
254
|
+
Urbanairship.master_secret = nil
|
255
|
+
|
256
|
+
lambda {
|
257
|
+
Urbanairship.batch_push(@valid_params)
|
258
|
+
}.should raise_error(RuntimeError, "Must configure application_key, master_secret before making this request.")
|
259
|
+
end
|
260
|
+
|
261
|
+
it "uses app key and secret to sign the request" do
|
262
|
+
Urbanairship.batch_push(@valid_params)
|
263
|
+
FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64('my_app_key:my_master_secret').chomp}"
|
264
|
+
end
|
265
|
+
|
266
|
+
it "returns true when it successfully pushes a notification" do
|
267
|
+
Urbanairship.batch_push(@valid_params).success?.should == true
|
268
|
+
end
|
269
|
+
|
270
|
+
it "returns false when the authorization is invalid" do
|
271
|
+
Urbanairship.application_key = "bad_key"
|
272
|
+
Urbanairship.batch_push(@valid_params).success?.should == false
|
273
|
+
end
|
274
|
+
|
275
|
+
it "adds schedule_for to the JSON payload" do
|
276
|
+
time = Time.parse("Oct 17th, 2010, 8:00 PM UTC")
|
277
|
+
@valid_params[0].merge!(:schedule_for => [time])
|
278
|
+
Urbanairship.batch_push(@valid_params)
|
279
|
+
request_json[0]['schedule_for'].should == ['2010-10-17T20:00:00Z']
|
280
|
+
end
|
281
|
+
|
282
|
+
it "accepts strings as schedule_for values" do
|
283
|
+
@valid_params[0].merge!(:schedule_for => ["2010-10-10 09:09:09 UTC"])
|
284
|
+
Urbanairship.batch_push(@valid_params)
|
285
|
+
request_json[0]['schedule_for'].should == ['2010-10-10T09:09:09Z']
|
286
|
+
end
|
287
|
+
|
288
|
+
it "returns false if urbanairship responds with a non-200 response" do
|
289
|
+
Urbanairship.application_key = "my_app_key2"
|
290
|
+
Urbanairship.master_secret = "my_master_secret2"
|
291
|
+
Urbanairship.batch_push.success?.should == false
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "::broadcast_push" do
|
296
|
+
before(:each) do
|
297
|
+
@valid_params = {:aps => {:alert => 'foo'}}
|
298
|
+
Urbanairship.application_key = "my_app_key"
|
299
|
+
Urbanairship.master_secret = "my_master_secret"
|
300
|
+
end
|
301
|
+
|
302
|
+
it "raises an error if call is made without an app key and master secret configured" do
|
303
|
+
Urbanairship.application_key = nil
|
304
|
+
Urbanairship.master_secret = nil
|
305
|
+
|
306
|
+
lambda {
|
307
|
+
Urbanairship.broadcast_push(@valid_params)
|
308
|
+
}.should raise_error(RuntimeError, "Must configure application_key, master_secret before making this request.")
|
309
|
+
end
|
310
|
+
|
311
|
+
it "uses app key and secret to sign the request" do
|
312
|
+
Urbanairship.broadcast_push(@valid_params)
|
313
|
+
FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64('my_app_key:my_master_secret').chomp}"
|
314
|
+
end
|
315
|
+
|
316
|
+
it "returns true when it successfully pushes a notification" do
|
317
|
+
Urbanairship.broadcast_push(@valid_params).success?.should == true
|
318
|
+
end
|
319
|
+
|
320
|
+
it "returns false when the authorization is invalid" do
|
321
|
+
Urbanairship.application_key = "bad_key"
|
322
|
+
Urbanairship.broadcast_push(@valid_params).success?.should == false
|
323
|
+
end
|
324
|
+
|
325
|
+
it "adds schedule_for to the JSON payload" do
|
326
|
+
time = Time.parse("Oct 17th, 2010, 8:00 PM UTC")
|
327
|
+
@valid_params[:schedule_for] = [time]
|
328
|
+
Urbanairship.broadcast_push(@valid_params)
|
329
|
+
request_json['schedule_for'].should == ['2010-10-17T20:00:00Z']
|
330
|
+
end
|
331
|
+
|
332
|
+
it "accepts strings as schedule_for values" do
|
333
|
+
@valid_params[:schedule_for] = ["2010-10-10 09:09:09 UTC"]
|
334
|
+
Urbanairship.broadcast_push(@valid_params)
|
335
|
+
request_json['schedule_for'].should == ['2010-10-10T09:09:09Z']
|
336
|
+
end
|
337
|
+
|
338
|
+
it "returns false if urbanairship responds with a non-200 response" do
|
339
|
+
Urbanairship.application_key = "my_app_key2"
|
340
|
+
Urbanairship.master_secret = "my_master_secret2"
|
341
|
+
Urbanairship.broadcast_push.success?.should == false
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
describe "::feedback" do
|
346
|
+
before(:each) do
|
347
|
+
Urbanairship.application_key = "my_app_key"
|
348
|
+
Urbanairship.master_secret = "my_master_secret"
|
349
|
+
end
|
350
|
+
|
351
|
+
it "raises an error if call is made without an app key and master secret configured" do
|
352
|
+
Urbanairship.application_key = nil
|
353
|
+
Urbanairship.master_secret = nil
|
354
|
+
|
355
|
+
lambda {
|
356
|
+
Urbanairship.feedback(Time.now)
|
357
|
+
}.should raise_error(RuntimeError, "Must configure application_key, master_secret before making this request.")
|
358
|
+
end
|
359
|
+
|
360
|
+
it "uses app key and secret to sign the request" do
|
361
|
+
Urbanairship.feedback(Time.now)
|
362
|
+
FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64('my_app_key:my_master_secret').chomp}"
|
363
|
+
end
|
364
|
+
|
365
|
+
it "encodes the time argument in UTC, ISO 8601 format" do
|
366
|
+
time = Time.parse("October 10, 2010, 8:00pm")
|
367
|
+
formatted_time = time.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
368
|
+
Urbanairship.feedback(time)
|
369
|
+
FakeWeb.last_request.path.should include(formatted_time)
|
370
|
+
end
|
371
|
+
|
372
|
+
it "accepts a string as the time argument" do
|
373
|
+
Urbanairship.feedback("Oct 07, 2010 8:00AM UTC")
|
374
|
+
FakeWeb.last_request.path.should include("2010-10-07T08:00:00Z")
|
375
|
+
end
|
376
|
+
|
377
|
+
it "returns an array of responses from the feedback API" do
|
378
|
+
response = Urbanairship.feedback(Time.now)
|
379
|
+
response[0].should include("device_token")
|
380
|
+
response[0].should include("marked_inactive_on")
|
381
|
+
response[0].should include("alias")
|
382
|
+
end
|
383
|
+
|
384
|
+
it "success? is false when the call doesn't return 200" do
|
385
|
+
Urbanairship.application_key = "my_app_key2"
|
386
|
+
Urbanairship.master_secret = "my_master_secret2"
|
387
|
+
Urbanairship.feedback(Time.now).success?.should == false
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "logging" do
|
392
|
+
|
393
|
+
before(:each) do
|
394
|
+
@logger = mock("logger", :info => true)
|
395
|
+
Urbanairship.application_key = "my_app_key"
|
396
|
+
Urbanairship.application_secret = "my_app_secret"
|
397
|
+
Urbanairship.master_secret = "my_master_secret"
|
398
|
+
Urbanairship.logger = @logger
|
399
|
+
end
|
400
|
+
|
401
|
+
it "logs request and response information when registering a device" do
|
402
|
+
@logger.should_receive(:info).with(/\/api\/device_tokens\/new_device_token/)
|
403
|
+
Urbanairship.register_device('new_device_token')
|
404
|
+
end
|
405
|
+
|
406
|
+
it "logs request and response information when sending push notifications" do
|
407
|
+
@logger.should_receive(:info).with(/\/api\/push/)
|
408
|
+
Urbanairship.push(:device_tokens => ["device_token"], :aps => {:alert => "foo"})
|
409
|
+
end
|
410
|
+
|
411
|
+
it "logs request and response information when sending batch push notifications" do
|
412
|
+
@logger.should_receive(:info).with(/\/api\/push\/batch/)
|
413
|
+
Urbanairship.batch_push([:device_tokens => ["device_token"], :aps => {:alert => "foo"}])
|
414
|
+
end
|
415
|
+
|
416
|
+
it "logs request and response information when sending feedback requests" do
|
417
|
+
@logger.should_receive(:info).with(/\/api\/device_tokens\/feedback/)
|
418
|
+
Urbanairship.feedback(Time.now)
|
419
|
+
end
|
420
|
+
|
421
|
+
it "flushes the logger buffer if it's an ActiveSupport::BufferedLogger (Default Rails logger)" do
|
422
|
+
@logger.stub(:flush).and_return("message in the buffer\n")
|
423
|
+
@logger.should_receive(:flush)
|
424
|
+
Urbanairship.feedback(Time.now)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
describe "request timeout" do
|
429
|
+
before(:each) do
|
430
|
+
@logger = mock("logger", :info => true)
|
431
|
+
Urbanairship.application_key = "my_app_key"
|
432
|
+
Urbanairship.application_secret = "my_app_secret"
|
433
|
+
Urbanairship.master_secret = "my_master_secret"
|
434
|
+
Urbanairship.logger = @logger
|
435
|
+
end
|
436
|
+
|
437
|
+
it "uses a default request_timeout value of five seconds" do
|
438
|
+
Urbanairship::Timer.should_receive(:timeout).with(5.0).and_raise(Timeout::Error)
|
439
|
+
@logger.should_receive(:error).with(/Urbanairship request timed out/)
|
440
|
+
|
441
|
+
Urbanairship.register_device('new_device_token')
|
442
|
+
end
|
443
|
+
|
444
|
+
it "accepts a configured request_timeout value" do
|
445
|
+
Urbanairship::Timer.should_receive(:timeout).with(1.23).and_raise(Timeout::Error)
|
446
|
+
@logger.should_receive(:error).with(/Urbanairship request timed out/)
|
447
|
+
|
448
|
+
Urbanairship.request_timeout = 1.23
|
449
|
+
Urbanairship.register_device('new_device_token')
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
def request_json
|
455
|
+
JSON.parse FakeWeb.last_request.body
|
456
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sparqcode-urbanairship
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Groupon, Inc.
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-06-14 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: json
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: fakeweb
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id003
|
62
|
+
description: Urbanairship is a Ruby library for interacting with the Urban Airship (http://urbanairship.com) API. Includes updates from ScoutMob.
|
63
|
+
email:
|
64
|
+
- rubygems@groupon.com
|
65
|
+
executables: []
|
66
|
+
|
67
|
+
extensions: []
|
68
|
+
|
69
|
+
extra_rdoc_files: []
|
70
|
+
|
71
|
+
files:
|
72
|
+
- lib/urbanairship/base.rb
|
73
|
+
- lib/urbanairship/response.rb
|
74
|
+
- lib/urbanairship/service.rb
|
75
|
+
- lib/urbanairship.rb
|
76
|
+
- README.markdown
|
77
|
+
- LICENSE
|
78
|
+
- Rakefile
|
79
|
+
- spec/response_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- spec/urbanairship_spec.rb
|
82
|
+
homepage: http://github.com/SPARQCode/urbanairship
|
83
|
+
licenses: []
|
84
|
+
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 59
|
96
|
+
segments:
|
97
|
+
- 1
|
98
|
+
- 8
|
99
|
+
- 6
|
100
|
+
version: 1.8.6
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
hash: 3
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
requirements: []
|
111
|
+
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.8.10
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: A Ruby wrapper for the Urban Airship API
|
117
|
+
test_files:
|
118
|
+
- spec/response_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
- spec/urbanairship_spec.rb
|