githug 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/README.md +90 -0
  5. data/Rakefile +1 -0
  6. data/bin/githug +4 -0
  7. data/githug.gemspec +27 -0
  8. data/levels/add.rb +17 -0
  9. data/levels/blame.rb +20 -0
  10. data/levels/blame/.githug/COMMIT_EDITMSG +1 -0
  11. data/levels/blame/.githug/HEAD +1 -0
  12. data/levels/blame/.githug/config +5 -0
  13. data/levels/blame/.githug/description +1 -0
  14. data/levels/blame/.githug/hooks/applypatch-msg.sample +15 -0
  15. data/levels/blame/.githug/hooks/commit-msg.sample +24 -0
  16. data/levels/blame/.githug/hooks/post-commit.sample +8 -0
  17. data/levels/blame/.githug/hooks/post-receive.sample +15 -0
  18. data/levels/blame/.githug/hooks/post-update.sample +8 -0
  19. data/levels/blame/.githug/hooks/pre-applypatch.sample +14 -0
  20. data/levels/blame/.githug/hooks/pre-commit.sample +46 -0
  21. data/levels/blame/.githug/hooks/pre-rebase.sample +169 -0
  22. data/levels/blame/.githug/hooks/prepare-commit-msg.sample +36 -0
  23. data/levels/blame/.githug/hooks/update.sample +128 -0
  24. data/levels/blame/.githug/index +0 -0
  25. data/levels/blame/.githug/info/exclude +6 -0
  26. data/levels/blame/.githug/logs/HEAD +5 -0
  27. data/levels/blame/.githug/logs/refs/heads/master +5 -0
  28. data/levels/blame/.githug/objects/00/d6bf5341b263ccaf32e7973be55126eb30a343 +0 -0
  29. data/levels/blame/.githug/objects/05/07c26fed4d111a8344763be9af68af90f0ecf2 +0 -0
  30. data/levels/blame/.githug/objects/09/4094808dc6dc336c93c8602190a9e5f7bd6a11 +2 -0
  31. data/levels/blame/.githug/objects/21/15d78864000292628872941b14521f90187eed +0 -0
  32. data/levels/blame/.githug/objects/31/11dda1f5b08d50ac44b99acabfa54f1e6e72b0 +2 -0
  33. data/levels/blame/.githug/objects/50/8db115ba34a0e4e8667653aebe0265bb4f7e80 +0 -0
  34. data/levels/blame/.githug/objects/5e/8863df752e3b7f2150df7c78f12bef6f1ff00e +0 -0
  35. data/levels/blame/.githug/objects/67/788a4b90180c7588d7bd0ad8032957b0f429ba +0 -0
  36. data/levels/blame/.githug/objects/70/d00535a3a25b0ac1736dd3d306d6271e5427ed +0 -0
  37. data/levels/blame/.githug/objects/97/bdd0cccf9f4b8730f78cb53a81a74f205dbcc2 +1 -0
  38. data/levels/blame/.githug/objects/ab/08819ba3ffaeba17d4f870dc3a458a904519f4 +0 -0
  39. data/levels/blame/.githug/objects/be/96fe46de646f6a5c728f90cc884aef96fa1d6f +0 -0
  40. data/levels/blame/.githug/objects/cd/9c6b9ab1a6f56cccc69b6aa661f1d67ba5fb46 +0 -0
  41. data/levels/blame/.githug/objects/dd/df1d8ebd60eec169c15a5b23cb49a58d2ed5a0 +4 -0
  42. data/levels/blame/.githug/objects/ff/d39c2dbfd94bdbca06d48686e0cbda642f3de7 +1 -0
  43. data/levels/blame/.githug/refs/heads/master +1 -0
  44. data/levels/blame/config.rb +16 -0
  45. data/levels/clone.rb +10 -0
  46. data/levels/clone_to_folder.rb +10 -0
  47. data/levels/commit.rb +17 -0
  48. data/levels/config.rb +28 -0
  49. data/levels/contribute.rb +25 -0
  50. data/levels/diff.rb +16 -0
  51. data/levels/diff/.githug/COMMIT_EDITMSG +1 -0
  52. data/levels/diff/.githug/HEAD +1 -0
  53. data/levels/diff/.githug/config +5 -0
  54. data/levels/diff/.githug/description +1 -0
  55. data/levels/diff/.githug/hooks/applypatch-msg.sample +15 -0
  56. data/levels/diff/.githug/hooks/commit-msg.sample +24 -0
  57. data/levels/diff/.githug/hooks/post-commit.sample +8 -0
  58. data/levels/diff/.githug/hooks/post-receive.sample +15 -0
  59. data/levels/diff/.githug/hooks/post-update.sample +8 -0
  60. data/levels/diff/.githug/hooks/pre-applypatch.sample +14 -0
  61. data/levels/diff/.githug/hooks/pre-commit.sample +46 -0
  62. data/levels/diff/.githug/hooks/pre-rebase.sample +169 -0
  63. data/levels/diff/.githug/hooks/prepare-commit-msg.sample +36 -0
  64. data/levels/diff/.githug/hooks/update.sample +128 -0
  65. data/levels/diff/.githug/index +0 -0
  66. data/levels/diff/.githug/info/exclude +6 -0
  67. data/levels/diff/.githug/logs/HEAD +1 -0
  68. data/levels/diff/.githug/logs/refs/heads/master +1 -0
  69. data/levels/diff/.githug/objects/1b/6582364621c92707b587409cedbc4f77fc0cee +0 -0
  70. data/levels/diff/.githug/objects/4f/703ca9bd25781b6758eeb3c42ed5348610ba6d +2 -0
  71. data/levels/diff/.githug/objects/dc/aa55e97af34402e84d5336da37abcccc23cba6 +3 -0
  72. data/levels/diff/.githug/refs/heads/master +1 -0
  73. data/levels/diff/app.rb +42 -0
  74. data/levels/init.rb +10 -0
  75. data/levels/status.rb +26 -0
  76. data/lib/githug.rb +11 -0
  77. data/lib/githug/cli.rb +68 -0
  78. data/lib/githug/game.rb +40 -0
  79. data/lib/githug/level.rb +83 -0
  80. data/lib/githug/profile.rb +41 -0
  81. data/lib/githug/repository.rb +42 -0
  82. data/lib/githug/ui.rb +73 -0
  83. data/lib/githug/version.rb +3 -0
  84. data/spec/githug/cli_spec.rb +80 -0
  85. data/spec/githug/game_spec.rb +56 -0
  86. data/spec/githug/level_spec.rb +131 -0
  87. data/spec/githug/profile_spec.rb +36 -0
  88. data/spec/githug/repository_spec.rb +98 -0
  89. data/spec/githug/ui_spec.rb +84 -0
  90. data/spec/spec_helper.rb +1 -0
  91. metadata +178 -0
