daigaku 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
# ![Daigaku](http://res.cloudinary.com/daigaku-ruby/image/upload/c_scale,h_100/v1426946323/rect5481_si3rjr.png)
|
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
|