githug 0.0.9
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.
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/README.md +90 -0
- data/Rakefile +1 -0
- data/bin/githug +4 -0
- data/githug.gemspec +27 -0
- data/levels/add.rb +17 -0
- data/levels/blame.rb +20 -0
- data/levels/blame/.githug/COMMIT_EDITMSG +1 -0
- data/levels/blame/.githug/HEAD +1 -0
- data/levels/blame/.githug/config +5 -0
- data/levels/blame/.githug/description +1 -0
- data/levels/blame/.githug/hooks/applypatch-msg.sample +15 -0
- data/levels/blame/.githug/hooks/commit-msg.sample +24 -0
- data/levels/blame/.githug/hooks/post-commit.sample +8 -0
- data/levels/blame/.githug/hooks/post-receive.sample +15 -0
- data/levels/blame/.githug/hooks/post-update.sample +8 -0
- data/levels/blame/.githug/hooks/pre-applypatch.sample +14 -0
- data/levels/blame/.githug/hooks/pre-commit.sample +46 -0
- data/levels/blame/.githug/hooks/pre-rebase.sample +169 -0
- data/levels/blame/.githug/hooks/prepare-commit-msg.sample +36 -0
- data/levels/blame/.githug/hooks/update.sample +128 -0
- data/levels/blame/.githug/index +0 -0
- data/levels/blame/.githug/info/exclude +6 -0
- data/levels/blame/.githug/logs/HEAD +5 -0
- data/levels/blame/.githug/logs/refs/heads/master +5 -0
- data/levels/blame/.githug/objects/00/d6bf5341b263ccaf32e7973be55126eb30a343 +0 -0
- data/levels/blame/.githug/objects/05/07c26fed4d111a8344763be9af68af90f0ecf2 +0 -0
- data/levels/blame/.githug/objects/09/4094808dc6dc336c93c8602190a9e5f7bd6a11 +2 -0
- data/levels/blame/.githug/objects/21/15d78864000292628872941b14521f90187eed +0 -0
- data/levels/blame/.githug/objects/31/11dda1f5b08d50ac44b99acabfa54f1e6e72b0 +2 -0
- data/levels/blame/.githug/objects/50/8db115ba34a0e4e8667653aebe0265bb4f7e80 +0 -0
- data/levels/blame/.githug/objects/5e/8863df752e3b7f2150df7c78f12bef6f1ff00e +0 -0
- data/levels/blame/.githug/objects/67/788a4b90180c7588d7bd0ad8032957b0f429ba +0 -0
- data/levels/blame/.githug/objects/70/d00535a3a25b0ac1736dd3d306d6271e5427ed +0 -0
- data/levels/blame/.githug/objects/97/bdd0cccf9f4b8730f78cb53a81a74f205dbcc2 +1 -0
- data/levels/blame/.githug/objects/ab/08819ba3ffaeba17d4f870dc3a458a904519f4 +0 -0
- data/levels/blame/.githug/objects/be/96fe46de646f6a5c728f90cc884aef96fa1d6f +0 -0
- data/levels/blame/.githug/objects/cd/9c6b9ab1a6f56cccc69b6aa661f1d67ba5fb46 +0 -0
- data/levels/blame/.githug/objects/dd/df1d8ebd60eec169c15a5b23cb49a58d2ed5a0 +4 -0
- data/levels/blame/.githug/objects/ff/d39c2dbfd94bdbca06d48686e0cbda642f3de7 +1 -0
- data/levels/blame/.githug/refs/heads/master +1 -0
- data/levels/blame/config.rb +16 -0
- data/levels/clone.rb +10 -0
- data/levels/clone_to_folder.rb +10 -0
- data/levels/commit.rb +17 -0
- data/levels/config.rb +28 -0
- data/levels/contribute.rb +25 -0
- data/levels/diff.rb +16 -0
- data/levels/diff/.githug/COMMIT_EDITMSG +1 -0
- data/levels/diff/.githug/HEAD +1 -0
- data/levels/diff/.githug/config +5 -0
- data/levels/diff/.githug/description +1 -0
- data/levels/diff/.githug/hooks/applypatch-msg.sample +15 -0
- data/levels/diff/.githug/hooks/commit-msg.sample +24 -0
- data/levels/diff/.githug/hooks/post-commit.sample +8 -0
- data/levels/diff/.githug/hooks/post-receive.sample +15 -0
- data/levels/diff/.githug/hooks/post-update.sample +8 -0
- data/levels/diff/.githug/hooks/pre-applypatch.sample +14 -0
- data/levels/diff/.githug/hooks/pre-commit.sample +46 -0
- data/levels/diff/.githug/hooks/pre-rebase.sample +169 -0
- data/levels/diff/.githug/hooks/prepare-commit-msg.sample +36 -0
- data/levels/diff/.githug/hooks/update.sample +128 -0
- data/levels/diff/.githug/index +0 -0
- data/levels/diff/.githug/info/exclude +6 -0
- data/levels/diff/.githug/logs/HEAD +1 -0
- data/levels/diff/.githug/logs/refs/heads/master +1 -0
- data/levels/diff/.githug/objects/1b/6582364621c92707b587409cedbc4f77fc0cee +0 -0
- data/levels/diff/.githug/objects/4f/703ca9bd25781b6758eeb3c42ed5348610ba6d +2 -0
- data/levels/diff/.githug/objects/dc/aa55e97af34402e84d5336da37abcccc23cba6 +3 -0
- data/levels/diff/.githug/refs/heads/master +1 -0
- data/levels/diff/app.rb +42 -0
- data/levels/init.rb +10 -0
- data/levels/status.rb +26 -0
- data/lib/githug.rb +11 -0
- data/lib/githug/cli.rb +68 -0
- data/lib/githug/game.rb +40 -0
- data/lib/githug/level.rb +83 -0
- data/lib/githug/profile.rb +41 -0
- data/lib/githug/repository.rb +42 -0
- data/lib/githug/ui.rb +73 -0
- data/lib/githug/version.rb +3 -0
- data/spec/githug/cli_spec.rb +80 -0
- data/spec/githug/game_spec.rb +56 -0
- data/spec/githug/level_spec.rb +131 -0
- data/spec/githug/profile_spec.rb +36 -0
- data/spec/githug/repository_spec.rb +98 -0
- data/spec/githug/ui_spec.rb +84 -0
- data/spec/spec_helper.rb +1 -0
- metadata +178 -0
data/levels/init.rb
ADDED
data/levels/status.rb
ADDED
@@ -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
|
data/lib/githug.rb
ADDED
data/lib/githug/cli.rb
ADDED
@@ -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
|
data/lib/githug/game.rb
ADDED
@@ -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
|
data/lib/githug/level.rb
ADDED
@@ -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
|
data/lib/githug/ui.rb
ADDED
@@ -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,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
|