daigaku 0.3.0 → 0.4.0

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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -3
  3. data/README.md +1 -1
  4. data/daigaku.gemspec +23 -26
  5. data/lib/daigaku.rb +0 -1
  6. data/lib/daigaku/chapter.rb +3 -4
  7. data/lib/daigaku/coloring.rb +13 -13
  8. data/lib/daigaku/configuration.rb +25 -28
  9. data/lib/daigaku/congratulator.rb +17 -5
  10. data/lib/daigaku/course.rb +9 -8
  11. data/lib/daigaku/exceptions.rb +0 -2
  12. data/lib/daigaku/generator.rb +13 -13
  13. data/lib/daigaku/github_client.rb +4 -4
  14. data/lib/daigaku/loadable.rb +11 -15
  15. data/lib/daigaku/loading/chapters.rb +0 -2
  16. data/lib/daigaku/loading/courses.rb +0 -2
  17. data/lib/daigaku/loading/units.rb +0 -2
  18. data/lib/daigaku/markdown.rb +1 -0
  19. data/lib/daigaku/markdown/printer.rb +89 -0
  20. data/lib/daigaku/markdown/ruby_doc.rb +6 -8
  21. data/lib/daigaku/solution.rb +18 -15
  22. data/lib/daigaku/storeable.rb +11 -12
  23. data/lib/daigaku/task.rb +1 -1
  24. data/lib/daigaku/terminal.rb +3 -4
  25. data/lib/daigaku/terminal/cli.rb +6 -8
  26. data/lib/daigaku/terminal/courses.rb +19 -16
  27. data/lib/daigaku/terminal/output.rb +0 -2
  28. data/lib/daigaku/terminal/setup.rb +13 -18
  29. data/lib/daigaku/terminal/solutions.rb +27 -32
  30. data/lib/daigaku/terminal/welcome.rb +9 -11
  31. data/lib/daigaku/test.rb +7 -10
  32. data/lib/daigaku/test_result.rb +13 -16
  33. data/lib/daigaku/unit.rb +1 -3
  34. data/lib/daigaku/version.rb +1 -1
  35. data/lib/daigaku/views.rb +4 -3
  36. data/lib/daigaku/views/chapters_menu.rb +16 -20
  37. data/lib/daigaku/views/courses_menu.rb +12 -15
  38. data/lib/daigaku/views/main_menu.rb +23 -23
  39. data/lib/daigaku/views/menu.rb +9 -13
  40. data/lib/daigaku/views/splash.rb +11 -13
  41. data/lib/daigaku/views/subscriber.rb +38 -0
  42. data/lib/daigaku/views/task_view.rb +80 -78
  43. data/lib/daigaku/views/top_bar.rb +4 -10
  44. data/lib/daigaku/views/units_menu.rb +16 -21
  45. data/lib/daigaku/window.rb +12 -70
  46. data/spec/daigaku/chapter_spec.rb +23 -18
  47. data/spec/daigaku/coloring_spec.rb +0 -1
  48. data/spec/daigaku/configuration_spec.rb +54 -50
  49. data/spec/daigaku/congratulator_spec.rb +11 -8
  50. data/spec/daigaku/course_spec.rb +70 -51
  51. data/spec/daigaku/generator_spec.rb +24 -25
  52. data/spec/daigaku/github_client_spec.rb +17 -18
  53. data/spec/daigaku/loading/chapters_spec.rb +2 -3
  54. data/spec/daigaku/loading/courses_spec.rb +2 -3
  55. data/spec/daigaku/loading/units_spec.rb +4 -5
  56. data/spec/daigaku/markdown/ruby_doc_spec.rb +3 -6
  57. data/spec/daigaku/reference_solution_spec.rb +8 -10
  58. data/spec/daigaku/solution_spec.rb +18 -20
  59. data/spec/daigaku/storeable_spec.rb +12 -10
  60. data/spec/daigaku/task_spec.rb +3 -4
  61. data/spec/daigaku/terminal/cli_spec.rb +29 -21
  62. data/spec/daigaku/terminal/courses_spec.rb +104 -99
  63. data/spec/daigaku/terminal/output_spec.rb +44 -39
  64. data/spec/daigaku/terminal/setup_spec.rb +1 -3
  65. data/spec/daigaku/terminal/solutions_spec.rb +0 -2
  66. data/spec/daigaku/terminal/welcome_spec.rb +0 -2
  67. data/spec/daigaku/terminal_spec.rb +5 -7
  68. data/spec/daigaku/test_example_spec.rb +16 -14
  69. data/spec/daigaku/test_result_spec.rb +21 -25
  70. data/spec/daigaku/test_spec.rb +11 -12
  71. data/spec/daigaku/unit_spec.rb +24 -27
  72. data/spec/daigaku/views/chapters_menu_spec.rb +0 -1
  73. data/spec/daigaku/views/courses_menu_spec.rb +0 -1
  74. data/spec/daigaku/views/menu_spec.rb +1 -2
  75. data/spec/daigaku/views/task_view_spec.rb +0 -2
  76. data/spec/daigaku/views/units_menu_spec.rb +0 -1
  77. data/spec/daigaku/views_spec.rb +0 -1
  78. data/spec/daigaku_spec.rb +9 -12
  79. data/spec/path_helpers_spec.rb +11 -12
  80. data/spec/resource_helpers_spec.rb +11 -12
  81. data/spec/spec_helper.rb +3 -4
  82. data/spec/support/macros/content_helpers.rb +16 -17
  83. data/spec/support/macros/mock_helpers.rb +6 -6
  84. data/spec/support/macros/path_helpers.rb +15 -15
  85. data/spec/support/macros/resource_helpers.rb +34 -35
  86. metadata +12 -10
