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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/README.md +5 -0
- data/Rakefile +5 -0
- data/belajar.gemspec +38 -0
- data/bin/belajar +12 -0
- data/lib/belajar.rb +24 -0
- data/lib/belajar/chapter.rb +23 -0
- data/lib/belajar/configuration.rb +89 -0
- data/lib/belajar/congratulator.rb +13 -0
- data/lib/belajar/course.rb +80 -0
- data/lib/belajar/exceptions.rb +19 -0
- data/lib/belajar/generator.rb +60 -0
- data/lib/belajar/github_client.rb +30 -0
- data/lib/belajar/loadable.rb +23 -0
- data/lib/belajar/loading/chapters.rb +9 -0
- data/lib/belajar/loading/courses.rb +9 -0
- data/lib/belajar/loading/units.rb +9 -0
- data/lib/belajar/reference_solution.rb +18 -0
- data/lib/belajar/solution.rb +53 -0
- data/lib/belajar/storeable.rb +32 -0
- data/lib/belajar/task.rb +10 -0
- data/lib/belajar/terminal.rb +12 -0
- data/lib/belajar/terminal/cli.rb +59 -0
- data/lib/belajar/terminal/courses.rb +179 -0
- data/lib/belajar/terminal/output.rb +78 -0
- data/lib/belajar/terminal/setup.rb +115 -0
- data/lib/belajar/terminal/solutions.rb +46 -0
- data/lib/belajar/terminal/texts/about.txt +19 -0
- data/lib/belajar/terminal/texts/congratulations.txt +12 -0
- data/lib/belajar/terminal/texts/courses_empty.txt +3 -0
- data/lib/belajar/terminal/texts/hint_course_download.txt +13 -0
- data/lib/belajar/terminal/texts/welcome.txt +12 -0
- data/lib/belajar/terminal/welcome.rb +98 -0
- data/lib/belajar/test.rb +46 -0
- data/lib/belajar/test_result.rb +86 -0
- data/lib/belajar/unit.rb +28 -0
- data/lib/belajar/version.rb +3 -0
- data/lib/belajar/views.rb +51 -0
- data/lib/belajar/views/chapters_menu.rb +60 -0
- data/lib/belajar/views/courses_menu.rb +52 -0
- data/lib/belajar/views/main_menu.rb +37 -0
- data/lib/belajar/views/menu.rb +89 -0
- data/lib/belajar/views/splash.rb +57 -0
- data/lib/belajar/views/task_view.rb +236 -0
- data/lib/belajar/views/top_bar.rb +40 -0
- data/lib/belajar/views/units_menu.rb +61 -0
- data/lib/belajar/window.rb +215 -0
- data/spec/belajar/chapter_spec.rb +76 -0
- data/spec/belajar/configuration_spec.rb +161 -0
- data/spec/belajar/congratulator_spec.rb +24 -0
- data/spec/belajar/course_spec.rb +201 -0
- data/spec/belajar/generator_spec.rb +82 -0
- data/spec/belajar/github_client_spec.rb +53 -0
- data/spec/belajar/loading/chapters_spec.rb +16 -0
- data/spec/belajar/loading/courses_spec.rb +16 -0
- data/spec/belajar/loading/units_spec.rb +21 -0
- data/spec/belajar/reference_solution_spec.rb +41 -0
- data/spec/belajar/solution_spec.rb +86 -0
- data/spec/belajar/storeable_spec.rb +35 -0
- data/spec/belajar/task_spec.rb +23 -0
- data/spec/belajar/terminal/cli_spec.rb +51 -0
- data/spec/belajar/terminal/courses_spec.rb +293 -0
- data/spec/belajar/terminal/output_spec.rb +151 -0
- data/spec/belajar/terminal/setup_spec.rb +10 -0
- data/spec/belajar/terminal/solutions_spec.rb +8 -0
- data/spec/belajar/terminal/welcome_spec.rb +12 -0
- data/spec/belajar/terminal_spec.rb +24 -0
- data/spec/belajar/test_example_spec.rb +54 -0
- data/spec/belajar/test_result_spec.rb +91 -0
- data/spec/belajar/test_spec.rb +48 -0
- data/spec/belajar/unit_spec.rb +85 -0
- data/spec/belajar/views/chapters_menu_spec.rb +6 -0
- data/spec/belajar/views/courses_menu_spec.rb +6 -0
- data/spec/belajar/views/menu_spec.rb +19 -0
- data/spec/belajar/views/task_view_spec.rb +7 -0
- data/spec/belajar/views/units_menu_spec.rb +6 -0
- data/spec/belajar/views_spec.rb +21 -0
- data/spec/belajar_spec.rb +51 -0
- data/spec/path_helpers_spec.rb +60 -0
- data/spec/resource_helpers_spec.rb +33 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/macros/content_helpers.rb +129 -0
- data/spec/support/macros/mock_helpers.rb +25 -0
- data/spec/support/macros/path_helpers.rb +139 -0
- data/spec/support/macros/resource_helpers.rb +157 -0
- data/spec/support/macros/test_helpers.rb +6 -0
- metadata +385 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Belajar
|
4
|
+
module Terminal
|
5
|
+
|
6
|
+
require_relative 'output'
|
7
|
+
|
8
|
+
class Setup < Thor
|
9
|
+
include Terminal::Output
|
10
|
+
|
11
|
+
desc 'init', 'Initially setup belajar paths'
|
12
|
+
def init
|
13
|
+
empty_line
|
14
|
+
say 'Please type the base path in which you want to save your belajar'
|
15
|
+
say 'files. The "courses" folder and "solutions" folder will be created'
|
16
|
+
say 'automatically.'
|
17
|
+
|
18
|
+
loop do
|
19
|
+
path = get 'path:'
|
20
|
+
|
21
|
+
begin
|
22
|
+
@belajar_path = File.expand_path("#{path}", Dir.pwd)
|
23
|
+
rescue
|
24
|
+
say_warning "#{path} is no valid path name. Try another!"
|
25
|
+
next
|
26
|
+
end
|
27
|
+
|
28
|
+
say_warning 'Do you want to use the following path as your belajar base path?'
|
29
|
+
say "\"#{@belajar_path}\""
|
30
|
+
|
31
|
+
confirmation = get '(yes|no)'
|
32
|
+
break if confirmation.downcase == 'yes'
|
33
|
+
|
34
|
+
empty_line
|
35
|
+
say 'No Problem. Just type another one!'
|
36
|
+
end
|
37
|
+
|
38
|
+
prepare_directories(@belajar_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'list', 'List the current belajar setup'
|
42
|
+
def list
|
43
|
+
say_info "Your current belajar setup is:\n\n#{Belajar.config.summary}"
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'set [OPTIONS]', 'Update the settings of your belajar environment'
|
47
|
+
method_option :courses_path,
|
48
|
+
type: :string,
|
49
|
+
aliases: '-c',
|
50
|
+
desc: 'Set courses_path directory'
|
51
|
+
method_option :solutions_path,
|
52
|
+
type: :string,
|
53
|
+
aliases: '-s',
|
54
|
+
desc: 'Set solutions_path directory'
|
55
|
+
method_option :paths,
|
56
|
+
type: :string,
|
57
|
+
aliases: '-p',
|
58
|
+
desc: 'Set all belajar paths to a certain path'
|
59
|
+
def set
|
60
|
+
courses_path = options[:paths] || options[:courses_path]
|
61
|
+
solutions_path = options[:paths] || options[:solutions_path]
|
62
|
+
|
63
|
+
if courses_path.nil? && solutions_path.nil?
|
64
|
+
say_warning "Please specify options when using this command!"
|
65
|
+
say %x{ belajar setup help set }
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
update_config(:courses_path, courses_path) if courses_path
|
70
|
+
update_config(:solutions_path, solutions_path) if solutions_path
|
71
|
+
|
72
|
+
Belajar.config.save
|
73
|
+
list
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def prepare_directories(path)
|
79
|
+
courses_dir = Belajar::Configuration::COURSES_DIR
|
80
|
+
courses_path = File.join(path, courses_dir)
|
81
|
+
Belajar.config.courses_path = courses_path
|
82
|
+
|
83
|
+
solutions_dir = Belajar::Configuration::SOLUTIONS_DIR
|
84
|
+
solutions_path = File.join(path, solutions_dir)
|
85
|
+
|
86
|
+
if Dir.exist? solutions_path
|
87
|
+
Belajar.config.solutions_path = solutions_path
|
88
|
+
end
|
89
|
+
|
90
|
+
generator = Belajar::Generator.new
|
91
|
+
generator.prepare
|
92
|
+
|
93
|
+
text = [
|
94
|
+
"Your Belajar directory is now set up.\n",
|
95
|
+
"Belajar created/updated following two paths for you:",
|
96
|
+
courses_path,
|
97
|
+
solutions_path
|
98
|
+
]
|
99
|
+
|
100
|
+
say_info text.join("\n")
|
101
|
+
end
|
102
|
+
|
103
|
+
def update_config(attribute, value)
|
104
|
+
begin
|
105
|
+
path = File.expand_path(value, Dir.pwd)
|
106
|
+
Belajar.config.send("#{attribute}=", path)
|
107
|
+
rescue Exception => e
|
108
|
+
say_warning e.message
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Belajar
|
2
|
+
module Terminal
|
3
|
+
|
4
|
+
require 'os'
|
5
|
+
require_relative 'output'
|
6
|
+
|
7
|
+
class Solutions < Thor
|
8
|
+
include Terminal::Output
|
9
|
+
|
10
|
+
desc 'solutions open [COURSE NAME]', 'Open the solutions folder of a course in a GUI window'
|
11
|
+
def open(course_name = '')
|
12
|
+
begin
|
13
|
+
path = File.join(Belajar.config.solutions_path, course_name)
|
14
|
+
|
15
|
+
unless Dir.exist?(path)
|
16
|
+
text = [
|
17
|
+
"The course directory \"#{File.basename(path)}\" is not available in",
|
18
|
+
"\"#{File.dirname(path)}\".\n",
|
19
|
+
'Hint:',
|
20
|
+
'Run "belajar scaffold" to create empty solution files for all courses.'
|
21
|
+
]
|
22
|
+
say_warning text.join("\n")
|
23
|
+
|
24
|
+
unless Loading::Courses.load(Belajar.config.courses_path).empty?
|
25
|
+
Terminal::Courses.new.list
|
26
|
+
end
|
27
|
+
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
if OS.windows?
|
32
|
+
system "explorer '#{path}'"
|
33
|
+
elsif OS.mac?
|
34
|
+
system "open '#{path}'"
|
35
|
+
elsif OS.linux?
|
36
|
+
system "xdg-open '#{path}'"
|
37
|
+
end
|
38
|
+
rescue ConfigurationError => e
|
39
|
+
say_warning e.message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
**********************************************************************
|
2
|
+
◇ ABOUT BELAJAR! ◇
|
3
|
+
**********************************************************************
|
4
|
+
|
5
|
+
Belajar is the Japanese word for "university".
|
6
|
+
With Belajar you can master your way of learning the Ruby programming
|
7
|
+
language with courses that are created by the community.
|
8
|
+
|
9
|
+
Belajar is a command line tool and a text based interface and provides
|
10
|
+
you with a number of learning tasks and explanations about the Ruby
|
11
|
+
programming language. You will learn Ruby step by step by solving small
|
12
|
+
language-explaining programming tasks.
|
13
|
+
|
14
|
+
Belajar's command line interface provides several commands which you
|
15
|
+
can use in your terminal to setup the system, download new courses,
|
16
|
+
and navigate through your solutions.
|
17
|
+
|
18
|
+
By typing "belajar help" in you terminal you are provided with an
|
19
|
+
overview of all available commands.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
You can download a new belajar course by using the
|
2
|
+
"belajar courses download [URL] [OPTIONS]" command, e.g.:
|
3
|
+
|
4
|
+
$ belajar courses download https://github.com/wong-bejo/Get_started_with_Ruby/archive/master.zip
|
5
|
+
|
6
|
+
For Github resources you can also use the `--github` (short `-g`) option:
|
7
|
+
|
8
|
+
$ belajar courses download -g wong-bejo/Get_started_with_Ruby
|
9
|
+
|
10
|
+
If you want to quick start with Daiaku's "Get started with Ruby"
|
11
|
+
course just run:
|
12
|
+
|
13
|
+
$ belajar courses download
|
@@ -0,0 +1,12 @@
|
|
1
|
+
**********************************************************************
|
2
|
+
◇ WELCOME TO BELAJAR! ◇
|
3
|
+
**********************************************************************
|
4
|
+
|
5
|
+
To get started, you need a folder where you can save your courses and
|
6
|
+
solutions. By default, belajar uses the same base path for both.
|
7
|
+
Your courses will be saved to a "courses" folder and your solutions
|
8
|
+
can be found in a "solutions" folder.
|
9
|
+
|
10
|
+
The "solutions" path and "courses" path can be changed later on.
|
11
|
+
See which command you can use to update your setup by simply typing
|
12
|
+
"belajar setup help set" in your command line.
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Belajar
|
2
|
+
module Terminal
|
3
|
+
|
4
|
+
class Welcome
|
5
|
+
include Terminal::Output
|
6
|
+
|
7
|
+
def self.run
|
8
|
+
self.new.run
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.about
|
12
|
+
self.new.about
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
empty_line
|
17
|
+
say Terminal.text :welcome
|
18
|
+
empty_line
|
19
|
+
say "For now, let's setup the belajar paths."
|
20
|
+
Belajar::Terminal::Setup.new.init
|
21
|
+
|
22
|
+
show_setup_list_announcement
|
23
|
+
show_courses_list_announcement
|
24
|
+
|
25
|
+
courses = Loading::Courses.load(Belajar.config.courses_path)
|
26
|
+
|
27
|
+
if courses.empty?
|
28
|
+
show_courses_download_announcement
|
29
|
+
show_solutions_open_announcement
|
30
|
+
end
|
31
|
+
|
32
|
+
empty_line
|
33
|
+
show_learn_announcement
|
34
|
+
end
|
35
|
+
|
36
|
+
def about
|
37
|
+
empty_line
|
38
|
+
say Terminal.text :about
|
39
|
+
empty_line
|
40
|
+
say %x{belajar help}
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def show_setup_list_announcement
|
46
|
+
command = 'belajar setup list'
|
47
|
+
text = [
|
48
|
+
"The courses path and solutions path have been added to your settings.",
|
49
|
+
"Just list your current settings with the \"#{command}\" command:"
|
50
|
+
].join("\n")
|
51
|
+
|
52
|
+
get_command(command, text)
|
53
|
+
end
|
54
|
+
|
55
|
+
def show_courses_list_announcement
|
56
|
+
command = 'belajar courses list'
|
57
|
+
text = [
|
58
|
+
"Well done. Now, type \"#{command}\" to see what courses are",
|
59
|
+
"available in your belajar folder:"
|
60
|
+
].join("\n")
|
61
|
+
|
62
|
+
get_command(command, text)
|
63
|
+
end
|
64
|
+
|
65
|
+
def show_courses_download_announcement
|
66
|
+
command = 'belajar courses download'
|
67
|
+
text = [
|
68
|
+
"Oh! You don't have any courses, yet?",
|
69
|
+
"Just enter \"#{command}\" to download the basic Belajar course:"
|
70
|
+
].join("\n")
|
71
|
+
|
72
|
+
get_command(command, text)
|
73
|
+
end
|
74
|
+
|
75
|
+
def show_solutions_open_announcement
|
76
|
+
command = 'belajar solutions open'
|
77
|
+
text = [
|
78
|
+
"When downloading a course, Belajar scaffolds empty solution files",
|
79
|
+
"for your code on the fly.\n",
|
80
|
+
"Type \"#{command}\" to open your solutions folder:"
|
81
|
+
].join("\n")
|
82
|
+
|
83
|
+
get_command(command, text)
|
84
|
+
end
|
85
|
+
|
86
|
+
def show_learn_announcement
|
87
|
+
command = 'belajar learn'
|
88
|
+
text = [
|
89
|
+
"Congratulations! You learned the first steps of using belajar.",
|
90
|
+
"To continue and start learning Ruby type \"#{command}\":"
|
91
|
+
].join("\n")
|
92
|
+
|
93
|
+
get_command(command, text)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
data/lib/belajar/test.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Belajar
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class Test
|
5
|
+
|
6
|
+
attr_reader :path
|
7
|
+
|
8
|
+
CODE_REGEX = /\[\['solution::code'\]\]/
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@unit_path = path
|
12
|
+
@path = Dir[File.join(path, '*spec.rb')].first
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(solution_code)
|
16
|
+
spec_code = File.read(@path)
|
17
|
+
patched_spec_code = insert_code(spec_code, solution_code.to_s)
|
18
|
+
|
19
|
+
temp_spec = File.join(File.dirname(@path), "temp_#{File.basename(@path)}")
|
20
|
+
create_temp_spec(temp_spec, patched_spec_code)
|
21
|
+
|
22
|
+
result = %x{ rspec --color --format j #{temp_spec} }
|
23
|
+
remove_file(temp_spec)
|
24
|
+
|
25
|
+
TestResult.new(result)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def insert_code(spec, code)
|
31
|
+
spec.gsub(CODE_REGEX, code)
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_temp_spec(path, content)
|
35
|
+
base_path = File.dirname(path)
|
36
|
+
FileUtils.mkdir_p(base_path) unless Dir.exist?(base_path)
|
37
|
+
File.open(path, 'w') { |f| f.puts content }
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove_file(path)
|
41
|
+
FileUtils.rm(path) if File.exist?(path)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Belajar
|
2
|
+
|
3
|
+
class TestResult
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
attr_reader :examples, :example_count, :failure_count
|
7
|
+
|
8
|
+
def initialize(result_json)
|
9
|
+
@result = begin
|
10
|
+
JSON.parse(result_json, symbolize_names: true)
|
11
|
+
rescue
|
12
|
+
syntax_error_json
|
13
|
+
end
|
14
|
+
|
15
|
+
@example_count = @result[:summary][:example_count]
|
16
|
+
@failure_count = @result[:summary][:failure_count]
|
17
|
+
|
18
|
+
@examples = @result[:examples].map do |example|
|
19
|
+
description = example[:full_description]
|
20
|
+
status = example[:status]
|
21
|
+
exception = example[:exception]
|
22
|
+
message = exception ? exception[:message] : nil
|
23
|
+
|
24
|
+
TestExample.new(description: description, status: status, message: message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def passed?
|
29
|
+
@examples.reduce(true) do |passed, example|
|
30
|
+
passed && example.passed?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def summary
|
35
|
+
if passed?
|
36
|
+
"Your code passed all tests. #{Belajar::Congratulator.message}"
|
37
|
+
else
|
38
|
+
build_failed_summary
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def summary_lines
|
43
|
+
summary.lines.map(&:strip)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def build_failed_summary
|
49
|
+
message = examples.map do |example|
|
50
|
+
"#{example.description}\n#{example.status}: #{example.message}"
|
51
|
+
end
|
52
|
+
|
53
|
+
summary = message.map(&:strip).join("\n" * 3)
|
54
|
+
end
|
55
|
+
|
56
|
+
def syntax_error_json
|
57
|
+
{
|
58
|
+
summary: {},
|
59
|
+
examples: [
|
60
|
+
{
|
61
|
+
status: 'failed',
|
62
|
+
exception: { message: ":( You got a syntax error in your code!" }
|
63
|
+
}
|
64
|
+
]
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class TestExample
|
70
|
+
|
71
|
+
attr_reader :description, :status, :message
|
72
|
+
|
73
|
+
EXAMPLE_PASSED_MESSAGE = "Your code passed this requirement."
|
74
|
+
|
75
|
+
def initialize(args = {})
|
76
|
+
@description = args[:description]
|
77
|
+
@status = args[:status]
|
78
|
+
@message = args[:message] || EXAMPLE_PASSED_MESSAGE
|
79
|
+
end
|
80
|
+
|
81
|
+
def passed?
|
82
|
+
@status == 'passed'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|