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
@@ -11,8 +11,8 @@ module Daigaku
11
11
  init_colors
12
12
  end
13
13
 
14
- def write(text, color = COLOR_TEXT, text_decoration = Curses::A_NORMAL )
15
- self.attron(Curses.color_pair(color) | text_decoration) { self << text.to_s }
14
+ def write(text, color = COLOR_TEXT, text_decoration = Curses::A_NORMAL)
15
+ attron(Curses.color_pair(color) | text_decoration) { self << text.to_s }
16
16
  end
17
17
 
18
18
  def emphasize(text, text_decoration = Curses::A_NORMAL)
@@ -50,13 +50,13 @@ module Daigaku
50
50
  write("#{prefix}#{text}", color, text_decoration)
51
51
  end
52
52
 
53
- # clear_line(options = {})
54
- # options: [:color, :text_decoration, :start_pos, :end_pos]
53
+ # clear_line(options = {})
54
+ # options: [:color, :text_decoration, :start_pos, :end_pos, :text]
55
55
  def clear_line(options = {})
56
- color = options[:color] || COLOR_TEXT
56
+ color = options[:color] || COLOR_TEXT
57
57
  text_decoration = options[:text_decoration] || Curses::A_NORMAL
58
- start = options[:start_pos] || 0
59
- stop = options[:end_pos] || maxx
58
+ start = options[:start_pos] || 0
59
+ stop = options[:end_pos] || maxx
60
60
 
61
61
  x = curx
62
62
  setpos(cury, start)
@@ -69,85 +69,27 @@ module Daigaku
69
69
  if object.respond_to?(:mastered?) && object.respond_to?(:started?)
70
70
  if object.mastered?
71
71
  green(text, text_decoration)
72
- write ' '
73
72
  elsif object.started?
74
73
  yellow(text, text_decoration)
75
- write ' '
76
74
  else
77
75
  red(text, text_decoration)
78
- write ' '
79
76
  end
80
77
  elsif object.respond_to?(:mastered?)
81
78
  if object.mastered?
82
79
  green(text, text_decoration)
83
- write ' '
84
80
  else
85
81
  red(text, text_decoration)
86
- write ' '
87
82
  end
88
83
  end
84
+
85
+ write ' '
89
86
  end
90
87
 
91
88
  def print_markdown(text)
92
89
  clear_line
93
90
 