@@ -2,7 +2,6 @@ require 'wisper'
2
2
 
3
3
  module Daigaku
4
4
  module Views
5
-
6
5
  class Menu
7
6
  include Views
8
7
  include Wisper::Publisher
@@ -12,7 +11,9 @@ module Daigaku
12
11
  'Enter menu with *RETURN*',
13
12
  'Go back with *BACKSPACE*',
14
13
  'Exit with *ESC*'
15
- ].join(' | ')
14
+ ].join(' | ').freeze
15
+
16
+ attr_writer :items_info
16
17
 
17
18
  def initialize
18
19
  @position = 0
@@ -46,13 +47,13 @@ module Daigaku
46
47
  def draw(window, active_index = 0)
47
48
  window.attrset(A_NORMAL)
48
49
  window.setpos(0, 1)
49
- window.print_markdown header_text
50
+ window.print_markdown(header_text)
50
51
 
51
52
  items.each_with_index do |item, index|
52
53
  window.setpos(index + 2, 1)
53
54
  window.print_indicator(models[index])
54
55
  window.attrset(index == active_index ? A_STANDOUT : A_NORMAL)
55
- window.write " #{item.to_s} "
56
+ window.write " #{item} "
56
57
  window.attrset(A_NORMAL)
57
58
  window.write " #{items_info[index].try(:join, ' ')}"
58
59
  end
@@ -61,29 +62,24 @@ module Daigaku
61
62
  end
62
63
 
63
64
  def interact_with(window)
64
- raise "Please implement the method #interact_with!"
65
+ raise 'Please implement the method #interact_with!'
65
66
  end
66
67
 
67
68
  def models
68
- raise "Please implement the method #models!"
69
+ raise 'Please implement the method #models!'
69
70
  end
70
71
 
71
72
  def items
72
- raise "Please implement the method #items!"
73
+ raise 'Please implement the method #items!'
73
74
  end
74
75
 
75
76
  def header_text
76
- raise "Please implement the method #header_text!"
77
+ raise 'Please implement the method #header_text!'
77
78
  end
78
79
 
79
80
  def items_info
80
81
  @items_info || []
81
82
  end
82
-
83
- def items_info=(items_info)
84
- @items_info = items_info
85
- end
86
83
  end
87
-
88
84
  end
89
85
  end
@@ -1,14 +1,12 @@
1
1
  module Daigaku
2
2
  module Views
3
-
4
3
  class Splash
5
4
  include Views
6
5
 
7
6
  def initialize
8
- title = "DAIGAKU"
9
- subtitle = "Learning the Ruby programming language dead easy."
10
-
11
- panel = default_window
7
+ title = 'DAIGAKU'
8
+ subtitle = 'Learning the Ruby programming language dead easy.'
9
+ panel = default_window
12
10
 
13
11
  lines.times do |line|
14
12
  panel.setpos(line, 0)
@@ -43,15 +41,15 @@ module Daigaku
43
41
 
44
42
  def ruby_ascii_art
45
43
  [
46
- " ___________ ",
47
- " /.\\ /.\\ /.\\ ",
48
- "/___\\/___\\/___\\",
49
- " \\ \\ . / . / ",
50
- " \\ \\ ./ ./ ",
51
- " \\\\ / / ",
52
- " \\./ "
44
+ ' ___________ ',
45
+ ' /.\\ /.\\ /.\\ ',
46
+ '/___\\/___\\/___\\',
47
+ ' \\ \\ . / . / ',
48
+ ' \\ \\ ./ ./ ',
49
+ ' \\\\ / / ',
50
+ ' \\./ '
53
51
  ]
