daigaku 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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