@@ -0,0 +1,10 @@
1
+ difficulty 1
2
+ description "Initialize an empty repository"
3
+
4
+ solution do
5
+ repo.valid?
6
+ end
7
+
8
+ hint do
9
+ puts "You can type `git` in your shell to get a list of available git commands"
10
+ end
@@ -0,0 +1,26 @@
1
+ difficulty 1
2
+ description "There are some files in this repository, one of the files is untracked, which file is it?"
3
+
4
+ setup do
5
+ repo.init
6
+ %w{config.rb README setup.rb deploy.rb Guardfile}.each do |file|
7
+ FileUtils.touch(file)
8
+ repo.add(file)
9
+ end
10
+ FileUtils.touch("database.yml")
11
+ end
12
+
13
+ solution do
14
+
15
+ name = request("What is the full file name of the untracked file?")
16
+
17
+ if name != "database.yml"
18
+ return false
19
+ end
20
+
21
+ true
22
+ end
23
+
24
+ hint do
25
+ puts "You are looking for a command to identify the status of the repository."
26
+ end
@@ -0,0 +1,11 @@
1
+ require 'grit'
2
+ require "githug/version"
3
+
4
+ require 'githug/ui'
5
+ require 'githug/game'
6
+ require 'githug/profile'
7
+ require 'githug/level'
8
+ require 'githug/repository'
9
+
10
+ Githug::UI.in_stream = STDIN
11
+ Githug::UI.out_stream = STDOUT
@@ -0,0 +1,68 @@
1
+ require 'thor'
2
+ require 'githug'
3
+ module Githug
4
+ class CLI < Thor
5
+
6
+
7
+ default_task :play
8
+
9
+ desc :play, "Initialize the game"
10
+
11
+ def play
12
+ UI.word_box("Githug")
13
+ make_directory
14
+ game = Game.new
15
+ game.play_level
16
+ end
17
+
18
+ desc :hint, "Get a hint for the current level"
19
+
20
+ def hint
21
+ if level = load_level
22
+ level.show_hint
23
+ end
24
+ end
25
+
26
+ desc :reset, "Reset the current level"
27
+
28
+ def reset
29
+ if level = load_level
30
+ UI.word_box("Githug")
31
+ UI.puts("resetting level")
32
+ level.setup_level
33
+ level.full_description
34
+ end
35
+ end
36
+
37
+ no_tasks do
38
+
39
+ def load_level
40
+ profile = Profile.load
41
+ Level.load(profile.level)
42
+ end
43
+
44
+
45
+ def make_directory
46
+ if File.exists?("./git_hug")
47
+ UI.puts "Please change into the git_hug directory"
48
+ exit
49
+ end
50
+
51
+ unless File.basename(Dir.pwd) == "git_hug"
52
+ if UI.ask("No githug directory found, do you wish to create one?")
53
+ Dir.mkdir("./git_hug")
54
+ Dir.chdir("git_hug")
55
+ File.open(".gitignore", "w") do |file|
56
+ file.write(".profile.yml")
57
+ end
58
+ else
59
+ UI.puts("Exiting")
60
+ exit
61
+ end
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,40 @@
1
+ module Githug
2
+ class Game
3
+
4
+ attr_accessor :profile
5
+
6
+ def initialize
7
+ @profile = Profile.load
8
+ end
9
+
10
+ def play_level
11
+ solve = true
12
+ if profile.level == 0
13
+ UI.puts("Welcome to Githug")
14
+ solve = false
15
+ level_bump
16
+ else
17
+ level = Level.load(profile.level)
18
+ if solve && level
19
+ if level.solve
20
+ UI.success "Congratulations, you have solved the level"
21
+ level_bump
22
+ else
23
+ UI.error "Sorry, this solution is not quite right!"
24
+ UI.puts level.full_description
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def level_bump
31
+ profile.level += 1
32
+ profile.save
33
+ if level = Level.load(profile.level)
34
+ UI.puts(level.full_description)
35
+ level.setup_level
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,83 @@
1
+ module Githug
2
+ class Level
3
+ include UI
4
+
5
+ LEVELS = [nil, "init", "add", "commit", "config", "clone", "clone_to_folder", "status", "diff", "blame", "contribute"]
6
+
7
+ attr_accessor :level_no, :level_path
8
+
9
+ class << self
10
+
11
+ def load(level_no)
12
+ level = new
13
+ level_path = "#{File.dirname(__FILE__)}/../../levels/#{LEVELS[level_no]}"
14
+ location = "#{level_path}.rb"
15
+ return false unless File.exists?(location)
16
+ level.instance_eval(File.read(location))
17
+ level.level_no = level_no
18
+ level.level_path = level_path
19
+ level
20
+ end
21
+
22
+ end
23
+
24
+ def init_from_level
25
+ FileUtils.cp_r("#{level_path}/.", ".")
26
+ FileUtils.mv(".githug", ".git")
27
+ end
28
+
29
+ def difficulty(num)
30
+ @difficulty = num
31
+ end
32
+
33
+ def description(description)
34
+ @description = description
35
+ end
36
+
37
+ def solution(&block)
38
+ @solution = block
39
+ end
40
+
41
+ def setup(&block)
42
+ @setup = block
43
+ end
44
+
45
+ def hint(&hint)
46
+ @hint = hint
47
+ end
48
+
49
+ def full_description
50
+ UI.puts
51
+ UI.puts "Level: #{level_no}"
52
+ UI.puts "Difficulty: #{"*"*@difficulty}"
53
+ UI.puts
54
+ UI.puts @description
55
+ UI.puts
56
+ end
57
+
58
+ def setup_level
59
+ repo.reset
60
+ @setup.call if @setup
61
+ end
62
+
63
+ def repo(location = "")
64
+ @repo ||= Repository.new(location)
65
+ end
66
+
67
+ def solve
68
+ @solution.call
69
+ rescue
70
+ false
71
+ end
72
+
73
+
74
+ def show_hint
75
+ UI.word_box("Githug")
76
+ if @hint
77
+ @hint.call
78
+ else
79
+ UI.puts("No hints available for this level")
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,41 @@
1
+ require 'yaml'
2
+ module Githug
3
+ class Profile
4
+ PROFILE_FILE = ".profile.yml"
5
+
6
+ attr_accessor :settings
7
+
8
+ class << self
9
+ def load
10
+ settings = {
11
+ :level => 0
12
+ }
13
+
14
+ settings.merge! YAML::load(File.open(PROFILE_FILE)) if File.exists?(PROFILE_FILE)
15
+ self.new(settings)
16
+ end
17
+ end
18
+
19
+
20
+ def method_missing(method, *args, &block)
21
+ if method.to_s.end_with?("=")
22
+ method = method.to_s.chop.to_sym
23
+ return settings[method] = args[0] if settings.include?(method)
24
+ end
25
+ return(settings[method]) if settings.include?(method)
26
+ super
27
+ end
28
+
29
+ def initialize(settings)
30
+ @settings = settings
31
+ end
32
+
33
+ def save
34
+ File.open(PROFILE_FILE, 'w') do |out|
35
+ YAML.dump(settings, out)
36
+ end
37
+ end
38
+
39
+
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ module Githug
2
+ class Repository
3
+
4
+ attr_accessor :grit
5
+
6
+ def initialize(location = ".")
7
+ @grit = Grit::Repo.new(location)
8
+ rescue Grit::InvalidGitRepositoryError
9
+ @grit = nil
10
+ end
11
+
12
+ def reset
13
+ dont_delete = ["..", ".", ".gitignore", ".profile.yml"]
14
+ if File.basename(Dir.pwd) == "git_hug"
15
+ Dir.entries(Dir.pwd).each do |file|
16
+ FileUtils.rm_rf(file) unless dont_delete.include?(file)
17
+ end
18
+ end
19
+ end
20
+
21
+ def valid?
22
+ !@grit.nil?
23
+ end
24
+
25
+ def init(gitignore = true)
26
+ @grit = Grit::Repo.init(".")
27
+ if gitignore
28
+ @grit.add(".gitignore")
29
+ @grit.commit("added .gitignore")
30
+ end
31
+ end
32
+
33
+ def method_missing(method, *args, &block)
34
+ if @grit && @grit.respond_to?(method)
35
+ return @grit.send(method, *args, &block)
36
+ end
37
+ super
38
+ end
39
+
40
+
41
+ end
42
+ end
@@ -0,0 +1,73 @@
1
+ module Githug
2
+ module UI
3
+
4
+ @@out_stream
5
+ @@in_stream
6
+
7
+ class << self
8
+
9
+ def out_stream=(out)
10
+ @@out_stream = out
11
+ end
12
+
13
+ def in_stream=(in_stream)
14
+ @@in_stream = in_stream
15
+ end
16
+
17
+ def puts(string = "")
18
+ @@out_stream.puts(string)
19
+ end
20
+
21
+ def print(string)
22
+ @@out_stream.print(string)
23
+ end
24
+
25
+ def gets
26
+ @@in_stream.gets
27
+ end
28
+
29
+ def line
30
+ puts("*"*80)
31
+ end
32
+
33
+ def word_box(string)
34
+ space_length = (80/2) - ((string.length/2)+1)
35
+ line
36
+ print "*"
37
+ print " "*space_length
38
+ print string
39
+ print " "*space_length
40
+ puts "*"
41
+ line
42
+ end
43
+
44
+ def request(msg)
45
+ print("#{msg} ")
46
+ gets.chomp
47
+ end
48
+
49
+ def ask(msg)
50
+ request("#{msg} [yn] ") == 'y'
51
+ end
52
+
53
+ def colorize(text, color_code)
54
+ puts "#{color_code}#{text}\033[0m"
55
+ end
56
+
57
+ def error(text)
58
+ colorize(text, "\033[31m")
59
+ end
60
+
61
+ def success(text)
62
+ colorize(text, "\033[32m")
63
+ end
64
+
65
+ end
66
+
67
+ def method_missing(method, *args, &block)
68
+ return UI.send(method, *args) if UI.methods(false).include?(method)
69
+ super
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module Githug
2
+ VERSION = "0.0.9"
3
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+ require 'githug/cli'
3
+
4
+ describe Githug::CLI do
5
+
6
+ before(:each) do
7
+ game = mock.as_null_object
8
+ @cli = Githug::CLI.new
9
+ Githug::Game.stub(:new).and_return(game)
10
+ end
11
+
12
+ it "should print the logo" do
13
+ Githug::UI.should_receive(:word_box).with("Githug")
14
+ @cli.stub(:make_directory)
15
+ @cli.play
16
+ end
17
+
18
+ it "should create a directory if one does not exist" do
19
+ Githug::UI.stub(:ask).and_return(true)
20
+ Dir.should_receive(:mkdir).with("./git_hug")
21
+ Dir.should_receive(:chdir).with("git_hug")
22
+ File.should_receive(:open).with(".gitignore", "w").and_return(true)
23
+ @cli.make_directory
24
+ end
25
+
26
+ it "should not make a directory if you are in the game directory" do
27
+ Dir.stub(:pwd).and_return("/home/git_hug")
28
+ Githug::UI.should_not_receive(:ask)
29
+ @cli.make_directory
30
+ end
31
+
32
+ it "should exit if the user selects no" do
33
+ Githug::UI.stub(:ask).and_return(false)
34
+ lambda {@cli.make_directory}.should raise_error(SystemExit)
35
+ end
36
+
37
+ it "should prompt to change into the directory if it exists" do
38
+ File.stub(:exists?).and_return(true)
39
+ Githug::UI.should_receive(:puts).with("Please change into the git_hug directory")
40
+ lambda {@cli.make_directory}.should raise_error(SystemExit)
41
+ end
42
+
43
+ describe "level methods" do
44
+ before(:each) do
45
+ @level = mock
46
+ @profile = mock
47
+ @profile.stub(:level).and_return(1)
48
+ Githug::Profile.stub(:load).and_return(@profile)
49
+ Githug::Level.stub(:load).and_return(@level)
50
+ end
51
+
52
+ it "should call the hint method on the level" do
53
+ @level.should_receive(:show_hint)
54
+ @cli.hint
55
+ end
56
+
57
+ describe "reset" do
58
+
59
+
60
+ it "should reset the current level" do
61
+ @level.should_receive(:setup_level)
62
+ @level.should_receive(:full_description)
63
+ Githug::UI.should_receive(:word_box).with("Githug")
64
+ Githug::UI.should_receive(:puts).with("resetting level")
65
+ @cli.reset
66
+ end
67
+
68
+ it "should not reset if the level cannot be loaded" do
69
+ Githug::Level.stub(:load).and_return(false)
70
+ @level.should_not_receive(:setup_level)
71
+ @level.should_not_receive(:full_description)
72
+ Githug::UI.should_not_receive(:word_box).with("Githug")
73
+ Githug::UI.should_not_receive(:puts).with("resetting level")
74
+ @cli.reset
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end