em_apn_manager 0.0.2 → 0.1.0
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +26 -10
- data/VERSION +1 -1
- data/bin/em_apn_manager +2 -0
- data/em_apn_manager.gemspec +32 -2
- data/lib/em_apn_manager.rb +2 -1
- data/lib/em_apn_manager/cli.rb +53 -18
- data/lib/em_apn_manager/client.rb +2 -2
- data/lib/em_apn_manager/generators/templates/em_apn_manager.yml +3 -13
- data/lib/em_apn_manager/manager.rb +5 -3
- metadata +142 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7488d9d6b4d3ffca37840e1efd52dd3bc555c4cb
|
4
|
+
data.tar.gz: 39053f313b6bdd6bb04469d2804c650ec0ca549f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a9906727741db1583fe89b897c7876944a31ce5b0fa231c955195371e6f624ff633b3c606868aa47204a379933bf5ef6c3038952516ad2256e38a44d795786c
|
7
|
+
data.tar.gz: a0e2b04ee2a8d50f83d10931ddd6b94f9ac08051905ea1edb93a6c25a27c48ae412cf4177bf260d65908d16777f540ee24c28eaef06a630d0cf156fe040a3ca3
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,24 +3,40 @@ EventMachine APN Manager
|
|
3
3
|
|
4
4
|
EventMachine APN Connection Manager, The purpose is to support multiple cert and multiple application with one process.
|
5
5
|
|
6
|
-
Steps
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
Steps for running with *Rails*:
|
7
|
+
|
8
|
+
1. Add `gem 'em_apn_manager', git: 'git@github.com:hlxwell/em_apn_manager.git'` to *Gemfile*.
|
9
|
+
|
10
|
+
2. Run `bundle exec rails g event_machine:apn_manager:install` to generate `config/em_apn_manager.yml` file.
|
11
|
+
|
12
|
+
3. Run `bundle exec em_apn_manager server -e development`.
|
13
|
+
|
14
|
+
|
15
|
+
Steps for running `Standalone`:
|
16
|
+
|
17
|
+
1. Run `gem install em_apn_manager`
|
18
|
+
|
19
|
+
2. Run `em_apn_manager server --redis-host 127.0.0.1 --redis-port 6379` or `em_apn_manager server --config CONFIG_FILE_PATH`
|
20
|
+
|
21
|
+
Put below line to your code for sending push notification:
|
22
|
+
|
11
23
|
`EM::ApnManager.push_notification({
|
12
|
-
|
24
|
+
env: CERT_ENVIRONMENT,
|
25
|
+
cert: PEM_CERT_TEXT_CONTENT,
|
13
26
|
token: DEVICE_TOKEN,
|
14
27
|
message: YOUR_MESSAGE
|
15
28
|
})`
|
16
29
|
|
30
|
+
Running server in background:
|
31
|
+
|
32
|
+
`em_apn_manager server --daemon`
|
17
33
|
|
18
34
|
Generate pem from p12
|
19
35
|
==================
|
36
|
+
|
37
|
+
This is how you get `p12` file:
|
38
|
+
http://docs.urbanairship.com/build/ios.html#set-up-your-application-with-apple
|
39
|
+
|
20
40
|
You have to convert p12 format to pem format by below command line.
|
21
41
|
`openssl pkcs12 -in cert.p12 -out cert.pem -nodes -clcerts`
|
22
42
|
|
23
|
-
|
24
|
-
TO DOs
|
25
|
-
==================
|
26
|
-
1. Implement running `bundle exec em_apn_manager -e development` in background, support `-daemon` and `-pid_file`
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/bin/em_apn_manager
CHANGED
data/em_apn_manager.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "em_apn_manager"
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Michael He"]
|
12
|
-
s.date = "2013-07-
|
12
|
+
s.date = "2013-07-17"
|
13
13
|
s.description = "EventMachine multiple APNs connections Management Solution. You can use multiple cert and connection to apple's APNs server."
|
14
14
|
s.email = "m.he@skillupjapan.co.jp"
|
15
15
|
s.executables = ["em_apn_manager"]
|
@@ -99,6 +99,16 @@ Gem::Specification.new do |s|
|
|
99
99
|
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
100
100
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
101
101
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
102
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
|
103
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
104
|
+
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
105
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
106
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
107
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
|
108
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
109
|
+
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
110
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
111
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
102
112
|
s.add_runtime_dependency(%q<thor>, ["~> 0.16"])
|
103
113
|
s.add_runtime_dependency(%q<eventmachine>, [">= 1.0.0"])
|
104
114
|
s.add_runtime_dependency(%q<yajl-ruby>, [">= 0.8.2"])
|
@@ -157,6 +167,16 @@ Gem::Specification.new do |s|
|
|
157
167
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
158
168
|
s.add_dependency(%q<bundler>, [">= 0"])
|
159
169
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
170
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
171
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
172
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
173
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
174
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
175
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
176
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
177
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
178
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
179
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
160
180
|
s.add_dependency(%q<thor>, ["~> 0.16"])
|
161
181
|
s.add_dependency(%q<eventmachine>, [">= 1.0.0"])
|
162
182
|
s.add_dependency(%q<yajl-ruby>, [">= 0.8.2"])
|
@@ -216,6 +236,16 @@ Gem::Specification.new do |s|
|
|
216
236
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
217
237
|
s.add_dependency(%q<bundler>, [">= 0"])
|
218
238
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
239
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
240
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
241
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
242
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
243
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
244
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
245
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
246
|
+
s.add_dependency(%q<rdoc>, [">= 0"])
|
247
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
248
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
219
249
|
s.add_dependency(%q<thor>, ["~> 0.16"])
|
220
250
|
s.add_dependency(%q<eventmachine>, [">= 1.0.0"])
|
221
251
|
s.add_dependency(%q<yajl-ruby>, [">= 0.8.2"])
|
data/lib/em_apn_manager.rb
CHANGED
@@ -13,10 +13,11 @@ module EventMachine
|
|
13
13
|
def push_notification options = {}
|
14
14
|
# FIXME Check options
|
15
15
|
$apn_manager_redis.publish "push-notification", {
|
16
|
+
env: options[:env],
|
16
17
|
cert: options[:cert],
|
17
18
|
token: options[:token],
|
18
19
|
message: options[:message]
|
19
20
|
}.to_json
|
20
21
|
end
|
21
22
|
end
|
22
|
-
end
|
23
|
+
end
|
data/lib/em_apn_manager/cli.rb
CHANGED
@@ -16,34 +16,48 @@ $apn_manager_redis = nil
|
|
16
16
|
module EventMachine
|
17
17
|
module ApnManager
|
18
18
|
class CLI < Thor
|
19
|
-
class_option :config,
|
20
|
-
class_option :environment,
|
19
|
+
class_option :config, :aliases => ["-c"], :type => :string
|
20
|
+
class_option :environment, :aliases => ["-e"], :type => :string
|
21
|
+
class_option :redis, :aliases => ["-r"], :type => :string
|
21
22
|
|
23
|
+
### 3 ways to specify the redis
|
24
|
+
# 1. config yml file
|
25
|
+
# 2. pass redis-url is 'redis://username:password@host:port/database'
|
26
|
+
# like `redis://test:test@localhost:6379/em_apn_manager`
|
27
|
+
#
|
22
28
|
def initialize(args = [], opts = [], config = {})
|
23
29
|
super(args, opts, config)
|
24
30
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
redis_config = options[:redis]
|
32
|
+
if redis_config.nil?
|
33
|
+
# read the environment var.
|
34
|
+
@environment = ENV["RAILS_ENV"] || "development"
|
35
|
+
@environment = options[:environment] if %w{test development production}.include? options[:environment]
|
36
|
+
|
37
|
+
# Read config option, or use default config yml
|
38
|
+
config_path = options[:config] || File.join(".", "config", "em_apn_manager.yml")
|
39
|
+
if config_path && File.exists?(config_path)
|
40
|
+
EM::ApnManager.config = Thor::CoreExt::HashWithIndifferentAccess.new(YAML.load_file(config_path))
|
41
|
+
redis_config = EM::ApnManager.config[@environment]
|
42
|
+
end
|
32
43
|
|
33
|
-
|
34
|
-
|
35
|
-
|
44
|
+
# default redis
|
45
|
+
redis_config ||= "redis://localhost:6379/em_apn_manager"
|
46
|
+
end
|
36
47
|
|
37
48
|
# create redis connection
|
38
|
-
$apn_manager_redis = Redis.new
|
49
|
+
$apn_manager_redis = Redis.new url: redis_config
|
39
50
|
end
|
40
51
|
|
41
52
|
desc "server", "Start manager server."
|
42
|
-
|
43
|
-
|
53
|
+
option :daemon, :aliases => ["-d"], :type => :boolean
|
54
|
+
option :pid_file, :aliases => ["-p"], :type => :string
|
44
55
|
def server
|
56
|
+
daemonize if options[:daemon]
|
57
|
+
write_pid_file(options[:pid_file]) if options[:pid_file]
|
58
|
+
|
45
59
|
EM::ApnManager.logger.info("Starting APN Manager")
|
46
|
-
EM.run { EM::ApnManager::Manager.run
|
60
|
+
EM.run { EM::ApnManager::Manager.run }
|
47
61
|
end
|
48
62
|
|
49
63
|
### For Testing ##################################################
|
@@ -52,8 +66,9 @@ module EventMachine
|
|
52
66
|
def push_test_message
|
53
67
|
10.times do |i|
|
54
68
|
EM::ApnManager.push_notification({
|
55
|
-
|
56
|
-
|
69
|
+
env: 'test',
|
70
|
+
cert: File.read(ENV["APN_CERT"]), # test cert
|
71
|
+
token: ["0F93C49EAAF3544B5218D2BAE893608C515F69B445279AB2B17511C37046C52B", "D42A6795D0C6C0E5F3CC762F905C3654D2A07E72D64CDEC1E2F74AC43C4CC440"].sample,
|
57
72
|
message: "Hahahaha I am going to spam you. #{i}-#{rand * 100}"
|
58
73
|
})
|
59
74
|
end
|
@@ -64,6 +79,26 @@ module EventMachine
|
|
64
79
|
EM::ApnManager.logger.info("Starting Mock APN Server")
|
65
80
|
EM.run { EM.start_server("127.0.0.1", 2195, EM::ApnManager::ApnServer) }
|
66
81
|
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Daemonize process (ruby >= 1.9 only)
|
86
|
+
# @return [void] Ruby ~>1.8
|
87
|
+
# @return [0] Ruby 1.9+ (see Process::daemon)
|
88
|
+
# @raise [Errno] on failure
|
89
|
+
def daemonize
|
90
|
+
if Process.respond_to?(:daemon)
|
91
|
+
Process.daemon(true, true)
|
92
|
+
else
|
93
|
+
Kernel.warn "Running process as daemon requires ruby >= 1.9"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Save worker's pid to file
|
98
|
+
# @return [void]
|
99
|
+
def write_pid_file(path = nil)
|
100
|
+
File.open(path, 'w'){ |f| f << Process.pid } if path
|
101
|
+
end
|
67
102
|
end
|
68
103
|
end
|
69
104
|
end
|
@@ -20,10 +20,10 @@ module EventMachine
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def initialize(options = {})
|
23
|
-
@cert = options[:cert]
|
23
|
+
@cert = options[:cert]
|
24
24
|
@port = options[:port] || PORT
|
25
25
|
@environment = options[:env]
|
26
|
-
@gateway = options[:gateway]
|
26
|
+
@gateway = options[:gateway]
|
27
27
|
@gateway ||= case @environment
|
28
28
|
when "test"
|
29
29
|
TEST_GATEWAY
|
@@ -1,13 +1,3 @@
|
|
1
|
-
production:
|
2
|
-
|
3
|
-
|
4
|
-
db: YOUR_PRODUCTION_REDIS
|
5
|
-
password: PASSWORD
|
6
|
-
|
7
|
-
development:
|
8
|
-
host: localhost
|
9
|
-
port: 6379
|
10
|
-
|
11
|
-
test:
|
12
|
-
host: localhost
|
13
|
-
port: 6379
|
1
|
+
production: redis://username:password@host:port/database
|
2
|
+
development: redis://localhost:6379/resque
|
3
|
+
test: redis://localhost:6379/resque
|
@@ -24,15 +24,17 @@ module EventMachine
|
|
24
24
|
|
25
25
|
### launch a new connect to apple when detected any pushs.
|
26
26
|
@redis.pubsub.subscribe('push-notification') do |msg|
|
27
|
-
msg_hash = Yajl::Parser.parse(msg) # might be some wrong json
|
27
|
+
msg_hash = Yajl::Parser.parse(msg) # FIXME might be some wrong json
|
28
|
+
|
28
29
|
# save the cert to local first, since the start_tls read from file.
|
29
30
|
cert_filename = save_cert_to_file msg_hash["cert"]
|
31
|
+
|
30
32
|
# cert filename is a key for connection pool
|
31
33
|
client = $connection_pool[cert_filename]
|
32
34
|
|
33
35
|
### Create client connection if doesn't exist in pool.
|
34
36
|
if client.nil?
|
35
|
-
client = EM::ApnManager::Client.new(options.merge!({cert: cert_filename}))
|
37
|
+
client = EM::ApnManager::Client.new(options.merge!({env: msg_hash["env"], cert: cert_filename}))
|
36
38
|
# Store the connection to pool
|
37
39
|
$connection_pool[cert_filename] = client
|
38
40
|
end
|
@@ -54,8 +56,8 @@ module EventMachine
|
|
54
56
|
|
55
57
|
private
|
56
58
|
|
59
|
+
# NOTICE should not put the 'certs' folder to a downloadable place.
|
57
60
|
def save_cert_to_file cert_content
|
58
|
-
# TODO, should store Rails.root/tmp/certs and this folder should be protected.
|
59
61
|
FileUtils.mkdir_p "certs"
|
60
62
|
filename = Base64.encode64(cert_content)[0..50]
|
61
63
|
filename = File.join "certs", filename
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em_apn_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael He
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em_apn_manager
|
@@ -724,6 +724,146 @@ dependencies:
|
|
724
724
|
- - ~>
|
725
725
|
- !ruby/object:Gem::Version
|
726
726
|
version: 1.8.4
|
727
|
+
- !ruby/object:Gem::Dependency
|
728
|
+
name: rspec
|
729
|
+
requirement: !ruby/object:Gem::Requirement
|
730
|
+
requirements:
|
731
|
+
- - ~>
|
732
|
+
- !ruby/object:Gem::Version
|
733
|
+
version: 2.6.0
|
734
|
+
type: :development
|
735
|
+
prerelease: false
|
736
|
+
version_requirements: !ruby/object:Gem::Requirement
|
737
|
+
requirements:
|
738
|
+
- - ~>
|
739
|
+
- !ruby/object:Gem::Version
|
740
|
+
version: 2.6.0
|
741
|
+
- !ruby/object:Gem::Dependency
|
742
|
+
name: shoulda
|
743
|
+
requirement: !ruby/object:Gem::Requirement
|
744
|
+
requirements:
|
745
|
+
- - '>='
|
746
|
+
- !ruby/object:Gem::Version
|
747
|
+
version: '0'
|
748
|
+
type: :development
|
749
|
+
prerelease: false
|
750
|
+
version_requirements: !ruby/object:Gem::Requirement
|
751
|
+
requirements:
|
752
|
+
- - '>='
|
753
|
+
- !ruby/object:Gem::Version
|
754
|
+
version: '0'
|
755
|
+
- !ruby/object:Gem::Dependency
|
756
|
+
name: rdoc
|
757
|
+
requirement: !ruby/object:Gem::Requirement
|
758
|
+
requirements:
|
759
|
+
- - '>='
|
760
|
+
- !ruby/object:Gem::Version
|
761
|
+
version: '0'
|
762
|
+
type: :development
|
763
|
+
prerelease: false
|
764
|
+
version_requirements: !ruby/object:Gem::Requirement
|
765
|
+
requirements:
|
766
|
+
- - '>='
|
767
|
+
- !ruby/object:Gem::Version
|
768
|
+
version: '0'
|
769
|
+
- !ruby/object:Gem::Dependency
|
770
|
+
name: bundler
|
771
|
+
requirement: !ruby/object:Gem::Requirement
|
772
|
+
requirements:
|
773
|
+
- - '>='
|
774
|
+
- !ruby/object:Gem::Version
|
775
|
+
version: '0'
|
776
|
+
type: :development
|
777
|
+
prerelease: false
|
778
|
+
version_requirements: !ruby/object:Gem::Requirement
|
779
|
+
requirements:
|
780
|
+
- - '>='
|
781
|
+
- !ruby/object:Gem::Version
|
782
|
+
version: '0'
|
783
|
+
- !ruby/object:Gem::Dependency
|
784
|
+
name: jeweler
|
785
|
+
requirement: !ruby/object:Gem::Requirement
|
786
|
+
requirements:
|
787
|
+
- - ~>
|
788
|
+
- !ruby/object:Gem::Version
|
789
|
+
version: 1.8.4
|
790
|
+
type: :development
|
791
|
+
prerelease: false
|
792
|
+
version_requirements: !ruby/object:Gem::Requirement
|
793
|
+
requirements:
|
794
|
+
- - ~>
|
795
|
+
- !ruby/object:Gem::Version
|
796
|
+
version: 1.8.4
|
797
|
+
- !ruby/object:Gem::Dependency
|
798
|
+
name: rspec
|
799
|
+
requirement: !ruby/object:Gem::Requirement
|
800
|
+
requirements:
|
801
|
+
- - ~>
|
802
|
+
- !ruby/object:Gem::Version
|
803
|
+
version: 2.6.0
|
804
|
+
type: :development
|
805
|
+
prerelease: false
|
806
|
+
version_requirements: !ruby/object:Gem::Requirement
|
807
|
+
requirements:
|
808
|
+
- - ~>
|
809
|
+
- !ruby/object:Gem::Version
|
810
|
+
version: 2.6.0
|
811
|
+
- !ruby/object:Gem::Dependency
|
812
|
+
name: shoulda
|
813
|
+
requirement: !ruby/object:Gem::Requirement
|
814
|
+
requirements:
|
815
|
+
- - '>='
|
816
|
+
- !ruby/object:Gem::Version
|
817
|
+
version: '0'
|
818
|
+
type: :development
|
819
|
+
prerelease: false
|
820
|
+
version_requirements: !ruby/object:Gem::Requirement
|
821
|
+
requirements:
|
822
|
+
- - '>='
|
823
|
+
- !ruby/object:Gem::Version
|
824
|
+
version: '0'
|
825
|
+
- !ruby/object:Gem::Dependency
|
826
|
+
name: rdoc
|
827
|
+
requirement: !ruby/object:Gem::Requirement
|
828
|
+
requirements:
|
829
|
+
- - '>='
|
830
|
+
- !ruby/object:Gem::Version
|
831
|
+
version: '0'
|
832
|
+
type: :development
|
833
|
+
prerelease: false
|
834
|
+
version_requirements: !ruby/object:Gem::Requirement
|
835
|
+
requirements:
|
836
|
+
- - '>='
|
837
|
+
- !ruby/object:Gem::Version
|
838
|
+
version: '0'
|
839
|
+
- !ruby/object:Gem::Dependency
|
840
|
+
name: bundler
|
841
|
+
requirement: !ruby/object:Gem::Requirement
|
842
|
+
requirements:
|
843
|
+
- - '>='
|
844
|
+
- !ruby/object:Gem::Version
|
845
|
+
version: '0'
|
846
|
+
type: :development
|
847
|
+
prerelease: false
|
848
|
+
version_requirements: !ruby/object:Gem::Requirement
|
849
|
+
requirements:
|
850
|
+
- - '>='
|
851
|
+
- !ruby/object:Gem::Version
|
852
|
+
version: '0'
|
853
|
+
- !ruby/object:Gem::Dependency
|
854
|
+
name: jeweler
|
855
|
+
requirement: !ruby/object:Gem::Requirement
|
856
|
+
requirements:
|
857
|
+
- - ~>
|
858
|
+
- !ruby/object:Gem::Version
|
859
|
+
version: 1.8.4
|
860
|
+
type: :development
|
861
|
+
prerelease: false
|
862
|
+
version_requirements: !ruby/object:Gem::Requirement
|
863
|
+
requirements:
|
864
|
+
- - ~>
|
865
|
+
- !ruby/object:Gem::Version
|
866
|
+
version: 1.8.4
|
727
867
|
- !ruby/object:Gem::Dependency
|
728
868
|
name: thor
|
729
869
|
requirement: !ruby/object:Gem::Requirement
|