sanjose 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/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +50 -0
- data/Rakefile +11 -0
- data/bin/gcm +69 -0
- data/lib/sanjose/client.rb +154 -0
- data/lib/sanjose/connection.rb +26 -0
- data/lib/sanjose/notification.rb +104 -0
- data/lib/sanjose/version.rb +3 -0
- data/lib/sanjose.rb +8 -0
- data/sanjose.gemspec +25 -0
- metadata +123 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Min Kim
|
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/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Sanjose
|
2
|
+
**Google Cloud Message.**
|
3
|
+
|
4
|
+
Sanjose is a simple gem for sending Google Cloud Message.
|
5
|
+
|
6
|
+
> This project is inspired by [houston](https://github.com/mattt/houston) and named as following the series of world-class command-line utilities.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'sanjose'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install sanjose
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
GCM = Sanjose::Client.new
|
26
|
+
GCM.gcm_api_key = "AIzaSyApdin5fMuTSGtW-OTC9gJrm2qz1hJPUzk"
|
27
|
+
|
28
|
+
# An example of the registration id sent back when a device registers for notifications
|
29
|
+
registration_id = "APA91bH35MqYza3xfc2hfag6Rr8VQPSOmi2nrUOPABlFwowfVMZNHaBGBpx-zQ7nuv9qzCEosepUMPKyOrVn0UncZMa__E2sWuM2Q53fjJ5loqIY1QKCza3MkxAu1rvyhhzJP3meEqpmv-kjBuRTeWe_ysRUICupE-awrK1eiStmmm2Y_VBBSs4"
|
30
|
+
|
31
|
+
# Create a notification that alerts a message to the user.
|
32
|
+
notification = Sanjose::Notification.new(devices: [registration_id])
|
33
|
+
notification.collapse_key = "Hello, World!"
|
34
|
+
notification.data = {foo: "bar"}
|
35
|
+
|
36
|
+
# And... sent! That's all it takes.
|
37
|
+
GCM.push(notification)
|
38
|
+
```
|
39
|
+
|
40
|
+
## Contact
|
41
|
+
|
42
|
+
Min Kim
|
43
|
+
|
44
|
+
- http://github.com/minsikzzang
|
45
|
+
- http://twitter.com/minsikzzang
|
46
|
+
- minsikzzang@gmail.com
|
47
|
+
|
48
|
+
## License
|
49
|
+
|
50
|
+
Sanjose is available under the MIT license. See the LICENSE file for more info.
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
gemspec = eval(File.read("sanjose.gemspec"))
|
5
|
+
|
6
|
+
task :build => "#{gemspec.full_name}.gem"
|
7
|
+
|
8
|
+
file "#{gemspec.full_name}.gem" => gemspec.files + ["sanjose.gemspec"] do
|
9
|
+
system "gem build houston.gemspec"
|
10
|
+
system "gem install sanjose-#{Houston::VERSION}.gem"
|
11
|
+
end
|
data/bin/gcm
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'commander/import'
|
4
|
+
|
5
|
+
require 'sanjose'
|
6
|
+
|
7
|
+
HighLine.track_eof = false # Fix for built-in Ruby
|
8
|
+
Signal.trap("INT") {} # Suppress backtrace when exiting command
|
9
|
+
|
10
|
+
program :version, Sanjose::VERSION
|
11
|
+
program :description, 'A command-line interface for sending push notifications for Android'
|
12
|
+
|
13
|
+
program :help, 'Author', 'Min Kim <minsikzzang@gmail.com>'
|
14
|
+
program :help, 'Website', 'https://github.com/minsikzzang'
|
15
|
+
program :help_formatter, :compact
|
16
|
+
|
17
|
+
default_command :help
|
18
|
+
|
19
|
+
command :push do |c|
|
20
|
+
c.syntax = 'gcm push DEVICE [...]'
|
21
|
+
c.summary = 'Sends an Google Cloud Message to specified devices'
|
22
|
+
c.description = ''
|
23
|
+
|
24
|
+
c.example 'description', 'gcm push <registration_id> -d "{\"foo\":\"bar\"}"" -k "AIzaSyApdin5fMuTSGtW-OTC9gJrm2qz1hJPUzk" -c "Hello, World!"'
|
25
|
+
c.option '-k', '--key KEY', 'Google Cloud Message api key'
|
26
|
+
c.option '-c', '--collapse_key CK', 'An arbitrary string (such as "Updates Available") that is used to collapse a group of like messages when the device is offline'
|
27
|
+
c.option '-r', '--dry_run DRY_RUN', 'It allows developers to test their request without actually sending a message'
|
28
|
+
c.option '-t', '--time_to_live TTL', 'How long (in seconds) the message should be kept on GCM storage if the device is offline.'
|
29
|
+
c.option '-p', '--restricted_package_name RPN', 'A string containing the package name of your application.'
|
30
|
+
c.option '-d', '--data DATA', 'A JSON object whose fields represents the key-value pairs of the message\'s payload data'
|
31
|
+
|
32
|
+
c.action do |args, options|
|
33
|
+
say_error "One or more device registration_id required" and abort if args.empty?
|
34
|
+
|
35
|
+
@key = options.key
|
36
|
+
say_error "Google Cloud api key is required" and abort unless @key
|
37
|
+
|
38
|
+
@data = options.data
|
39
|
+
@time_to_live = options.time_to_live
|
40
|
+
@collapse_key = options.collapse_key
|
41
|
+
@restricted_package_name = options.restricted_package_name
|
42
|
+
@dry_run = options.dry_run
|
43
|
+
|
44
|
+
client = Sanjose::Client.new
|
45
|
+
client.gcm_api_key = @key
|
46
|
+
a = "APA91bH35MqYza3xfc2hfag6Rr8VQPSOmi2nrUOPABlFwowfVMZNHaBGBpx-zQ7nuv9qzCEosepUMPKyOrVn0UncZMa__E2sWuM2Q53fjJ5loqIY1QKCza3MkxAu1rvyhhzJP3meEqpmv-kjBuRTeWe_ysRUICupE-awrK1eiStmmm2Y_VBBSs4"
|
47
|
+
b = "APA91bHAX-Owu0Ulm5XubHs7BYy6a4O87Gk8-2JOW3eJ2TauVzWsB0d4yCxjzxMXl40elIIwG3E0Lpvd1_5xGldZm64UO4fqC0RNpvGWKUSr7hMNhavRS8w2NS2XUwYsluysVaXZU0rvmq0zSCH6JHGZiqd0qlUsmg"
|
48
|
+
|
49
|
+
notification = Sanjose::Notification.new
|
50
|
+
args.each do |device|
|
51
|
+
notification.add_device(device)
|
52
|
+
end
|
53
|
+
|
54
|
+
notification.data = JSON.parse(@data)
|
55
|
+
notification.collapse_key = @collapse_key
|
56
|
+
notification.dry_run = @dry_run
|
57
|
+
notification.restricted_package_name = @restricted_package_name
|
58
|
+
notification.time_to_live = @time_to_live
|
59
|
+
|
60
|
+
begin
|
61
|
+
results = client.push(notification)
|
62
|
+
puts results.inspect
|
63
|
+
rescue => e
|
64
|
+
say_error "Exception sending notification: #{e}" and abort
|
65
|
+
end
|
66
|
+
|
67
|
+
say_ok "Push notifications successfully sent"
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module Sanjose
|
2
|
+
GCM_GATEWAY_URI = "https://android.googleapis.com/gcm/send"
|
3
|
+
MULTICAST_SIZE = 1000
|
4
|
+
TOKEN_CANONICAL_REG_ID = 'registration_id'
|
5
|
+
JSON_SUCCESS = 'success'
|
6
|
+
JSON_FAILURE ='failure'
|
7
|
+
JSON_CANONICAL_IDS = 'canonical_ids'
|
8
|
+
JSON_MULTICAST_ID = 'multicast_id'
|
9
|
+
JSON_RESULTS = 'results'
|
10
|
+
JSON_MESSAGE_ID = 'message_id'
|
11
|
+
JSON_ERROR = 'error'
|
12
|
+
ERROR_UNAVAILABLE = "Unavailable";
|
13
|
+
|
14
|
+
# Initial delay before first retry
|
15
|
+
BACKOFF_INITIAL_DELAY = 1000
|
16
|
+
|
17
|
+
# Maximum delay before a retry.
|
18
|
+
MAX_BACKOFF_DELAY = 1024000
|
19
|
+
|
20
|
+
class Client
|
21
|
+
attr_accessor :gcm_gateway_uri, :gcm_api_key
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@gcm_gateway_uri = GCM_GATEWAY_URI
|
25
|
+
@gcm_api_key = ENV['GCM_API_KEY']
|
26
|
+
end
|
27
|
+
|
28
|
+
def push(notification, retries = 5)
|
29
|
+
return if not notification or notification.sent?
|
30
|
+
|
31
|
+
attempt = 0
|
32
|
+
try_again = true
|
33
|
+
muticast_ids = []
|
34
|
+
results = {}
|
35
|
+
unsent_reg_ids = notification.devices
|
36
|
+
backoff = BACKOFF_INITIAL_DELAY
|
37
|
+
|
38
|
+
while try_again do
|
39
|
+
attempt += 1
|
40
|
+
multicast_result = push_no_retry(notification,
|
41
|
+
connection_options_for_endpoint(:gateway), unsent_reg_ids)
|
42
|
+
|
43
|
+
if multicast_result
|
44
|
+
muticast_ids << multicast_result.multicast_id
|
45
|
+
unsent_reg_ids = update_status(unsent_reg_ids, results, multicast_result)
|
46
|
+
end
|
47
|
+
|
48
|
+
try_again = !unsent_reg_ids.empty? and attempt <= retries
|
49
|
+
|
50
|
+
if try_again
|
51
|
+
sleep_time = backoff / 2 + rand(backoff)
|
52
|
+
sleep(sleep_time / 1000)
|
53
|
+
if 2 * backoff < MAX_BACKOFF_DELAY
|
54
|
+
backoff *= 2
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# calculate summary
|
60
|
+
success = 0
|
61
|
+
failure = 0
|
62
|
+
canonical_ids = 0
|
63
|
+
|
64
|
+
results.values.each do |result|
|
65
|
+
if result.message_id
|
66
|
+
success += 1
|
67
|
+
if result.canonical_reg_id
|
68
|
+
canonical_ids += 1
|
69
|
+
end
|
70
|
+
else
|
71
|
+
failure += 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# build a new object with the overall result
|
76
|
+
multicast_id = muticast_ids.pop(0)
|
77
|
+
builder = MulticastResult.new(
|
78
|
+
:success => success,
|
79
|
+
:failure => failure,
|
80
|
+
:canonical_ids => canonical_ids,
|
81
|
+
:multicast_id => multicast_id)
|
82
|
+
builder.retry_multicast_ids = muticast_ids
|
83
|
+
|
84
|
+
# add results, in the same order as the input
|
85
|
+
notification.devices.each do |device|
|
86
|
+
builder.add_result(results[device])
|
87
|
+
end
|
88
|
+
|
89
|
+
builder
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def update_status(unsent_reg_ids, all_results, multicast_result)
|
94
|
+
results = multicast_result.results
|
95
|
+
if results.length != unsent_reg_ids.length
|
96
|
+
# should never heppan, unless there is a flaw in the algorithm
|
97
|
+
raise RuntimeError
|
98
|
+
"internal error: sizes do not match. current_results: #{results}; unsent_reg_ids: #{unsent_reg_ids}"
|
99
|
+
end
|
100
|
+
|
101
|
+
new_unsent_reg_ids = []
|
102
|
+
i = 0
|
103
|
+
unsent_reg_ids.each do |reg_id|
|
104
|
+
result = results.at(i)
|
105
|
+
all_results[reg_id] = result
|
106
|
+
i += 1
|
107
|
+
if result.error and result.error == ERROR_UNAVAILABLE
|
108
|
+
new_unsent_reg_ids << reg_id
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
new_unsent_reg_ids
|
113
|
+
end
|
114
|
+
|
115
|
+
def push_no_retry(notification, uri, reg_ids)
|
116
|
+
multicast_result = nil
|
117
|
+
messages = notification.clone
|
118
|
+
messages.devices = reg_ids
|
119
|
+
|
120
|
+
Connection.open(uri) do |connection|
|
121
|
+
message = messages.message
|
122
|
+
|
123
|
+
# Need to put gcm api keyand content length in header
|
124
|
+
headers = {"Authorization" => "key=#{@gcm_api_key}",
|
125
|
+
"Content-type" => "application/json"}
|
126
|
+
response = connection.post(uri.path, message, headers)
|
127
|
+
return nil if response.code != "200"
|
128
|
+
|
129
|
+
json = JSON.parse(response.body)
|
130
|
+
multicast_result = MulticastResult.new(
|
131
|
+
:success => json[JSON_SUCCESS],
|
132
|
+
:failure => json[JSON_FAILURE],
|
133
|
+
:canonical_ids => json[JSON_CANONICAL_IDS],
|
134
|
+
:multicast_id => json[JSON_MULTICAST_ID])
|
135
|
+
results = json[JSON_RESULTS]
|
136
|
+
results.each do |result|
|
137
|
+
multicast_result.add_result(
|
138
|
+
Result.new(:message_id => result[JSON_MESSAGE_ID],
|
139
|
+
:canonical_reg_id => result[TOKEN_CANONICAL_REG_ID],
|
140
|
+
:error => result[JSON_ERROR]))
|
141
|
+
end
|
142
|
+
end
|
143
|
+
multicast_result
|
144
|
+
end
|
145
|
+
|
146
|
+
def connection_options_for_endpoint(endpoint = :gateway)
|
147
|
+
uri = case endpoint
|
148
|
+
when :gateway then URI(@gcm_gateway_uri)
|
149
|
+
else
|
150
|
+
raise ArgumentError
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Sanjose
|
4
|
+
class Connection
|
5
|
+
class << self
|
6
|
+
def open(uri)
|
7
|
+
return if uri == nil
|
8
|
+
|
9
|
+
connection = connection_for_uri(uri)
|
10
|
+
connection.start
|
11
|
+
|
12
|
+
yield connection
|
13
|
+
|
14
|
+
connection.finish
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def self.connection_for_uri(uri)
|
21
|
+
connection = Net::HTTP.new(uri.host, uri.port)
|
22
|
+
connection.use_ssl = uri.scheme == 'https'
|
23
|
+
connection
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Sanjose
|
4
|
+
class Notification
|
5
|
+
attr_accessor :data, :collapse_key, :delay_when_idle, :time_to_live,
|
6
|
+
:dry_run, :restricted_package_name, :devices
|
7
|
+
attr_reader :sent_at
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
# Required field
|
11
|
+
# A string array with the list of devices (registration IDs) receiving
|
12
|
+
# the message. It must contain at least 1 and at most 1000 registration IDs.
|
13
|
+
if !options[:devices]
|
14
|
+
@devices = []
|
15
|
+
else
|
16
|
+
@devices = options[:devices]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Optional fields
|
20
|
+
# An arbitraru string (such as "Updates Available") that is used to
|
21
|
+
# collapse a group of like messages when the device is offline, so
|
22
|
+
# that only the last message gets sent to the client.
|
23
|
+
@collapse_key = options[:collapse_key]
|
24
|
+
|
25
|
+
# If included, indicates that the message should not be sent immediately
|
26
|
+
# if the device is idle.
|
27
|
+
@delay_when_idle = options[:delay_when_idle]
|
28
|
+
|
29
|
+
# How long (in seconds) the message should be kept on GCM storage if the
|
30
|
+
# device is offline.
|
31
|
+
@time_to_live = options[:time_to_live]
|
32
|
+
|
33
|
+
# If included, allows developers to test their request without actually
|
34
|
+
# sending a message. Optional. The default value is false, and must be a
|
35
|
+
# JSON boolean.
|
36
|
+
@dry_run = options[:dry_run]
|
37
|
+
|
38
|
+
# A string containing the package name of your application. When set,
|
39
|
+
# messages will only be sent to registration IDs that match the package
|
40
|
+
# name.
|
41
|
+
@restricted_package_name = options[:restricted_package_name]
|
42
|
+
|
43
|
+
# A JSON object whose fields represents the key-value pairs of the message's
|
44
|
+
# payload data. There is no limit on the number of key/value pairs, though
|
45
|
+
# there is a limit on the total size of the message (4kb).
|
46
|
+
@data = options[:data]
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_device(device)
|
50
|
+
@devices << device
|
51
|
+
end
|
52
|
+
|
53
|
+
def device_size
|
54
|
+
@devices.length
|
55
|
+
end
|
56
|
+
|
57
|
+
def message
|
58
|
+
# plan-text format
|
59
|
+
# 'registration_id=APA91bH35MqYza3xfc2hfag6Rr8VQPSOmi2nrUOPABlFwowfVMZNHaBGBpx-zQ7nuv9qzCEosepUMPKyOrVn0UncZMa__E2sWuM2Q53fjJ5loqIY1QKCza3MkxAu1rvyhhzJP3meEqpmv-kjBuRTeWe_ysRUICupE-awrK1eiStmmm2Y_VBBSs4'
|
60
|
+
# json format
|
61
|
+
# '{"registration_ids":["APA91bH35MqYza3xfc2hfag6Rr8VQPSOmi2nrUOPABlFwowfVMZNHaBGBpx-zQ7nuv9qzCEosepUMPKyOrVn0UncZMa__E2sWuM2Q53fjJ5loqIY1QKCza3MkxAu1rvyhhzJP3meEqpmv-kjBuRTeWe_ysRUICupE-awrK1eiStmmm2Y_VBBSs4","APA91bHAX-Owu0Ulm5XubHs7BYy6a4O87Gk8-2JOW3eJ2TauVzWsB0d4yCxjzxMXl40elIIwG3E0Lpvd1_5xGldZm64UO4fqC0RNpvGWKUSr7hMNhavRS8w2NS2XUwYsluysVaXZU0rvmq0zSCH6JHGZiqd0qlUsmg"]}'
|
62
|
+
|
63
|
+
json = {}
|
64
|
+
if @devices.empty?
|
65
|
+
raise ArgumentError 'devices cannot be empty'
|
66
|
+
else
|
67
|
+
json['registration_ids'] = @devices
|
68
|
+
end
|
69
|
+
|
70
|
+
if @collapse_key
|
71
|
+
json['collapse_key'] = @collapse_key
|
72
|
+
end
|
73
|
+
if @delay_when_idle
|
74
|
+
json['delay_when_idle'] = @delay_when_idle
|
75
|
+
end
|
76
|
+
|
77
|
+
if @time_to_live
|
78
|
+
json['time_to_live'] = @time_to_live
|
79
|
+
end
|
80
|
+
|
81
|
+
if @data
|
82
|
+
json['data'] = @data
|
83
|
+
end
|
84
|
+
|
85
|
+
if @restricted_package_name
|
86
|
+
json['restricted_package_name'] = @restricted_package_name
|
87
|
+
end
|
88
|
+
|
89
|
+
if @dry_run
|
90
|
+
json['dry_run'] = @dry_run
|
91
|
+
end
|
92
|
+
|
93
|
+
json.to_json
|
94
|
+
end
|
95
|
+
|
96
|
+
def mark_as_sent!
|
97
|
+
@sent_at = Time.now
|
98
|
+
end
|
99
|
+
|
100
|
+
def sent?
|
101
|
+
!!@sent_at
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/sanjose.rb
ADDED
data/sanjose.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sanjose'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "sanjose"
|
8
|
+
s.version = Sanjose::VERSION
|
9
|
+
s.authors = ["Min Kim"]
|
10
|
+
s.email = ["minsikzzang@gmail.com", "minsik.kim@livestation.com"]
|
11
|
+
s.description = "Send Google Cloud Message"
|
12
|
+
s.summary = "Sanjose is a simple gem for sending Google Cloud Message"
|
13
|
+
s.homepage = "http://github.com/minsikzzang/sanjose"
|
14
|
+
|
15
|
+
s.add_dependency "commander", "~> 4.1.2"
|
16
|
+
s.add_dependency "json", "~> 1.7.3"
|
17
|
+
|
18
|
+
s.add_development_dependency "rspec", "~> 0.6.1"
|
19
|
+
s.add_development_dependency "rake", "~> 0.9.2"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split($/)
|
22
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
23
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sanjose
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Min Kim
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: commander
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 4.1.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 4.1.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.7.3
|
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.7.3
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.6.1
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.6.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.9.2
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.9.2
|
78
|
+
description: Send Google Cloud Message
|
79
|
+
email:
|
80
|
+
- minsikzzang@gmail.com
|
81
|
+
- minsik.kim@livestation.com
|
82
|
+
executables:
|
83
|
+
- gcm
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- Gemfile
|
89
|
+
- LICENSE.txt
|
90
|
+
- README.md
|
91
|
+
- Rakefile
|
92
|
+
- bin/gcm
|
93
|
+
- lib/sanjose.rb
|
94
|
+
- lib/sanjose/client.rb
|
95
|
+
- lib/sanjose/connection.rb
|
96
|
+
- lib/sanjose/notification.rb
|
97
|
+
- lib/sanjose/version.rb
|
98
|
+
- sanjose.gemspec
|
99
|
+
homepage: http://github.com/minsikzzang/sanjose
|
100
|
+
licenses: []
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 1.8.24
|
120
|
+
signing_key:
|
121
|
+
specification_version: 3
|
122
|
+
summary: Sanjose is a simple gem for sending Google Cloud Message
|
123
|
+
test_files: []
|