belajar 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 +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
|