daigaku 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -0
  3. data/README.md +25 -3
  4. data/Rakefile +3 -0
  5. data/daigaku.gemspec +3 -2
  6. data/lib/daigaku/configuration.rb +7 -4
  7. data/lib/daigaku/congratulator.rb +13 -0
  8. data/lib/daigaku/course.rb +5 -0
  9. data/lib/daigaku/generator.rb +13 -6
  10. data/lib/daigaku/github_client.rb +30 -0
  11. data/lib/daigaku/reference_solution.rb +10 -2
  12. data/lib/daigaku/solution.rb +19 -8
  13. data/lib/daigaku/storeable.rb +32 -0
  14. data/lib/daigaku/terminal/courses.rb +103 -11
  15. data/lib/daigaku/terminal/output.rb +6 -0
  16. data/lib/daigaku/terminal/texts/congratulations.txt +12 -0
  17. data/lib/daigaku/terminal.rb +2 -1
  18. data/lib/daigaku/test_result.rb +5 -3
  19. data/lib/daigaku/version.rb +1 -1
  20. data/lib/daigaku/views/chapters_menu.rb +19 -50
  21. data/lib/daigaku/views/courses_menu.rb +14 -49
  22. data/lib/daigaku/views/main_menu.rb +6 -6
  23. data/lib/daigaku/views/menu.rb +89 -0
  24. data/lib/daigaku/views/task_view.rb +29 -11
  25. data/lib/daigaku/views/top_bar.rb +9 -17
  26. data/lib/daigaku/views/units_menu.rb +21 -52
  27. data/lib/daigaku/views.rb +4 -12
  28. data/lib/daigaku/window.rb +46 -3
  29. data/lib/daigaku.rb +1 -4
  30. data/spec/daigaku/configuration_spec.rb +11 -11
  31. data/spec/daigaku/congratulator_spec.rb +24 -0
  32. data/spec/daigaku/course_spec.rb +18 -0
  33. data/spec/daigaku/generator_spec.rb +4 -4
  34. data/spec/daigaku/github_client_spec.rb +53 -0
  35. data/spec/daigaku/reference_solution_spec.rb +20 -2
  36. data/spec/daigaku/solution_spec.rb +13 -6
  37. data/spec/daigaku/storeable_spec.rb +35 -0
  38. data/spec/daigaku/terminal/courses_spec.rb +215 -5
  39. data/spec/daigaku/terminal/output_spec.rb +31 -3
  40. data/spec/daigaku/terminal_spec.rb +12 -2
  41. data/spec/daigaku/test_result_spec.rb +12 -2
  42. data/spec/daigaku/views/chapters_menu_spec.rb +1 -3
  43. data/spec/daigaku/views/courses_menu_spec.rb +1 -3
  44. data/spec/daigaku/views/menu_spec.rb +19 -0
  45. data/spec/daigaku/views/task_view_spec.rb +1 -1
  46. data/spec/daigaku/views/units_menu_spec.rb +1 -3
  47. data/spec/daigaku/views_spec.rb +0 -2
  48. data/spec/daigaku_spec.rb +0 -6
  49. data/spec/support/macros/content_helpers.rb +1 -1
  50. data/spec/support/macros/mock_helpers.rb +6 -1
  51. data/spec/support/macros/path_helpers.rb +12 -6
  52. data/spec/support/macros/resource_helpers.rb +3 -1
  53. metadata +33 -8
  54. data/lib/daigaku/database.rb +0 -64
  55. data/spec/daigaku/database_spec.rb +0 -79
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3ce9d43dc806807d9613ddac880f1aaafedc6f2f
4
- data.tar.gz: f1abac8e7d72762851395bfdd5dc397f6b1d7833
3
+ metadata.gz: 579a43d2967ed7592ae65d76b826b2a14b7dac14
4
+ data.tar.gz: 54a8f9846c685f2b0184d3dd8e2f9e95921b5fae
5
5
  SHA512:
