belajar 0.1.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 (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,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe Belajar::Views::ChaptersMenu, type: :view do
4
+
5
+ it { is_expected.to be_a Belajar::Views::Menu }
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe Belajar::Views::CoursesMenu, type: :view do
4
+
5
+ it { is_expected.to be_a Belajar::Views::Menu }
6
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Belajar::Views::Menu do
4
+
5
+ it { is_expected.to respond_to :enter }
6
+ it { is_expected.to respond_to :reenter }
7
+
8
+ [
9
+ :show,
10
+ :draw,
11
+ :interact_with,
12
+ :models,
13
+ :items
14
+ ].each do |method|
15
+ it "has a protected method ##{method}" do
16
+ expect(subject.protected_methods).to include(method)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Belajar::Views::TaskView, type: :view do
4
+
5
+ it { is_expected.to respond_to :enter }
6
+
7
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe Belajar::Views::UnitsMenu, type: :view do
4
+
5
+ it { is_expected.to be_a Belajar::Views::Menu }
6
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Belajar::Views do
4
+
5
+ subject do
6
+ class Test
7
+ include Belajar::Views
8
+ end
9
+
10
+ Test.new
11
+ end
12
+
13
+ [
14
+ :default_window,
15
+ :sub_window_below_top_bar
16
+ ].each do |method|
17
+ it "has a private method ::#{method}" do
18
+ expect(subject.private_methods.include?(method)).to be_truthy
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Belajar module" do
4
+
5
+ describe "::config" do
6
+
7
+ subject { Belajar.config }
8
+
9
+ [:config, :configure, :start].each do |method|
10
+ it "responds to ::#{method}" do
11
+ expect(Belajar.singleton_methods).to include method
12
+ end
13
+ end
14
+
15
+ it "returns Configuration of class Belajar::Configuration" do
16
+ expect(subject).to be_an_instance_of Belajar::Configuration
17
+ end
18
+
19
+ it "returns a singleton setting" do
20
+ expect(subject).to be Belajar.config
21
+ end
22
+ end
23
+
24
+ describe "::configure" do
25
+
26
+ let(:configure) do
27
+ proc do
28
+ Belajar.configure do |config|
29
+ config.solutions_path = test_basepath
30
+ end
31
+ end
32
+ end
33
+
34
+ it "allows to configure the app" do
35
+ expect { configure.call }.not_to raise_error
36
+ end
37
+
38
+ it "sets configutation properties" do
39
+ configure.call
40
+ expect(Belajar.config.solutions_path).to eq test_basepath
41
+ end
42
+
43
+ it "allows to change the config during runtime" do
44
+ Belajar.configure do |config|
45
+ config.solutions_path = courses_basepath
46
+ end
47
+
48
+ expect(Belajar.config.solutions_path).to eq courses_basepath
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe "PathHelpers" do
4
+
5
+ it "provides a temp base path" do
6
+ puts "\n* temp base path:"
7
+ puts temp_basepath
8
+ end
9
+
10
+ it "provides a test base path" do
11
+ puts "\n* test base path:"
12
+ puts test_basepath
13
+ end
14
+
15
+ it "provides a courses base path" do
16
+ puts "\n* courses base path:"
17
+ puts courses_basepath
18
+ end
19
+
20
+ it "provides the course directories" do
21
+ puts "\n* course dirs:"
22
+ puts course_dirs
23
+ end
24
+
25
+ it "provides each course's chapter directories" do
26
+ puts "\n* chapter dirs: "
27
+
28
+ course_dir_names.each do |course_name|
29
+ puts chapter_dirs(course_name)
30
+ end
31
+ end
32
+
33
+ it "provides each chapter's unit directories" do
34
+ puts "\n* unit dirs:"
35
+
36
+ course_dir_names.each do |course_name|
37
+ puts unit_dirs(course_name)
38
+ end
39
+ end
40
+
41
+ it "provides all unit directories as flattened array" do
42
+ puts "\n* all unit dirs:"
43
+ puts all_unit_dirs
44
+ end
45
+
46
+ it "provides all solution file paths" do
47
+ puts "\n* all solution file paths:"
48
+ puts all_solution_file_paths
49
+ end
50
+
51
+ it "provides all test file paths" do
52
+ puts "\n* all test file paths:"
53
+ puts all_test_file_paths
54
+ end
55
+
56
+ it "provides the local_storage_file path" do
57
+ puts "\n* local storage file path:"
58
+ puts local_storage_file
59
+ end
60
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ResourceHelpers" do
4
+
5
+ let(:course) { course_dir_names.first }
6
+ let(:chapter) { chapter_dir_names.first }
7
+ let(:unit) { unit_dir_names.first }
8
+
9
+ it "provides the available courses" do
10
+ puts "\n* available courses:"
11
+ puts available_courses.map &:inspect
12
+ end
13
+
14
+ it "provides a course's available chapters" do
15
+ puts "\n* available chapters:"
16
+ puts available_chapters(course).map &:inspect
17
+ end
18
+
19
+ it "provides a chapter's avaliable units" do
20
+ puts "\n* available units:"
21
+ puts available_units(course, chapter).map &:inspect
22
+ end
23
+
24
+ it "provides a unit's task file" do
25
+ puts "\n* task:"
26
+ puts available_task(course, chapter, unit).map &:inspect
27
+ end
28
+
29
+ it "provides a unit's reference solution file" do
30
+ puts "\n* reference solution:"
31
+ puts available_reference_solution(course, chapter, unit).map &:inspect
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ require 'rspec'
2
+ require 'webmock/rspec'
3
+
4
+ def require_files_from(paths = [])
5
+ paths.each do |path|
6
+ Dir[File.join(File.expand_path("#{path}*.rb", __FILE__))].sort.each do |file|
7
+ require file
8
+ end
9
+ end
10
+ end
11
+
12
+ RSpec.configure do |config|
13
+ config.color = true
14
+
15
+ require File.expand_path('../../lib/belajar', __FILE__)
16
+ require_files_from ["../support/**/"]
17
+
18
+ config.include TestHelpers
19
+
20
+ config.before(:each, type: :view) { mock_default_window }
21
+
22
+ config.before(:all) do
23
+ prepare_courses
24
+ use_test_storage_file
25
+ end
26
+
27
+ config.after(:all) { cleanup_temp_data }
28
+ end
@@ -0,0 +1,129 @@
1
+ module ContentHelpers
2
+
3
+ TASK_FILE_CONTENT = [
4
+ "Heading\n======", "##Task",
5
+ "Solve this task!",
6
+ "##Hints",
7
+ "Just do it right..."
8
+ ].join("\n\n")
9
+
10
+ SOLUTION_CONTENT = 'print "hello world".upcase'
11
+
12
+ TEST_CONTENT = [
13
+ "require 'rspec'\n",
14
+ "describe 'Your code' do",
15
+ " it 'prints out HELLO WORLD' do",
16
+ " expect { [['solution::code']] }.to output('HELLO WORLD').to_stdout",
17
+ " end\n",
18
+ " it 'uses the method #upcase to get capital letters' do",
19
+ " allow(self).to receive(:puts).and_return ''",
20
+ " allow(self).to receive(:print).and_return ''",
21
+ " expect_any_instance_of(String).to receive(:upcase).and_return('HELLO WORLD')\n",
22
+ " [['solution::code']]",
23
+ " end",
24
+ "end"
25
+ ].join("\n")
26
+
27
+ TEST_FAILED_JSON =
28
+ %Q#
29
+ { "examples":
30
+ [
31
+ { "description": "description 1",
32
+ "full_description": "full description 1",
33
+ "status": "failed",
34
+ "file_path": "./spec.rb",
35
+ "line_number": 4,
36
+ "run_time": 0.001,
37
+ "exception": {
38
+ "class": "RSpec::Expectations::ExpectationNotMetError",
39
+ "message": "message 1",
40
+ "backtrace": ["backtrace 1_a", "backtrace 1_b"]
41
+ }
42
+ },
43
+ { "description": "description 2",
44
+ "full_description": "full description 2",
45
+ "status": "passed",
46
+ "file_path": "./spec.rb",
47
+ "line_number": 8,
48
+ "run_time": 0.002
49
+ }
50
+ ],
51
+ "summary": {
52
+ "duration": 0.003,
53
+ "example_count": 2,
54
+ "failure_count": 1,
55
+ "pending_count": 0
56
+ },
57
+ "summary_line": "2 example, 1 failure"
58
+ }
59
+ #
60
+
61
+ TEST_PASSED_JSON =
62
+ %Q#
63
+ { "examples":
64
+ [
65
+ { "description":"description 1",
66
+ "full_description":"full description 1",
67
+ "status":"passed",
68
+ "file_path":"spec.rb",
69
+ "line_number":4,
70
+ "run_time":0.001
71
+ },
72
+ { "description":"description 2",
73
+ "full_description":"full description 2",
74
+ "status":"passed",
75
+ "file_path":"spec.rb",
76
+ "line_number":8,
77
+ "run_time":0.002
78
+ }
79
+ ],
80
+ "summary":{
81
+ "duration":0.003,
82
+ "example_count":2,
83
+ "failure_count":0,
84
+ "pending_count":0
85
+ },
86
+ "summary_line":"2 example, 0 failures"
87
+ }
88
+ #
89
+
90
+ TEST_PASSED_MESSAGE = "Your code passed all tests."
91
+ EXAMPLE_PASSED_MESSAGE = "Your code passed this requirement."
92
+
93
+ def task_file_content
94
+ TASK_FILE_CONTENT
95
+ end
96
+
97
+ def solution_content
98
+ SOLUTION_CONTENT
99
+ end
100
+
101
+ def test_content
102
+ TEST_CONTENT
103
+ end
104
+
105
+ def test_failed_json
106
+ TEST_FAILED_JSON
107
+ end
108
+
109
+ def test_passed_json
110
+ TEST_PASSED_JSON
111
+ end
112
+
113
+ def test_passed_json_parsed
114
+ JSON.parse(test_passed_json, symbolize_names: true)
115
+ end
116
+
117
+ def test_failed_json_parsed
118
+ JSON.parse(test_failed_json, symbolize_names: true)
119
+ end
120
+
121
+ def test_passed_summary
122
+ TEST_PASSED_MESSAGE
123
+ end
124
+
125
+ def example_passed_message
126
+ EXAMPLE_PASSED_MESSAGE
127
+ end
128
+
129
+ end
@@ -0,0 +1,25 @@
1
+ module MockHelpers
2
+
3
+ def mock_default_window
4
+ allow_any_instance_of(described_class).to receive(:default_window) { true }
5
+ end
6
+
7
+ def use_test_storage_file
8
+ Belajar::Configuration.send(:new)
9
+ Belajar.config.instance_variable_set(:@storage_file, local_storage_file)
10
+
11
+ QuickStore.configure do |config|
12
+ config.file_path = Belajar.config.storage_file
13
+ end
14
+
15
+ QuickStore.store.send(:new)
16
+ end
17
+
18
+ def suppress_print_out
19
+ allow(described_class).to receive(:say_warning) {}
20
+ allow(described_class).to receive(:say_info) {}
21
+ allow(described_class).to receive(:say) {}
22
+ allow($stdout).to receive(:puts) {}
23
+ allow($stdout).to receive(:print) {}
24
+ end
25
+ end
@@ -0,0 +1,139 @@
1
+ module PathHelpers
2
+ LOCAL_DIR = '.belajar'
3
+ CONFIGURATION_FILE = 'belajar.settings'
4
+ COURSES = 'courses'
5
+ SOLUTIONS = 'solutions'
6
+ TEMP_PATH = File.expand_path("../../../../tmp/", __FILE__)
7
+ COURSE_DIR_NAMES = ['Course_A', 'Course_B']
8
+ CHAPTER_DIR_NAMES = ['1_Chapter-A', '2_Chapter-B']
9
+ UNIT_DIR_NAMES = ['1_unit-a', '2_unit-b']
10
+ TASK_NAME = 'task.md'
11
+ REFERENCE_SOLUTION_NAME = 'solution.rb'
12
+ TEST_NAME = 'solution_spec.rb'
13
+ STORAGE_FILE = 'belajar.db.yml'
14
+
15
+ def temp_basepath
16
+ TEMP_PATH
17
+ end
18
+
19
+ def test_basepath
20
+ File.join(TEMP_PATH, 'test')
21
+ end
22
+
23
+ def course_dir_names
24
+ COURSE_DIR_NAMES
25
+ end
26
+
27
+ def chapter_dir_names
28
+ CHAPTER_DIR_NAMES
29
+ end
30
+
31
+ def unit_dir_names
32
+ UNIT_DIR_NAMES
33
+ end
34
+
35
+ def task_name
36
+ TASK_NAME
37
+ end
38
+
39
+ def reference_solution_name
40
+ REFERENCE_SOLUTION_NAME
41
+ end
42
+
43
+ def test_name
44
+ TEST_NAME
45
+ end
46
+
47
+ def courses_basepath
48
+ File.join(test_basepath, LOCAL_DIR, COURSES)
49
+ end
50
+
51
+ def solutions_basepath
52
+ File.join(test_basepath, SOLUTIONS)
53
+ end
54
+
55
+ def course_dirs
56
+ course_dir_names.map do |dir|
57
+ File.join(courses_basepath, dir)
58
+ end
59
+ end
60
+
61
+ def chapter_dirs(course_name)
62
+ chapter_dir_names.map do |chapter|
63
+ File.join(courses_basepath, course_name, chapter)
64
+ end
65
+ end
66
+
67
+ def unit_dirs(course_name)
68
+ chapter_dir_names.map do |chapter|
69
+ unit_dir_names.map do |unit|
70
+ File.join(courses_basepath, course_name, chapter, unit)
71
+ end
72
+ end
73
+ end
74
+
75
+ def all_unit_dirs
76
+ dirs = course_dirs.map do |course_dir|
77
+ chapter_dir_names.map do |chapter_name|
78
+ unit_dir_names.map do |unit_name|
79
+ File.join(course_dir, chapter_name, unit_name)
80
+ end
81
+ end
82
+ end
83
+
84
+ dirs.flatten
85
+ end
86
+
87
+ def all_solution_file_paths
88
+ all_unit_dirs.map do |unit_dir|
89
+ underscored_unit_dir = File.basename(unit_dir).gsub(/[\_\-\.]+/, '_')
90
+ file_name = underscored_unit_dir + Belajar::Solution::FILE_SUFFIX
91
+
92
+ unit_path = File.join(solutions_basepath, unit_dir.split('/')[-3..-1])
93
+ parts = File.join(File.dirname(unit_path), file_name).split('/')
94
+
95
+ course_parts = parts[-3..-1].map do |part|
96
+ part.gsub(/^[\d]+\_/, '').gsub(/[\_\-]+/, '_').downcase
97
+ end
98
+
99
+ [*parts[0...-3], *course_parts].join('/')
100
+ end
101
+ end
102
+
103
+ def all_test_file_paths
104
+ all_unit_dirs.map do |unit_dir|
105
+ File.join(unit_dir, test_name)
106
+ end
107
+ end
108
+
109
+ def course_titles
110
+ gsub_underscores(course_dir_names)
111
+ end
112
+
113
+ def chapter_titles
114
+ gsub_underscores(chapter_dir_names)
115
+ end
116
+
117
+ def unit_titles
118
+ gsub_underscores(unit_dir_names)
119
+ end
120
+
121
+ def gsub_underscores(names)
122
+ names.map { |unit| unit.gsub(/\_+/, ' ') }
123
+ end
124
+
125
+ def local_courses_path
126
+ local_path = File.join(test_basepath, LOCAL_DIR, COURSES)
127
+ File.expand_path(local_path, __FILE__)
128
+ end
129
+
130
+ def local_configuration_file
131
+ local_path = File.join(test_basepath, LOCAL_DIR, CONFIGURATION_FILE)
132
+ File.expand_path(local_path, __FILE__)
133
+ end
134
+
135
+ def local_storage_file
136
+ local_path = File.join(test_basepath, LOCAL_DIR, STORAGE_FILE)
137
+ File.expand_path(local_path, __FILE__)
138
+ end
139
+ end