daigaku 0.6.0 → 1.0.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/.travis.yml +1 -5
- data/README.md +1 -1
- data/bin/daigaku +6 -2
- data/daigaku.gemspec +4 -4
- data/lib/daigaku/github_client.rb +1 -1
- data/lib/daigaku/solution.rb +7 -2
- data/lib/daigaku/terminal/cli.rb +2 -0
- data/lib/daigaku/terminal/courses.rb +1 -1
- data/lib/daigaku/test.rb +1 -1
- data/lib/daigaku/test_result.rb +45 -9
- data/lib/daigaku/unit.rb +1 -1
- data/lib/daigaku/version.rb +1 -1
- data/lib/daigaku/views/menu.rb +4 -4
- data/lib/daigaku/views/task_view.rb +5 -6
- data/spec/daigaku/solution_spec.rb +3 -2
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d2569151b28f6803d8c351ad6c131e13d741c7515a08e3d6e5ff2db007d085b
|
4
|
+
data.tar.gz: d53b84a072e46320f7e4555c00ba3955e9de81a0729037257c4c41e217e72c67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3d43f800a282522f4cae4550e56785e92b1feee01f179306e5022e81223716437fd2b3b813adb37328d9d6b835cfafacd6842de8d7db5c8cbe05c4703deb4ad
|
7
|
+
data.tar.gz: 6373c4ae4ba47cb9ae150d5048b16898b98cf4e768d8f70b9f46d406e2b6951e0e4d260b141fe85e5602007be44dc92f55b25a3763000e81b366d55534e786c0
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -16,7 +16,7 @@ language-explaining programming tasks.
|
|
16
16
|
## Installation
|
17
17
|
|
18
18
|
First of all make sure Ruby is installed on your computer.
|
19
|
-
Daigaku works with [MRI Ruby](https://www.ruby-lang.org/en/documentation/installation/) v2.
|
19
|
+
Daigaku works with [MRI Ruby](https://www.ruby-lang.org/en/documentation/installation/) v2.5 or higher.
|
20
20
|
|
21
21
|
Then open a terminal and install Daigaku by running:
|
22
22
|
|
data/bin/daigaku
CHANGED
data/daigaku.gemspec
CHANGED
@@ -16,17 +16,17 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
17
|
spec.require_paths = ['lib']
|
18
18
|
|
19
|
-
spec.required_ruby_version = '>= 2.
|
19
|
+
spec.required_ruby_version = '>= 2.5'
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'curses', '~> 1.3'
|
22
22
|
spec.add_runtime_dependency 'rspec', '~> 3.0'
|
23
|
-
spec.add_runtime_dependency 'thor', '~> 0
|
23
|
+
spec.add_runtime_dependency 'thor', '~> 1.0'
|
24
24
|
spec.add_runtime_dependency 'os', '~> 1.0'
|
25
25
|
spec.add_runtime_dependency 'colorize', '~> 0.8'
|
26
26
|
spec.add_runtime_dependency 'rubyzip', '~> 2.0'
|
27
27
|
spec.add_runtime_dependency 'wisper', '~> 2.0'
|
28
|
-
spec.add_runtime_dependency 'quick_store', '~> 0
|
29
|
-
spec.add_runtime_dependency 'code_breaker', '~> 0
|
28
|
+
spec.add_runtime_dependency 'quick_store', '~> 1.0'
|
29
|
+
spec.add_runtime_dependency 'code_breaker', '~> 1.0'
|
30
30
|
|
31
31
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
32
32
|
spec.add_development_dependency 'rake', '~> 13.0'
|
@@ -12,7 +12,7 @@ module Daigaku
|
|
12
12
|
# Returns the timestamp of updated_at for the repo from the Github API.
|
13
13
|
def self.updated_at(user_and_repo)
|
14
14
|
url = "https://api.github.com/repos/#{user_and_repo}"
|
15
|
-
JSON.parse(open(url).read)['updated_at']
|
15
|
+
JSON.parse(URI.open(url).read)['updated_at']
|
16
16
|
end
|
17
17
|
|
18
18
|
# Returns whether the pushed_at time from Github API is newer than the
|
data/lib/daigaku/solution.rb
CHANGED
@@ -7,12 +7,13 @@ module Daigaku
|
|
7
7
|
def initialize(unit_path)
|
8
8
|
@unit_path = unit_path
|
9
9
|
@path = solution_path(unit_path)
|
10
|
-
@code =
|
10
|
+
@code = load_code(@path)
|
11
11
|
@verified = store_state
|
12
12
|
end
|
13
13
|
|
14
14
|
def verify!
|
15
|
-
|
15
|
+
@code = load_code(@path)
|
16
|
+
result = Daigaku::Test.new(@unit_path).run(@code)
|
16
17
|
self.store_state = result.passed?
|
17
18
|
result
|
18
19
|
end
|
@@ -32,6 +33,10 @@ module Daigaku
|
|
32
33
|
|
33
34
|
private
|
34
35
|
|
36
|
+
def load_code(path)
|
37
|
+
File.read(path).strip if File.file?(path)
|
38
|
+
end
|
39
|
+
|
35
40
|
def solution_path(path)
|
36
41
|
local_path = Daigaku.config.solutions_path
|
37
42
|
sub_directory = Storeable.key(directory_from(path))
|
data/lib/daigaku/terminal/cli.rb
CHANGED
@@ -37,7 +37,7 @@ module Daigaku
|
|
37
37
|
|
38
38
|
file_name = File.join(courses_path, url.split('/').last)
|
39
39
|
|
40
|
-
File.open(file_name, 'w') { |file| file << open(url).read }
|
40
|
+
File.open(file_name, 'w') { |file| file << URI.open(url).read }
|
41
41
|
course = Course.unzip(file_name, github_repo: github)
|
42
42
|
|
43
43
|
if github
|
data/lib/daigaku/test.rb
CHANGED
@@ -18,7 +18,7 @@ module Daigaku
|
|
18
18
|
temp_spec = File.join(File.dirname(@path), "temp_#{File.basename(@path)}")
|
19
19
|
create_temp_spec(temp_spec, patched_spec_code)
|
20
20
|
|
21
|
-
result = `rspec --color --format j #{temp_spec}`
|
21
|
+
result = `rspec --no-color --order defined --format j #{temp_spec}`
|
22
22
|
remove_file(temp_spec)
|
23
23
|
|
24
24
|
TestResult.new(result)
|
data/lib/daigaku/test_result.rb
CHANGED
@@ -2,17 +2,26 @@ require 'json'
|
|
2
2
|
|
3
3
|
module Daigaku
|
4
4
|
class TestResult
|
5
|
+
CODE_ERROR_MESSAGE = ':( You got an error in your code!'.freeze
|
6
|
+
|
5
7
|
attr_reader :examples, :example_count, :failure_count
|
6
8
|
|
7
9
|
def initialize(result_json)
|
8
10
|
@result = begin
|
9
11
|
JSON.parse(result_json, symbolize_names: true)
|
10
|
-
rescue
|
11
|
-
syntax_error_json
|
12
|
+
rescue => error
|
13
|
+
syntax_error_json(error)
|
12
14
|
end
|
13
15
|
|
14
|
-
@example_count = @result
|
15
|
-
@failure_count = @result
|
16
|
+
@example_count = @result.dig(:summary, :example_count)
|
17
|
+
@failure_count = @result.dig(:summary, :failure_count)
|
18
|
+
error_count = @result.dig(:summary, :errors_outside_of_examples_count) || 0
|
19
|
+
|
20
|
+
if error_count > 0
|
21
|
+
@failure_count = error_count
|
22
|
+
details = error_details(@result)
|
23
|
+
@result = error_json(details)
|
24
|
+
end
|
16
25
|
|
17
26
|
@examples = @result[:examples].map do |example|
|
18
27
|
description = example[:full_description]
|
@@ -52,32 +61,59 @@ module Daigaku
|
|
52
61
|
message.join("\n" * 3)
|
53
62
|
end
|
54
63
|
|
55
|
-
def syntax_error_json
|
64
|
+
def syntax_error_json(error)
|
65
|
+
details = failure_details(error)
|
66
|
+
error_json(details)
|
67
|
+
end
|
68
|
+
|
69
|
+
def error_details(result)
|
70
|
+
result[:messages]
|
71
|
+
.first
|
72
|
+
.split('\n')
|
73
|
+
.each_with_index
|
74
|
+
.select { |line, index| index > 0 && line.matches?(/temp_.+\.rb/) }
|
75
|
+
.first.to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
def error_json(details)
|
56
79
|
{
|
57
80
|
summary: {},
|
58
81
|
examples: [
|
59
82
|
{
|
60
|
-
status:
|
61
|
-
exception: { message:
|
83
|
+
status: TestExample::FAILED,
|
84
|
+
exception: { message: "#{CODE_ERROR_MESSAGE}\n\n#{details}" }
|
62
85
|
}
|
63
86
|
]
|
64
87
|
}
|
65
88
|
end
|
89
|
+
|
90
|
+
def failure_details(error)
|
91
|
+
line = error.backtrace.first
|
92
|
+
error_message = remove_colorization(error.message)
|
93
|
+
"#{error.class} in #{line}:\n#{error_message}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def remove_colorization(text)
|
97
|
+
text.gsub(/\x1b\[[0-9]*m/i, '')
|
98
|
+
end
|
66
99
|
end
|
67
100
|
|
68
101
|
class TestExample
|
102
|
+
PASSED = 'passed'.freeze
|
103
|
+
FAILED = 'failed'.freeze
|
104
|
+
|
69
105
|
attr_reader :description, :status, :message
|
70
106
|
|
71
107
|
EXAMPLE_PASSED_MESSAGE = 'Your code passed this requirement.'.freeze
|
72
108
|
|
73
|
-
def initialize(
|
109
|
+
def initialize(status:, description: nil, message: nil)
|
74
110
|
@description = description
|
75
111
|
@status = status
|
76
112
|
@message = message || EXAMPLE_PASSED_MESSAGE
|
77
113
|
end
|
78
114
|
|
79
115
|
def passed?
|
80
|
-
@status ==
|
116
|
+
@status == PASSED
|
81
117
|
end
|
82
118
|
end
|
83
119
|
end
|
data/lib/daigaku/unit.rb
CHANGED
data/lib/daigaku/version.rb
CHANGED
data/lib/daigaku/views/menu.rb
CHANGED
@@ -7,10 +7,10 @@ module Daigaku
|
|
7
7
|
include Wisper::Publisher
|
8
8
|
|
9
9
|
TOP_BAR_TEXT = [
|
10
|
-
'Use *
|
11
|
-
'Enter menu with *
|
12
|
-
'Go back with *
|
13
|
-
'Exit with *
|
10
|
+
'Use * 🠕 * and * 🠗 * for menu navigation',
|
11
|
+
'Enter menu with * ⏎ *',
|
12
|
+
'Go back with * ⟵ *',
|
13
|
+
'Exit with *Esc*'
|
14
14
|
].join(' | ').freeze
|
15
15
|
|
16
16
|
attr_writer :items_info
|
@@ -8,11 +8,11 @@ module Daigaku
|
|
8
8
|
include Wisper::Publisher
|
9
9
|
|
10
10
|
TOP_BAR_TEXT = [
|
11
|
-
'Scroll with *
|
11
|
+
'Scroll with * 🠕 * and * 🠗 *',
|
12
12
|
'Open solution file with *o*',
|
13
13
|
'Verify solution with *v*',
|
14
14
|
'Clear validation with *c*',
|
15
|
-
'Exit with *
|
15
|
+
'Exit with *Esc*'
|
16
16
|
].join(' | ').freeze
|
17
17
|
|
18
18
|
def initialize
|
@@ -201,11 +201,10 @@ module Daigaku
|
|
201
201
|
@lines = [''] + @test_result_lines + ['', ''] + @unit.task.markdown.lines
|
202
202
|
@examples = result.examples
|
203
203
|
|
204
|
-
@example_heights = @examples.
|
204
|
+
@example_heights = @examples.each_with_object({}) do |example, hash|
|
205
205
|
start = hash.values.reduce(0) { |sum, results| sum + results.count }
|
206
206
|
range = (start..(start + example.message.split("\n").count) + 2)
|
207
207
|
hash[hash.keys.count] = range
|
208
|
-
hash
|
209
208
|
end
|
210
209
|
|
211
210
|
lines_count = @lines.count + @top_bar_height + @head_height
|
@@ -223,8 +222,8 @@ module Daigaku
|
|
223
222
|
def code_error_lines(code)
|
224
223
|
begin
|
225
224
|
eval(code)
|
226
|
-
rescue StandardError =>
|
227
|
-
return
|
225
|
+
rescue StandardError, ScriptError => error
|
226
|
+
return error.inspect.gsub(/(\A.*#<|>.*$)/, '').lines.map(&:rstrip)
|
228
227
|
end
|
229
228
|
|
230
229
|
[]
|
@@ -62,10 +62,11 @@ describe Daigaku::Solution do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
it 'sets the solution’s state in the store to unverified unless passed' do
|
65
|
-
|
65
|
+
allow(File).to receive(:read).and_return('puts "I ❤ Daigaku!"')
|
66
|
+
QuickStore.store.set(subject.store_key, true)
|
67
|
+
|
66
68
|
subject.verify!
|
67
69
|
mastered = QuickStore.store.get(subject.store_key)
|
68
|
-
|
69
70
|
expect(mastered).to be_falsey
|
70
71
|
end
|
71
72
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: daigaku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Götze
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0
|
47
|
+
version: '1.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0
|
54
|
+
version: '1.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: os
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,28 +114,28 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0
|
117
|
+
version: '1.0'
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0
|
124
|
+
version: '1.0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: code_breaker
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0
|
131
|
+
version: '1.0'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0
|
138
|
+
version: '1.0'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: bundler
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -310,14 +310,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
310
310
|
requirements:
|
311
311
|
- - ">="
|
312
312
|
- !ruby/object:Gem::Version
|
313
|
-
version: 2.
|
313
|
+
version: '2.5'
|
314
314
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
315
315
|
requirements:
|
316
316
|
- - ">="
|
317
317
|
- !ruby/object:Gem::Version
|
318
318
|
version: '0'
|
319
319
|
requirements: []
|
320
|
-
rubygems_version: 3.
|
320
|
+
rubygems_version: 3.1.3
|
321
321
|
signing_key:
|
322
322
|
specification_version: 4
|
323
323
|
summary: Learning Ruby on the command line.
|