6
- metadata.gz: 385ee9c126906aa38936e02a74217f22f25b527d879ee882446b6cfbd890b6bf5433d6a4d5d34395b13d0d3c96fc317201c509aaad3247ab31dcca22e70aa3b1
7
- data.tar.gz: f4bfe1ebffd9570f41ef05082addd694666c2400ec21cdfd362d54ed73cd8fe80c2bfd4e67f101eb5cc3f4fe003f61515e17d9ff2f3aafec9b955e9ff9eadb24
6
+ metadata.gz: 8b94570b37b186fdb35b3b875f1cad97e355a95d62df87ed179536f5792dd3ffeb88d55d4b9aba1622720dd2c50e10d5e50666b497264141518c63ee7ed00f96
7
+ data.tar.gz: 9903fe01ea858ad2605d38888bd5bdc4527e2eca195b780ad7f9627af4d478200e68e83080bd8a263f5bbbaa3b9ee8eb731b741933116f02b7fb7fc4ee8cfaa2
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.2.0
5
+ - rbx-2
6
+ - ruby-head
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # ![Daigaku](http://res.cloudinary.com/daigaku-ruby/image/upload/c_scale,h_100/v1426946323/rect5481_si3rjr.png)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/daigaku.svg)](http://badge.fury.io/rb/daigaku)
4
+ [![Travis Build](https://travis-ci.org/daigaku-ruby/daigaku.svg)](https://travis-ci.org/daigaku-ruby/daigaku)
4
5
 
5
6
  Daigaku (大学) is the Japanese word for **university**.
6
7
 
@@ -36,29 +37,50 @@ and navigate through your solutions.
36
37
 
37
38
  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.
38
39
 
40
+ ![Daigaku CLI screenshot](http://res.cloudinary.com/daigaku-ruby/image/upload/v1427558807/daigaku-cli-screenshot_xgpav6.png)
41
+
39
42
  ## Daigaku screen
40
43
 
41
44
  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.
42
45
 
43
46
  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.
44
47
 
48
+ ![Daigaku screen screenshot](http://res.cloudinary.com/daigaku-ruby/image/upload/v1430859202/daigaku-taskview_erwzrh.png)
49
+
45
50
  ## Contributing
46
51
 
47
52
  We encourage you to contribute to Daigaku development and course creation.
48
53
 
49
54
  ### Creating Daigaku courses
50
55
 
51
- You can create your own Daigaku courses and make them available to the community.
56
+ Daigaku is a great tool, but it's nothing without courses to learn from.
57
+ Go ahead and help with making Daigaku a worthwile and fun resource for learning Ruby!
58
+
59
+ Daigaku uses the course "Get started with Ruby" by default.
60
+ Any contributions to the basic Daigaku course are more than welcome.
61
+ To add chapters to the course fork it from https://github.com/daigaku-ruby/Get_started_with_Ruby
62
+ and follow its guidelines for adding chapters or units.
63
+
64
+ You can also create your own Daigaku courses and make them available to the community.
52
65
  Learn how to create a Daigaku course in the [Daigaku Wiki](https://github.com/daigaku-ruby/daigaku/wiki/How-to-create-a-Daigaku-course).
53
66
 
54
67
  ### Development
55
68
 
69
+ Any ideas, feature proposals, filing and feedback on issues are very welcome.
70
+ We use the [git branching model](http://nvie.com/posts/a-successful-git-branching-model/) described by [nvie](https://github.com/nvie).
71
+
72
+ Here's how to contribute:
73
+
56
74
  1. Fork it ( https://github.com/daigaku-ruby/daigaku/fork )
57
- 2. Create your feature branch (`git checkout -b my-new-feature`)
75
+ 2. Create your feature branch (`git checkout -b feature/my-new-feature develop`)
58
76
  3. Commit your changes (`git commit -am 'Add some feature'`)
59
- 4. Push to the branch (`git push origin my-new-feature`)
77
+ 4. Push to the branch (`git push origin feature/my-new-feature`)
60
78
  5. Create a new Pull Request
61
79
 
80
+ Please try to add RSpec tests with your new features. This will ensure that your code does not break existing functionality and that your feature is working as expected.
81
+
82
+ Ah, don't forget step 6: Celebrate that you made Daigaku a better tool after your code was merged in! :octocat: :tada:
83
+
62
84
  ### License
63
85
 
64
86
  Daigaku is released under the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,2 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
2
3
 
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task default: :spec
data/daigaku.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  lib = File.expand_path('../lib', __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'daigaku/version'
@@ -6,10 +5,11 @@ require 'daigaku/version'
6
5
  Gem::Specification.new do |spec|
7
6
  spec.name = "daigaku"
8
7
  spec.version = Daigaku::VERSION
8
+ spec.required_ruby_version = '~> 2.0'
9
9
  spec.authors = ["Paul Götze"]
10
10
  spec.email = ["paul.christoph.goetze@gmail.com"]
11
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.}
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
13
  spec.homepage = "https://github.com/daigaku-ruby/daigaku"
14
14
  spec.license = "MIT"
15
15
 
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_runtime_dependency "colorize", "~> 0.7.5"
30
30
  spec.add_runtime_dependency "rubyzip", ">= 1.0", "< 2.0"
31
31
  spec.add_runtime_dependency "wisper", ">= 2.0.0.rc1", "< 3.0"
32
+ spec.add_runtime_dependency "quick_store", "~> 0.1.0"
32
33
 
33
34
  spec.add_development_dependency "bundler", "~> 1.7"
34
35
  spec.add_development_dependency "rake", "~> 10.0"
@@ -1,6 +1,5 @@
1
1
  module Daigaku
2
2
  require 'singleton'
3
- require 'yaml'
4
3
  require 'fileutils'
5
4
 
6
5
  class Configuration
@@ -19,6 +18,10 @@ module Daigaku
19
18
  @courses_path = local_path_to(COURSES_DIR)
20
19
  @storage_file = local_path_to(STORAGE_FILE)
21
20
 
21
+ QuickStore.configure do |config|
22
+ config.file_path = @storage_file
23
+ end
24
+
22
25
  yield if block_given?
23
26
  end
24
27
 
@@ -48,13 +51,13 @@ module Daigaku
48
51
  settings.each do |variable|
49
52
  key = variable.to_s.delete('@')
50
53
  value = self.instance_variable_get(variable.to_sym)
51
- Database.set(key, value)
54
+ QuickStore.store.set(key, value)
52
55
  end
53
56
  end
54
57
 
55
58
  def import!
56
- @courses_path = Database.courses_path || @courses_path
57
- @solutions_path = Database.solutions_path || @solutions_path
59
+ @courses_path = QuickStore.store.courses_path || @courses_path
60
+ @solutions_path = QuickStore.store.solutions_path || @solutions_path
58
61
  self
59
62
  end
60
63
 
@@ -0,0 +1,13 @@
1
+ module Daigaku
2
+
3
+ class Congratulator
4
+
5
+ def self.message
6
+ lines = Terminal.text(:congratulations).lines.map(&:strip).compact
7
+ count = lines.count.zero? ? 0 : (lines.count - 1)
8
+ random_value = rand(0..count)
9
+ lines[random_value]
10
+ end
11
+
12
+ end
13
+ end
@@ -6,6 +6,7 @@ module Daigaku
6
6
  def initialize(path)
7
7
  @path = path
8
8
  @title = File.basename(path).gsub(/\_+/, ' ')
9
+ @author = QuickStore.store.get(key(:author))
9
10
  end
10
11
 
11
12
  def chapters
@@ -19,5 +20,9 @@ module Daigaku
19
20
  def mastered?
20
21
  chapters.reduce(true) { |mastered, chapter| mastered &&= chapter.mastered? }
21
22
  end
23
+
24
+ def key(key_name)
25
+ Storeable.key(title, prefix: 'courses', suffix: key_name)
26
+ end
22
27
  end
23
28
  end
@@ -5,15 +5,16 @@ module Daigaku
5
5
 
6
6
  class Generator
7
7
 
8
- SOLUTION_SUFFIX = '_solution.rb'
9
-
10
8
  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])
9
+ Dir[File.join(courses_path, "*/*/*/*.md")].each do |file|
10
+ content_dir_parts = file.split('/')[-4..-2].map do |part|
11
+ clean_up_path_part(part)
12
+ end
13
+
14
+ content_dir = File.join(content_dir_parts)
13
15
  directory = File.join(target_path, File.dirname(content_dir))
14
16
 
15
- unit_name = File.basename(content_dir)
16
- solution_file = unit_name.gsub(/(\_+|\-+|\.+)/, '_') + SOLUTION_SUFFIX
17
+ solution_file = File.basename(content_dir) + Solution::FILE_SUFFIX
17
18
  file_path = File.join(directory, solution_file)
18
19
 
19
20
  create_dir(directory)
@@ -49,5 +50,11 @@ module Daigaku
49
50
  create_dir(File.dirname(path))
50
51
  FileUtils.touch(path) unless File.exist?(path)
51
52
  end
53
+
54
+ def clean_up_path_part(text)
55
+ leading_numbers = /^\d+[\_\-\s]/
56
+ part_joints = /[\_\-\s]+/
57
+ text.gsub(leading_numbers, '').gsub(part_joints, '_').downcase
58
+ end
52
59
  end
53
60
  end
@@ -0,0 +1,30 @@
1
+ require 'open-uri'
2
+ require 'json'
3
+ require 'date'
4
+
5
+ module Daigaku
6
+ module GithubClient
7
+
8
+ # Returns the url to the master zip file of the Github repo.
9
+ def self.master_zip_url(user_and_repo)
10
+ "https://github.com/#{user_and_repo}/archive/master.zip"
11
+ end
12
+
13
+ # Returns the timestamp of updated_at for the repo from the Github API.
14
+ def self.updated_at(user_and_repo)
15
+ url = "https://api.github.com/repos/#{user_and_repo}"
16
+ JSON.parse(open(url).read)['updated_at']
17
+ end
18
+
19
+ # Returns whether the pushed_at time from Github API is newer than the
20
+ # stored one.
21
+ def self.updated?(user_and_repo)
22
+ return false unless user_and_repo
23
+
24
+ course = Course.new(user_and_repo.split('/').last)
25
+ stored_time = QuickStore.store.get(course.key(:updated_at))
26
+ current_time = self.updated_at(user_and_repo)
27
+ DateTime.parse(stored_time) < DateTime.parse(current_time)
28
+ end
29
+ end
30
+ end
@@ -1,10 +1,18 @@
1
1
  module Daigaku
2
2
  class ReferenceSolution
3
- attr_reader :code, :path
3
+ attr_reader :path
4
4
 
5
5
  def initialize(path)
6
6
  @path = Dir[File.join(path, '*solution.rb')].first
7
7
  @code = File.read(@path).strip if @path
8
8
  end
9
+
10
+ def code
11
+ @code.to_s
12
+ end
13
+
14
+ def code_lines
15
+ code.lines.map(&:chomp)
16
+ end
9
17
  end
10
- end
18
+ end
@@ -1,18 +1,20 @@
1
1
  module Daigaku
2
2
  class Solution
3
3
 
4
+ FILE_SUFFIX = '_solution.rb'
5
+
4
6
  attr_reader :code, :path, :errors
5
7
 
6
8
  def initialize(unit_path)
7
9
  @unit_path = unit_path
8
10
  @path = solution_path(unit_path)
9
11
  @code = File.read(@path).strip if File.file?(@path)
10
- @verified = get_database_state
12
+ @verified = get_store_state
11
13
  end
12
14
 
13
15
  def verify!
14
16
  result = Daigaku::Test.new(@unit_path).run(self.code)
15
- set_database_state(result.passed?)
17
+ set_store_state(result.passed?)
16
18
  result
17
19
  end
18
20
 
@@ -20,23 +22,32 @@ module Daigaku
20
22
  !!@verified
21
23
  end
22
24
 
25
+ def store_key
26
+ unless @store_key
27
+ part_path = path.split('/')[-3..-1].join('/').gsub(FILE_SUFFIX, '')
28
+ @store_key = Storeable.key(part_path, prefix: 'verified')
29
+ end
30
+
31
+ @store_key
32
+ end
33
+
23
34
  private
24
35
 
25
36
  def solution_path(path)
26
37
  local_path = Daigaku.config.solutions_path
27
- sub_dirs = path.split('/')[-3..-2]
28
- file = File.basename(path).gsub(/(\_+|\-+|\.+)/, '_') + '_solution.rb'
38
+ sub_dirs = Storeable.key(path.split('/')[-3..-2].join('/').gsub(FILE_SUFFIX, ''))
39
+ file = Storeable.key(File.basename(path)) + FILE_SUFFIX
29
40
 
30
41
  File.join(local_path, sub_dirs, file)
31
42
  end
32
43
 
33
- def set_database_state(verified)
44
+ def set_store_state(verified)
34
45
  @verified = verified
35
- Daigaku.database.set(@path, verified?)
46
+ QuickStore.store.set(store_key, verified?)
36
47
  end
37
48
 
38
- def get_database_state
39
- Daigaku.database.get(@path)
49
+ def get_store_state
50
+ QuickStore.store.get(store_key)
40
51
  end
41
52
  end
42
53
  end
@@ -0,0 +1,32 @@
1
+ module Daigaku
2
+ module Storeable
3
+
4
+ LEADING_NUMBERS = /^\d+[\_\-\s]+/
5
+ PART_JOINTS = /[\_\-\s]+/
6
+
7
+ class << self
8
+ def key(text, options = {})
9
+ separator = QuickStore.config.key_separator
10
+ prefix = options[:prefix]
11
+ suffix = clean(options[:suffix])
12
+ suffixes = options[:suffixes]
13
+ suffixes_items = suffixes ? suffixes.map { |s| clean(s) }.compact : nil
14
+
15
+ [prefix, clean(text), suffix || suffixes_items].compact.join(separator)
16
+ end
17
+
18
+ private
19
+
20
+ def clean(text)
21
+ if text
22
+ parts = text.to_s.split(QuickStore.config.key_separator).map do |key|
23
+ key.gsub(LEADING_NUMBERS, '').gsub(PART_JOINTS, '_').downcase
24
+ end
25
+
26
+ parts.join(QuickStore.config.key_separator)
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -15,15 +15,12 @@ module Daigaku
15
15
  say_info courses_list_text(courses)
16
16
  end
17
17
 
18
- method_option :github,
19
- type: :string,
20
- aliases: '-g',
21
- desc: 'Download Github repository'
18
+ method_option :github, type: :string, aliases: '-g', desc: 'Download Github repository'
22
19
  desc 'download [URL] [OPTIONS]', 'Download a new daigaku course from [URL]'
23
- def download(url = nil)
20
+ def download(url = nil, action = 'downloaded')
24
21
  use_initial_course = url.nil? && options[:github].nil?
25
- url = github_repo(Daigaku.config.initial_course) if use_initial_course
26
- url = github_repo(options[:github]) if options[:github]
22
+ url = GithubClient.master_zip_url(Daigaku.config.initial_course) if use_initial_course
23
+ url = GithubClient.master_zip_url(options[:github]) if options[:github]
27
24
 
28
25
  url_given = (url =~ /\A#{URI::regexp(['http', 'https'])}\z/)
29
26
  github = use_initial_course || options[:github] || url.match(/github\.com/)
@@ -38,9 +35,18 @@ module Daigaku
38
35
 
39
36
  File.open(file_name, 'w') { |file| file << open(url).read }
40
37
  course_name = unzip(file_name, github)
38
+
39
+ if github
40
+ user_and_repo = url.match(/github.com\/(.*)\/archive\/master.zip/).captures.first
41
+ store_repo_data(options[:github] || user_and_repo)
42
+ end
43
+
44
+ course = Course.new(course_name)
45
+ QuickStore.store.set(course.key(:url), url)
46
+ QuickStore.store.set(course.key(:updated_at), Time.now.to_s)
41
47
  scaffold_solutions
42
48
 
43
- say_info "Successfully downloaded the course \"#{course_name}\"!"
49
+ say_info "Successfully #{action} the course \"#{course_name}\"!"
44
50
  rescue Download::NoUrlError => e
45
51
  print_download_warning(url, "\"#{url}\" is not a valid URL!")
46
52
  rescue Download::NoZipFileUrlError => e
@@ -51,6 +57,58 @@ module Daigaku
51
57
  FileUtils.rm(file_name) if File.exist?(file_name.to_s)
52
58
  end
53
59
 
60
+ method_option :all, type: :boolean, aliases: '-a', desc: 'Update all courses'
61
+ desc 'update [COURSE_NAME] [OPTIONS]', 'Update Daigak courses.'
62
+ def update(course_name = nil)
63
+ if options[:all]
64
+ courses = Loading::Courses.load(Daigaku.config.courses_path)
65
+ courses.each { |course| update_course(course) }
66
+ elsif course_name
67
+ path = File.join(Daigaku.config.courses_path, course_name)
68
+
69
+ unless Dir.exist?(path)
70
+ print_course_not_available(course_name)
71
+ return
72
+ end
73
+
74
+ update_course(Course.new(course_name))
75
+ else
76
+ system 'daigaku course help update'
77
+ end
78
+ end
79
+
80
+ method_option :all, type: :boolean, aliases: '-a', desc: 'Delete all courses'
81
+ desc 'delete [COURSE_NAME] [OPTIONS]', 'Delete Daigaku courses.'
82
+ def delete(course_name = nil)
83
+ if options[:all]
84
+ get_confirm('Are you shure you want to delete all courses?') do
85
+ course_dirs = Dir[File.join(Daigaku.config.courses_path, '*')]
86
+
87
+ course_dirs.each do |dir|
88
+ FileUtils.remove_dir(dir)
89
+ QuickStore.store.delete(Storeable.key(File.basename(dir), prefix: 'courses'))
90
+ end
91
+
92
+ say_info "All daigaku courses were successfully deleted."
93
+ end
94
+ elsif course_name
95
+ path = File.join(Daigaku.config.courses_path, course_name)
96
+
97
+ unless Dir.exist?(path)
98
+ print_course_not_available(course_name)
99
+ return
100
+ end
101
+
102
+ get_confirm("Are you shure you want to delete the course \"#{course_name}\"?") do
103
+ FileUtils.remove_dir(path)
104
+ QuickStore.store.delete(Storeable.key(course_name, prefix: 'courses'))
105
+ say_info "The course \"#{course_name}\" was successfully deleted."
106
+ end
107
+ else
108
+ system 'daigaku courses help delete'
109
+ end
110
+ end
111
+
54
112
  private
55
113
 
56
114
  def courses_list_text(courses)
@@ -66,8 +124,14 @@ module Daigaku
66
124
  "#{text}\n#{Terminal.text :hint_course_download}"
67
125
  end
68
126
 
69
- def github_repo(user_and_repo)
70
- "https://github.com/#{user_and_repo}/archive/master.zip"
127
+ def store_repo_data(user_and_repo)
128
+ parts = (user_and_repo ||= Daigaku.config.initial_course).split('/')
129
+ author = parts.first
130
+ course = parts.second
131
+
132
+ course = Course.new(course)
133
+ QuickStore.store.set(course.key(:author), author)
134
+ QuickStore.store.set(course.key(:github), user_and_repo)
71
135
  end
72
136
 
73
137
  def unzip(file_path, github = false)
@@ -84,7 +148,10 @@ module Daigaku
84
148
  directory = entry.to_s
85
149
  end
86
150
 
87
- course_name ||= directory.split('/').first.gsub(/_+/, ' ')
151
+ if directory != '/'
152
+ course_name ||= directory.split('/').first.gsub(/_+/, ' ')
153
+ end
154
+
88
155
  zip_file.extract(entry, "#{target_dir}/#{directory}") { true }
89
156
  end
90
157
  end
@@ -108,6 +175,31 @@ module Daigaku
108
175
 
109
176
  say_warning message
110
177
  end
178
+
179
+ def update_course(course)
180
+ url = QuickStore.store.get(course.key(:url))
181
+ github_repo = QuickStore.store.get(course.key(:github))
182
+ updated = GithubClient.updated?(github_repo)
183
+
184
+ if !github_repo || updated
185
+ download(url, 'updated') if url
186
+ else
187
+ say_info "Course \"#{course.title}\" is still up to date."
188
+ end
189
+ end
190
+
191
+ def print_course_not_available(course_name)
192
+ text = [
193
+ "The course \"#{course_name}\" is not available in",
194
+ "\"#{Daigaku.config.courses_path}\".\n",
195
+ ]
196
+
197
+ say_warning text.join("\n")
198
+
199
+ unless Loading::Courses.load(Daigaku.config.courses_path).empty?
200
+ Terminal::Courses.new.list
201
+ end
202
+ end
111
203
  end
112
204
 
113
205
  end
@@ -65,6 +65,12 @@ module Daigaku
65
65
  break
66
66
  end
67
67
  end
68
+
69
+ def get_confirm(description)
70
+ say_warning description
71
+ confirm = get '(yes|no)'
72
+ yield if confirm == 'yes' && block_given?
73
+ end
68
74
  end
69
75
  end
70
76
 
@@ -0,0 +1,12 @@
1
+ Well done!
2
+ Three cheers!
3
+ You did it!
4
+ Congrats!
5
+ Bravo!
6
+ Hip, hip, hurrah!
7
+ Congratulations!
8
+ Kudos!
9
+ Props!
10
+ Hats off!
11
+ Yay!
12
+ Well done! Ready for the next task?
@@ -4,7 +4,8 @@ module Daigaku
4
4
  # text should be of a width of 70 columns or less
5
5
  def self.text(file_name)
6
6
  texts_path = File.expand_path('../terminal/texts', __FILE__)
7
- File.read(File.join(texts_path, "#{file_name.to_s}.txt"))
7
+ file = File.join(texts_path, "#{file_name.to_s}.txt")
8
+ (File.exist?(file) ? File.read(file).to_s : '')
8
9
  end
9
10
 
10
11
  end
@@ -5,8 +5,6 @@ module Daigaku
5
5
 
6
6
  attr_reader :examples, :example_count, :failure_count
7
7
 
8
- TEST_PASSED_MESSAGE = "Your code passed all tests. Congratulations!"
9
-
10
8
  def initialize(result_json)
11
9
  @result = begin
12
10
  JSON.parse(result_json, symbolize_names: true)
@@ -35,12 +33,16 @@ module Daigaku
35
33
 
36
34
  def summary
37
35
  if passed?
38
- TEST_PASSED_MESSAGE
36
+ "Your code passed all tests. #{Daigaku::Congratulator.message}"
39
37
  else
40
38
  build_failed_summary
41
39
  end
42
40
  end
43
41
 
42
+ def summary_lines
43
+ summary.lines.map(&:strip)
44
+ end
45
+
44
46
  private
45
47
 
46
48
  def build_failed_summary
@@ -1,3 +1,3 @@
1
1
  module Daigaku
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end