94
- h1 = /^\#{1}[^#]+/ # '# heading'
95
- h2 = /^\#{2}[^#]+/ # '## sub heading'
96
- bold = /(\*[^*]*\*)/ # '*text*'
97
- line = /^-{3,}/ # '---' vertical line
98
- code = /(\`*\`)/ # '`code line`'
99
- ruby_doc_core = /(\(ruby-doc core:.*\))/ # '(ruby-doc core: Kernel#print)'
100
- ruby_doc_stdlib = /(\(ruby-doc stdlib:.*\))/ # '(ruby-doc stdlib: CSV#Row::<<)'
101
-
102
- text = Markdown::RubyDoc.parse(text)
103
-
104
- case text
105
- when h1
106
- heading(text.gsub(/^#\s?/, ''))
107
- when h2
108
- text_decoration = Curses::A_UNDERLINE | Curses::A_NORMAL
109
- emphasize(text.gsub(/^##\s?/, ''), text_decoration)
110
- when (code || bold)
111
- emphasized = false
112
- highlighted = false
113
-
114
- text.chars.each_with_index do |char, index|
115
- if char == '*' && text[index - 1] != '\\'
116
- emphasized = !emphasized
117
- next
118
- end
119
-
120
- if char == '`'
121
- highlighted = !highlighted
122
- next
123
- end
124
-
125
- character = "#{text[index..(index + 1)]}" == '\\*' ? '' : char
126
-
127
- if highlighted
128
- red(character)
129
- elsif emphasized
130
- emphasize(character)
131
- else
132
- write(character)
133
- end
134
- end
135
- when bold
136
- text.chars.each_with_index do |char, index|
137
- if char == '*' && text[index - 1] != '\\'
138
- emphasized = !emphasized
139
- next
140
- end
141
-
142
- character = "#{text[index..(index + 1)]}" == '\\*' ? '' : char
143
- emphasized ? emphasize(character) : write(character)
144
- end
145
- when line
146
- write('-' * (Curses.cols - 2))
147
- else
148
- write(text.gsub(/(\\#)/, '#'))
149
- end
91
+ printer = Markdown::Printer.new(window: self)
92
+ printer.print(text)
150
93
  end
151
-
152
94
  end
153
- end
95
+ end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Daigaku::Chapter do
4
-
5
4
  it { is_expected.to respond_to :title }
6
5
  it { is_expected.to respond_to :units }
7
6
  it { is_expected.to respond_to :path }
@@ -18,58 +17,64 @@ describe Daigaku::Chapter do
18
17
 
19
18
  subject { Daigaku::Chapter.new(chapter_path) }
20
19
 
21
- it "has the prescribed title" do
20
+ it 'has the prescribed title' do
22
21
  expect(subject.title).to eq chapter_titles.first
23
22
  end
24
23
 
25
- it "has the prescribed path" do
24
+ it 'has the prescribed path' do
26
25
  expect(subject.path).to eq chapter_path
27
26
  end
28
27
 
29
- it "is not started by default" do
28
+ it 'is not started by default' do
30
29
  expect(subject.started?).to be_falsey
31
30
  end
32
31
 
33
- it "is not mastered by default" do
32
+ it 'is not mastered by default' do
34
33
  expect(subject.mastered?).to be_falsey
35
34
  end
36
35
 
37
- describe "#units" do
38
- it "loads the prescribed number of units" do
36
+ describe '#units' do
37
+ it 'loads the prescribed number of units' do
39
38
  course_name = course_dir_names.first
40
39
  chapter_name = File.basename(chapter_path)
41
40
  units_count = available_units(course_name, chapter_name).count
42
41
  expect(subject.units.count).to eq units_count
43
42
  end
44
43
 
45
- it "lazy-loads the units" do
44
+ it 'lazy-loads the units' do
46
45
  expect(subject.instance_variable_get(:@units)).to be_nil
47
46
  subject.units
48
47
  expect(subject.instance_variable_get(:@units)).not_to be_nil
49
48
  end
50
49
  end
51
50
 
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 }
51
+ describe '#started?' do
52
+ it 'returns true if at least one unit has been verified' do
53
+ allow(subject.units.first).to receive(:mastered?).and_return(true)
55
54
  expect(subject.started?).to be true
56
55
  end
57
56
 
58
- it "returns false if no unit has been verified" do
59
- allow_any_instance_of(Daigaku::Unit).to receive(:mastered?) { false }
57
+ it 'returns false if no unit has been verified' do
58
+ allow_any_instance_of(Daigaku::Unit)
59
+ .to receive(:mastered?)
60
+ .and_return(false)
61
+
60
62
  expect(subject.started?).to be false
61
63
  end
62
64
  end
63
65
 
64
- describe "#mastered?" do
65
- it "returns true if all units have been verified" do
66
+ describe '#mastered?' do
67
+ it 'returns true if all units have been verified' do
66
68
  subject.units.each { |unit| unit.solution.verify! }
67
69
  expect(subject.mastered?).to be true
68
70
  end
69
71
 
70
- it "returns false unless all units have been verified" do
71
- allow_any_instance_of(Daigaku::Unit).to receive(:mastered?) { false }
72
- allow(subject.units.first).to receive(:mastered?) { true }
72
+ it 'returns false unless all units have been verified' do
73
+ allow_any_instance_of(Daigaku::Unit)
74
+ .to receive(:mastered?)
75
+ .and_return(false)
76
+
77
+ allow(subject.units.first).to receive(:mastered?).and_return(true)
73
78
  expect(subject.mastered?).to be false
74
79
  end
75
80
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Daigaku::Coloring do
4
-
5
4
  subject do
6
5
  class Example
7
6
  include Daigaku::Coloring
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Daigaku::Configuration do
4
-
5
4
  subject { Daigaku::Configuration.send(:new) }
6
5
 
7
6
  it { is_expected.to respond_to :solutions_path }
@@ -10,85 +9,90 @@ describe Daigaku::Configuration do
10
9
  it { is_expected.to respond_to :courses_path= }
11
10
  it { is_expected.to respond_to :storage_file }
12
11
  it { is_expected.to respond_to :save }
13
- it { is_expected.to respond_to :import! }
12
+ it { is_expected.to respond_to :import }
14
13
  it { is_expected.to respond_to :summary }
15
14
 
16
15
  before do
17
16
  subject.instance_variable_set(:@storage_file, local_storage_file)
17
+ File.open(local_storage_file, 'w')
18
18
  end
19
19
 
20
- describe "#courses_path" do
21
- it "returns the appropriate initial local courses path" do
20
+ describe '#courses_path' do
21
+ it 'returns the appropriate initial local courses path' do
22
22
  courses_path = File.expand_path('~/.daigaku/courses', __FILE__)
23
23
  expect(subject.courses_path).to eq courses_path
24
24
  end
25
25
 
26
- it "returns the appropriate set courses path" do
26
+ it 'returns the appropriate set courses path' do
27
27
  subject.courses_path = local_courses_path
28
28
  expect(subject.courses_path).to eq local_courses_path
29
29
  end
30
30
  end
31
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(Daigaku::ConfigurationError)
32
+ describe '#solutions_path=' do
33
+ context 'if the given path is no existent dir' do
34
+ it 'raises a configuration error' do
35
+ expect { subject.solutions_path = 'no/existent/dir' }
36
+ .to raise_error(Daigaku::ConfigurationError)
37
+ end
36
38
  end
37
39
  end
38
40
 
39
- describe "#solutions_path" do
40
- it "raises an error if not set" do
41
- expect { subject.solutions_path }
42
- .to raise_error(Daigaku::ConfigurationError)
41
+ describe '#solutions_path' do
42
+ context 'if not set' do
43
+ it 'raises an error' do
44
+ expect { subject.solutions_path }
45
+ .to raise_error(Daigaku::ConfigurationError)
46
+ end
43
47
  end
44
48
 
45
- it "returns the solutions path if set" do
46
- subject.solutions_path = test_basepath
47
- expect { subject.solutions_path }.not_to raise_error
49
+ context 'if set' do
50
+ it 'returns the solutions path' do
51
+ subject.solutions_path = test_basepath
52
+ expect(subject.solutions_path).to eq test_basepath
53
+ end
48
54
  end
49
55
  end
50
56
 
51
- describe "#storage_path" do
52
- it "returns the appropriate path to the storage file" do
57
+ describe '#storage_path' do
58
+ it 'returns the appropriate path to the storage file' do
53
59
  expect(subject.storage_file).to eq local_storage_file
54
60
  end
55
61
  end
56
62
 
57
- describe "#save" do
58
- it "saves the configured courses path to the daigaku store" do
63
+ describe '#save' do
64
+ it 'saves the configured courses path to the daigaku store' do
59
65
  subject.courses_path = local_courses_path
60
66
  subject.save
61
67
 
62
68
  expect(QuickStore.store.courses_path).to eq local_courses_path
63
69
  end
64
70
 
65
- it "saves the configured solution_path to the daigaku store" do
71
+ it 'saves the configured solution_path to the daigaku store' do
66
72
  path = File.join(test_basepath, 'test_solutions')
67
- FileUtils.makedirs(path)
73
+ create_directory(path)
68
74
  subject.solutions_path = path
69
75
  subject.save
70
76
 
71
77
  expect(QuickStore.store.solutions_path).to eq path
72
78
  end
73
79
 
74
- it "does not save the storage file path" do
80
+ it 'does not save the storage file path' do
75
81
  subject.save
76
82
  expect(QuickStore.store.storage_file).to be_nil
77
83
  end
78
84
  end
79
85
 
80
- describe "#import!" do
81
- context "with non-existent daigaku store entries:" do
82
- before do
83
- FileUtils.rm(local_storage_file) if File.exist?(local_storage_file)
84
- end
86
+ describe '#import' do
87
+ context 'with non-existent daigaku store entries:' do
88
+ before { remove_file(local_storage_file) }
85
89
 
86
- it "uses the default configuration" do
87
- QuickStore.store.courses_path = nil
90
+ it 'uses the default configuration' do
91
+ QuickStore.store.courses_path = nil
88
92
  QuickStore.store.solutions_path = nil
89
93
  subject.instance_variable_set(:@courses_path, local_courses_path)
90
94
 
91
- loaded_config = subject.import!
95
+ loaded_config = subject.import
92
96
 
93
97
  expect(loaded_config.courses_path).to eq local_courses_path
94
98
  expect { loaded_config.solutions_path }
@@ -96,17 +100,18 @@ describe Daigaku::Configuration do
96
100
  end
97
101
  end
98
102
 
99
- context "with existing daigaku storage file:" do
100
- it "returns a Daigaku::Configuration" do
101
- expect(subject.import!).to be_a Daigaku::Configuration
103
+ context 'with existing daigaku storage file:' do
104
+ it 'returns a Daigaku::Configuration' do
105
+ expect(subject.import).to be_a Daigaku::Configuration
102
106
  end
103
107
 
104
- it "loads the daigaku store entries into the configuration" do
105
- wanted_courses_path = "/courses/path"
108
+ it 'loads the daigaku store entries into the configuration' do
109
+ wanted_courses_path = '/courses/path'
106
110
  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)
111
+ temp_solutions_path = File.join(solutions_basepath, 'temp')
112
+
113
+ create_directory(wanted_solutions_path)
114
+ create_directory(temp_solutions_path)
110
115
 
111
116
  # save wanted settings
112
117
  subject.courses_path = wanted_courses_path
@@ -114,11 +119,11 @@ describe Daigaku::Configuration do
114
119
  subject.save
115
120
 
116
121
  # overwrite in memory settings
117
- subject.courses_path = '/some/other/path/'
122
+ subject.courses_path = '/some/other/path/'
118
123
  subject.solutions_path = temp_solutions_path
119
124
 
120
125
  # fetch stored settings
121
- subject.import!
126
+ subject.import
122
127
  expect(File.exist?(local_storage_file)).to be_truthy
123
128
  expect(subject.courses_path).to eq wanted_courses_path
124
129
  expect(subject.solutions_path).to eq wanted_solutions_path
@@ -128,34 +133,33 @@ describe Daigaku::Configuration do
128
133
 
129
134
  describe '#summary' do
130
135
  before do
131
- subject.courses_path = "wanted/courses/path"
136
+ subject.courses_path = 'wanted/courses/path'
132
137
  subject.solutions_path = solutions_basepath
133
- @summary = subject.summary
138
+ @summary = subject.summary
134
139
  end
135
140
 
136
- it "returns a string" do
141
+ it 'returns a string' do
137
142
  expect(@summary).to be_a String
138
143
  end
139
144
 
140
- it "returns a string with all properties but @configuration_file" do
145
+ it 'returns a string with all properties but @configuration_file' do
141
146
  expect(@summary.lines.count).to eq subject.instance_variables.count - 1
142
147
  end
143
148
 
144
- it "returns a string including the courses path" do
149
+ it 'returns a string including the courses path' do
145
150
  expect(@summary =~ /courses path/).to be_truthy
146
151
  end
147
152
 
148
- it "returns a string including the courses path" do
153
+ it 'returns a string including the courses path' do
149
154
  expect(@summary =~ /solutions path/).to be_truthy
150
155
  end
151
156
  end
152
157
 
153
158
  describe '#initial_course' do
154
- it { is_expected.to respond_to :initial_course }
159
+ it { is_expected.to respond_to :initial_course }
155
160
 
156
- it "returns the initial course github repo partial path" do
161
+ it 'returns the initial course github repo partial path' do
157
162
  expect(subject.initial_course).to eq 'daigaku-ruby/Get_started_with_Ruby'
158
163
  end
159
164
  end
160
-
161
165
  end
@@ -1,23 +1,26 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Daigaku::Congratulator do
4
-
5
- it "responds to #message" do
4
+ it 'responds to #message' do
6
5
  expect(Daigaku::Congratulator).to respond_to :message
7
6
  end
8
7
 
9
- describe "#message" do
10
- it "returns a string" do
8
+ describe '#message' do
9
+ it 'returns a string' do
11
10
  expect(Daigaku::Congratulator.message).to be_a String
12
11
  end
13
12
 
14
- it "returns a random congratulation method" do
15
- messages = 1.upto(10).map { |i| Daigaku::Congratulator.message }
13
+ it 'returns a random congratulation method' do
14
+ messages = 1.upto(10).map { |_| Daigaku::Congratulator.message }
16
15
  expect(messages.uniq.count).to be > 1
17
16
  end
18
17
 
19
- it "receives the congratulation texts from a Terminal text" do
20
- expect(Daigaku::Terminal).to receive(:text).with(:congratulations) { '' }
18
+ it 'receives the congratulation texts from a Terminal text' do
19
+ expect(Daigaku::Terminal)
20
+ .to receive(:text)
21
+ .with(:congratulations)
22
+ .and_return('')
23
+
21
24
  Daigaku::Congratulator.message
22
25
  end
23
26
  end