daigaku 0.0.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.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +4 -0
  4. data/Guardfile +5 -0
  5. data/README.md +62 -0
  6. data/Rakefile +2 -0
  7. data/bin/daigaku +12 -0
  8. data/daigaku.gemspec +37 -0
  9. data/lib/daigaku.rb +27 -0
  10. data/lib/daigaku/chapter.rb +23 -0
  11. data/lib/daigaku/configuration.rb +86 -0
  12. data/lib/daigaku/course.rb +23 -0
  13. data/lib/daigaku/database.rb +64 -0
  14. data/lib/daigaku/exceptions.rb +19 -0
  15. data/lib/daigaku/generator.rb +53 -0
  16. data/lib/daigaku/loadable.rb +23 -0
  17. data/lib/daigaku/loading/chapters.rb +9 -0
  18. data/lib/daigaku/loading/courses.rb +9 -0
  19. data/lib/daigaku/loading/units.rb +9 -0
  20. data/lib/daigaku/reference_solution.rb +10 -0
  21. data/lib/daigaku/solution.rb +42 -0
  22. data/lib/daigaku/task.rb +10 -0
  23. data/lib/daigaku/terminal.rb +11 -0
  24. data/lib/daigaku/terminal/cli.rb +59 -0
  25. data/lib/daigaku/terminal/courses.rb +114 -0
  26. data/lib/daigaku/terminal/output.rb +72 -0
  27. data/lib/daigaku/terminal/setup.rb +115 -0
  28. data/lib/daigaku/terminal/solutions.rb +46 -0
  29. data/lib/daigaku/terminal/texts/about.txt +19 -0
  30. data/lib/daigaku/terminal/texts/courses_empty.txt +3 -0
  31. data/lib/daigaku/terminal/texts/hint_course_download.txt +13 -0
  32. data/lib/daigaku/terminal/texts/welcome.txt +12 -0
  33. data/lib/daigaku/terminal/welcome.rb +98 -0
  34. data/lib/daigaku/test.rb +46 -0
  35. data/lib/daigaku/test_result.rb +69 -0
  36. data/lib/daigaku/unit.rb +28 -0
  37. data/lib/daigaku/version.rb +3 -0
  38. data/lib/daigaku/views.rb +59 -0
  39. data/lib/daigaku/views/chapters_menu.rb +91 -0
  40. data/lib/daigaku/views/courses_menu.rb +87 -0
  41. data/lib/daigaku/views/main_menu.rb +37 -0
  42. data/lib/daigaku/views/splash.rb +57 -0
  43. data/lib/daigaku/views/task_view.rb +206 -0
  44. data/lib/daigaku/views/top_bar.rb +48 -0
  45. data/lib/daigaku/views/units_menu.rb +92 -0
  46. data/lib/daigaku/window.rb +160 -0
  47. data/spec/daigaku/chapter_spec.rb +76 -0
  48. data/spec/daigaku/configuration_spec.rb +161 -0
  49. data/spec/daigaku/course_spec.rb +75 -0
  50. data/spec/daigaku/database_spec.rb +79 -0
  51. data/spec/daigaku/generator_spec.rb +82 -0
  52. data/spec/daigaku/loading/chapters_spec.rb +16 -0
  53. data/spec/daigaku/loading/courses_spec.rb +16 -0
  54. data/spec/daigaku/loading/units_spec.rb +21 -0
  55. data/spec/daigaku/reference_solution_spec.rb +23 -0
  56. data/spec/daigaku/solution_spec.rb +79 -0
  57. data/spec/daigaku/task_spec.rb +23 -0
  58. data/spec/daigaku/terminal/cli_spec.rb +51 -0
  59. data/spec/daigaku/terminal/courses_spec.rb +60 -0
  60. data/spec/daigaku/terminal/output_spec.rb +123 -0
  61. data/spec/daigaku/terminal/setup_spec.rb +10 -0
  62. data/spec/daigaku/terminal/solutions_spec.rb +8 -0
  63. data/spec/daigaku/terminal/welcome_spec.rb +12 -0
  64. data/spec/daigaku/terminal_spec.rb +14 -0
  65. data/spec/daigaku/test_example_spec.rb +54 -0
  66. data/spec/daigaku/test_result_spec.rb +81 -0
  67. data/spec/daigaku/test_spec.rb +48 -0
  68. data/spec/daigaku/unit_spec.rb +85 -0
  69. data/spec/daigaku/views/chapters_menu_spec.rb +8 -0
  70. data/spec/daigaku/views/courses_menu_spec.rb +8 -0
  71. data/spec/daigaku/views/task_view_spec.rb +7 -0
  72. data/spec/daigaku/views/units_menu_spec.rb +8 -0
  73. data/spec/daigaku/views_spec.rb +23 -0
  74. data/spec/daigaku_spec.rb +57 -0
  75. data/spec/path_helpers_spec.rb +60 -0
  76. data/spec/resource_helpers_spec.rb +33 -0
  77. data/spec/spec_helper.rb +28 -0
  78. data/spec/support/macros/content_helpers.rb +129 -0
  79. data/spec/support/macros/mock_helpers.rb +20 -0
  80. data/spec/support/macros/path_helpers.rb +133 -0
  81. data/spec/support/macros/resource_helpers.rb +119 -0
  82. data/spec/support/macros/test_helpers.rb +6 -0
  83. metadata +361 -0
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Database do
4
+
5
+ subject { Daigaku::Database.send(:new) }
6
+
7
+ before do
8
+ Daigaku::Configuration.send(:new)
9
+
10
+ allow_any_instance_of(Daigaku::Configuration).to \
11
+ receive(:storage_file) { local_storage_file }
12
+ end
13
+
14
+ it { is_expected.to respond_to :get }
15
+ it { is_expected.to respond_to :set }
16
+ it { is_expected.to respond_to :file }
17
+
18
+ it "creates the database file(s) in the .daigaku directory on access" do
19
+ Daigaku::Database.call_an_arbitrary_method
20
+ expect(File.exist?(local_storage_file)).to be_truthy
21
+ end
22
+
23
+ it "allows setting arbitrary keys by setter methods" do
24
+ expect { Daigaku::Database.brownie = "brownie" }
25
+ .not_to raise_error
26
+ end
27
+
28
+ it "allows getting subsequently set keys" do
29
+ Daigaku::Database.carrots = "carrots"
30
+ expect(Daigaku::Database.carrots).to eq "carrots"
31
+ end
32
+
33
+ it "returns nil for not set keys" do
34
+ expect(Daigaku::Database.hamburger).to be_nil
35
+ end
36
+
37
+ it "raises an method missing errror for non getter/setter methods" do
38
+ expect { Daigaku::Database.arbitrary_method(1, 2) }
39
+ .to raise_error NoMethodError
40
+ end
41
+
42
+ it "responds to ::get" do
43
+ expect(Daigaku::Database).to respond_to :get
44
+ end
45
+
46
+ it "responds to ::set" do
47
+ expect(Daigaku::Database).to respond_to :set
48
+ end
49
+
50
+ it "responds to ::file" do
51
+ expect(Daigaku::Database).to respond_to :file
52
+ end
53
+
54
+ describe "::get" do
55
+ it "returns the value of the given key" do
56
+ toast = 'toast'
57
+ Daigaku::Database.toast = toast
58
+ expect(Daigaku::Database.get :toast).to eq toast
59
+ end
60
+ end
61
+
62
+ describe "::set" do
63
+ it "sets the value for the given key" do
64
+ juice = 'orange juice'
65
+ Daigaku::Database.set :juice, juice
66
+ expect(Daigaku::Database.juice).to eq juice
67
+ end
68
+ end
69
+
70
+ describe "::file" do
71
+ it "returns the storage file path" do
72
+ expect(Daigaku::Database.file).to eq Daigaku.config.storage_file
73
+ end
74
+ end
75
+
76
+ it "raises an error if the related getter for a setter is already defined" do
77
+ expect { Daigaku::Database.clone = 'defined' }.to raise_error
78
+ end
79
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Generator do
4
+
5
+ it { is_expected.to respond_to :scaffold }
6
+ it { is_expected.to respond_to :prepare }
7
+
8
+ subject { Daigaku::Generator.new }
9
+
10
+ before do
11
+ Daigaku.config.instance_variable_set(:@storage_file, local_storage_file)
12
+ end
13
+
14
+ describe "#scaffold" do
15
+ it "creates blank solution files for all available units" do
16
+ subject.scaffold(courses_basepath, solutions_basepath)
17
+
18
+ all_solution_file_paths.each do |file_path|
19
+ expect(File.exist?(file_path)).to be_truthy
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#prepare" do
25
+ context "with an existing solutions_path" do
26
+ before do
27
+ Daigaku.configure do |config|
28
+ config.solutions_path = solutions_basepath
29
+ config.courses_path = local_courses_path
30
+ end
31
+
32
+ subject.prepare
33
+ end
34
+
35
+ it "generates a '<basepath>/.daigaku/daigaku.db.yml' file" do
36
+ expect(File.exist?(local_storage_file)).to be_truthy
37
+ end
38
+
39
+ it "generates a '<basepath>/.daigaku/courses' folder" do
40
+ expect(Dir.exist?(local_courses_path)).to be_truthy
41
+ end
42
+
43
+ it "saves the current config info" do
44
+ expect(File.exist?(local_storage_file)).to be_truthy
45
+ expect(Daigaku::Database.courses_path).to eq local_courses_path
46
+ expect(Daigaku::Database.solutions_path).to eq solutions_basepath
47
+ end
48
+ end
49
+
50
+ context "with a missing solutions_path" do
51
+ before do
52
+ FileUtils.rm_r(solutions_basepath) if Dir.exist?(solutions_basepath)
53
+ base_path = File.dirname(Daigaku.config.courses_path)
54
+ @solutions_path = File.join(base_path, 'solutions')
55
+
56
+ Daigaku.config.instance_variable_set(:@solutions_path, nil)
57
+ Daigaku.configure { |config| config.courses_path = local_courses_path }
58
+
59
+ subject.prepare
60
+ end
61
+
62
+ it "generates a 'solutions' path on the base directory as the courses" do
63
+ expect(Dir.exist?(@solutions_path)).to be_truthy
64
+ end
65
+
66
+ it "generates a '<basepath>/.daigaku/daigaku.db.yml' file" do
67
+ expect(File.exist?(local_storage_file)).to be_truthy
68
+ end
69
+
70
+ it "generates a '<basepath>/.daigaku/courses' folder" do
71
+ expect(Dir.exist?(local_courses_path)).to be_truthy
72
+ end
73
+
74
+ it "saves the current config info" do
75
+ expect(File.exist?(local_storage_file)).to be_truthy
76
+ expect(Daigaku::Database.courses_path).to eq local_courses_path
77
+ expect(Daigaku::Database.solutions_path).to eq @solutions_path
78
+ end
79
+ end
80
+ end
81
+
82
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Loading::Chapters do
4
+
5
+ let(:subjects) { Daigaku::Loading::Chapters.load(course_dirs.first) }
6
+
7
+ it "has the prescribed number of chapters" do
8
+ expect(subjects.count).to eq available_chapters(course_dirs.first).count
9
+ end
10
+
11
+ it "loads the available chapters" do
12
+ subjects.each_with_index do |chapter, index|
13
+ expect(chapter.title).to eq chapter_titles[index]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Loading::Courses do
4
+
5
+ let(:subjects) { Daigaku::Loading::Courses.load(courses_basepath) }
6
+
7
+ it "has the prescribed number of courses" do
8
+ expect(subjects.count).to eq available_courses.count
9
+ end
10
+
11
+ it "loads the available courses" do
12
+ subjects.each_with_index do |course, index|
13
+ expect(course.title).to eq course_titles[index]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Loading::Units do
4
+
5
+ let(:course_name) { course_dir_names.first }
6
+ let(:chapter_path) { chapter_dirs(course_name).first }
7
+ let(:chapter_name) { File.basename(chapter_path) }
8
+
9
+ let(:subjects) { Daigaku::Loading::Units.load(chapter_path) }
10
+
11
+ it "has the prescribed number of units" do
12
+ units_count = available_units(course_name, chapter_name).count
13
+ expect(subjects.count).to eq units_count
14
+ end
15
+
16
+ it "loads the available units" do
17
+ subjects.each_with_index do |unit, index|
18
+ expect(unit.title).to eq unit_titles[index]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::ReferenceSolution do
4
+
5
+ it { is_expected.to respond_to :code }
6
+ it { is_expected.to respond_to :path }
7
+
8
+ let(:unit_path) do
9
+ course_name = course_dir_names.first
10
+ unit_dirs(course_name)[0].first
11
+ end
12
+
13
+ subject { Daigaku::ReferenceSolution.new(unit_path) }
14
+
15
+ it "has the prescribed path" do
16
+ path = File.join(unit_path, reference_solution_name)
17
+ expect(subject.path).to eq path
18
+ end
19
+
20
+ it "has the prescribed code" do
21
+ expect(subject.code).to eq solution_content
22
+ end
23
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Solution do
4
+
5
+ it { is_expected.to respond_to :code }
6
+ it { is_expected.to respond_to :path }
7
+ it { is_expected.to respond_to :verify! }
8
+ it { is_expected.to respond_to :verified? }
9
+ it { is_expected.to respond_to :errors }
10
+
11
+ before(:all) do
12
+ prepare_solutions
13
+ Daigaku.config.solutions_path = solutions_basepath
14
+ end
15
+
16
+ let(:solution_path) { all_solution_file_paths.first }
17
+ let(:unit_path) { all_unit_dirs.first }
18
+
19
+ subject { Daigaku::Solution.new(unit_path) }
20
+
21
+ it "has the prescribed solution path from the given unit path" do
22
+ expect(subject.path).to eq solution_path
23
+ end
24
+
25
+ it "has the prescribed code" do
26
+ expect(subject.code).to eq solution_content
27
+ end
28
+
29
+ it "loads the verified state from the database on creation" do
30
+ Daigaku::Solution.new(unit_path).verify!
31
+ solution = Daigaku::Solution.new(unit_path)
32
+
33
+ expect(solution).to be_verified
34
+ end
35
+
36
+ context "Verification" do
37
+ describe "#verify!" do
38
+ it "returns a TestResult" do
39
+ expect(subject.verify!).to be_a Daigaku::TestResult
40
+ end
41
+
42
+ it "sets @verified true if Test passed" do
43
+ Daigaku::Database.set(subject.path, false)
44
+ solution = Daigaku::Solution.new(unit_path)
45
+
46
+ expect(solution.instance_variable_get(:@verified)).to be_falsey
47
+ solution.verify!
48
+ expect(solution.instance_variable_get(:@verified)).to be_truthy
49
+ end
50
+
51
+ it "sets the solution's state in the database to verified if passed" do
52
+ subject.verify!
53
+ mastered = Daigaku::Database.get(subject.path)
54
+
55
+ expect(mastered).to be_truthy
56
+ end
57
+
58
+ it "sets the solution's state in the database to unverified unless passed" do
59
+ subject.instance_variable_set(:@code, 'puts "I ❤ Daigaku!"')
60
+ subject.verify!
61
+ mastered = Daigaku::Database.get(subject.path)
62
+
63
+ expect(mastered).to be_falsey
64
+ end
65
+ end
66
+
67
+ describe "#verified?" do
68
+ it "is false by default" do
69
+ expect(subject.verified?).to be_falsey
70
+ end
71
+
72
+ it "returns true if #verify! passed" do
73
+ subject.verify!
74
+ expect(subject.verified?).to be_truthy
75
+ end
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Task do
4
+
5
+ it { is_expected.to respond_to :markdown }
6
+ it { is_expected.to respond_to :path }
7
+
8
+ let(:unit_path) do
9
+ course_name = course_dir_names.first
10
+ unit_dirs(course_name)[0].first
11
+ end
12
+
13
+ subject { Daigaku::Task.new(unit_path) }
14
+
15
+ it "has the prescribed path" do
16
+ path = File.join(unit_path, task_name)
17
+ expect(subject.path).to eq path
18
+ end
19
+
20
+ it "has the prescribed markdown" do
21
+ expect(subject.markdown).to eq task_file_content
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Terminal::CLI do
4
+
5
+ it { is_expected.to be_a Thor }
6
+ it { is_expected.to respond_to :about }
7
+ it { is_expected.to respond_to :welcome }
8
+ it { is_expected.to respond_to :scaffold }
9
+ it { is_expected.to respond_to :learn }
10
+ it { is_expected.to respond_to :courses }
11
+ it { is_expected.to respond_to :solutions }
12
+ it { is_expected.to respond_to :setup }
13
+
14
+ describe "#learn" do
15
+ it "starts the daigaku terminal app if there are courses" do
16
+ allow(Daigaku::Loading::Courses).to receive(:load) { [1] }
17
+ allow(Daigaku).to receive(:start) { true }
18
+ expect(Daigaku).to receive(:start)
19
+
20
+ subject.learn
21
+ end
22
+
23
+ it "does not start the daigaku terminal app if there are no courses" do
24
+ suppress_print_out
25
+ allow(Daigaku::Loading::Courses).to receive(:load) { [] }
26
+ allow(Daigaku).to receive(:start) { true }
27
+ expect(Daigaku).not_to receive(:start)
28
+
29
+ subject.learn
30
+ end
31
+ end
32
+
33
+ describe "#welcome" do
34
+ it "runs the welcome routine" do
35
+ allow(Daigaku::Terminal::Welcome).to receive(:run) { true }
36
+ expect(Daigaku::Terminal::Welcome).to receive(:run).once
37
+
38
+ subject.welcome
39
+ end
40
+ end
41
+
42
+ describe "#scaffold" do
43
+ it "runs the scaffolding" do
44
+ allow($stdout).to receive(:puts) {}
45
+ allow_any_instance_of(Daigaku::Generator).to receive(:scaffold) { true }
46
+ expect_any_instance_of(Daigaku::Generator).to receive(:scaffold).once
47
+
48
+ subject.scaffold
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Terminal::Courses do
4
+
5
+ before { suppress_print_out }
6
+
7
+ it { is_expected.to be_a Thor }
8
+
9
+ describe "commands" do
10
+ [:list, :download].each do |method|
11
+ it { is_expected.to respond_to method }
12
+ end
13
+ end
14
+
15
+ describe "#download" do
16
+
17
+ before do
18
+ Daigaku.config.courses_path = local_courses_path
19
+
20
+ @zip_file_name = "repo.zip"
21
+ @file_content = prepare_download(@zip_file_name)
22
+ @url = "https://example.com/#{@zip_file_name}"
23
+
24
+ stub_request(:get, @url)
25
+ .with(headers: {
26
+ 'Accept' => '*/*',
27
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
28
+ 'User-Agent' => 'Ruby'
29
+ })
30
+ .to_return(status: 200, body: @file_content, headers: {})
31
+ end
32
+
33
+ after { cleanup_download(@zip_file_name) }
34
+
35
+ it "downloads the file from a given url" do
36
+ expect{ subject.download(@url) }.not_to raise_error
37
+ end
38
+
39
+ it "creates a new courses folder in the daigaku courses directory" do
40
+ target_path = File.join(Daigaku.config.courses_path, File.basename(course_dirs.first))
41
+
42
+ dirs = Dir[File.join(Daigaku.config.courses_path, '**')]
43
+ puts "target_path: #{target_path}"
44
+ puts dirs.to_s
45
+
46
+ expect(dirs.include?(target_path)).to be_truthy
47
+ end
48
+
49
+ it "raises an error if param is no url" do
50
+ expect(subject).to receive(:say_warning)
51
+ subject.download('no-url')
52
+ end
53
+
54
+ it "raises an error if param is no url to a zip file" do
55
+ expect(subject).to receive(:say_warning)
56
+ subject.download('http://exmaple.com/something-else')
57
+ end
58
+ end
59
+
60
+ end