et 0.5.5 → 0.5.6.beta
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/.ruby-version +1 -1
- data/bin/et +1 -1
- data/lib/et.rb +10 -8
- data/lib/et/api.rb +35 -23
- data/lib/et/archive_manager.rb +49 -0
- data/lib/et/lesson.rb +20 -12
- data/lib/et/operating_system.rb +37 -0
- data/lib/et/runner.rb +6 -5
- data/lib/et/version.rb +1 -1
- data/spec/lib/api_spec.rb +83 -5
- data/spec/lib/archive_manager_spec.rb +27 -0
- data/spec/lib/lesson_spec.rb +24 -0
- data/spec/lib/operating_system_spec.rb +20 -0
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2782275fe3bc5bae13bec94ba826d026cb9e7c0
|
4
|
+
data.tar.gz: 0e65bdf3385e33a0073aac29dbd10607227455e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7e91173a2eb580bd11ddfc80da3f05d7c78ce533c176722fcf5d16cd0f6dfffde7da84f1f05f96c08261bb29cc81f071fbbae54e10b036f7dd0bcbeb0e45fef
|
7
|
+
data.tar.gz: a9f8c1d3ca5ad1f8c4130f1670d5b07b84e5896b249804c9e5375af7da3966febb74a2c7717d9ad7b0971546ec2acfd896aee1d4268c7b7ab5657b4e39b93f73
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.2.
|
1
|
+
2.2.3
|
data/bin/et
CHANGED
data/lib/et.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require "tmpdir"
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
require_relative "et/version"
|
3
|
+
require_relative "et/runner"
|
4
|
+
require_relative "et/operating_system"
|
5
|
+
require_relative "et/api"
|
6
|
+
require_relative "et/config"
|
7
|
+
require_relative "et/formatter"
|
8
|
+
require_relative "et/lesson"
|
9
|
+
require_relative "et/challenge"
|
10
|
+
require_relative "et/exercise"
|
11
|
+
require_relative "et/archive_manager"
|
data/lib/et/api.rb
CHANGED
@@ -2,6 +2,7 @@ require "net/http/post/multipart"
|
|
2
2
|
require "securerandom"
|
3
3
|
require "base64"
|
4
4
|
require "json"
|
5
|
+
require "openssl"
|
5
6
|
|
6
7
|
module ET
|
7
8
|
class API
|
@@ -17,12 +18,7 @@ module ET
|
|
17
18
|
request = Net::HTTP::Get.new(lessons_url)
|
18
19
|
request["Authorization"] = auth_header
|
19
20
|
|
20
|
-
response =
|
21
|
-
Net::HTTP.start(lessons_url.host, lessons_url.port,
|
22
|
-
use_ssl: lessons_url.scheme == "https") do |http|
|
23
|
-
|
24
|
-
response = http.request(request)
|
25
|
-
end
|
21
|
+
response = issue_request(request)
|
26
22
|
JSON.parse(response.body, symbolize_names: true)[:lessons]
|
27
23
|
end
|
28
24
|
|
@@ -30,12 +26,8 @@ module ET
|
|
30
26
|
request = Net::HTTP::Get.new(lesson_url(slug))
|
31
27
|
request["Authorization"] = auth_header
|
32
28
|
|
33
|
-
response =
|
34
|
-
Net::HTTP.start(lessons_url.host, lessons_url.port,
|
35
|
-
use_ssl: lessons_url.scheme == "https") do |http|
|
29
|
+
response = issue_request(request)
|
36
30
|
|
37
|
-
response = http.request(request)
|
38
|
-
end
|
39
31
|
body = JSON.parse(response.body, symbolize_names: true)
|
40
32
|
body[:lesson]
|
41
33
|
end
|
@@ -44,17 +36,16 @@ module ET
|
|
44
36
|
uri = URI(url)
|
45
37
|
dest = random_filename
|
46
38
|
|
47
|
-
Net::HTTP.
|
48
|
-
|
49
|
-
|
50
|
-
resp = http.get(uri.path)
|
51
|
-
|
39
|
+
request = Net::HTTP::Get.new(uri.path)
|
40
|
+
response = issue_request(request, url)
|
41
|
+
if response.code == "200"
|
52
42
|
open(dest, 'wb') do |file|
|
53
|
-
file.write(
|
43
|
+
file.write(response.body)
|
54
44
|
end
|
45
|
+
dest
|
46
|
+
else
|
47
|
+
nil
|
55
48
|
end
|
56
|
-
|
57
|
-
dest
|
58
49
|
end
|
59
50
|
|
60
51
|
def submit_lesson(lesson)
|
@@ -66,16 +57,33 @@ module ET
|
|
66
57
|
"submission[archive]" => UploadIO.new(f, "application/x-tar", "archive.tar.gz"))
|
67
58
|
request["Authorization"] = auth_header
|
68
59
|
|
69
|
-
|
70
|
-
|
60
|
+
issue_request(request)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def issue_request(request, url = nil)
|
66
|
+
uri = URI.parse(url || @host)
|
67
|
+
begin
|
68
|
+
Net::HTTP.start(uri.host, uri.port,
|
69
|
+
use_ssl: uri.scheme == "https") do |http|
|
71
70
|
|
72
71
|
http.request(request)
|
73
72
|
end
|
73
|
+
rescue OpenSSL::SSL::SSLError => e
|
74
|
+
if operating_system.platform_family?(:windows)
|
75
|
+
https = Net::HTTP.new(uri.host, uri.port)
|
76
|
+
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
77
|
+
https.use_ssl = uri.scheme == 'https'
|
78
|
+
https.start do |http|
|
79
|
+
http.request(request)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
raise e
|
83
|
+
end
|
74
84
|
end
|
75
85
|
end
|
76
86
|
|
77
|
-
private
|
78
|
-
|
79
87
|
def lesson_url(slug)
|
80
88
|
URI.join(host, "lessons/#{slug}.json?submittable=1")
|
81
89
|
end
|
@@ -99,5 +107,9 @@ module ET
|
|
99
107
|
def auth_header
|
100
108
|
"Basic #{credentials}"
|
101
109
|
end
|
110
|
+
|
111
|
+
def operating_system
|
112
|
+
@os ||= ET::OperatingSystem.new
|
113
|
+
end
|
102
114
|
end
|
103
115
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "rubygems/package"
|
2
|
+
require "pry"
|
3
|
+
|
4
|
+
class ET::ArchiveManager
|
5
|
+
attr_reader :archive, :destination, :unpacked_files
|
6
|
+
|
7
|
+
def initialize(archive, destination)
|
8
|
+
@archive = archive
|
9
|
+
@destination = destination
|
10
|
+
end
|
11
|
+
|
12
|
+
def delete_archive
|
13
|
+
File.delete(archive)
|
14
|
+
end
|
15
|
+
|
16
|
+
def unpack
|
17
|
+
@unpacked_files = []
|
18
|
+
File.open(archive, "rb") do |tar_gz|
|
19
|
+
uncompress(tar_gz)
|
20
|
+
end
|
21
|
+
@unpacked_files
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def uncompress(file)
|
27
|
+
Zlib::GzipReader.open(file) do |tar|
|
28
|
+
process_tar(tar)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_tar(tar)
|
33
|
+
Gem::Package::TarReader.new(tar) do |entries|
|
34
|
+
entries.each { |entry| create_file(entry) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_file(entry)
|
39
|
+
if entry.file?
|
40
|
+
filename = File.join(destination, entry.full_name)
|
41
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
42
|
+
File.open(filename, "wb") do |f|
|
43
|
+
f.write(entry.read)
|
44
|
+
end
|
45
|
+
File.chmod(entry.header.mode, filename)
|
46
|
+
@unpacked_files << filename
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/et/lesson.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "pathname"
|
2
2
|
require "securerandom"
|
3
|
+
require "rubygems/package"
|
3
4
|
|
4
5
|
module ET
|
5
6
|
class Lesson
|
@@ -13,19 +14,26 @@ module ET
|
|
13
14
|
if exists?
|
14
15
|
filepath = random_archive_path
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
17
|
+
File.open(filepath, "wb") do |file|
|
18
|
+
Zlib::GzipWriter.wrap(file) do |gz|
|
19
|
+
Gem::Package::TarWriter.new(gz) do |tar|
|
20
|
+
Dir.glob(File.join(dir, "**/*")).each do |file|
|
21
|
+
relative_path = file.gsub(dir + "/", "")
|
22
|
+
if !ignored_files.include?(relative_path)
|
23
|
+
if FileTest.directory?(file)
|
24
|
+
tar.mkdir(relative_path, 0755)
|
25
|
+
else
|
26
|
+
file_contents = File.read(file)
|
27
|
+
tar.add_file_simple("./" + relative_path, 0555, file_contents.length) do |io|
|
28
|
+
io.write(file_contents)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
28
35
|
end
|
36
|
+
filepath
|
29
37
|
else
|
30
38
|
nil
|
31
39
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
module ET
|
4
|
+
class OperatingSystem
|
5
|
+
attr_reader :raw_name, :version
|
6
|
+
|
7
|
+
def initialize(os = nil, version = nil)
|
8
|
+
@raw_name, @version = os, version
|
9
|
+
if @raw_name.nil?
|
10
|
+
derive_raw_name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
#cribbed from Selenium
|
15
|
+
def name
|
16
|
+
case @raw_name
|
17
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
18
|
+
:windows
|
19
|
+
when /darwin|mac os/
|
20
|
+
:mac
|
21
|
+
when /linux/
|
22
|
+
:linux
|
23
|
+
when /solaris|bsd/
|
24
|
+
:unix
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def platform_family?(platform)
|
29
|
+
name == platform.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
def derive_raw_name
|
34
|
+
@raw_name = RbConfig::CONFIG['host_os']
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/et/runner.rb
CHANGED
@@ -50,13 +50,14 @@ module ET
|
|
50
50
|
cmdargs.each do |slug|
|
51
51
|
lesson = api.get_lesson(slug)
|
52
52
|
archive = api.download_file(lesson[:archive_url])
|
53
|
+
archive_manager = ET::ArchiveManager.new(archive, cwd)
|
54
|
+
archive_manager.unpack
|
53
55
|
|
54
|
-
if
|
55
|
-
|
56
|
-
|
57
|
-
puts "Extracted challenge to #{challenge_dir}"
|
56
|
+
if !archive_manager.unpacked_files.empty?
|
57
|
+
archive_manager.delete_archive
|
58
|
+
puts "'#{slug}' extracted to '#{archive_manager.destination}'"
|
58
59
|
else
|
59
|
-
raise StandardError.new("Failed to extract the
|
60
|
+
raise StandardError.new("Failed to extract the archive.")
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
data/lib/et/version.rb
CHANGED
data/spec/lib/api_spec.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
describe ET::API do
|
2
2
|
let(:api) { ET::API.new(host: "http://localhost:3000") }
|
3
|
+
let(:lessons_uri) do
|
4
|
+
URI("http://localhost:3000/lessons.json?submittable=1")
|
5
|
+
end
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
7
|
+
let(:lessons_response) do
|
8
|
+
File.read("spec/data/lessons.json")
|
9
|
+
end
|
8
10
|
|
11
|
+
describe "lessons" do
|
9
12
|
it "queries for a list of lessons" do
|
10
13
|
request = {}
|
11
14
|
response = double
|
12
15
|
http = double
|
13
|
-
lessons_uri = URI("http://localhost:3000/lessons.json?submittable=1")
|
14
16
|
expect(Net::HTTP::Get).to receive(:new).
|
15
17
|
with(lessons_uri).
|
16
18
|
and_return(request)
|
@@ -38,6 +40,7 @@ describe ET::API do
|
|
38
40
|
request = {}
|
39
41
|
response = double
|
40
42
|
http = double
|
43
|
+
|
41
44
|
lesson_uri = URI("http://localhost:3000/lessons/rock-paper-scissors.json?submittable=1")
|
42
45
|
expect(Net::HTTP::Get).to receive(:new).
|
43
46
|
with(lesson_uri).
|
@@ -56,4 +59,79 @@ describe ET::API do
|
|
56
59
|
expect(result[:archive_url]).to eq("http://example.com/rock-paper-scissors.tar.gz")
|
57
60
|
end
|
58
61
|
end
|
62
|
+
|
63
|
+
context 'ssl verification' do
|
64
|
+
it 're-raises an exception for non Windows machines' do
|
65
|
+
dbl_os = double
|
66
|
+
allow(dbl_os).to receive(:platform_family?).with(:windows).and_return(false)
|
67
|
+
expect(ET::OperatingSystem).to receive(:new).and_return(dbl_os)
|
68
|
+
|
69
|
+
expect(Net::HTTP).to receive(:start).and_raise(OpenSSL::SSL::SSLError)
|
70
|
+
expect{ api.list_lessons }.to raise_error(OpenSSL::SSL::SSLError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'swallows the exception for windows machines and reissues' do
|
74
|
+
http = double
|
75
|
+
allow(http).to receive(:start).and_yield(http)
|
76
|
+
allow(http).to receive(:verify_mode=)
|
77
|
+
allow(http).to receive(:use_ssl=)
|
78
|
+
response = double
|
79
|
+
|
80
|
+
allow(http).to receive(:request).and_return(response)
|
81
|
+
allow(response).to receive(:body).and_return(lessons_response)
|
82
|
+
|
83
|
+
allow(Net::HTTP).to receive(:start).
|
84
|
+
with(
|
85
|
+
lessons_uri.host,
|
86
|
+
lessons_uri.port,
|
87
|
+
use_ssl: lessons_uri.scheme == 'https').
|
88
|
+
and_raise(OpenSSL::SSL::SSLError)
|
89
|
+
|
90
|
+
expect(Net::HTTP).to receive(:new).with(
|
91
|
+
lessons_uri.host,
|
92
|
+
lessons_uri.port).
|
93
|
+
and_return(http)
|
94
|
+
|
95
|
+
dbl_os = double
|
96
|
+
allow(dbl_os).to receive(:platform_family?).and_return(:windows)
|
97
|
+
allow(ET::OperatingSystem).to receive(:new).and_return(dbl_os)
|
98
|
+
|
99
|
+
api.list_lessons
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'downloading files' do
|
104
|
+
it 'returns nil when a 404 is encountered' do
|
105
|
+
|
106
|
+
http = double
|
107
|
+
response = double
|
108
|
+
allow(response).to receive(:code).and_return("404")
|
109
|
+
allow(http).to receive(:request).and_return(response)
|
110
|
+
allow(Net::HTTP).to receive(:start).and_yield(http)
|
111
|
+
|
112
|
+
expect(api.download_file("http://example.com/somefile.tar.gz")).to be_nil
|
113
|
+
end
|
114
|
+
it 'returns a local file when a challenge is successfully downloaded' do
|
115
|
+
path = '/tmp/et'
|
116
|
+
filename = 'fab'
|
117
|
+
|
118
|
+
FileUtils.rm_rf(File.join(path, filename))
|
119
|
+
FileUtils.mkdir_p(path)
|
120
|
+
|
121
|
+
allow(Dir).to receive(:mktmpdir).and_return(path)
|
122
|
+
allow(SecureRandom).to receive(:hex).and_return(filename)
|
123
|
+
|
124
|
+
http = double
|
125
|
+
response = double
|
126
|
+
file_contents = File.read(File.join(File.dirname(__FILE__), "../data/some-challenge.tar.gz"))
|
127
|
+
allow(response).to receive(:body).and_return(file_contents)
|
128
|
+
allow(response).to receive(:code).and_return("200")
|
129
|
+
allow(http).to receive(:request).and_return(response)
|
130
|
+
allow(Net::HTTP).to receive(:start).and_yield(http)
|
131
|
+
|
132
|
+
url = 'http://example.com/some-challenge.tar.gz'
|
133
|
+
|
134
|
+
expect(api.download_file(url)).to eql(File.join(path, filename))
|
135
|
+
end
|
136
|
+
end
|
59
137
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
describe ET::ArchiveManager do
|
2
|
+
let!(:archive) { File.join(File.dirname(__FILE__), "..", "data", "some-challenge.tar.gz") }
|
3
|
+
let!(:destination) { Dir.mktmpdir }
|
4
|
+
let!(:lesson_extractor) { ET::ArchiveManager.new(archive, destination) }
|
5
|
+
|
6
|
+
describe "#new" do
|
7
|
+
it "takes an archive and destination" do
|
8
|
+
expect(lesson_extractor).to be_a(ET::ArchiveManager)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#unpack" do
|
13
|
+
it "extracts files from the archive" do
|
14
|
+
lesson_extractor.unpack
|
15
|
+
extracted_files = Dir.entries(File.join(destination, "some-challenge"))
|
16
|
+
expect(extracted_files).to include("README.md")
|
17
|
+
expect(extracted_files).to include("sample.rb")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns an array of extracted filenames" do
|
21
|
+
result = lesson_extractor.unpack
|
22
|
+
expect(result).to be_an(Array)
|
23
|
+
expect(result.size).to eq(2)
|
24
|
+
expect(result.first).to match /sample.rb/
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ET::Lesson do
|
4
|
+
context "archive! method" do
|
5
|
+
it "creates a tar.gz file" do
|
6
|
+
path = '/tmp/et'
|
7
|
+
filename = 'fab'
|
8
|
+
|
9
|
+
FileUtils.rm_rf(File.join(path, filename))
|
10
|
+
FileUtils.mkdir_p(path)
|
11
|
+
|
12
|
+
allow(Dir).to receive(:mktmpdir).and_return(path)
|
13
|
+
allow(SecureRandom).to receive(:hex).and_return(filename)
|
14
|
+
|
15
|
+
exercise_path = File.expand_path(
|
16
|
+
File.join(File.dirname(__FILE__), '../data/sample-exercise'))
|
17
|
+
lesson = ET::Lesson.new(exercise_path)
|
18
|
+
resulting_file = lesson.archive!
|
19
|
+
|
20
|
+
expect(resulting_file).to_not be_nil
|
21
|
+
expect(FileTest).to exist(resulting_file)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
describe ET::OperatingSystem do
|
2
|
+
context '10.10' do
|
3
|
+
let(:minor) { '10.10' }
|
4
|
+
let(:os) { ET::OperatingSystem.new('darwin', minor) }
|
5
|
+
|
6
|
+
it 'has a name' do
|
7
|
+
expect(os.name).to eq(:mac)
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
context '10.9' do
|
13
|
+
let(:minor) { '10.9' }
|
14
|
+
let(:os) { ET::OperatingSystem.new('darwin', minor + '.4') }
|
15
|
+
|
16
|
+
it 'has a minor version' do
|
17
|
+
expect(os.name).to eq(:mac)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: et
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.6.beta
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Sheehan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -116,11 +116,13 @@ files:
|
|
116
116
|
- et.gemspec
|
117
117
|
- lib/et.rb
|
118
118
|
- lib/et/api.rb
|
119
|
+
- lib/et/archive_manager.rb
|
119
120
|
- lib/et/challenge.rb
|
120
121
|
- lib/et/config.rb
|
121
122
|
- lib/et/exercise.rb
|
122
123
|
- lib/et/formatter.rb
|
123
124
|
- lib/et/lesson.rb
|
125
|
+
- lib/et/operating_system.rb
|
124
126
|
- lib/et/runner.rb
|
125
127
|
- lib/et/version.rb
|
126
128
|
- spec/cli/get_lesson_spec.rb
|
@@ -139,9 +141,12 @@ files:
|
|
139
141
|
- spec/data/sample-exercise/test/sample_exercise_test.rb
|
140
142
|
- spec/data/some-challenge.tar.gz
|
141
143
|
- spec/lib/api_spec.rb
|
144
|
+
- spec/lib/archive_manager_spec.rb
|
142
145
|
- spec/lib/challenge_spec.rb
|
143
146
|
- spec/lib/config_spec.rb
|
144
147
|
- spec/lib/exercise_spec.rb
|
148
|
+
- spec/lib/lesson_spec.rb
|
149
|
+
- spec/lib/operating_system_spec.rb
|
145
150
|
- spec/spec_helper.rb
|
146
151
|
- spec/support/helpers/archive_helper.rb
|
147
152
|
- spec/support/helpers/output_catcher.rb
|
@@ -163,12 +168,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
163
168
|
version: '0'
|
164
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
170
|
requirements:
|
166
|
-
- - "
|
171
|
+
- - ">"
|
167
172
|
- !ruby/object:Gem::Version
|
168
|
-
version:
|
173
|
+
version: 1.3.1
|
169
174
|
requirements: []
|
170
175
|
rubyforge_project:
|
171
|
-
rubygems_version: 2.
|
176
|
+
rubygems_version: 2.4.5.1
|
172
177
|
signing_key:
|
173
178
|
specification_version: 4
|
174
179
|
summary: Command-line interface for the event horizon.
|