54
52
  end
55
53
  end
56
54
  end
57
- end
55
+ end
@@ -0,0 +1,38 @@
1
+ module Daigaku
2
+ module Views
3
+ class Subscriber
4
+ attr_reader :courses_menu, :chapters_menu, :units_menu, :task_view
5
+
6
+ def initialize(courses_menu:, chapters_menu:, units_menu:, task_view:)
7
+ @courses_menu = courses_menu
8
+ @chapters_menu = chapters_menu
9
+ @units_menu = units_menu
10
+ @task_view = task_view
11
+ end
12
+
13
+ def subscribe_events!
14
+ subscribe_top_down_navigation
15
+ subscribe_bottom_up_navigation
16
+ subscribe_menu_position_reset
17
+ end
18
+
19
+ def subscribe_top_down_navigation
20
+ courses_menu.subscribe(chapters_menu, on: :enter)
21
+ chapters_menu.subscribe(units_menu, on: :enter)
22
+ units_menu.subscribe(task_view, on: :enter)
23
+ end
24
+
25
+ def subscribe_bottom_up_navigation
26
+ chapters_menu.subscribe(courses_menu, on: :reenter)
27
+ units_menu.subscribe(chapters_menu, on: :reenter)
28
+ task_view.subscribe(units_menu, on: :reenter)
29
+ end
30
+
31
+ def subscribe_menu_position_reset
32
+ courses_menu.subscribe(chapters_menu, on: :reset_menu_position)
33
+ courses_menu.subscribe(units_menu, on: :reset_menu_position)
34
+ chapters_menu.subscribe(units_menu, on: :reset_menu_position)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,41 +1,41 @@
1
+ require 'wisper'
2
+ require 'os'
3
+
1
4
  module Daigaku
2
5
  module Views
3
- require 'wisper'
4
- require 'os'
5
-
6
6
  class TaskView
7
7
  include Views
8
8
  include Wisper::Publisher
9
9
 
10
10
  TOP_BAR_TEXT = [
11
- 'Scroll with *UP KEY* and *DOWN KEY*',
12
- 'Open solution file with *o*',
13
- 'Verify solution with *v*',
14
- 'Clear validation with *c*',
15
- 'Exit with *ESC*'
16
- ].join(' | ')
11
+ 'Scroll with *UP KEY* and *DOWN KEY*',
12
+ 'Open solution file with *o*',
13
+ 'Verify solution with *v*',
14
+ 'Clear validation with *c*',
15
+ 'Exit with *ESC*'
16
+ ].join(' | ').freeze
17
17
 
18
18
  def initialize
19
19
  @lines = []
20
- @top = nil
20
+ @top = nil
21
21
  end
22
22
 
23
23
  def enter(course, chapter, unit)
24
- @course = course
24
+ @course = course
25
25
  @chapter = chapter
26
- @unit = unit
26
+ @unit = unit
27
27
 
28
28
  @test_result_lines = nil
29
- @lines = @unit.task.markdown.lines
30
- @top_bar_height = 4
31
- @head_height = 2
29
+ @lines = @unit.task.markdown.lines
30
+ @top_bar_height = 4
31
+ @head_height = 2
32
32
 
33
33
  initialize_window(@lines.count + @top_bar_height + @head_height)
34
34
  end
35
35
 
36
36
  private
37
37
 
38
- def set_head(window)
38
+ def print_head(window)
39
39
  window.setpos(0, 1)
40
40
  window.clear_line
41
41
 
@@ -55,7 +55,7 @@ module Daigaku
55
55
  def draw(window)
56
56
  @top = 0
57
57
  window.attrset(A_NORMAL)
58
- set_head(window)
58
+ print_head(window)
59
59
 
60
60
  @lines.each_with_index do |line, index|
61
61
  window.setpos(index + 2, 1)
@@ -67,24 +67,23 @@ module Daigaku
67
67
  end
68
68
 
69
69
  def scroll_up(window)
70
- if @top > 0
71
- window.scrl(-1)
72
- set_head(window)
70
+ return unless @top > 0
73
71
 
74
- @top -= 1
75
- line = @lines[@top]
72
+ window.scrl(-1)
73
+ print_head(window)
76
74
 
77
- if line
78
- window.setpos(2, 1)
79
- print_line(window, line, @top)
80
- end
81
- end
75
+ @top -= 1
76
+ line = @lines[@top]
77
+
78
+ return unless line
79
+ window.setpos(2, 1)
80
+ print_line(window, line, @top)
82
81
  end
