em_apn_manager 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|