belajar 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +5 -0
  6. data/README.md +5 -0
  7. data/Rakefile +5 -0
  8. data/belajar.gemspec +38 -0
  9. data/bin/belajar +12 -0
  10. data/lib/belajar.rb +24 -0
  11. data/lib/belajar/chapter.rb +23 -0
  12. data/lib/belajar/configuration.rb +89 -0
  13. data/lib/belajar/congratulator.rb +13 -0
  14. data/lib/belajar/course.rb +80 -0
  15. data/lib/belajar/exceptions.rb +19 -0
  16. data/lib/belajar/generator.rb +60 -0
  17. data/lib/belajar/github_client.rb +30 -0
  18. data/lib/belajar/loadable.rb +23 -0
  19. data/lib/belajar/loading/chapters.rb +9 -0
  20. data/lib/belajar/loading/courses.rb +9 -0
  21. data/lib/belajar/loading/units.rb +9 -0
  22. data/lib/belajar/reference_solution.rb +18 -0
  23. data/lib/belajar/solution.rb +53 -0
  24. data/lib/belajar/storeable.rb +32 -0
  25. data/lib/belajar/task.rb +10 -0
  26. data/lib/belajar/terminal.rb +12 -0
  27. data/lib/belajar/terminal/cli.rb +59 -0
  28. data/lib/belajar/terminal/courses.rb +179 -0
  29. data/lib/belajar/terminal/output.rb +78 -0
  30. data/lib/belajar/terminal/setup.rb +115 -0
  31. data/lib/belajar/terminal/solutions.rb +46 -0
  32. data/lib/belajar/terminal/texts/about.txt +19 -0
  33. data/lib/belajar/terminal/texts/congratulations.txt +12 -0
  34. data/lib/belajar/terminal/texts/courses_empty.txt +3 -0
  35. data/lib/belajar/terminal/texts/hint_course_download.txt +13 -0
  36. data/lib/belajar/terminal/texts/welcome.txt +12 -0
  37. data/lib/belajar/terminal/welcome.rb +98 -0
  38. data/lib/belajar/test.rb +46 -0
  39. data/lib/belajar/test_result.rb +86 -0
  40. data/lib/belajar/unit.rb +28 -0
  41. data/lib/belajar/version.rb +3 -0
  42. data/lib/belajar/views.rb +51 -0
  43. data/lib/belajar/views/chapters_menu.rb +60 -0
  44. data/lib/belajar/views/courses_menu.rb +52 -0
  45. data/lib/belajar/views/main_menu.rb +37 -0
  46. data/lib/belajar/views/menu.rb +89 -0
  47. data/lib/belajar/views/splash.rb +57 -0
  48. data/lib/belajar/views/task_view.rb +236 -0
  49. data/lib/belajar/views/top_bar.rb +40 -0
  50. data/lib/belajar/views/units_menu.rb +61 -0
  51. data/lib/belajar/window.rb +215 -0
  52. data/spec/belajar/chapter_spec.rb +76 -0
  53. data/spec/belajar/configuration_spec.rb +161 -0
  54. data/spec/belajar/congratulator_spec.rb +24 -0
  55. data/spec/belajar/course_spec.rb +201 -0
  56. data/spec/belajar/generator_spec.rb +82 -0
  57. data/spec/belajar/github_client_spec.rb +53 -0
  58. data/spec/belajar/loading/chapters_spec.rb +16 -0
  59. data/spec/belajar/loading/courses_spec.rb +16 -0
  60. data/spec/belajar/loading/units_spec.rb +21 -0
  61. data/spec/belajar/reference_solution_spec.rb +41 -0
  62. data/spec/belajar/solution_spec.rb +86 -0
  63. data/spec/belajar/storeable_spec.rb +35 -0
  64. data/spec/belajar/task_spec.rb +23 -0
  65. data/spec/belajar/terminal/cli_spec.rb +51 -0
  66. data/spec/belajar/terminal/courses_spec.rb +293 -0
  67. data/spec/belajar/terminal/output_spec.rb +151 -0
  68. data/spec/belajar/terminal/setup_spec.rb +10 -0
  69. data/spec/belajar/terminal/solutions_spec.rb +8 -0
  70. data/spec/belajar/terminal/welcome_spec.rb +12 -0
  71. data/spec/belajar/terminal_spec.rb +24 -0
  72. data/spec/belajar/test_example_spec.rb +54 -0
  73. data/spec/belajar/test_result_spec.rb +91 -0
  74. data/spec/belajar/test_spec.rb +48 -0
  75. data/spec/belajar/unit_spec.rb +85 -0
  76. data/spec/belajar/views/chapters_menu_spec.rb +6 -0
  77. data/spec/belajar/views/courses_menu_spec.rb +6 -0
  78. data/spec/belajar/views/menu_spec.rb +19 -0
  79. data/spec/belajar/views/task_view_spec.rb +7 -0
  80. data/spec/belajar/views/units_menu_spec.rb +6 -0
  81. data/spec/belajar/views_spec.rb +21 -0
  82. data/spec/belajar_spec.rb +51 -0
  83. data/spec/path_helpers_spec.rb +60 -0
  84. data/spec/resource_helpers_spec.rb +33 -0
  85. data/spec/spec_helper.rb +28 -0
  86. data/spec/support/macros/content_helpers.rb +129 -0
  87. data/spec/support/macros/mock_helpers.rb +25 -0
  88. data/spec/support/macros/path_helpers.rb +139 -0
  89. data/spec/support/macros/resource_helpers.rb +157 -0
  90. data/spec/support/macros/test_helpers.rb +6 -0
  91. 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