Решение на Пета задача от Андрея Костов

Обратно към всички решения

Към профила на Андрея Костов

Резултати

  • 4 точки от тестове
  • 0 бонус точки
  • 4 точки общо
  • 18 успешни тест(а)
  • 12 неуспешни тест(а)

Код

require 'digest/sha1'
class ObjectStore
ADD_TO_STAGE_MSG = 'Added %s to stage.'
COMMIT_MSG = "%s\n\t%s objects changed"
CHECKOUT_COMMIT_MSG = 'HEAD is now at %s.'
NOTHING_TO_COMMIT_MSG = 'Nothing to commit, working directory clean.'
COMMIT_DOES_NOT_EXIST_MSG = 'Commit %s does not exist.'
NO_COMMITS_IN_BRANCH_MSG = 'Branch %s does not have any commits yet.'
attr_accessor :current_branch
attr_reader :branches
def self.init(&block)
object_store = ObjectStore.new
object_store.instance_eval(&block) if block_given?
object_store
end
def add(name, object)
@staged.store(name, object)
Result.new(ADD_TO_STAGE_MSG % name, :success, object)
end
def commit(message)
if @staged.empty?
Operation.new(NOTHING_TO_COMMIT_MSG, :error)
else
date = Time.now
commit_hash = Digest::SHA1.hexdigest("#{date}#{message}")
commit = Commit.new(date, message, @staged.dup, commit_hash)
@current_branch.commits.store(commit.hash, commit)
@staged.clear
operation_message = COMMIT_MSG % [message, commit.objects.size]
Result.new(operation_message, :success, commit)
end
end
def checkout(commit_hash)
if @current_branch.commits.key?(commit_hash)
commit = @current_branch.commits[commit_hash]
@current_branch.commits.delete_if { |_, v| v.date > commit.date }
message = CHECKOUT_COMMIT_MSG % commit_hash
Result.new(message, :success, commit)
else
Operation.new(COMMIT_DOES_NOT_EXIST_MSG % commit_hash, :error)
end
end
def branch
@current_branch
end
def log
if @current_branch.commits.empty?
message = NO_COMMITS_IN_BRANCH_MSG % @current_branch.name
Operation.new(message, :error)
else
message = construct_log_message
Operation.new(message, :success)
end
end
def head
if @current_branch.commits.empty?
message = NO_COMMITS_IN_BRANCH_MSG % @current_branch.name
Operation.new(message, :error)
else
last_commit = @current_branch.commits.values.last
Result.new("#{last_commit.message}", :success, last_commit)
end
end
private
def initialize
@current_branch = Branch.new(self, 'master', {})
@branches = { @current_branch.name => @current_branch }
@staged = {}
end
def construct_log_message
@current_branch.commits.values.sort { |f, s| f.date <=> s.date }
.collect do |commit|
date = commit.date.strftime('%a %b %-d %H:%M %Y %z')
"Commit #{commit.hash}\n" \
"Date: #{date}\n\n" \
"\t#{commit.message}"
end
.reverse
.join("\n\n")
end
end
class Branch
CREATED_BRANCH_MSG = 'Created branch %s.'
BRANCH_EXISTS_MSG = 'Branch %s already exists.'
BRANCH_REMOVED_MSG = 'Removed branch %s.'
BRANCH_SWITCH_MSG = 'Switched to branch %s.'
BRANCH_DOES_NOT_EXIST_MSG = 'Branch %s does not exist.'
CANNOT_REMOVE_BRANCH_MSG = 'Cannot remove current branch.'
attr_accessor :name, :commits
def create(branch_name)
if @object_store.branches.key?(branch_name)
Operation.new(BRANCH_EXISTS_MSG % branch_name, :error)
else
branch = Branch.new(@object_store, branch_name, @commits.dup)
@object_store.branches.store(branch.name, branch)
Operation.new(CREATED_BRANCH_MSG % branch_name, :success)
end
end
def checkout(branch_name)
if @object_store.branches.key?(branch_name)
@object_store.current_branch = @object_store.branches[branch_name]
Operation.new(BRANCH_SWITCH_MSG % branch_name, :success)
else
Operation.new(BRANCH_DOES_NOT_EXIST_MSG % branch_name, :error)
end
end
def remove(branch_name)
if @object_store.branches.key?(branch_name)
if (@name == branch_name)
Operation.new(CANNOT_REMOVE_BRANCH_MSG, :error)
else
@object_store.branches.delete(branch_name)
Operation.new(BRANCH_REMOVED_MSG % branch_name, :success)
end
else
Operation.new(BRANCH_DOES_NOT_EXIST_MSG % branch_name, :error)
end
end
def list
branch_names = @object_store.branches.keys.collect do |name|
prefix = name == @object_store.current_branch.name ? '* ' : ' '
prefix + name
end
Operation.new(branch_names.join("\n"), :success)
end
def initialize(object_store, name, commits)
@object_store = object_store
@name = name
@commits = commits
end
end
class Operation
attr_reader :message
def initialize(message, status)
@message = message
@status = status
end
def success?
@status == :success
end
def error?
@status == :error
end
end
class Result < Operation
attr_reader :result
def initialize(message, status, result)
super(message, status)
@result = result
end
end
class Commit
attr_reader :date, :message, :hash
def initialize(date, message, objects, hash)
@date = date
@message = message
@objects = objects
@hash = hash
end
def objects
@objects.values
end
end

