et 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/Gemfile.lock +3 -3
- data/lib/et.rb +2 -0
- data/lib/et/api.rb +10 -10
- data/lib/et/challenge.rb +2 -67
- data/lib/et/config.rb +7 -3
- data/lib/et/exercise.rb +15 -0
- data/lib/et/lesson.rb +72 -0
- data/lib/et/runner.rb +27 -22
- data/lib/et/version.rb +1 -1
- data/spec/cli/{get_challenge_spec.rb → get_lesson_spec.rb} +6 -6
- data/spec/cli/list_lessons_spec.rb +29 -0
- data/spec/cli/run_exercise_test_suite_spec.rb +31 -0
- data/spec/cli/submit_lesson_spec.rb +37 -0
- data/spec/data/challenge.json +8 -1
- data/spec/data/lessons.json +19 -0
- data/spec/data/sample-challenge/.lesson.yml +6 -0
- data/spec/data/sample-challenge/problem.rb +1 -0
- data/spec/data/sample-challenge/sample-challenge.md +3 -0
- data/spec/data/sample-exercise/.lesson.yml +6 -0
- data/spec/data/sample-exercise/lib/sample_exercise.rb +1 -0
- data/spec/data/sample-exercise/sample-exercise.md +3 -0
- data/spec/data/sample-exercise/test/sample_exercise_test.rb +7 -0
- data/spec/lib/api_spec.rb +15 -14
- data/spec/lib/challenge_spec.rb +20 -32
- data/spec/lib/config_spec.rb +48 -1
- data/spec/lib/exercise_spec.rb +28 -0
- data/spec/support/helpers/sample_files.rb +11 -13
- metadata +17 -6
- data/spec/cli/list_challenges_spec.rb +0 -25
- data/spec/cli/submit_challenge_spec.rb +0 -22
- data/spec/data/challenges.json +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44921ec7a8dc12f41fa49bac47557a76f75de660
|
4
|
+
data.tar.gz: 074a87d6f612a8ac878f8608222f2a69b0eb6b34
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5a6d4ac016be8a94adb73d46880ff5da19266734d6d41b814312d638d5a84ce3d832d3f114da3212b7e509bfbc181d7ec123edb7c5da7936addfc0257bf4ce4
|
7
|
+
data.tar.gz: 13b8218ceccd48c032c2ab8b158fa597b4505de41309c87b28796a0faafc6b80733cec84aad3d08467b6adacaedd5222f5860e6b9a3f8fec2dfa27b27a1aebda
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.3
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
et (0.
|
4
|
+
et (0.5.0)
|
5
5
|
gli (= 2.11.0)
|
6
6
|
rest-client (~> 1.7)
|
7
7
|
|
@@ -10,8 +10,8 @@ GEM
|
|
10
10
|
specs:
|
11
11
|
diff-lcs (1.2.5)
|
12
12
|
gli (2.11.0)
|
13
|
-
mime-types (2.3)
|
14
|
-
netrc (0.
|
13
|
+
mime-types (2.4.3)
|
14
|
+
netrc (0.8.0)
|
15
15
|
rake (10.3.2)
|
16
16
|
rest-client (1.7.2)
|
17
17
|
mime-types (>= 1.16, < 3.0)
|
data/lib/et.rb
CHANGED
data/lib/et/api.rb
CHANGED
@@ -13,13 +13,13 @@ module ET
|
|
13
13
|
@token = options[:token]
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
response = RestClient.get(
|
16
|
+
def list_lessons
|
17
|
+
response = RestClient.get(lessons_url)
|
18
18
|
JSON.parse(response, symbolize_names: true)[:lessons]
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
response = RestClient.get(
|
21
|
+
def get_lesson(slug)
|
22
|
+
response = RestClient.get(lesson_url(slug))
|
23
23
|
body = JSON.parse(response, symbolize_names: true)
|
24
24
|
body[:lesson]
|
25
25
|
end
|
@@ -41,21 +41,21 @@ module ET
|
|
41
41
|
dest
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
45
|
-
submission_file =
|
46
|
-
RestClient.post(submission_url(
|
44
|
+
def submit_lesson(lesson)
|
45
|
+
submission_file = lesson.archive!
|
46
|
+
RestClient.post(submission_url(lesson.slug),
|
47
47
|
{ submission: { archive: File.new(submission_file) }},
|
48
48
|
{ "Authorization" => auth_header })
|
49
49
|
end
|
50
50
|
|
51
51
|
private
|
52
52
|
|
53
|
-
def
|
53
|
+
def lesson_url(slug)
|
54
54
|
URI.join(host, "lessons/#{slug}.json").to_s
|
55
55
|
end
|
56
56
|
|
57
|
-
def
|
58
|
-
URI.join(host, "lessons.json?
|
57
|
+
def lessons_url
|
58
|
+
URI.join(host, "lessons.json?submittable=1").to_s
|
59
59
|
end
|
60
60
|
|
61
61
|
def submission_url(slug)
|
data/lib/et/challenge.rb
CHANGED
@@ -1,72 +1,7 @@
|
|
1
|
-
require "pathname"
|
2
|
-
require "securerandom"
|
3
|
-
|
4
1
|
module ET
|
5
|
-
class Challenge
|
6
|
-
attr_reader :cwd
|
7
|
-
|
8
|
-
def initialize(cwd)
|
9
|
-
@cwd = cwd
|
10
|
-
end
|
11
|
-
|
12
|
-
def archive!
|
13
|
-
if exists?
|
14
|
-
filepath = random_archive_path
|
15
|
-
|
16
|
-
cmd = "tar zcf #{filepath} -C #{dir}"
|
17
|
-
|
18
|
-
ignored_files.each do |file|
|
19
|
-
cmd += " --exclude='#{file}'"
|
20
|
-
end
|
21
|
-
|
22
|
-
cmd += " ."
|
23
|
-
|
24
|
-
if system(cmd)
|
25
|
-
filepath
|
26
|
-
else
|
27
|
-
nil
|
28
|
-
end
|
29
|
-
else
|
30
|
-
nil
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def dir
|
35
|
-
@dir ||= find_challenge_dir(cwd)
|
36
|
-
end
|
37
|
-
|
38
|
-
def slug
|
39
|
-
File.basename(dir)
|
40
|
-
end
|
41
|
-
|
2
|
+
class Challenge < Lesson
|
42
3
|
def exists?
|
43
|
-
!dir.nil?
|
44
|
-
end
|
45
|
-
|
46
|
-
def ignored_files
|
47
|
-
(config["ignore"] || []) + [".lesson.yml"]
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def config
|
53
|
-
@config ||= YAML.load(File.read(File.join(dir, ".lesson.yml")))
|
54
|
-
end
|
55
|
-
|
56
|
-
def random_archive_path
|
57
|
-
File.join(Dir.mktmpdir, "#{SecureRandom.hex}.tar.gz")
|
58
|
-
end
|
59
|
-
|
60
|
-
def find_challenge_dir(current_dir)
|
61
|
-
path = File.join(current_dir, ".lesson.yml")
|
62
|
-
|
63
|
-
if File.exists?(path)
|
64
|
-
current_dir
|
65
|
-
elsif current_dir == "." || Pathname.new(current_dir).root?
|
66
|
-
nil
|
67
|
-
else
|
68
|
-
find_challenge_dir(File.dirname(current_dir))
|
69
|
-
end
|
4
|
+
!dir.nil? && config["type"] == "challenge"
|
70
5
|
end
|
71
6
|
end
|
72
7
|
end
|
data/lib/et/config.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "yaml"
|
1
2
|
require "pathname"
|
2
3
|
|
3
4
|
module ET
|
@@ -36,9 +37,12 @@ module ET
|
|
36
37
|
options[key]
|
37
38
|
end
|
38
39
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
40
|
+
def save!(options)
|
41
|
+
if exists?
|
42
|
+
File.write(path, options.to_yaml)
|
43
|
+
else
|
44
|
+
File.write(File.join(current_dir, ".et"), options.to_yaml)
|
45
|
+
end
|
42
46
|
end
|
43
47
|
|
44
48
|
private
|
data/lib/et/exercise.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module ET
|
2
|
+
class Exercise < Lesson
|
3
|
+
def run_tests
|
4
|
+
system("rspec", "--color", "--fail-fast", spec_file)
|
5
|
+
end
|
6
|
+
|
7
|
+
def exists?
|
8
|
+
!dir.nil? && config["type"] == "exercise"
|
9
|
+
end
|
10
|
+
|
11
|
+
def spec_file
|
12
|
+
File.join(dir, "test", "#{slug.gsub("-", "_")}_test.rb")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/et/lesson.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "securerandom"
|
3
|
+
|
4
|
+
module ET
|
5
|
+
class Lesson
|
6
|
+
attr_reader :cwd
|
7
|
+
|
8
|
+
def initialize(cwd)
|
9
|
+
@cwd = cwd
|
10
|
+
end
|
11
|
+
|
12
|
+
def archive!
|
13
|
+
if exists?
|
14
|
+
filepath = random_archive_path
|
15
|
+
|
16
|
+
cmd = "tar zcf #{filepath} -C #{dir}"
|
17
|
+
|
18
|
+
ignored_files.each do |file|
|
19
|
+
cmd += " --exclude='#{file}'"
|
20
|
+
end
|
21
|
+
|
22
|
+
cmd += " ."
|
23
|
+
|
24
|
+
if system(cmd)
|
25
|
+
filepath
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def dir
|
35
|
+
@dir ||= find_lesson_dir(cwd)
|
36
|
+
end
|
37
|
+
|
38
|
+
def slug
|
39
|
+
File.basename(dir)
|
40
|
+
end
|
41
|
+
|
42
|
+
def exists?
|
43
|
+
!dir.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
def ignored_files
|
47
|
+
(config["ignore"] || []) + [".lesson.yml"]
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def config
|
53
|
+
@config ||= YAML.load_file(File.join(dir, ".lesson.yml"))
|
54
|
+
end
|
55
|
+
|
56
|
+
def random_archive_path
|
57
|
+
File.join(Dir.mktmpdir, "#{SecureRandom.hex}.tar.gz")
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_lesson_dir(current_dir)
|
61
|
+
path = File.join(current_dir, ".lesson.yml")
|
62
|
+
|
63
|
+
if File.exists?(path)
|
64
|
+
current_dir
|
65
|
+
elsif current_dir == "." || Pathname.new(current_dir).root?
|
66
|
+
nil
|
67
|
+
else
|
68
|
+
find_lesson_dir(File.dirname(current_dir))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/et/runner.rb
CHANGED
@@ -16,12 +16,12 @@ module ET
|
|
16
16
|
|
17
17
|
pre { |_, _, _, _| check_config! }
|
18
18
|
|
19
|
-
desc "Initialize current directory as
|
19
|
+
desc "Initialize current directory as a work area."
|
20
20
|
skips_pre
|
21
21
|
command :init do |c|
|
22
22
|
c.flag [:u, :user], desc: "Username"
|
23
23
|
c.flag [:t, :token], desc: "Login token"
|
24
|
-
c.flag [:h, :host], desc: "Server hosting the
|
24
|
+
c.flag [:h, :host], desc: "Server hosting the lessons"
|
25
25
|
|
26
26
|
c.action do |_global_options, options, _cmdargs|
|
27
27
|
settings = {
|
@@ -31,25 +31,25 @@ module ET
|
|
31
31
|
}
|
32
32
|
|
33
33
|
settings = prompt_for_missing(settings)
|
34
|
-
|
34
|
+
config.save!(settings)
|
35
35
|
|
36
36
|
puts "Saved configuration to #{config.path}"
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
desc "List available
|
40
|
+
desc "List available lessons."
|
41
41
|
command :list do |c|
|
42
42
|
c.action do |_global_options, _options, _cmdargs|
|
43
|
-
Formatter.print_table(api.
|
43
|
+
Formatter.print_table(api.list_lessons, :slug, :title, :type)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
desc "Download
|
47
|
+
desc "Download lesson to your working area."
|
48
48
|
command :get do |c|
|
49
49
|
c.action do |_global_options, _options, cmdargs|
|
50
50
|
cmdargs.each do |slug|
|
51
|
-
|
52
|
-
archive = api.download_file(
|
51
|
+
lesson = api.get_lesson(slug)
|
52
|
+
archive = api.download_file(lesson[:archive_url])
|
53
53
|
|
54
54
|
if system("tar zxf #{archive} -C #{cwd}")
|
55
55
|
system("rm #{archive}")
|
@@ -62,16 +62,29 @@ module ET
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
desc "Submit the
|
65
|
+
desc "Submit the lesson in this directory."
|
66
66
|
command :submit do |c|
|
67
67
|
c.action do |_global_options, _options, _cmdargs|
|
68
|
-
|
68
|
+
lesson = Lesson.new(cwd)
|
69
69
|
|
70
|
-
if
|
71
|
-
api.
|
72
|
-
puts "
|
70
|
+
if lesson.exists?
|
71
|
+
api.submit_lesson(lesson)
|
72
|
+
puts "Lesson submitted"
|
73
73
|
else
|
74
|
-
raise StandardError.new("Not in a
|
74
|
+
raise StandardError.new("Not in a lesson directory.")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Run an exercise test suite."
|
80
|
+
command :test do |c|
|
81
|
+
c.action do |_global_options, _options, _cmdargs|
|
82
|
+
exercise = Exercise.new(cwd)
|
83
|
+
|
84
|
+
if exercise.exists?
|
85
|
+
exercise.run_tests
|
86
|
+
else
|
87
|
+
raise StandardError.new("Not in an exercise directory.")
|
75
88
|
end
|
76
89
|
end
|
77
90
|
end
|
@@ -137,13 +150,5 @@ module ET
|
|
137
150
|
"Run `et init` to create one.")
|
138
151
|
end
|
139
152
|
end
|
140
|
-
|
141
|
-
def save_config(settings)
|
142
|
-
if config.exists?
|
143
|
-
config.update(settings)
|
144
|
-
else
|
145
|
-
File.write(File.join(cwd, ".et"), settings.to_yaml)
|
146
|
-
end
|
147
|
-
end
|
148
153
|
end
|
149
154
|
end
|
data/lib/et/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
describe "get
|
2
|
-
let(:
|
1
|
+
describe "get lesson" do
|
2
|
+
let(:lesson_info) do
|
3
3
|
{
|
4
4
|
title: "Some Challenge",
|
5
5
|
slug: "some-challenge",
|
@@ -12,13 +12,13 @@ describe "get challenge" do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
context "when in a working area" do
|
15
|
-
it "downloads and extracts the
|
15
|
+
it "downloads and extracts the lesson" do
|
16
16
|
tmp_archive_path = File.join(Dir.tmpdir, "some-challenge.tar.gz")
|
17
|
-
system("cp
|
17
|
+
system("cp", sample_archive_path.to_s, tmp_archive_path)
|
18
18
|
|
19
|
-
expect_any_instance_of(ET::API).to receive(:
|
19
|
+
expect_any_instance_of(ET::API).to receive(:get_lesson).
|
20
20
|
with("some-challenge").
|
21
|
-
and_return(
|
21
|
+
and_return(lesson_info)
|
22
22
|
|
23
23
|
expect_any_instance_of(ET::API).to receive(:download_file).
|
24
24
|
with("http://localhost:3000/some-challenge.tar.gz").
|
@@ -0,0 +1,29 @@
|
|
1
|
+
describe "list lessons" do
|
2
|
+
let(:sample_lessons_file) { project_root.join("spec/data/lessons.json") }
|
3
|
+
|
4
|
+
let(:sample_lessons) do
|
5
|
+
JSON.parse(File.read(sample_lessons_file), symbolize_names: true)[:lessons]
|
6
|
+
end
|
7
|
+
|
8
|
+
it "prints the titles and slug" do
|
9
|
+
expect_any_instance_of(ET::API).to receive(:list_lessons).
|
10
|
+
and_return(sample_lessons)
|
11
|
+
|
12
|
+
Dir.mktmpdir("test") do |tmpdir|
|
13
|
+
write_sample_config_to(tmpdir)
|
14
|
+
|
15
|
+
runner = ET::Runner.new(tmpdir)
|
16
|
+
stdout, _ = capture_output do
|
17
|
+
expect(runner.go(["list"])).to eq(0)
|
18
|
+
end
|
19
|
+
|
20
|
+
expect(stdout).to include("Max Number")
|
21
|
+
expect(stdout).to include("max-number")
|
22
|
+
expect(stdout).to include("exercise")
|
23
|
+
|
24
|
+
expect(stdout).to include("Optimal Guesser")
|
25
|
+
expect(stdout).to include("optimal-guesser")
|
26
|
+
expect(stdout).to include("challenge")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
describe "run exercise test suite" do
|
2
|
+
context "when in an exercise directory" do
|
3
|
+
it "runs the test suite" do
|
4
|
+
Dir.mktmpdir("test") do |tmpdir|
|
5
|
+
write_sample_config_to(tmpdir)
|
6
|
+
exercise_dir = add_sample_exercise(tmpdir)
|
7
|
+
|
8
|
+
expect_any_instance_of(ET::Exercise).to receive(:run_tests).and_return(true)
|
9
|
+
|
10
|
+
runner = ET::Runner.new(exercise_dir)
|
11
|
+
_, _ = capture_output do
|
12
|
+
expect(runner.go(["test"])).to eq(0)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when not in an exercise directory" do
|
19
|
+
it "fails to run the test suite" do
|
20
|
+
Dir.mktmpdir("test") do |tmpdir|
|
21
|
+
write_sample_config_to(tmpdir)
|
22
|
+
expect_any_instance_of(ET::Exercise).to_not receive(:run_tests)
|
23
|
+
|
24
|
+
runner = ET::Runner.new(tmpdir)
|
25
|
+
_, _ = capture_output do
|
26
|
+
expect(runner.go(["test"])).to eq(1)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
describe "submit lesson" do
|
2
|
+
let(:sample_archive_path) do
|
3
|
+
project_root.join("spec/data/archive.tar.gz")
|
4
|
+
end
|
5
|
+
|
6
|
+
context "when in a working area" do
|
7
|
+
it "packages and uploads a challenge directory" do
|
8
|
+
Dir.mktmpdir("test") do |tmpdir|
|
9
|
+
write_sample_config_to(tmpdir)
|
10
|
+
challenge_dir = add_sample_challenge(tmpdir)
|
11
|
+
|
12
|
+
expect_any_instance_of(ET::API).to receive(:submit_lesson).
|
13
|
+
and_return(true)
|
14
|
+
|
15
|
+
runner = ET::Runner.new(challenge_dir)
|
16
|
+
_, _ = capture_output do
|
17
|
+
expect(runner.go(["submit"])).to eq(0)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "packages and uploads an exercise directory" do
|
23
|
+
Dir.mktmpdir("test") do |tmpdir|
|
24
|
+
write_sample_config_to(tmpdir)
|
25
|
+
exercise_dir = add_sample_exercise(tmpdir)
|
26
|
+
|
27
|
+
expect_any_instance_of(ET::API).to receive(:submit_lesson).
|
28
|
+
and_return(true)
|
29
|
+
|
30
|
+
runner = ET::Runner.new(exercise_dir)
|
31
|
+
_, _ = capture_output do
|
32
|
+
expect(runner.go(["submit"])).to eq(0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/data/challenge.json
CHANGED
@@ -1 +1,8 @@
|
|
1
|
-
{
|
1
|
+
{
|
2
|
+
"lesson": {
|
3
|
+
"archive_url": "http://example.com/rock-paper-scissors.tar.gz",
|
4
|
+
"body": "body goes here...",
|
5
|
+
"slug": "rock-paper-scissors",
|
6
|
+
"title": "Rock, Paper, Scissors"
|
7
|
+
}
|
8
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"lessons": [
|
3
|
+
{
|
4
|
+
"slug": "max-number",
|
5
|
+
"title": "Max Number",
|
6
|
+
"type": "exercise"
|
7
|
+
},
|
8
|
+
{
|
9
|
+
"slug": "guess-the-number",
|
10
|
+
"title": "Guess the Number",
|
11
|
+
"type": "challenge"
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"slug": "optimal-guesser",
|
15
|
+
"title": "Optimal Guesser",
|
16
|
+
"type": "challenge"
|
17
|
+
}
|
18
|
+
]
|
19
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
# YOUR CODE GOES HERE
|
@@ -0,0 +1 @@
|
|
1
|
+
puts "hi"
|
data/spec/lib/api_spec.rb
CHANGED
@@ -1,33 +1,34 @@
|
|
1
1
|
describe ET::API do
|
2
2
|
let(:api) { ET::API.new(host: "http://localhost:3000") }
|
3
3
|
|
4
|
-
describe "
|
5
|
-
let(:
|
6
|
-
File.read("spec/data/
|
4
|
+
describe "lessons" do
|
5
|
+
let(:lessons_response) do
|
6
|
+
File.read("spec/data/lessons.json")
|
7
7
|
end
|
8
8
|
|
9
|
-
it "queries for a list of
|
9
|
+
it "queries for a list of lessons" do
|
10
10
|
expect(RestClient).to receive(:get).
|
11
|
-
with("http://localhost:3000/lessons.json?
|
12
|
-
and_return(
|
11
|
+
with("http://localhost:3000/lessons.json?submittable=1").
|
12
|
+
and_return(lessons_response)
|
13
13
|
|
14
|
-
results = api.
|
14
|
+
results = api.list_lessons
|
15
15
|
|
16
|
-
expect(results.count).to eq(
|
17
|
-
expect(results[0][:title]).to eq("
|
18
|
-
expect(results[0][:slug]).to eq("
|
16
|
+
expect(results.count).to eq(3)
|
17
|
+
expect(results[0][:title]).to eq("Max Number")
|
18
|
+
expect(results[0][:slug]).to eq("max-number")
|
19
|
+
expect(results[0][:type]).to eq("exercise")
|
19
20
|
end
|
20
21
|
|
21
|
-
let(:
|
22
|
+
let(:lesson_response) do
|
22
23
|
File.read("spec/data/challenge.json")
|
23
24
|
end
|
24
25
|
|
25
|
-
it "queries for a single
|
26
|
+
it "queries for a single lesson" do
|
26
27
|
expect(RestClient).to receive(:get).
|
27
28
|
with("http://localhost:3000/lessons/rock-paper-scissors.json").
|
28
|
-
and_return(
|
29
|
+
and_return(lesson_response)
|
29
30
|
|
30
|
-
result = api.
|
31
|
+
result = api.get_lesson("rock-paper-scissors")
|
31
32
|
|
32
33
|
expect(result[:title]).to eq("Rock, Paper, Scissors")
|
33
34
|
expect(result[:archive_url]).to eq("http://example.com/rock-paper-scissors.tar.gz")
|
data/spec/lib/challenge_spec.rb
CHANGED
@@ -1,18 +1,10 @@
|
|
1
1
|
require "yaml"
|
2
2
|
|
3
3
|
describe ET::Challenge do
|
4
|
-
let(:challenge_info) do
|
5
|
-
{
|
6
|
-
"title" => "Guess the Number",
|
7
|
-
"ignore" => ["README.md"]
|
8
|
-
}
|
9
|
-
end
|
10
|
-
|
11
4
|
describe "#dir" do
|
12
5
|
it "selects the directory containing the challenge file" do
|
13
|
-
Dir.mktmpdir do |
|
14
|
-
|
15
|
-
File.write(challenge_path, challenge_info.to_yaml)
|
6
|
+
Dir.mktmpdir do |tmpdir|
|
7
|
+
challenge_dir = add_sample_challenge(tmpdir)
|
16
8
|
|
17
9
|
challenge = ET::Challenge.new(challenge_dir)
|
18
10
|
expect(challenge.dir).to eq(challenge_dir)
|
@@ -20,20 +12,22 @@ describe ET::Challenge do
|
|
20
12
|
end
|
21
13
|
|
22
14
|
it "checks parent directories for the challenge file" do
|
23
|
-
Dir.mktmpdir do |
|
24
|
-
|
25
|
-
File.write(challenge_path, challenge_info.to_yaml)
|
15
|
+
Dir.mktmpdir do |tmpdir|
|
16
|
+
challenge_dir = add_sample_challenge(tmpdir)
|
26
17
|
|
27
|
-
child_dir = File.join(
|
18
|
+
child_dir = File.join(challenge_dir, "child")
|
19
|
+
Dir.mkdir(child_dir)
|
28
20
|
|
29
21
|
challenge = ET::Challenge.new(child_dir)
|
30
|
-
expect(challenge.dir).to eq(
|
22
|
+
expect(challenge.dir).to eq(challenge_dir)
|
31
23
|
end
|
32
24
|
end
|
33
25
|
|
34
26
|
it "returns nil if no challenge file found" do
|
35
|
-
|
36
|
-
|
27
|
+
Dir.mktmpdir do |tmpdir|
|
28
|
+
challenge = ET::Challenge.new(tmpdir)
|
29
|
+
expect(challenge.dir).to eq(nil)
|
30
|
+
end
|
37
31
|
end
|
38
32
|
end
|
39
33
|
|
@@ -42,18 +36,14 @@ describe ET::Challenge do
|
|
42
36
|
archive_path = nil
|
43
37
|
|
44
38
|
begin
|
45
|
-
Dir.mktmpdir do |
|
46
|
-
|
47
|
-
File.write(challenge_path, challenge_info.to_yaml)
|
48
|
-
|
49
|
-
file_path = File.join(challenge_dir, "file.rb")
|
50
|
-
File.write(file_path, "2 + 2 == 5")
|
39
|
+
Dir.mktmpdir do |tmpdir|
|
40
|
+
challenge_dir = add_sample_challenge(tmpdir)
|
51
41
|
|
52
42
|
challenge = ET::Challenge.new(challenge_dir)
|
53
43
|
archive_path = challenge.archive!
|
54
44
|
|
55
|
-
contents = read_file_from_gzipped_archive(archive_path, "./
|
56
|
-
expect(contents).to eq("
|
45
|
+
contents = read_file_from_gzipped_archive(archive_path, "./problem.rb")
|
46
|
+
expect(contents).to eq("# YOUR CODE GOES HERE\n")
|
57
47
|
end
|
58
48
|
ensure
|
59
49
|
if archive_path && File.exist?(archive_path)
|
@@ -66,18 +56,16 @@ describe ET::Challenge do
|
|
66
56
|
archive_path = nil
|
67
57
|
|
68
58
|
begin
|
69
|
-
Dir.mktmpdir do |
|
70
|
-
|
71
|
-
File.write(File.join(dir, "file.rb"), "2 + 2 == 5")
|
72
|
-
File.write(File.join(dir, "README.md"), "Ignore me!")
|
59
|
+
Dir.mktmpdir do |tmpdir|
|
60
|
+
challenge_dir = add_sample_challenge(tmpdir)
|
73
61
|
|
74
|
-
challenge = ET::Challenge.new(
|
62
|
+
challenge = ET::Challenge.new(challenge_dir)
|
75
63
|
archive_path = challenge.archive!
|
76
64
|
|
77
65
|
files = list_files_in_gzipped_archive(archive_path)
|
78
66
|
|
79
|
-
expect(files).to include("./
|
80
|
-
expect(files).to_not include("./
|
67
|
+
expect(files).to include("./problem.rb")
|
68
|
+
expect(files).to_not include("./sample-challenge.md")
|
81
69
|
expect(files).to_not include("./.lesson.yml")
|
82
70
|
end
|
83
71
|
ensure
|
data/spec/lib/config_spec.rb
CHANGED
@@ -1,4 +1,51 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
1
3
|
describe ET::Config do
|
4
|
+
describe "#save" do
|
5
|
+
let(:options) do
|
6
|
+
{
|
7
|
+
"username" => "foobar",
|
8
|
+
"token" => "supersecret",
|
9
|
+
"host" => "http://example.com"
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
it "writes a new config file if doesn't exist" do
|
14
|
+
Dir.mktmpdir("test") do |tmpdir|
|
15
|
+
config = ET::Config.new(tmpdir)
|
16
|
+
config.save!(options)
|
17
|
+
|
18
|
+
config_file = File.join(tmpdir, ".et")
|
19
|
+
expect(File.exists?(config_file)).to eq(true)
|
20
|
+
|
21
|
+
saved_options = YAML.load_file(config_file)
|
22
|
+
|
23
|
+
options.each do |key, value|
|
24
|
+
expect(saved_options[key]).to eq(value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "updates an existing config file with new options" do
|
30
|
+
Dir.mktmpdir("test") do |parent_dir|
|
31
|
+
nested_dir = File.join(parent_dir, "nested")
|
32
|
+
Dir.mkdir(nested_dir)
|
33
|
+
|
34
|
+
write_sample_config_to(parent_dir)
|
35
|
+
|
36
|
+
config = ET::Config.new(nested_dir)
|
37
|
+
config.save!(options)
|
38
|
+
|
39
|
+
expect(File.exists?(File.join(nested_dir, ".et"))).to eq(false)
|
40
|
+
|
41
|
+
saved_options = YAML.load_file(File.join(parent_dir, ".et"))
|
42
|
+
options.each do |key, value|
|
43
|
+
expect(saved_options[key]).to eq(value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
2
49
|
describe "#path" do
|
3
50
|
it "finds the config file in the given directory" do
|
4
51
|
Dir.mktmpdir("test") do |tmpdir|
|
@@ -37,7 +84,7 @@ describe ET::Config do
|
|
37
84
|
end
|
38
85
|
end
|
39
86
|
|
40
|
-
it "
|
87
|
+
it "prepends http if scheme not provided" do
|
41
88
|
Dir.mktmpdir("test") do |tmpdir|
|
42
89
|
write_sample_config_to(tmpdir, "host" => "example.com")
|
43
90
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
describe ET::Exercise do
|
2
|
+
describe "#exists?" do
|
3
|
+
it "is true if within an exercise directory" do
|
4
|
+
Dir.mktmpdir do |tmpdir|
|
5
|
+
exercise_dir = add_sample_exercise(tmpdir)
|
6
|
+
exercise = ET::Exercise.new(exercise_dir)
|
7
|
+
|
8
|
+
expect(exercise.exists?).to eq(true)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "is false when in a challenge directory" do
|
13
|
+
Dir.mktmpdir do |tmpdir|
|
14
|
+
challenge_dir = add_sample_challenge(tmpdir)
|
15
|
+
exercise = ET::Exercise.new(challenge_dir)
|
16
|
+
|
17
|
+
expect(exercise.exists?).to eq(false)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "is false when not in a lesson dir" do
|
22
|
+
Dir.mktmpdir do |tmpdir|
|
23
|
+
exercise = ET::Exercise.new(tmpdir)
|
24
|
+
expect(exercise.exists?).to eq(false)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -2,29 +2,27 @@ require "yaml"
|
|
2
2
|
|
3
3
|
module SampleFiles
|
4
4
|
def write_sample_config_to(dir, additional_settings = nil)
|
5
|
-
|
5
|
+
settings = {
|
6
6
|
"username" => "bob",
|
7
7
|
"token" => "1234",
|
8
8
|
"host" => "http://localhost:3000"
|
9
9
|
}
|
10
10
|
|
11
11
|
if additional_settings
|
12
|
-
|
12
|
+
settings = settings.merge(additional_settings)
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
config = ET::Config.new(dir)
|
16
|
+
config.save!(settings)
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
system("mkdir #{dir}")
|
24
|
-
|
25
|
-
File.write(File.join(dir, "README.md"), "# README")
|
26
|
-
File.write(File.join(dir, ".lesson.yml"), options.to_yaml)
|
19
|
+
def add_sample_exercise(dir)
|
20
|
+
system("cp", "-r", project_root.join("spec/data/sample-exercise").to_s, dir)
|
21
|
+
File.join(dir, "sample-exercise")
|
22
|
+
end
|
27
23
|
|
28
|
-
|
24
|
+
def add_sample_challenge(dir)
|
25
|
+
system("cp", "-r", project_root.join("spec/data/sample-challenge").to_s, dir)
|
26
|
+
File.join(dir, "sample-challenge")
|
29
27
|
end
|
30
28
|
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.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Sheehan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -104,19 +104,30 @@ files:
|
|
104
104
|
- lib/et/api.rb
|
105
105
|
- lib/et/challenge.rb
|
106
106
|
- lib/et/config.rb
|
107
|
+
- lib/et/exercise.rb
|
107
108
|
- lib/et/formatter.rb
|
109
|
+
- lib/et/lesson.rb
|
108
110
|
- lib/et/runner.rb
|
109
111
|
- lib/et/version.rb
|
110
|
-
- spec/cli/
|
112
|
+
- spec/cli/get_lesson_spec.rb
|
111
113
|
- spec/cli/init_spec.rb
|
112
|
-
- spec/cli/
|
113
|
-
- spec/cli/
|
114
|
+
- spec/cli/list_lessons_spec.rb
|
115
|
+
- spec/cli/run_exercise_test_suite_spec.rb
|
116
|
+
- spec/cli/submit_lesson_spec.rb
|
114
117
|
- spec/data/challenge.json
|
115
|
-
- spec/data/
|
118
|
+
- spec/data/lessons.json
|
119
|
+
- spec/data/sample-challenge/.lesson.yml
|
120
|
+
- spec/data/sample-challenge/problem.rb
|
121
|
+
- spec/data/sample-challenge/sample-challenge.md
|
122
|
+
- spec/data/sample-exercise/.lesson.yml
|
123
|
+
- spec/data/sample-exercise/lib/sample_exercise.rb
|
124
|
+
- spec/data/sample-exercise/sample-exercise.md
|
125
|
+
- spec/data/sample-exercise/test/sample_exercise_test.rb
|
116
126
|
- spec/data/some-challenge.tar.gz
|
117
127
|
- spec/lib/api_spec.rb
|
118
128
|
- spec/lib/challenge_spec.rb
|
119
129
|
- spec/lib/config_spec.rb
|
130
|
+
- spec/lib/exercise_spec.rb
|
120
131
|
- spec/spec_helper.rb
|
121
132
|
- spec/support/helpers/archive_helper.rb
|
122
133
|
- spec/support/helpers/output_catcher.rb
|
@@ -1,25 +0,0 @@
|
|
1
|
-
describe "list challenges" do
|
2
|
-
let(:sample_challenges) do
|
3
|
-
JSON.parse(File.read("spec/data/challenges.json"), symbolize_names: true)[:lessons]
|
4
|
-
end
|
5
|
-
|
6
|
-
it "prints the titles and slug" do
|
7
|
-
expect_any_instance_of(ET::API).to receive(:list_challenges).
|
8
|
-
and_return(sample_challenges)
|
9
|
-
|
10
|
-
Dir.mktmpdir("test") do |tmpdir|
|
11
|
-
write_sample_config_to(tmpdir)
|
12
|
-
|
13
|
-
runner = ET::Runner.new(tmpdir)
|
14
|
-
stdout, _ = capture_output do
|
15
|
-
expect(runner.go(["list"])).to eq(0)
|
16
|
-
end
|
17
|
-
|
18
|
-
expect(stdout).to include("Guess the Number")
|
19
|
-
expect(stdout).to include("guess-the-number")
|
20
|
-
|
21
|
-
expect(stdout).to include("Auto-Guesser")
|
22
|
-
expect(stdout).to include("auto-guesser")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
describe "submit challenge" do
|
2
|
-
let(:sample_archive_path) do
|
3
|
-
project_root.join("spec/data/archive.tar.gz")
|
4
|
-
end
|
5
|
-
|
6
|
-
context "when in a working area" do
|
7
|
-
it "packages and uploads directory" do
|
8
|
-
Dir.mktmpdir("test") do |tmpdir|
|
9
|
-
write_sample_config_to(tmpdir)
|
10
|
-
challenge_dir = write_sample_challenge_to(tmpdir, "some-challenge")
|
11
|
-
|
12
|
-
expect_any_instance_of(ET::API).to receive(:submit_challenge).
|
13
|
-
and_return(true)
|
14
|
-
|
15
|
-
runner = ET::Runner.new(challenge_dir)
|
16
|
-
_, _ = capture_output do
|
17
|
-
expect(runner.go(["submit"])).to eq(0)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
data/spec/data/challenges.json
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"lessons":[{"title":"Auto-Guesser","slug":"auto-guesser"},{"title":"Guess the Number","slug":"guess-the-number"}]}
|