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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 579a43d2967ed7592ae65d76b826b2a14b7dac14
4
- data.tar.gz: 54a8f9846c685f2b0184d3dd8e2f9e95921b5fae
3
+ metadata.gz: bc609a20eb768060e29650848a0c5e18c3734564
4
+ data.tar.gz: fe5a9c1b16ef1dbb90bd9bb5f93cb1f34d6cbb78
5
5
  SHA512:
6
- metadata.gz: 8b94570b37b186fdb35b3b875f1cad97e355a95d62df87ed179536f5792dd3ffeb88d55d4b9aba1622720dd2c50e10d5e50666b497264141518c63ee7ed00f96
7
- data.tar.gz: 9903fe01ea858ad2605d38888bd5bdc4527e2eca195b780ad7f9627af4d478200e68e83080bd8a263f5bbbaa3b9ee8eb731b741933116f02b7fb7fc4ee8cfaa2
6
+ metadata.gz: 3f602698e655947c62bb4ad461a2f6f0bb66ee5ffe8a809a10444a8d98096b02fef63f6f7e0149e66f8e7d78c1a8a5c1adb28a17aa37459bca0483b9002ac777
7
+ data.tar.gz: 06f241f79407d17e233e6c4d82993d6a54ef97de3a8d05b9a2c19b4bbac81373bc1b46cb9755a5562dac59ebd7b9f016c1415284d336baefe0d14be463234aea
@@ -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
- course_name = unzip(file_name, github)
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 \"#{course_name}\"!"
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
@@ -1,3 +1,3 @@
1
1
  module Daigaku
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -122,8 +122,8 @@ module Daigaku
122
122
  emphasized = false
123
123
  highlighted = false
124
124
 
125
- text.chars.each do |char|
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(char)
139
+ red(character)
138
140
  elsif emphasized
139
- emphasize(char)
141
+ emphasize(character)
140
142
  else
141
- write(char)
143
+ write(character)
142
144
  end
143
145
  end
144
146
  when bold
145
- text.chars.each do |char|
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
- emphasized ? emphasize(char) : write(char)
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
 
@@ -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
- directory = File.dirname(course_dirs.first)
32
- zip_file_path = File.join(File.dirname(directory), zip_file_name)
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(directory, '**', '**')].each do |file|
36
- if file.match(course_dir_names.first)
37
- zip_file.add(file.sub(directory, '')[1..-1], file) { true }
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.0
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-09 00:00:00.000000000 Z
11
+ date: 2015-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curses