Лог от изпълнението

...FFF..FFFF.F........FFF....F

Failures:

  1) ObjectStore can remove objects
     Failure/Error: expect(repo.remove("object1")).to be_success("Added object1 for removal.", "content1")
     NoMethodError:
       undefined method `remove' for #<ObjectStore:0x007f270c947598>
     # /tmp/d20160111-5693-15v3hk3/spec.rb:43:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) ObjectStore can commit changes which include only removed objects
     Failure/Error: repo.remove("object2")
     NoMethodError:
       undefined method `remove' for #<ObjectStore:0x007f270c944780>
     # /tmp/d20160111-5693-15v3hk3/spec.rb:52:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) ObjectStore cannot remove objects that are not committed
     Failure/Error: expect(repo.remove("object2")).to be_error("Object object2 is not committed.")
     NoMethodError:
       undefined method `remove' for #<ObjectStore:0x007f270c9410d0>
     # /tmp/d20160111-5693-15v3hk3/spec.rb:60:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) ObjectStore can show log of changes for a single commit
     Failure/Error: expect(repo.log).to be_success("Commit #{commit_hash}\nDate: #{Time.now.strftime("%a %b %d %H:%M %Y %z")}\n\n\tSo cool!")
       expected #<Operation:0x007f270c911da8 @message="Commit 30d47e8baa4e5d81e78d0aec7b60c85e7d972ae3\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!", @status=:success> to be success "Commit 020f94292ff683fc536310fe33c03adfbf64bbca\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!"
     # /tmp/d20160111-5693-15v3hk3/spec.rb:83:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) ObjectStore can show log of changes for a single commit
     Failure/Error: expect(repo.log).to be_success("Commit #{commit_hash}\nDate: #{Time.now.strftime("%a %b %d %H:%M %Y %z")}\n\n\tSo cool!")
       expected #<Operation:0x007f270c8f1fd0 @message="Commit 30d47e8baa4e5d81e78d0aec7b60c85e7d972ae3\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!", @status=:success> to be success "Commit 020f94292ff683fc536310fe33c03adfbf64bbca\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!"
     # /tmp/d20160111-5693-15v3hk3/spec.rb:92:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) ObjectStore can show log of changes for multiple commits
     Failure/Error: expect(repo.log).to be_success("Commit #{commit2_hash}\nDate: #{current_time}\n\n\tSecond commit\n\nCommit #{commit1_hash}\nDate: #{current_time}\n\n\tFirst commit")
       expected #<Operation:0x007f270c8e7120 @message="Commit d57229f4fb5085f4b7998aee6db4f1c68b28eb64\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSecond commit\n\nCommit 39589db70e0b7bc6359d5026870a568a9d098c61\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit", @status=:success> to be success "Commit a6bf7130a3150d375443c25d06c1bf8077e4b4fb\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSecond commit\n\nCommit 9a97b358afe869ba1e523d99dd2101dfc0570dc0\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit"
     # /tmp/d20160111-5693-15v3hk3/spec.rb:108:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  7) ObjectStore shows the log for the current branch only
     Failure/Error: expect(repo.log).to be_success("Commit #{commit1_hash}\nDate: #{current_time}\n\n\tFirst commit")
       expected #<Operation:0x007f270c8e16a8 @message="Commit 39589db70e0b7bc6359d5026870a568a9d098c61\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit", @status=:success> to be success "Commit 9a97b358afe869ba1e523d99dd2101dfc0570dc0\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit"
     # /tmp/d20160111-5693-15v3hk3/spec.rb:128:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  8) ObjectStore can list branches
     Failure/Error: expect(repo.branch.list).to be_success("  develop\n  feature\n* master")
       expected #<Operation:0x007f270c8cddd8 @message="* master\n  develop\n  feature", @status=:success> to be success "  develop\n  feature\n* master"
     # /tmp/d20160111-5693-15v3hk3/spec.rb:140:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  9) ObjectStore can return objects
     Failure/Error: expect(repo.get("number")).to be_success("Found object number.", 21)
     NoMethodError:
       undefined method `get' for #<ObjectStore:0x007f270c495748>
     # /tmp/d20160111-5693-15v3hk3/spec.rb:202:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  10) ObjectStore cannot return not committed objects
     Failure/Error: expect(repo.get("string")).to be_error("Object string is not committed.")
     NoMethodError:
       undefined method `get' for #<ObjectStore:0x007f270c490ce8>
     # /tmp/d20160111-5693-15v3hk3/spec.rb:209:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  11) ObjectStore cannot return objects when no commits
     Failure/Error: expect(repo.get("string")).to be_error("Object string is not committed.")
     NoMethodError:
       undefined method `get' for #<ObjectStore:0x007f270c4790c0>
     # /tmp/d20160111-5693-15v3hk3/spec.rb:214:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  12) ObjectStore can show the objects of a repo after removing an object
     Failure/Error: repo.remove("object2")
     NoMethodError:
       undefined method `remove' for #<ObjectStore:0x007f270c3aa6f8>
     # /tmp/d20160111-5693-15v3hk3/spec.rb:261:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.02721 seconds
30 examples, 12 failures

Failed examples:

rspec /tmp/d20160111-5693-15v3hk3/spec.rb:38 # ObjectStore can remove objects
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:46 # ObjectStore can commit changes which include only removed objects
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:56 # ObjectStore cannot remove objects that are not committed
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:77 # ObjectStore can show log of changes for a single commit
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:86 # ObjectStore can show log of changes for a single commit
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:95 # ObjectStore can show log of changes for multiple commits
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:111 # ObjectStore shows the log for the current branch only
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:136 # ObjectStore can list branches
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:198 # ObjectStore can return objects
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:205 # ObjectStore cannot return not committed objects
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:212 # ObjectStore cannot return objects when no commits
rspec /tmp/d20160111-5693-15v3hk3/spec.rb:253 # ObjectStore can show the objects of a repo after removing an object

История (1 версия и 0 коментара)

Андрея обнови решението на 23.11.2015 16:45 (преди около 9 години)

+require 'digest/sha1'
+
+class ObjectStore
+ ADD_TO_STAGE_MSG = 'Added %s to stage.'
+ COMMIT_MSG = "%s\n\t%s objects changed"
+ CHECKOUT_COMMIT_MSG = 'HEAD is now at %s.'
+ NOTHING_TO_COMMIT_MSG = 'Nothing to commit, working directory clean.'
+ COMMIT_DOES_NOT_EXIST_MSG = 'Commit %s does not exist.'
+ NO_COMMITS_IN_BRANCH_MSG = 'Branch %s does not have any commits yet.'
+
+ attr_accessor :current_branch
+ attr_reader :branches
+
+ def self.init(&block)
+ object_store = ObjectStore.new
+ object_store.instance_eval(&block) if block_given?
+ object_store
+ end
+
+ def add(name, object)
+ @staged.store(name, object)
+ Result.new(ADD_TO_STAGE_MSG % name, :success, object)
+ end
+
+ def commit(message)
+ if @staged.empty?
+ Operation.new(NOTHING_TO_COMMIT_MSG, :error)
+ else
+ date = Time.now
+ commit_hash = Digest::SHA1.hexdigest("#{date}#{message}")
+ commit = Commit.new(date, message, @staged.dup, commit_hash)
+ @current_branch.commits.store(commit.hash, commit)
+ @staged.clear
+ operation_message = COMMIT_MSG % [message, commit.objects.size]
+ Result.new(operation_message, :success, commit)
+ end
+ end
+
+ def checkout(commit_hash)
+ if @current_branch.commits.key?(commit_hash)
+ commit = @current_branch.commits[commit_hash]
+ @current_branch.commits.delete_if { |_, v| v.date > commit.date }
+ message = CHECKOUT_COMMIT_MSG % commit_hash
+ Result.new(message, :success, commit)
+ else
+ Operation.new(COMMIT_DOES_NOT_EXIST_MSG % commit_hash, :error)
+ end
+ end
+
+ def branch
+ @current_branch
+ end
+
+ def log
+ if @current_branch.commits.empty?
+ message = NO_COMMITS_IN_BRANCH_MSG % @current_branch.name
+ Operation.new(message, :error)
+ else
+ message = construct_log_message
+ Operation.new(message, :success)
+ end
+ end
+
+ def head
+ if @current_branch.commits.empty?
+ message = NO_COMMITS_IN_BRANCH_MSG % @current_branch.name
+ Operation.new(message, :error)
+ else
+ last_commit = @current_branch.commits.values.last
+ Result.new("#{last_commit.message}", :success, last_commit)
+ end
+ end
+
+ private
+
+ def initialize
+ @current_branch = Branch.new(self, 'master', {})
+ @branches = { @current_branch.name => @current_branch }
+ @staged = {}
+ end
+
+ def construct_log_message
+ @current_branch.commits.values.sort { |f, s| f.date <=> s.date }
+ .collect do |commit|
+ date = commit.date.strftime('%a %b %-d %H:%M %Y %z')
+ "Commit #{commit.hash}\n" \
+ "Date: #{date}\n\n" \
+ "\t#{commit.message}"
+ end
+ .reverse
+ .join("\n\n")
+ end
+end
+
+class Branch
+ CREATED_BRANCH_MSG = 'Created branch %s.'
+ BRANCH_EXISTS_MSG = 'Branch %s already exists.'
+ BRANCH_REMOVED_MSG = 'Removed branch %s.'
+ BRANCH_SWITCH_MSG = 'Switched to branch %s.'
+ BRANCH_DOES_NOT_EXIST_MSG = 'Branch %s does not exist.'
+ CANNOT_REMOVE_BRANCH_MSG = 'Cannot remove current branch.'
+ attr_accessor :name, :commits
+
+ def create(branch_name)
+ if @object_store.branches.key?(branch_name)
+ Operation.new(BRANCH_EXISTS_MSG % branch_name, :error)
+ else
+ branch = Branch.new(@object_store, branch_name, @commits.dup)
+ @object_store.branches.store(branch.name, branch)
+ Operation.new(CREATED_BRANCH_MSG % branch_name, :success)
+ end
+ end
+
+ def checkout(branch_name)
+ if @object_store.branches.key?(branch_name)
+ @object_store.current_branch = @object_store.branches[branch_name]
+ Operation.new(BRANCH_SWITCH_MSG % branch_name, :success)
+ else
+ Operation.new(BRANCH_DOES_NOT_EXIST_MSG % branch_name, :error)
+ end
+ end
+
+ def remove(branch_name)
+ if @object_store.branches.key?(branch_name)
+ if (@name == branch_name)
+ Operation.new(CANNOT_REMOVE_BRANCH_MSG, :error)
+ else
+ @object_store.branches.delete(branch_name)
+ Operation.new(BRANCH_REMOVED_MSG % branch_name, :success)
+ end
+ else
+ Operation.new(BRANCH_DOES_NOT_EXIST_MSG % branch_name, :error)
+ end
+ end
+
+ def list
+ branch_names = @object_store.branches.keys.collect do |name|
+ prefix = name == @object_store.current_branch.name ? '* ' : ' '
+ prefix + name
+ end
+ Operation.new(branch_names.join("\n"), :success)
+ end
+
+ def initialize(object_store, name, commits)
+ @object_store = object_store
+ @name = name
+ @commits = commits
+ end
+end
+
+class Operation
+ attr_reader :message
+
+ def initialize(message, status)
+ @message = message
+ @status = status
+ end
+
+ def success?
+ @status == :success
+ end
+
+ def error?
+ @status == :error
+ end
+end
+
+class Result < Operation
+ attr_reader :result
+
+ def initialize(message, status, result)
+ super(message, status)
+ @result = result
+ end
+end
+
+class Commit
+ attr_reader :date, :message, :hash
+
+ def initialize(date, message, objects, hash)
+ @date = date
+ @message = message
+ @objects = objects
+ @hash = hash
+ end
+
+ def objects
+ @objects.values
+ end
+end