belajar 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/README.md +5 -0
- data/Rakefile +5 -0
- data/belajar.gemspec +38 -0
- data/bin/belajar +12 -0
- data/lib/belajar.rb +24 -0
- data/lib/belajar/chapter.rb +23 -0
- data/lib/belajar/configuration.rb +89 -0
- data/lib/belajar/congratulator.rb +13 -0
- data/lib/belajar/course.rb +80 -0
- data/lib/belajar/exceptions.rb +19 -0
- data/lib/belajar/generator.rb +60 -0
- data/lib/belajar/github_client.rb +30 -0
- data/lib/belajar/loadable.rb +23 -0
- data/lib/belajar/loading/chapters.rb +9 -0
- data/lib/belajar/loading/courses.rb +9 -0
- data/lib/belajar/loading/units.rb +9 -0
- data/lib/belajar/reference_solution.rb +18 -0
- data/lib/belajar/solution.rb +53 -0
- data/lib/belajar/storeable.rb +32 -0
- data/lib/belajar/task.rb +10 -0
- data/lib/belajar/terminal.rb +12 -0
- data/lib/belajar/terminal/cli.rb +59 -0
- data/lib/belajar/terminal/courses.rb +179 -0
- data/lib/belajar/terminal/output.rb +78 -0
- data/lib/belajar/terminal/setup.rb +115 -0
- data/lib/belajar/terminal/solutions.rb +46 -0
- data/lib/belajar/terminal/texts/about.txt +19 -0
- data/lib/belajar/terminal/texts/congratulations.txt +12 -0
- data/lib/belajar/terminal/texts/courses_empty.txt +3 -0
- data/lib/belajar/terminal/texts/hint_course_download.txt +13 -0
- data/lib/belajar/terminal/texts/welcome.txt +12 -0
- data/lib/belajar/terminal/welcome.rb +98 -0
- data/lib/belajar/test.rb +46 -0
- data/lib/belajar/test_result.rb +86 -0
- data/lib/belajar/unit.rb +28 -0
- data/lib/belajar/version.rb +3 -0
- data/lib/belajar/views.rb +51 -0
- data/lib/belajar/views/chapters_menu.rb +60 -0
- data/lib/belajar/views/courses_menu.rb +52 -0
- data/lib/belajar/views/main_menu.rb +37 -0
- data/lib/belajar/views/menu.rb +89 -0
- data/lib/belajar/views/splash.rb +57 -0
- data/lib/belajar/views/task_view.rb +236 -0
- data/lib/belajar/views/top_bar.rb +40 -0
- data/lib/belajar/views/units_menu.rb +61 -0
- data/lib/belajar/window.rb +215 -0
- data/spec/belajar/chapter_spec.rb +76 -0
- data/spec/belajar/configuration_spec.rb +161 -0
- data/spec/belajar/congratulator_spec.rb +24 -0
- data/spec/belajar/course_spec.rb +201 -0
- data/spec/belajar/generator_spec.rb +82 -0
- data/spec/belajar/github_client_spec.rb +53 -0
- data/spec/belajar/loading/chapters_spec.rb +16 -0
- data/spec/belajar/loading/courses_spec.rb +16 -0
- data/spec/belajar/loading/units_spec.rb +21 -0
- data/spec/belajar/reference_solution_spec.rb +41 -0
- data/spec/belajar/solution_spec.rb +86 -0
- data/spec/belajar/storeable_spec.rb +35 -0
- data/spec/belajar/task_spec.rb +23 -0
- data/spec/belajar/terminal/cli_spec.rb +51 -0
- data/spec/belajar/terminal/courses_spec.rb +293 -0
- data/spec/belajar/terminal/output_spec.rb +151 -0
- data/spec/belajar/terminal/setup_spec.rb +10 -0
- data/spec/belajar/terminal/solutions_spec.rb +8 -0
- data/spec/belajar/terminal/welcome_spec.rb +12 -0
- data/spec/belajar/terminal_spec.rb +24 -0
- data/spec/belajar/test_example_spec.rb +54 -0
- data/spec/belajar/test_result_spec.rb +91 -0
- data/spec/belajar/test_spec.rb +48 -0
- data/spec/belajar/unit_spec.rb +85 -0
- data/spec/belajar/views/chapters_menu_spec.rb +6 -0
- data/spec/belajar/views/courses_menu_spec.rb +6 -0
- data/spec/belajar/views/menu_spec.rb +19 -0
- data/spec/belajar/views/task_view_spec.rb +7 -0
- data/spec/belajar/views/units_menu_spec.rb +6 -0
- data/spec/belajar/views_spec.rb +21 -0
- data/spec/belajar_spec.rb +51 -0
- data/spec/path_helpers_spec.rb +60 -0
- data/spec/resource_helpers_spec.rb +33 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/macros/content_helpers.rb +129 -0
- data/spec/support/macros/mock_helpers.rb +25 -0
- data/spec/support/macros/path_helpers.rb +139 -0
- data/spec/support/macros/resource_helpers.rb +157 -0
- data/spec/support/macros/test_helpers.rb +6 -0
- metadata +385 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
module Belajar
|
2
|
+
module Views
|
3
|
+
|
4
|
+
class TopBar
|
5
|
+
include Curses
|
6
|
+
|
7
|
+
HEIGHT = 4
|
8
|
+
|
9
|
+
attr_reader :height, :width, :panel
|
10
|
+
|
11
|
+
def initialize(window, text = '')
|
12
|
+
@height = HEIGHT
|
13
|
+
@width = window.maxx
|
14
|
+
@panel = create_panel(window, @width, @height, text)
|
15
|
+
end
|
16
|
+
|
17
|
+
def show
|
18
|
+
@panel.refresh
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def create_panel(window, width, height, text)
|
24
|
+
panel = window.subwin(height, window.maxx, 0, 0)
|
25
|
+
|
26
|
+
panel.setpos(1, 1)
|
27
|
+
panel.print_markdown(text)
|
28
|
+
panel.setpos(2, 1)
|
29
|
+
panel.clear_line(text: '_')
|
30
|
+
|
31
|
+
panel
|
32
|
+
end
|
33
|
+
|
34
|
+
def emphasized(panel, text)
|
35
|
+
panel.write(text, Window::COLOR_2)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'belajar/views/menu'
|
2
|
+
|
3
|
+
module Belajar
|
4
|
+
module Views
|
5
|
+
|
6
|
+
class UnitsMenu < Menu
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def before_enter(*args)
|
11
|
+
@course = args[0]
|
12
|
+
@chapter = args[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_reenter(*args)
|
16
|
+
@course = args[0]
|
17
|
+
@chapter = args[1]
|
18
|
+
@unit = args[2]
|
19
|
+
|
20
|
+
@position = @chapter.units.find_index(@unit)
|
21
|
+
end
|
22
|
+
|
23
|
+
def header_text
|
24
|
+
"*#{@course.title}* > *#{@chapter.title}* - available units:"
|
25
|
+
end
|
26
|
+
|
27
|
+
def interact_with(window)
|
28
|
+
while char = window.getch
|
29
|
+
case char
|
30
|
+
when KEY_UP
|
31
|
+
@position -= 1
|
32
|
+
when KEY_DOWN
|
33
|
+
@position += 1
|
34
|
+
when 10 # Enter
|
35
|
+
broadcast(:enter, @course, @chapter, models[@position])
|
36
|
+
return
|
37
|
+
when 263 # Backspace
|
38
|
+
broadcast(:reenter, @course, @chapter)
|
39
|
+
return
|
40
|
+
when 27 # ESC
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
|
44
|
+
@position = items.length - 1 if @position < 0
|
45
|
+
@position = 0 if @position >= items.length
|
46
|
+
draw(window, @position)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def models
|
51
|
+
@chapter.units
|
52
|
+
end
|
53
|
+
|
54
|
+
def items
|
55
|
+
models.map(&:title)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'curses'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module Belajar
|
5
|
+
class Window < Curses::Window
|
6
|
+
|
7
|
+
COLOR_TEXT = Curses::COLOR_YELLOW unless defined? COLOR_TEXT
|
8
|
+
COLOR_TEXT_EMPHASIZE = Curses::COLOR_CYAN unless defined? COLOR_TEXT_EMPHASIZE
|
9
|
+
COLOR_HEADING = Curses::COLOR_WHITE unless defined? COLOR_HEADING
|
10
|
+
COLOR_RED = Curses::COLOR_BLUE unless defined? COLOR_RED
|
11
|
+
COLOR_GREEN = Curses::COLOR_MAGENTA unless defined? COLOR_GREEN
|
12
|
+
COLOR_YELLOW = Curses::COLOR_RED unless defined? COLOR_YELLOW
|
13
|
+
|
14
|
+
BACKGROUND = Curses::COLOR_WHITE unless defined? BACKGROUND
|
15
|
+
FONT = Curses::COLOR_BLACK unless defined? FONT
|
16
|
+
FONT_HEADING = Curses::COLOR_MAGENTA unless defined? FONT_HEADING
|
17
|
+
FONT_EMPHASIZE = Curses::COLOR_BLUE unless defined? FONT_EMPHASIZE
|
18
|
+
RED = Curses::COLOR_RED unless defined? RED
|
19
|
+
GREEN = Curses::COLOR_GREEN unless defined? GREEN
|
20
|
+
YELLOW = Curses::COLOR_YELLOW unless defined? YELLOW
|
21
|
+
|
22
|
+
def initialize(height = Curses.lines, width = Curses.cols, top = 0, left = 0)
|
23
|
+
super(height, width, top, left)
|
24
|
+
init_colors
|
25
|
+
end
|
26
|
+
|
27
|
+
def write(text, color = COLOR_TEXT, text_decoration = Curses::A_NORMAL )
|
28
|
+
self.attron(Curses.color_pair(color) | text_decoration) { self << text.to_s }
|
29
|
+
end
|
30
|
+
|
31
|
+
def emphasize(text, text_decoration = Curses::A_NORMAL)
|
32
|
+
write(text, Window::COLOR_TEXT_EMPHASIZE, text_decoration)
|
33
|
+
end
|
34
|
+
|
35
|
+
def heading(text, text_decoration = Curses::A_UNDERLINE)
|
36
|
+
write(text, Window::COLOR_HEADING, text_decoration)
|
37
|
+
end
|
38
|
+
|
39
|
+
def red(text, text_decoration = Curses::A_NORMAL, options = {})
|
40
|
+
colored(text, Window::COLOR_RED, text_decoration, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def yellow(text, text_decoration = Curses::A_NORMAL, options = {})
|
44
|
+
colored(text, Window::COLOR_YELLOW, text_decoration, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def green(text, text_decoration = Curses::A_NORMAL, options = {})
|
48
|
+
colored(text, Window::COLOR_GREEN, text_decoration, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
def colored(text, color, text_decoration = Curses::A_NORMAL, options = {})
|
52
|
+
if options[:full_line]
|
53
|
+
clear_line(
|
54
|
+
color: color,
|
55
|
+
text_decoration: Curses::A_STANDOUT,
|
56
|
+
start_pos: 1,
|
57
|
+
end_pos: maxx - 2
|
58
|
+
)
|
59
|
+
|
60
|
+
prefix = ' '
|
61
|
+
end
|
62
|
+
|
63
|
+
write("#{prefix}#{text}", color, text_decoration)
|
64
|
+
end
|
65
|
+
|
66
|
+
# clear_line(options = {})
|
67
|
+
# options: [:color, :text_decoration, :start_pos, :end_pos]
|
68
|
+
def clear_line(options = {})
|
69
|
+
color = options[:color] || COLOR_TEXT
|
70
|
+
text_decoration = options[:text_decoration] || Curses::A_NORMAL
|
71
|
+
start = options[:start_pos] || 0
|
72
|
+
stop = options[:end_pos] || maxx
|
73
|
+
|
74
|
+
x = curx
|
75
|
+
setpos(cury, start)
|
76
|
+
write((options[:text] || ' ') * (stop - 1), color, text_decoration)
|
77
|
+
setpos(cury, x)
|
78
|
+
refresh
|
79
|
+
end
|
80
|
+
|
81
|
+
def print_indicator(object, text = ' ', text_decoration = Curses::A_STANDOUT)
|
82
|
+
if object.respond_to?(:mastered?) && object.respond_to?(:started?)
|
83
|
+
if object.mastered?
|
84
|
+
green(text, text_decoration)
|
85
|
+
write ' '
|
86
|
+
elsif object.started?
|
87
|
+
yellow(text, text_decoration)
|
88
|
+
write ' '
|
89
|
+
else
|
90
|
+
red(text, text_decoration)
|
91
|
+
write ' '
|
92
|
+
end
|
93
|
+
elsif object.respond_to?(:mastered?)
|
94
|
+
if object.mastered?
|
95
|
+
green(text, text_decoration)
|
96
|
+
write ' '
|
97
|
+
else
|
98
|
+
red(text, text_decoration)
|
99
|
+
write ' '
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def print_markdown(text)
|
105
|
+
clear_line
|
106
|
+
|
107
|
+
h1 = /^\#{1}[^#]+/ # '# heading'
|
108
|
+
h2 = /^\#{2}[^#]+/ # '## sub heading'
|
109
|
+
bold = /(\*[^*]*\*)/ # '*text*'
|
110
|
+
line = /^-{3,}/ # '---' vertical line
|
111
|
+
code = /(\`*\`)/ # '`code line`'
|
112
|
+
ruby_doc_core = /(\(ruby-doc core:.*\))/ # '(ruby-doc core: Kernel#print)'
|
113
|
+
ruby_doc_stdlib = /(\(ruby-doc stdlib:.*\))/ # '(ruby-doc stdlib: CSV#Row::<<)'
|
114
|
+
|
115
|
+
case text
|
116
|
+
when h1
|
117
|
+
heading(text.gsub(/^#\s?/, ''))
|
118
|
+
when h2
|
119
|
+
text_decoration = Curses::A_UNDERLINE | Curses::A_NORMAL
|
120
|
+
emphasize(text.gsub(/^##\s?/, ''), text_decoration)
|
121
|
+
when (code || bold)
|
122
|
+
emphasized = false
|
123
|
+
highlighted = false
|
124
|
+
|
125
|
+
text.chars.each_with_index do |char, index|
|
126
|
+
if char == '*' && text[index - 1] != '\\'
|
127
|
+
emphasized = !emphasized
|
128
|
+
next
|
129
|
+
end
|
130
|
+
|
131
|
+
if char == '`'
|
132
|
+
highlighted = !highlighted
|
133
|
+
next
|
134
|
+
end
|
135
|
+
|
136
|
+
character = "#{text[index..(index + 1)]}" == '\\*' ? '' : char
|
137
|
+
|
138
|
+
if highlighted
|
139
|
+
red(character)
|
140
|
+
elsif emphasized
|
141
|
+
emphasize(character)
|
142
|
+
else
|
143
|
+
write(character)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
when bold
|
147
|
+
text.chars.each_with_index do |char, index|
|
148
|
+
if char == '*' && text[index - 1] != '\\'
|
149
|
+
emphasized = !emphasized
|
150
|
+
next
|
151
|
+
end
|
152
|
+
|
153
|
+
character = "#{text[index..(index + 1)]}" == '\\*' ? '' : char
|
154
|
+
emphasized ? emphasize(character) : write(character)
|
155
|
+
end
|
156
|
+
when line
|
157
|
+
write('-' * (Curses.cols - 2))
|
158
|
+
when ruby_doc_core
|
159
|
+
capture = text.match(/\(ruby-doc core:\s?(.*)\)/).captures.first
|
160
|
+
write text.gsub(ruby_doc_core, ruby_doc_core_link(capture))
|
161
|
+
when ruby_doc_stdlib
|
162
|
+
capture = text.match(/\(ruby-doc stdlib:\s?(.*)\)/).captures.first
|
163
|
+
write text.gsub(ruby_doc_stdlib, ruby_doc_stdlib_link(capture))
|
164
|
+
else
|
165
|
+
write(text.gsub(/(\\#)/, '#'))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
protected
|
170
|
+
|
171
|
+
def init_colors
|
172
|
+
Curses.start_color
|
173
|
+
Curses.init_pair(COLOR_TEXT, FONT, BACKGROUND)
|
174
|
+
Curses.init_pair(COLOR_TEXT_EMPHASIZE, FONT_EMPHASIZE, BACKGROUND)
|
175
|
+
Curses.init_pair(COLOR_HEADING, FONT_HEADING, BACKGROUND)
|
176
|
+
Curses.init_pair(COLOR_RED, RED, BACKGROUND)
|
177
|
+
Curses.init_pair(COLOR_GREEN, GREEN, BACKGROUND)
|
178
|
+
Curses.init_pair(COLOR_YELLOW, YELLOW, BACKGROUND)
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def ruby_doc_core_link(text)
|
184
|
+
base_url = "http://ruby-doc.org/core-#{RUBY_VERSION}"
|
185
|
+
class_part = ruby_doc_class_parts(text).join('/')
|
186
|
+
method = ruby_doc_method(text)
|
187
|
+
|
188
|
+
"#{base_url}/#{class_part}.html#{method}"
|
189
|
+
end
|
190
|
+
|
191
|
+
def ruby_doc_stdlib_link(text)
|
192
|
+
base_url = "http://ruby-doc.org/stdlib-#{RUBY_VERSION}"
|
193
|
+
class_parts = ruby_doc_class_parts(text)
|
194
|
+
libdoc_part = "libdoc/#{class_parts.first.downcase}/rdoc"
|
195
|
+
method = ruby_doc_method(text)
|
196
|
+
|
197
|
+
"#{base_url}/#{libdoc_part}/#{class_parts.join('/')}.html#{method}"
|
198
|
+
end
|
199
|
+
|
200
|
+
def ruby_doc_class_parts(text)
|
201
|
+
parts = text.split(/::|#/)
|
202
|
+
parts[0..(parts.count > 1 ? -2 : -1)]
|
203
|
+
end
|
204
|
+
|
205
|
+
def ruby_doc_method(text)
|
206
|
+
parts = text.split(/::|#/)
|
207
|
+
|
208
|
+
if parts.count > 1
|
209
|
+
method_type = text.match(/#/) ? 'i' : 'c'
|
210
|
+
method_name = CGI.escape(parts.last.strip).gsub('%', '-').gsub(/\A-/, '')
|
211
|
+
"#method-#{method_type}-#{method_name}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Belajar::Chapter do
|
4
|
+
|
5
|
+
it { is_expected.to respond_to :title }
|
6
|
+
it { is_expected.to respond_to :units }
|
7
|
+
it { is_expected.to respond_to :path }
|
8
|
+
|
9
|
+
it { is_expected.to respond_to :mastered? }
|
10
|
+
it { is_expected.to respond_to :started? }
|
11
|
+
|
12
|
+
let(:chapter_path) { chapter_dirs(course_dir_names.first).first }
|
13
|
+
|
14
|
+
before(:all) do
|
15
|
+
prepare_solutions
|
16
|
+
Belajar.config.solutions_path = solutions_basepath
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { Belajar::Chapter.new(chapter_path) }
|
20
|
+
|
21
|
+
it "has the prescribed title" do
|
22
|
+
expect(subject.title).to eq chapter_titles.first
|
23
|
+
end
|
24
|
+
|
25
|
+
it "has the prescribed path" do
|
26
|
+
expect(subject.path).to eq chapter_path
|
27
|
+
end
|
28
|
+
|
29
|
+
it "is not started by default" do
|
30
|
+
expect(subject.started?).to be_falsey
|
31
|
+
end
|
32
|
+
|
33
|
+
it "is not mastered by default" do
|
34
|
+
expect(subject.mastered?).to be_falsey
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#units" do
|
38
|
+
it "loads the prescribed number of units" do
|
39
|
+
course_name = course_dir_names.first
|
40
|
+
chapter_name = File.basename(chapter_path)
|
41
|
+
units_count = available_units(course_name, chapter_name).count
|
42
|
+
expect(subject.units.count).to eq units_count
|
43
|
+
end
|
44
|
+
|
45
|
+
it "lazy-loads the units" do
|
46
|
+
expect(subject.instance_variable_get(:@units)).to be_nil
|
47
|
+
subject.units
|
48
|
+
expect(subject.instance_variable_get(:@units)).not_to be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#started?" do
|
53
|
+
it "returns true if at least one unit has been verified" do
|
54
|
+
allow(subject.units.first).to receive(:mastered?) { true }
|
55
|
+
expect(subject.started?).to be true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns false if no unit has been verified" do
|
59
|
+
allow_any_instance_of(Belajar::Unit).to receive(:mastered?) { false }
|
60
|
+
expect(subject.started?).to be false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#mastered?" do
|
65
|
+
it "returns true if all units have been verified" do
|
66
|
+
subject.units.each { |unit| unit.solution.verify! }
|
67
|
+
expect(subject.mastered?).to be true
|
68
|
+
end
|
69
|
+
|
70
|
+
it "returns false unless all units have been verified" do
|
71
|
+
allow_any_instance_of(Belajar::Unit).to receive(:mastered?) { false }
|
72
|
+
allow(subject.units.first).to receive(:mastered?) { true }
|
73
|
+
expect(subject.mastered?).to be false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Belajar::Configuration do
|
4
|
+
|
5
|
+
subject { Belajar::Configuration.send(:new) }
|
6
|
+
|
7
|
+
it { is_expected.to respond_to :solutions_path }
|
8
|
+
it { is_expected.to respond_to :solutions_path= }
|
9
|
+
it { is_expected.to respond_to :courses_path }
|
10
|
+
it { is_expected.to respond_to :courses_path= }
|
11
|
+
it { is_expected.to respond_to :storage_file }
|
12
|
+
it { is_expected.to respond_to :save }
|
13
|
+
it { is_expected.to respond_to :import! }
|
14
|
+
it { is_expected.to respond_to :summary }
|
15
|
+
|
16
|
+
before do
|
17
|
+
subject.instance_variable_set(:@storage_file, local_storage_file)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#courses_path" do
|
21
|
+
it "returns the appropriate initial local courses path" do
|
22
|
+
courses_path = File.expand_path('~/.belajar/courses', __FILE__)
|
23
|
+
expect(subject.courses_path).to eq courses_path
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns the appropriate set courses path" do
|
27
|
+
subject.courses_path = local_courses_path
|
28
|
+
expect(subject.courses_path).to eq local_courses_path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#solutions_path=" do
|
33
|
+
it "raises an error if the given path is no existent dir" do
|
34
|
+
expect { subject.solutions_path = "no/existent/dir" }
|
35
|
+
.to raise_error(Belajar::ConfigurationError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#solutions_path" do
|
40
|
+
it "raises an error if not set" do
|
41
|
+
expect { subject.solutions_path }
|
42
|
+
.to raise_error(Belajar::ConfigurationError)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns the solutions path if set" do
|
46
|
+
subject.solutions_path = test_basepath
|
47
|
+
expect { subject.solutions_path }.not_to raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#storage_path" do
|
52
|
+
it "returns the appropriate path to the storage file" do
|
53
|
+
expect(subject.storage_file).to eq local_storage_file
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#save" do
|
58
|
+
it "saves the configured courses path to the belajar store" do
|
59
|
+
subject.courses_path = local_courses_path
|
60
|
+
subject.save
|
61
|
+
|
62
|
+
expect(QuickStore.store.courses_path).to eq local_courses_path
|
63
|
+
end
|
64
|
+
|
65
|
+
it "saves the configured solution_path to the belajar store" do
|
66
|
+
path = File.join(test_basepath, 'test_solutions')
|
67
|
+
FileUtils.makedirs(path)
|
68
|
+
subject.solutions_path = path
|
69
|
+
subject.save
|
70
|
+
|
71
|
+
expect(QuickStore.store.solutions_path).to eq path
|
72
|
+
end
|
73
|
+
|
74
|
+
it "does not save the storage file path" do
|
75
|
+
subject.save
|
76
|
+
expect(QuickStore.store.storage_file).to be_nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#import!" do
|
81
|
+
context "with non-existent belajar store entries:" do
|
82
|
+
before do
|
83
|
+
FileUtils.rm(local_storage_file) if File.exist?(local_storage_file)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "uses the default configuration" do
|
87
|
+
QuickStore.store.courses_path = nil
|
88
|
+
QuickStore.store.solutions_path = nil
|
89
|
+
subject.instance_variable_set(:@courses_path, local_courses_path)
|
90
|
+
|
91
|
+
loaded_config = subject.import!
|
92
|
+
|
93
|
+
expect(loaded_config.courses_path).to eq local_courses_path
|
94
|
+
expect { loaded_config.solutions_path }
|
95
|
+
.to raise_error Belajar::ConfigurationError
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "with existing belajar storage file:" do
|
100
|
+
it "returns a Belajar::Configuration" do
|
101
|
+
expect(subject.import!).to be_a Belajar::Configuration
|
102
|
+
end
|
103
|
+
|
104
|
+
it "loads the belajar store entries into the configuration" do
|
105
|
+
wanted_courses_path = "/courses/path"
|
106
|
+
wanted_solutions_path = solutions_basepath
|
107
|
+
temp_solutions_path = File.join(solutions_basepath, 'temp')
|
108
|
+
FileUtils.makedirs(wanted_solutions_path)
|
109
|
+
FileUtils.makedirs(temp_solutions_path)
|
110
|
+
|
111
|
+
# save wanted settings
|
112
|
+
subject.courses_path = wanted_courses_path
|
113
|
+
subject.solutions_path = wanted_solutions_path
|
114
|
+
subject.save
|
115
|
+
|
116
|
+
# overwrite in memory settings
|
117
|
+
subject.courses_path = '/some/other/path/'
|
118
|
+
subject.solutions_path = temp_solutions_path
|
119
|
+
|
120
|
+
# fetch stored settings
|
121
|
+
subject.import!
|
122
|
+
expect(File.exist?(local_storage_file)).to be_truthy
|
123
|
+
expect(subject.courses_path).to eq wanted_courses_path
|
124
|
+
expect(subject.solutions_path).to eq wanted_solutions_path
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe '#summary' do
|
130
|
+
before do
|
131
|
+
subject.courses_path = "wanted/courses/path"
|
132
|
+
subject.solutions_path = solutions_basepath
|
133
|
+
@summary = subject.summary
|
134
|
+
end
|
135
|
+
|
136
|
+
it "returns a string" do
|
137
|
+
expect(@summary).to be_a String
|
138
|
+
end
|
139
|
+
|
140
|
+
it "returns a string with all properties but @configuration_file" do
|
141
|
+
expect(@summary.lines.count).to eq subject.instance_variables.count - 1
|
142
|
+
end
|
143
|
+
|
144
|
+
it "returns a string including the courses path" do
|
145
|
+
expect(@summary =~ /courses path/).to be_truthy
|
146
|
+
end
|
147
|
+
|
148
|
+
it "returns a string including the courses path" do
|
149
|
+
expect(@summary =~ /solutions path/).to be_truthy
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#initial_course' do
|
154
|
+
it { is_expected.to respond_to :initial_course }
|
155
|
+
|
156
|
+
it "returns the initial course github repo partial path" do
|
157
|
+
expect(subject.initial_course).to eq 'wong-bejo/Get_started_with_Ruby'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|