daigaku 0.1.0 → 0.1.1
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/lib/daigaku/course.rb +52 -0
- data/lib/daigaku/terminal/courses.rb +2 -29
- data/lib/daigaku/version.rb +1 -1
- data/lib/daigaku/window.rb +12 -9
- data/spec/daigaku/course_spec.rb +108 -0
- data/spec/daigaku/terminal/courses_spec.rb +23 -0
- data/spec/support/macros/resource_helpers.rb +42 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc609a20eb768060e29650848a0c5e18c3734564
|
4
|
+
data.tar.gz: fe5a9c1b16ef1dbb90bd9bb5f93cb1f34d6cbb78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f602698e655947c62bb4ad461a2f6f0bb66ee5ffe8a809a10444a8d98096b02fef63f6f7e0149e66f8e7d78c1a8a5c1adb28a17aa37459bca0483b9002ac777
|
7
|
+
data.tar.gz: 06f241f79407d17e233e6c4d82993d6a54ef97de3a8d05b9a2c19b4bbac81373bc1b46cb9755a5562dac59ebd7b9f016c1415284d336baefe0d14be463234aea
|
data/lib/daigaku/course.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
1
3
|
module Daigaku
|
2
4
|
class Course
|
3
5
|
|
@@ -24,5 +26,55 @@ module Daigaku
|
|
24
26
|
def key(key_name)
|
25
27
|
Storeable.key(title, prefix: 'courses', suffix: key_name)
|
26
28
|
end
|
29
|
+
|
30
|
+
# Unzips a zipped file and removes the zipped file.
|
31
|
+
# Returns a Daigaku::Course of the unzipped content.
|
32
|
+
#
|
33
|
+
# Example:
|
34
|
+
# Daigaku::Course.unzip('/path/to/file.zip')
|
35
|
+
# # => Daigaku::Course
|
36
|
+
#
|
37
|
+
# Daigaku::Course.unzip(/path/to/master.zip, github_repo: true)
|
38
|
+
# # => Daigaku::Course
|
39
|
+
#
|
40
|
+
class << self
|
41
|
+
def unzip(file_path, options = {})
|
42
|
+
target_dir = File.dirname(file_path)
|
43
|
+
course_dir = nil
|
44
|
+
|
45
|
+
Zip::File.open(file_path) do |zip_file|
|
46
|
+
zip_file.each do |entry|
|
47
|
+
|
48
|
+
if options[:github_repo]
|
49
|
+
first, *others = entry.to_s.split('/')
|
50
|
+
directory = File.join(first.split('-')[0..-2].join('-'), others)
|
51
|
+
else
|
52
|
+
directory = entry.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
if course_dir.nil? && directory != '/'
|
56
|
+
course_dir = File.join(target_dir, directory.gsub(/\/$/, ''))
|
57
|
+
|
58
|
+
if Dir.exist?(course_dir)
|
59
|
+
FileUtils.copy_entry("#{course_dir}/", "#{course_dir}_old/", true)
|
60
|
+
FileUtils.rm_rf("#{course_dir}/.", secure: true)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
zip_file.extract(entry, "#{target_dir}/#{directory}") { true }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
FileUtils.rm(file_path)
|
69
|
+
rescue Exception => e
|
70
|
+
puts e
|
71
|
+
old_dir = "#{course_dir}_old/"
|
72
|
+
FileUtils.copy_entry(old_dir, "#{course_dir}/", true) if Dir.exist?(old_dir)
|
73
|
+
ensure
|
74
|
+
old_dir = "#{course_dir}_old/"
|
75
|
+
FileUtils.rm_r(old_dir) if Dir.exist?(old_dir)
|
76
|
+
return Course.new(course_dir) if course_dir
|
77
|
+
end
|
78
|
+
end
|
27
79
|
end
|
28
80
|
end
|
@@ -34,19 +34,18 @@ module Daigaku
|
|
34
34
|
file_name = File.join(courses_path, url.split('/').last)
|
35
35
|
|
36
36
|
File.open(file_name, 'w') { |file| file << open(url).read }
|
37
|
-
|
37
|
+
course = Course.unzip(file_name, github_repo: github)
|
38
38
|
|
39
39
|
if github
|
40
40
|
user_and_repo = url.match(/github.com\/(.*)\/archive\/master.zip/).captures.first
|
41
41
|
store_repo_data(options[:github] || user_and_repo)
|
42
42
|
end
|
43
43
|
|
44
|
-
course = Course.new(course_name)
|
45
44
|
QuickStore.store.set(course.key(:url), url)
|
46
45
|
QuickStore.store.set(course.key(:updated_at), Time.now.to_s)
|
47
46
|
scaffold_solutions
|
48
47
|
|
49
|
-
say_info "Successfully #{action} the course \"#{
|
48
|
+
say_info "Successfully #{action} the course \"#{course.title}\"!"
|
50
49
|
rescue Download::NoUrlError => e
|
51
50
|
print_download_warning(url, "\"#{url}\" is not a valid URL!")
|
52
51
|
rescue Download::NoZipFileUrlError => e
|
@@ -134,32 +133,6 @@ module Daigaku
|
|
134
133
|
QuickStore.store.set(course.key(:github), user_and_repo)
|
135
134
|
end
|
136
135
|
|
137
|
-
def unzip(file_path, github = false)
|
138
|
-
target_dir = File.dirname(file_path)
|
139
|
-
course_name = nil
|
140
|
-
|
141
|
-
Zip::File.open(file_path) do |zip_file|
|
142
|
-
zip_file.each do |entry|
|
143
|
-
|
144
|
-
if github
|
145
|
-
first, *others = entry.to_s.split('/')
|
146
|
-
directory = File.join(first.split('-')[0..-2].join('-'), others)
|
147
|
-
else
|
148
|
-
directory = entry.to_s
|
149
|
-
end
|
150
|
-
|
151
|
-
if directory != '/'
|
152
|
-
course_name ||= directory.split('/').first.gsub(/_+/, ' ')
|
153
|
-
end
|
154
|
-
|
155
|
-
zip_file.extract(entry, "#{target_dir}/#{directory}") { true }
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
FileUtils.rm(file_path)
|
160
|
-
course_name
|
161
|
-
end
|
162
|
-
|
163
136
|
def scaffold_solutions
|
164
137
|
generator = Generator.new
|
165
138
|
generator.prepare
|
data/lib/daigaku/version.rb
CHANGED
data/lib/daigaku/window.rb
CHANGED
@@ -122,8 +122,8 @@ module Daigaku
|
|
122
122
|
emphasized = false
|
123
123
|
highlighted = false
|
124
124
|
|
125
|
-
text.chars.
|
126
|
-
if char == '*'
|
125
|
+
text.chars.each_with_index do |char, index|
|
126
|
+
if char == '*' && text[index - 1] != '\\'
|
127
127
|
emphasized = !emphasized
|
128
128
|
next
|
129
129
|
end
|
@@ -133,22 +133,25 @@ module Daigaku
|
|
133
133
|
next
|
134
134
|
end
|
135
135
|
|
136
|
+
character = "#{text[index..(index + 1)]}" == '\\*' ? '' : char
|
137
|
+
|
136
138
|
if highlighted
|
137
|
-
red(
|
139
|
+
red(character)
|
138
140
|
elsif emphasized
|
139
|
-
emphasize(
|
141
|
+
emphasize(character)
|
140
142
|
else
|
141
|
-
write(
|
143
|
+
write(character)
|
142
144
|
end
|
143
145
|
end
|
144
146
|
when bold
|
145
|
-
text.chars.
|
146
|
-
if char == '*'
|
147
|
+
text.chars.each_with_index do |char, index|
|
148
|
+
if char == '*' && text[index - 1] != '\\'
|
147
149
|
emphasized = !emphasized
|
148
150
|
next
|
149
151
|
end
|
150
152
|
|
151
|
-
|
153
|
+
character = "#{text[index..(index + 1)]}" == '\\*' ? '' : char
|
154
|
+
emphasized ? emphasize(character) : write(character)
|
152
155
|
end
|
153
156
|
when line
|
154
157
|
write('-' * (Curses.cols - 2))
|
@@ -159,7 +162,7 @@ module Daigaku
|
|
159
162
|
capture = text.match(/\(ruby-doc stdlib:\s?(.*)\)/).captures.first
|
160
163
|
write text.gsub(ruby_doc_stdlib, ruby_doc_stdlib_link(capture))
|
161
164
|
else
|
162
|
-
write(text)
|
165
|
+
write(text.gsub(/(\\#)/, '#'))
|
163
166
|
end
|
164
167
|
end
|
165
168
|
|
data/spec/daigaku/course_spec.rb
CHANGED
@@ -13,6 +13,8 @@ describe Daigaku::Course do
|
|
13
13
|
|
14
14
|
let(:course_path) { course_dirs.first }
|
15
15
|
|
16
|
+
before { suppress_print_out }
|
17
|
+
|
16
18
|
before(:all) do
|
17
19
|
prepare_solutions
|
18
20
|
Daigaku.config.solutions_path = solutions_basepath
|
@@ -20,6 +22,10 @@ describe Daigaku::Course do
|
|
20
22
|
|
21
23
|
subject { Daigaku::Course.new(course_path) }
|
22
24
|
|
25
|
+
it "responds to ::unzip" do
|
26
|
+
expect(Daigaku::Course).to respond_to :unzip
|
27
|
+
end
|
28
|
+
|
23
29
|
it "has the prescribed title" do
|
24
30
|
expect(subject.title).to eq course_titles.first
|
25
31
|
end
|
@@ -90,4 +96,106 @@ describe Daigaku::Course do
|
|
90
96
|
expect(course.author).to eq author
|
91
97
|
end
|
92
98
|
end
|
99
|
+
|
100
|
+
describe "::unzip" do
|
101
|
+
before do
|
102
|
+
Daigaku.config.courses_path = local_courses_path
|
103
|
+
@zip_file_name = "unzip/repo.zip"
|
104
|
+
@zip_file_path = File.join(courses_basepath, @zip_file_name)
|
105
|
+
@file_content = prepare_download(@zip_file_name)
|
106
|
+
end
|
107
|
+
|
108
|
+
after do
|
109
|
+
cleanup_download(@zip_file_name)
|
110
|
+
dir = File.dirname(@zip_file_path)
|
111
|
+
FileUtils.rm_r(dir) if Dir.exist?(dir)
|
112
|
+
end
|
113
|
+
|
114
|
+
def expect_course_dirs_exists_to_be(boolean)
|
115
|
+
unit_dirs(course_dir_names.first).each do |chapter_dirs|
|
116
|
+
chapter_dirs.each do |dir|
|
117
|
+
path = [dir.split('/')[0..-4], 'unzip', dir.split('/')[-3..-1]].join('/')
|
118
|
+
expect(Dir.exist?(path)).to be boolean
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it "unzips a course zip file" do
|
124
|
+
expect_course_dirs_exists_to_be false
|
125
|
+
Daigaku::Course.unzip(@zip_file_path)
|
126
|
+
expect_course_dirs_exists_to_be true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "returns the unzipped course" do
|
130
|
+
dir = course_dirs.first
|
131
|
+
path = File.join(File.dirname(dir), 'unzip', File.basename(dir))
|
132
|
+
course = Daigaku::Course.new(path)
|
133
|
+
|
134
|
+
expect(Daigaku::Course.unzip(@zip_file_path).to_json).to eql course.to_json
|
135
|
+
end
|
136
|
+
|
137
|
+
it "removes the zip file" do
|
138
|
+
expect(File.exist?(@zip_file_path)).to be true
|
139
|
+
Daigaku::Course.unzip(@zip_file_path)
|
140
|
+
expect(File.exist?(@zip_file_path)).to be false
|
141
|
+
end
|
142
|
+
|
143
|
+
context "with the same course already available:" do
|
144
|
+
before do
|
145
|
+
dir = course_dirs.first
|
146
|
+
@path = File.join(File.dirname(dir), 'unzip', File.basename(dir))
|
147
|
+
@old_chapter_dir = File.join(@path, 'Old_chapter')
|
148
|
+
|
149
|
+
FileUtils.mkdir_p(@old_chapter_dir)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "overwrites all chapters" do
|
153
|
+
expect(Dir.exist?(@old_chapter_dir)).to be true
|
154
|
+
Daigaku::Course.unzip(@zip_file_path)
|
155
|
+
expect(Dir.exist?(@old_chapter_dir)).to be false
|
156
|
+
end
|
157
|
+
|
158
|
+
context "if an errior occurs" do
|
159
|
+
before do
|
160
|
+
allow_any_instance_of(Zip::File)
|
161
|
+
.to receive(:extract) { raise Exception.new }
|
162
|
+
end
|
163
|
+
|
164
|
+
it "restores an old state if an error occurs" do
|
165
|
+
Daigaku::Course.unzip(@zip_file_path)
|
166
|
+
expect(Dir.exist?(@old_chapter_dir)).to be true
|
167
|
+
expect(Dir.exist?("#{@path}_old")).to be false
|
168
|
+
end
|
169
|
+
|
170
|
+
it "keeps the zip file if an error occurs" do
|
171
|
+
expect(File.exist?(@zip_file_path)).to be true
|
172
|
+
Daigaku::Course.unzip(@zip_file_path)
|
173
|
+
expect(File.exist?(@zip_file_path)).to be true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "with the github_repo option:" do
|
179
|
+
before { @github_course_dir = prepare_github_course }
|
180
|
+
after { FileUtils.rm_r(@github_course_dir) }
|
181
|
+
|
182
|
+
it "removes the '-master' from the root directory" do
|
183
|
+
zip_file_name = "unzip/repo-master.zip"
|
184
|
+
zip_file_path = File.join(courses_basepath, zip_file_name)
|
185
|
+
prepare_github_download(zip_file_name)
|
186
|
+
|
187
|
+
expect(File.exist?(zip_file_path)).to be true
|
188
|
+
Daigaku::Course.unzip(zip_file_path, github_repo: true)
|
189
|
+
|
190
|
+
unit_dirs("#{course_dir_names.first}-master").each do |chapter_dirs|
|
191
|
+
chapter_dirs.each do |dir|
|
192
|
+
path = [dir.split('/')[0..-4], 'unzip', dir.split('/')[-3..-1]].join('/')
|
193
|
+
expect(Dir.exist?(path)).to be false
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
expect_course_dirs_exists_to_be true
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
93
201
|
end
|
@@ -39,6 +39,11 @@ describe Daigaku::Terminal::Courses do
|
|
39
39
|
expect{ subject.download(@url) }.not_to raise_error
|
40
40
|
end
|
41
41
|
|
42
|
+
it "uses Courses.unzip to unzip the course" do
|
43
|
+
expect(Daigaku::Course).to receive(:unzip).once
|
44
|
+
subject.download(@url)
|
45
|
+
end
|
46
|
+
|
42
47
|
it "creates a new courses folder in the daigaku courses directory" do
|
43
48
|
target_path = File.join(Daigaku.config.courses_path, File.basename(course_dirs.first))
|
44
49
|
dirs = Dir[File.join(Daigaku.config.courses_path, '**')]
|
@@ -165,6 +170,24 @@ describe Daigaku::Terminal::Courses do
|
|
165
170
|
expect(subject).not_to receive(:download)
|
166
171
|
subject.update('Course_A')
|
167
172
|
end
|
173
|
+
|
174
|
+
it "updates all courses if --all option is given" do
|
175
|
+
file_content = prepare_download(@zip_file_name, multiple_courses: true)
|
176
|
+
|
177
|
+
stub_request(:get, @url)
|
178
|
+
.with(
|
179
|
+
headers: {
|
180
|
+
'Accept' => '*/*',
|
181
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
182
|
+
'User-Agent' => 'Ruby'
|
183
|
+
}
|
184
|
+
).to_return(status: 200, body: file_content, headers: {})
|
185
|
+
|
186
|
+
allow(subject).to receive(:options) { { all: true } }
|
187
|
+
allow(subject).to receive(:download).exactly(course_dirs.count).times
|
188
|
+
|
189
|
+
subject.update
|
190
|
+
end
|
168
191
|
end
|
169
192
|
|
170
193
|
describe '#delete' do
|
@@ -19,6 +19,13 @@ module ResourceHelpers
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def prepare_github_course
|
23
|
+
prepare_courses
|
24
|
+
github_course_dir = "#{course_dirs.first}-master/"
|
25
|
+
FileUtils.copy_entry("#{course_dirs.first}/", github_course_dir)
|
26
|
+
github_course_dir
|
27
|
+
end
|
28
|
+
|
22
29
|
def prepare_solutions
|
23
30
|
all_solution_file_paths.each do |path|
|
24
31
|
base_dir = File.dirname(path)
|
@@ -27,14 +34,35 @@ module ResourceHelpers
|
|
27
34
|
end
|
28
35
|
end
|
29
36
|
|
30
|
-
def prepare_download(zip_file_name)
|
31
|
-
|
32
|
-
|
37
|
+
def prepare_download(zip_file_name, options = {})
|
38
|
+
zip_file_path = File.join(courses_basepath, zip_file_name)
|
39
|
+
|
40
|
+
unless Dir.exist?(File.dirname(zip_file_path))
|
41
|
+
FileUtils.makedirs(File.dirname(zip_file_path))
|
42
|
+
end
|
43
|
+
|
44
|
+
Zip::File.open(zip_file_path, Zip::File::CREATE) do |zip_file|
|
45
|
+
Dir[File.join(courses_basepath, '**', '**')].each do |file|
|
46
|
+
if course_match?(file, options[:multiple_courses])
|
47
|
+
zip_file.add(file.sub(courses_basepath, '')[1..-1], file) { true }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
File.read(zip_file_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def prepare_github_download(zip_file_name)
|
56
|
+
zip_file_path = File.join(courses_basepath, zip_file_name)
|
57
|
+
|
58
|
+
unless Dir.exist?(File.dirname(zip_file_path))
|
59
|
+
FileUtils.makedirs(File.dirname(zip_file_path))
|
60
|
+
end
|
33
61
|
|
34
62
|
Zip::File.open(zip_file_path, Zip::File::CREATE) do |zip_file|
|
35
|
-
Dir[File.join(
|
36
|
-
if file.match(
|
37
|
-
zip_file.add(file.sub(
|
63
|
+
Dir[File.join(courses_basepath, '**', '**')].each do |file|
|
64
|
+
if file.match(/.*\-master/)
|
65
|
+
zip_file.add(file.sub(courses_basepath, '')[1..-1], file) { true }
|
38
66
|
end
|
39
67
|
end
|
40
68
|
end
|
@@ -42,6 +70,14 @@ module ResourceHelpers
|
|
42
70
|
File.read(zip_file_path)
|
43
71
|
end
|
44
72
|
|
73
|
+
def course_match?(name, multiple_courses)
|
74
|
+
if multiple_courses
|
75
|
+
name.match(course_dirs.first) || name.match(course_dirs.second)
|
76
|
+
else
|
77
|
+
name.match(course_dirs.first)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
45
81
|
def cleanup_download(zip_file_name)
|
46
82
|
directory = course_dirs.first
|
47
83
|
zip_file = File.join(File.dirname(directory), zip_file_name)
|
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.1.
|
4
|
+
version: 0.1.1
|
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: 2015-05-
|
11
|
+
date: 2015-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|