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
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
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /.idea
16
+ .project
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in daigaku.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'rspec', cmd: 'rspec', all_after_pass: true do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
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
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/daigaku ADDED
@@ -0,0 +1,12 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'daigaku'
7
+ rescue LoadError => e
8
+ warn "could not load \"daigaku\"\n#{e}"
9
+ exit -1
10
+ end
11
+
12
+ Daigaku::Terminal::CLI.start
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