83
82
 
84
83
  def scroll_down(window)
85
84
  if @top + Curses.lines <= @lines.count + @top_bar_height + @head_height
86
85
  window.scrl(1)
87
- set_head(window)
86
+ print_head(window)
88
87
 
89
88
  @top += 1
90
89
  line = @lines[@top + window.maxy - 1]
@@ -125,47 +124,47 @@ module Daigaku
125
124
  scrollable = true
126
125
 
127
126
  case char
128
- when 'v' # verify
129
- print_test_results(window)
130
- return
131
- when 'c' # clear
132
- reset_screen(window)
133
- return
134
- when 'o' # open solution file
135
- open_editor(@unit.solution.path)
136
- when Curses::KEY_DOWN, Curses::KEY_CTRL_N
137
- scrollable = scroll_down(window)
138
- when Curses::KEY_UP, Curses::KEY_CTRL_P
139
- scrollable = scroll_up(window)
140
- when Curses::KEY_NPAGE, ?\s # white space
141
- 0.upto(window.maxy - 2) do |n|
142
- scrolled = scroll_down(window)
143
-
144
- unless scrolled
145
- scrollable = false if n == 0
146
- break
147
- end
148
- end
149
- when Curses::KEY_PPAGE
150
- 0.upto(window.maxy - 2) do |n|
151
- scrolled = scroll_up(window)
152
-
153
- unless scrolled
154
- scrollable = false if n == 0
155
- break
156
- end
157
- end
158
- when Curses::KEY_LEFT, Curses::KEY_CTRL_T
159
- while scroll_up(window)
127
+ when 'v' # verify
128
+ print_test_results
129
+ return
130
+ when 'c' # clear
131
+ reset_screen
132
+ return
133
+ when 'o' # open solution file
134
+ open_editor(@unit.solution.path)
135
+ when Curses::KEY_DOWN, Curses::KEY_CTRL_N
136
+ scrollable = scroll_down(window)
137
+ when Curses::KEY_UP, Curses::KEY_CTRL_P
138
+ scrollable = scroll_up(window)
139
+ when Curses::KEY_NPAGE, '?\s' # white space
140
+ 0.upto(window.maxy - 2) do |n|
141
+ scrolled = scroll_down(window)
142
+
143
+ unless scrolled
144
+ scrollable = false if n == 0
145
+ break
160
146
  end
161
- when Curses::KEY_RIGHT, Curses::KEY_CTRL_B
162
- while scroll_down(window)
147
+ end
148
+ when Curses::KEY_PPAGE
149
+ 0.upto(window.maxy - 2) do |n|
150
+ scrolled = scroll_up(window)
151
+
152
+ unless scrolled
153
+ scrollable = false if n == 0
154
+ break
163
155
  end
164
- when Curses::KEY_BACKSPACE
165
- broadcast(:reenter, @course, @chapter, @unit)
166
- return
167
- when 27 # ESC
168
- exit
156
+ end
157
+ when Curses::KEY_LEFT, Curses::KEY_CTRL_T
158
+ while scroll_up(window)
159
+ end
160
+ when Curses::KEY_RIGHT, Curses::KEY_CTRL_B
161
+ while scroll_down(window)
162
+ end
163
+ when Curses::KEY_BACKSPACE
164
+ broadcast(:reenter, @course, @chapter, @unit)
165
+ return
166
+ when 27 # ESC
167
+ exit
169
168
  end
170
169
 
171
170
  Curses.beep unless scrollable
@@ -184,8 +183,8 @@ module Daigaku
184
183
  end
185
184
  end
186
185
 
187
- def print_test_results(window)
188
- result = @unit.solution.verify!
186
+ def print_test_results
187
+ result = @unit.solution.verify!
189
188
  @test_result_lines = test_result_lines(result)
190
189
 
191
190
  if result.passed?
@@ -193,7 +192,7 @@ module Daigaku
193
192
 
194
193
  unless code_lines.empty?
195
194
  code_lines.map! { |line| " #{line}" }
196
- code_lines.unshift('', "Reference code:", '')
195
+ code_lines.unshift('', 'Reference code:', '')
197
196
  end
198
197
 
199
198
  @test_result_lines += code_lines
@@ -203,13 +202,15 @@ module Daigaku
203
202
  @examples = result.examples
204
203
 
205
204
  @example_heights = @examples.reduce({}) do |hash, example|
