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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/README.md +62 -0
- data/Rakefile +2 -0
- data/bin/daigaku +12 -0
- data/daigaku.gemspec +37 -0
- data/lib/daigaku.rb +27 -0
- data/lib/daigaku/chapter.rb +23 -0
- data/lib/daigaku/configuration.rb +86 -0
- data/lib/daigaku/course.rb +23 -0
- data/lib/daigaku/database.rb +64 -0
- data/lib/daigaku/exceptions.rb +19 -0
- data/lib/daigaku/generator.rb +53 -0
- data/lib/daigaku/loadable.rb +23 -0
- data/lib/daigaku/loading/chapters.rb +9 -0
- data/lib/daigaku/loading/courses.rb +9 -0
- data/lib/daigaku/loading/units.rb +9 -0
- data/lib/daigaku/reference_solution.rb +10 -0
- data/lib/daigaku/solution.rb +42 -0
- data/lib/daigaku/task.rb +10 -0
- data/lib/daigaku/terminal.rb +11 -0
- data/lib/daigaku/terminal/cli.rb +59 -0
- data/lib/daigaku/terminal/courses.rb +114 -0
- data/lib/daigaku/terminal/output.rb +72 -0
- data/lib/daigaku/terminal/setup.rb +115 -0
- data/lib/daigaku/terminal/solutions.rb +46 -0
- data/lib/daigaku/terminal/texts/about.txt +19 -0
- data/lib/daigaku/terminal/texts/courses_empty.txt +3 -0
- data/lib/daigaku/terminal/texts/hint_course_download.txt +13 -0
- data/lib/daigaku/terminal/texts/welcome.txt +12 -0
- data/lib/daigaku/terminal/welcome.rb +98 -0
- data/lib/daigaku/test.rb +46 -0
- data/lib/daigaku/test_result.rb +69 -0
- data/lib/daigaku/unit.rb +28 -0
- data/lib/daigaku/version.rb +3 -0
- data/lib/daigaku/views.rb +59 -0
- data/lib/daigaku/views/chapters_menu.rb +91 -0
- data/lib/daigaku/views/courses_menu.rb +87 -0
- data/lib/daigaku/views/main_menu.rb +37 -0
- data/lib/daigaku/views/splash.rb +57 -0
- data/lib/daigaku/views/task_view.rb +206 -0
- data/lib/daigaku/views/top_bar.rb +48 -0
- data/lib/daigaku/views/units_menu.rb +92 -0
- data/lib/daigaku/window.rb +160 -0
- data/spec/daigaku/chapter_spec.rb +76 -0
- data/spec/daigaku/configuration_spec.rb +161 -0
- data/spec/daigaku/course_spec.rb +75 -0
- data/spec/daigaku/database_spec.rb +79 -0
- data/spec/daigaku/generator_spec.rb +82 -0
- data/spec/daigaku/loading/chapters_spec.rb +16 -0
- data/spec/daigaku/loading/courses_spec.rb +16 -0
- data/spec/daigaku/loading/units_spec.rb +21 -0
- data/spec/daigaku/reference_solution_spec.rb +23 -0
- data/spec/daigaku/solution_spec.rb +79 -0
- data/spec/daigaku/task_spec.rb +23 -0
- data/spec/daigaku/terminal/cli_spec.rb +51 -0
- data/spec/daigaku/terminal/courses_spec.rb +60 -0
- data/spec/daigaku/terminal/output_spec.rb +123 -0
- data/spec/daigaku/terminal/setup_spec.rb +10 -0
- data/spec/daigaku/terminal/solutions_spec.rb +8 -0
- data/spec/daigaku/terminal/welcome_spec.rb +12 -0
- data/spec/daigaku/terminal_spec.rb +14 -0
- data/spec/daigaku/test_example_spec.rb +54 -0
- data/spec/daigaku/test_result_spec.rb +81 -0
- data/spec/daigaku/test_spec.rb +48 -0
- data/spec/daigaku/unit_spec.rb +85 -0
- data/spec/daigaku/views/chapters_menu_spec.rb +8 -0
- data/spec/daigaku/views/courses_menu_spec.rb +8 -0
- data/spec/daigaku/views/task_view_spec.rb +7 -0
- data/spec/daigaku/views/units_menu_spec.rb +8 -0
- data/spec/daigaku/views_spec.rb +23 -0
- data/spec/daigaku_spec.rb +57 -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 +20 -0
- data/spec/support/macros/path_helpers.rb +133 -0
- data/spec/support/macros/resource_helpers.rb +119 -0
- data/spec/support/macros/test_helpers.rb +6 -0
- metadata +361 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d8b67152f8cdc2685c5b2edfa2cf611f1f81eb61
|
4
|
+
data.tar.gz: e969647bd2749977c6f6a4967afbf826b46c291e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 431903dc0fb3e12805b76b94950d47a794180617dd21b25c6dc7c486734f750fadb27cfc4059d6f6a507a72a7995f15e5b2e0e0f356f266f25955624d05986a2
|
7
|
+
data.tar.gz: fb34667ddd6b7c30af0a22aa86d1bc5a2b6090fc2f0e22d9726fd5b2beb8b1b77592edb5e1241204a4d3a80f955d5050876f4f8633bed70864e3bfdd8d74cc9d
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# 
|
2
|
+
|
3
|
+
Daigaku (大学) is the Japanese word for **university**.
|
4
|
+
|
5
|
+
With Daigaku you can master your way of learning the Ruby programming
|
6
|
+
language with courses that are created by the community.
|
7
|
+
|
8
|
+
Daigaku is a command line tool and a text based interface and provides
|
9
|
+
you with a number of learning tasks and explanations about the Ruby
|
10
|
+
programming language. You will learn Ruby step by step by solving small
|
11
|
+
language-explaining programming tasks.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
First of all make sure Ruby is installed on your computer.
|
16
|
+
|
17
|
+
Then open a terminal and install Daigaku by running:
|
18
|
+
|
19
|
+
$ gem install daigaku
|
20
|
+
|
21
|
+
## Get started
|
22
|
+
|
23
|
+
To get started open a terminal and run following line:
|
24
|
+
|
25
|
+
$ daigaku welcome
|
26
|
+
|
27
|
+
Daigaku will lead you through the setup and some important commands.
|
28
|
+
|
29
|
+
## Command line interface
|
30
|
+
|
31
|
+
Daigaku's command line interface provides several commands which you
|
32
|
+
can use in your terminal to setup the system, download new courses,
|
33
|
+
and navigate through your solutions.
|
34
|
+
|
35
|
+
Please visit the [Daigaku Wiki](https://github.com/daigaku-ruby/daigaku/wiki/How-to-use-Daigaku%27s-command-line-interface-%28CLI%29) to learn more about available commands.
|
36
|
+
|
37
|
+
## Daigaku screen
|
38
|
+
|
39
|
+
Daigaku's text based interface - the Daigaku screen - shows your installed courses and allows you to navigate through their chapters and units. In the task view you can read the unit's task and validate your solution code.
|
40
|
+
|
41
|
+
Please visit the [Diagaku Wiki](https://github.com/daigaku-ruby/daigaku/wiki/How-to-learn-Ruby-in-the-Daigaku-screen) to learn how to use the Daigaku screen.
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
We encourage you to contribute to Daigaku development and course creation.
|
46
|
+
|
47
|
+
### Creating Daigaku courses
|
48
|
+
|
49
|
+
You can create your own Daigaku courses and make them available to the community.
|
50
|
+
Learn how to create a Daigaku course in the [Daigaku Wiki](https://github.com/daigaku-ruby/daigaku/wiki/How-to-create-a-Daigaku-course).
|
51
|
+
|
52
|
+
### Development
|
53
|
+
|
54
|
+
1. Fork it ( https://github.com/daigaku-ruby/daigaku/fork )
|
55
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
56
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
57
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
58
|
+
5. Create a new Pull Request
|
59
|
+
|
60
|
+
### License
|
61
|
+
|
62
|
+
Daigaku is released under the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/daigaku
ADDED
data/daigaku.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'daigaku/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "daigaku"
|
8
|
+
spec.version = Daigaku::VERSION
|
9
|
+
spec.authors = ["Paul Götze"]
|
10
|
+
spec.email = ["paul.christoph.goetze@gmail.com"]
|
11
|
+
spec.summary = %q{Learning Ruby on the command line.}
|
12
|
+
spec.description = %q{Daigaku is the Japanese word for university. With Daigaku you can interactively learn the Ruby Programming language using the command line.}
|
13
|
+
spec.homepage = "https://github.com/daigaku-ruby/daigaku"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
if RUBY_VERSION >= '2.1'
|
22
|
+
spec.add_runtime_dependency "curses", ">= 1.0", "< 2.0"
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.add_runtime_dependency "activesupport", ">= 4.0", "< 5.0"
|
26
|
+
spec.add_runtime_dependency "rspec", ">= 3.0", "< 4.0"
|
27
|
+
spec.add_runtime_dependency "thor", "~> 0.19.1"
|
28
|
+
spec.add_runtime_dependency "os", "~> 0.9.6"
|
29
|
+
spec.add_runtime_dependency "colorize", "~> 0.7.5"
|
30
|
+
spec.add_runtime_dependency "rubyzip", ">= 1.0", "< 2.0"
|
31
|
+
spec.add_runtime_dependency "wisper", ">= 2.0.0.rc1", "< 3.0"
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
+
spec.add_development_dependency "webmock", "~> 1.20.4"
|
36
|
+
spec.add_development_dependency "guard-rspec", "~> 4.5.0"
|
37
|
+
end
|
data/lib/daigaku.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'daigaku/window'
|
2
|
+
|
3
|
+
Dir[File.join("#{File.dirname(__FILE__)}/**/*.rb")].sort.each do |file|
|
4
|
+
require file
|
5
|
+
end
|
6
|
+
|
7
|
+
module Daigaku
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def config
|
11
|
+
Configuration.instance
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure
|
15
|
+
yield(config) if block_given?
|
16
|
+
end
|
17
|
+
|
18
|
+
def start
|
19
|
+
Views::Splash.new
|
20
|
+
Views::MainMenu.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def database
|
24
|
+
Database.instance
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Daigaku
|
2
|
+
class Chapter
|
3
|
+
|
4
|
+
attr_reader :title, :path
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
@path = path
|
8
|
+
@title = File.basename(path).gsub(/\_+/, ' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def units
|
12
|
+
@units ||= Loading::Units.load(@path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def started?
|
16
|
+
units.reduce(false) { |started, unit| started ||= unit.mastered? }
|
17
|
+
end
|
18
|
+
|
19
|
+
def mastered?
|
20
|
+
units.reduce(true) { |mastered, unit| mastered &&= unit.mastered? }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Daigaku
|
2
|
+
require 'singleton'
|
3
|
+
require 'yaml'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
class Configuration
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
LOCAL_DIR = '.daigaku'
|
10
|
+
COURSES_DIR = 'courses'
|
11
|
+
SOLUTIONS_DIR = 'solutions'
|
12
|
+
STORAGE_FILE = 'daigaku.db.yml'
|
13
|
+
DAIGAKU_INITIAL_COURSE = 'daigaku-ruby/Get_started_with_Ruby'
|
14
|
+
|
15
|
+
attr_accessor :courses_path
|
16
|
+
attr_reader :storage_file
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@courses_path = local_path_to(COURSES_DIR)
|
20
|
+
@storage_file = local_path_to(STORAGE_FILE)
|
21
|
+
|
22
|
+
yield if block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
def solutions_path
|
26
|
+
@solutions_path || raise(Daigaku::ConfigurationError, 'Solutions path is not set.')
|
27
|
+
end
|
28
|
+
|
29
|
+
def solutions_path=(path)
|
30
|
+
full_path = File.expand_path(path, Dir.pwd)
|
31
|
+
|
32
|
+
unless Dir.exist?(full_path)
|
33
|
+
error = [
|
34
|
+
Daigaku::ConfigurationError,
|
35
|
+
"Solutions path \"#{path}\" isn't an existing directory."
|
36
|
+
]
|
37
|
+
|
38
|
+
raise(*error)
|
39
|
+
end
|
40
|
+
|
41
|
+
@solutions_path = full_path
|
42
|
+
end
|
43
|
+
|
44
|
+
def save
|
45
|
+
settings = self.instance_variables
|
46
|
+
settings.delete(:@storage_file)
|
47
|
+
|
48
|
+
settings.each do |variable|
|
49
|
+
key = variable.to_s.delete('@')
|
50
|
+
value = self.instance_variable_get(variable.to_sym)
|
51
|
+
Database.set(key, value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def import!
|
56
|
+
@courses_path = Database.courses_path || @courses_path
|
57
|
+
@solutions_path = Database.solutions_path || @solutions_path
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def summary
|
62
|
+
settings = self.instance_variables
|
63
|
+
settings.delete(:@storage_file)
|
64
|
+
|
65
|
+
lines = settings.map do |variable|
|
66
|
+
key = variable.to_s.delete('@').gsub('_', ' ')
|
67
|
+
value = self.instance_variable_get(variable.to_sym)
|
68
|
+
"* #{key}: #{value}"
|
69
|
+
end
|
70
|
+
|
71
|
+
lines.join("\n")
|
72
|
+
end
|
73
|
+
|
74
|
+
def initial_course
|
75
|
+
DAIGAKU_INITIAL_COURSE
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def local_path_to(*resource)
|
81
|
+
path = File.join('~', LOCAL_DIR, resource)
|
82
|
+
File.expand_path(path, __FILE__)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Daigaku
|
2
|
+
class Course
|
3
|
+
|
4
|
+
attr_reader :title, :path, :author, :link
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
@path = path
|
8
|
+
@title = File.basename(path).gsub(/\_+/, ' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def chapters
|
12
|
+
@chapters ||= Loading::Chapters.load(@path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def started?
|
16
|
+
chapters.reduce(false) { |started, chapter| started ||= chapter.started? }
|
17
|
+
end
|
18
|
+
|
19
|
+
def mastered?
|
20
|
+
chapters.reduce(true) { |mastered, chapter| mastered &&= chapter.mastered? }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'yaml/store'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Daigaku
|
5
|
+
|
6
|
+
class Database
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
attr_reader :file
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@file = Daigaku.config.storage_file
|
13
|
+
directory = File.dirname(@file)
|
14
|
+
FileUtils.makedirs(directory) unless Dir.exist?(directory)
|
15
|
+
|
16
|
+
@db = YAML::Store.new(@file)
|
17
|
+
end
|
18
|
+
|
19
|
+
def set(key, value)
|
20
|
+
@db.transaction { @db[key.to_s] = value }
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(key)
|
24
|
+
@db.transaction { @db[key.to_s] }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.get(key)
|
28
|
+
instance.get(key)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.set(key, value)
|
32
|
+
instance.set(key, value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.file
|
36
|
+
instance.file
|
37
|
+
end
|
38
|
+
|
39
|
+
# Defines getter and setter methods for arbitrarily named methods.
|
40
|
+
# @xample
|
41
|
+
# Diagaku::Database.answer = 42
|
42
|
+
# => saves 'answer: 42' to database
|
43
|
+
#
|
44
|
+
# Daigaku::Database.answer
|
45
|
+
# => 42
|
46
|
+
def self.method_missing(method, *args, &block)
|
47
|
+
if method =~ /.*=$/
|
48
|
+
if singleton_methods.include?(method.to_s.chop.to_sym)
|
49
|
+
raise "There is a \"#{method.to_s.chop}\" instance method already " +
|
50
|
+
"defined. This will lead to problems while getting values " +
|
51
|
+
"from the database. Please use another key than " +
|
52
|
+
"#{singleton_methods.map(&:to_s)}."
|
53
|
+
end
|
54
|
+
|
55
|
+
instance.set(method.to_s.gsub(/=$/, ''), args[0])
|
56
|
+
elsif args.count == 0
|
57
|
+
instance.get(method)
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Daigaku
|
2
|
+
|
3
|
+
class Error < StandardError; end
|
4
|
+
class CourseNotFoundError < Error; end
|
5
|
+
class ChaptersNotFoundError < Error; end
|
6
|
+
class UnitsNotFoundError < Error; end
|
7
|
+
class TaskNotFoundError < Error; end
|
8
|
+
class ReferenceSolutionNotFoundError; end
|
9
|
+
class SolutionNotFoundError < Error; end
|
10
|
+
class ScaffoldError < Error; end
|
11
|
+
|
12
|
+
class ConfigurationError < Error; end
|
13
|
+
|
14
|
+
module Download
|
15
|
+
class NoUrlError < Error; end
|
16
|
+
class NoZipFileUrlError < Error; end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Daigaku
|
2
|
+
require 'fileutils'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
|
6
|
+
class Generator
|
7
|
+
|
8
|
+
SOLUTION_SUFFIX = '_solution.rb'
|
9
|
+
|
10
|
+
def scaffold(courses_path, target_path)
|
11
|
+
Dir[File.join(courses_path, "**/*.md")].each do |file|
|
12
|
+
content_dir = File.join(*file.split('/')[-4..-2])
|
13
|
+
directory = File.join(target_path, File.dirname(content_dir))
|
14
|
+
|
15
|
+
unit_name = File.basename(content_dir)
|
16
|
+
solution_file = unit_name.gsub(/(\_+|\-+|\.+)/, '_') + SOLUTION_SUFFIX
|
17
|
+
file_path = File.join(directory, solution_file)
|
18
|
+
|
19
|
+
create_dir(directory)
|
20
|
+
create_file(file_path)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def prepare
|
25
|
+
begin
|
26
|
+
solutions_path = Daigaku.config.solutions_path
|
27
|
+
rescue ConfigurationError => e
|
28
|
+
base_dir = File.dirname(Daigaku.config.courses_path)
|
29
|
+
solutions_dir = Daigaku::Configuration::SOLUTIONS_DIR
|
30
|
+
solutions_path = File.join(base_dir, solutions_dir)
|
31
|
+
end
|
32
|
+
|
33
|
+
create_dir(Daigaku.config.courses_path)
|
34
|
+
create_dir(solutions_path)
|
35
|
+
|
36
|
+
Daigaku.config.solutions_path = solutions_path
|
37
|
+
Daigaku.config.save
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def create_dir(path)
|
43
|
+
return if path.blank?
|
44
|
+
FileUtils.makedirs(path) unless Dir.exist?(path)
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_file(path)
|
48
|
+
return if path.blank?
|
49
|
+
create_dir(File.dirname(path))
|
50
|
+
FileUtils.touch(path) unless File.exist?(path)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|