206
- start = hash.values.reduce(0) { |sum, r| sum += r.count }
205
+ start = hash.values.reduce(0) { |sum, results| sum + results.count }
207
206
  range = (start..(start + example.message.split("\n").count) + 2)
208
207
  hash[hash.keys.count] = range
209
208
  hash
210
209
  end
211
210
 
212
- height = [@lines.count + @top_bar_height + @head_height, Curses.lines].max
211
+ lines_count = @lines.count + @top_bar_height + @head_height
212
+ height = [lines_count, Curses.lines].max
213
+
213
214
  initialize_window(height)
214
215
  end
215
216
 
@@ -222,17 +223,19 @@ module Daigaku
222
223
  def code_error_lines(code)
223
224
  begin
224
225
  eval(code)
225
- rescue Exception => e
226
- return e.inspect.gsub(/(^.*#<|>.*$)/, '').lines.map(&:rstrip)
226
+ rescue StandardError => e
227
+ return e.inspect.gsub(/(\A.*#<|>.*$)/, '').lines.map(&:rstrip)
227
228
  end
228
229
 
229
230
  []
230
231
  end
231
232
 
232
- def reset_screen(window)
233
+ def reset_screen
233
234
  @test_result_lines = nil
234
- @lines = @unit.task.markdown.lines
235
- height = [@lines.count + @top_bar_height + @head_height, Curses.lines].max
235
+ @lines = @unit.task.markdown.lines
236
+ lines_count = @lines.count + @top_bar_height + @head_height
237
+ height = [lines_count, Curses.lines].max
238
+
236
239
  initialize_window(height)
237
240
  end
238
241
 
@@ -247,6 +250,5 @@ module Daigaku
247
250
  heights.values.index { |range| range.include?(index) }.to_i
248
251
  end
249
252
  end
250
-
251
253
  end
252
254
  end
@@ -1,6 +1,5 @@
1
1
  module Daigaku
2
2
  module Views
3
-
4
3
  class TopBar
5
4
  include Curses
6
5
 
@@ -10,8 +9,8 @@ module Daigaku
10
9
 
11
10
  def initialize(window, text = '')
12
11
  @height = HEIGHT
13
- @width = window.maxx
14
- @panel = create_panel(window, @width, @height, text)
12
+ @width = window.maxx
13
+ @panel = create_panel(window, @width, @height, text)
15
14
  end
16
15
 
17
16
  def show
@@ -21,7 +20,7 @@ module Daigaku
21
20
  private
22
21
 
23
22
  def create_panel(window, width, height, text)
24
- panel = window.subwin(height, window.maxx, 0, 0)
23
+ panel = window.subwin(height, width, 0, 0)
25
24
 
26
25
  panel.setpos(1, 1)
27
26
  panel.print_markdown(text)
@@ -30,11 +29,6 @@ module Daigaku
30
29
 
31
30
  panel
32
31
  end
33
-
34
- def emphasized(panel, text)
35
- panel.write(text, Window::COLOR_2)
36
- end
37
32
  end
38
-
39
33
  end
40
- end
34
+ end
@@ -2,21 +2,18 @@ require 'daigaku/views/menu'
2
2
 
3
3
  module Daigaku
4
4
  module Views
5
-
6
5
  class UnitsMenu < Menu
7
-
8
6
  private
9
7
 
10
8
  def before_enter(*args)
11
- @course = args[0]
9
+ @course = args[0]
12
10
  @chapter = args[1]
13
11
  end
14
12
 
15
13
  def before_reenter(*args)
16
- @course = args[0]
17
- @chapter = args[1]
18
- @unit = args[2]
19
-
14
+ @course = args[0]
15
+ @chapter = args[1]
16
+ @unit = args[2]
20
17
  @position = @chapter.units.find_index(@unit)
21
18
  end
22
19
 
@@ -27,18 +24,18 @@ module Daigaku
27
24
  def interact_with(window)
28
25
  while char = window.getch
29
26
  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
27
+ when KEY_UP
28
+ @position -= 1
29
+ when KEY_DOWN
30
+ @position += 1
31
+ when 10 # Enter
32
+ broadcast(:enter, @course, @chapter, models[@position])
33
+ return
34
+ when 263 # Backspace
35
+ broadcast(:reenter, @course, @chapter)
36
+ return
37
+ when 27 # ESC
38
+ exit
42
39
  end
43
40
 
44
41
  @position = items.length - 1 if @position < 0
@@ -54,8 +51,6 @@ module Daigaku
54
51
  def items
55
52
  models.map(&:title)
56
53
  end
57
-
58
54
  end
59
-
60
55
  end
61
56
  end