Решение на Пета задача от Станимира Влаева

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

Към профила на Станимира Влаева

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 25 успешни тест(а)
  • 5 неуспешни тест(а)

Код

require 'digest/sha1'
class OperationMessage
attr_reader :message, :result
def initialize(successful, message, result = nil)
@successful = successful
@message = message
@result = result
end
def success?
@successful
end
def error?
not @successful
end
end
class Commit
attr_reader :index, :date, :message, :hash, :files, :objects
@@commits_count = 0
def initialize(message, stage, repository_files)
@index = @@commits_count
@date = Time.now
@message = message
@hash = Digest::SHA1.hexdigest "#{date}#{message}"
@files = {
changed: stage[:changed].dup,
removed: stage[:removed].dup,
}
@objects = repository_files.values
@@commits_count += 1
end
def changed
@files[:changed]
end
def removed
@files[:removed]
end
def to_s
name = "Commit #{@hash}\n"
date = "Date: #{@date.strftime('%a %b %-d %H:%M %Y %z')}\n\n"
message = "\t#{@message}\n\n"
name << date << message
end
end
class Branch
attr_reader :current
def initialize
@current = :master
@branches = {@current => []}
@files = {@current => {}}
end
def create(name)
name = name.to_sym
if @branches.has_key?(name)
OperationMessage.new(false, "Branch #{name} already exists.")
else
@branches[name] = @branches[@current].dup
@files[name] = @files[@current].dup
OperationMessage.new(true, "Created branch #{name}.")
end
end
def checkout(name)
unless @branches.has_key?(name.to_sym)
OperationMessage.new(false, "Branch #{name} does not exist.")
else
@current = name.to_sym
OperationMessage.new(true, "Switched to branch #{name}.")
end
end
def remove(name)
if not @branches.has_key?(name.to_sym)
OperationMessage.new(false, "Branch #{name} does not exist.")
elsif name.to_sym == @current
OperationMessage.new(false, "Cannot remove current branch.")
else
@branches.delete(name.to_sym)
OperationMessage.new(true, "Removed branch #{name}.")
end
end
def list
message = ""
@branches.keys.sort.each do |name|
message << list_prefix(name)
message << name.to_s << "\n"
end
message.chop!
OperationMessage.new(true, message)
end
def commit(message, stage)
stage[:changed].each { |name, object| @files[@current][name] = object }
stage[:removed].each { |name, object| @files[@current].delete(name) }
new_commit = Commit.new(message, stage, @files[@current])
@branches[@current] << new_commit
new_commit
end
def head
if @branches[@current].length == 0
OperationMessage.new(false, "Branch #{@current}\
does not have any commits yet.")
else
last_commit = @branches[@current].last
OperationMessage.new(true, last_commit.message, last_commit)
end
end
def get_file(name)
@files[@current][name.to_sym]
end
def get_commit(hash)
@branches[@current].find { |commit| commit.hash == hash }
end
def checkout_commit(last_commit)
@files[@current] = last_commit.objects
@branches[@current].select! { |c| c.index <= last_commit.index }
end
def log(branch)
message = ""
@branches[branch].sort_by { |commit| commit.index }.
reverse.
each { |commit| message << commit.to_s }
message.strip!
end
private
def list_prefix(branch_name)
branch_name == :master ? "* " : " "
end
end
class ObjectStore
attr_accessor :branch
class << self
def init(&block)
self.new &block
end
end
def initialize(&block)
@branch = Branch.new
@stage = {changed: {}, removed: {}}
if block_given?
instance_eval &block
end
end
def add(name, object)
@stage[:changed][name.to_sym] = object
OperationMessage.new(true, "Added #{name} to stage.", object)
end
def commit(message)
if @stage[:changed].length == 0 and @stage[:removed].length == 0
OperationMessage.new(false, "Nothing to commit, working directory clean.")
else
new_commit = @branch.commit(message, @stage)
changed_files = new_commit.changed.length + new_commit.removed.length
message = "#{message}\n\t#{changed_files} objects changed"
@stage[:changed].clear
@stage[:removed].clear
OperationMessage.new(true, message, new_commit)
end
end
def remove(name)
object = @branch.get_file(name)
unless object
OperationMessage.new(false, "Object #{name} is not committed.")
else
@stage[:removed][name.to_sym] = object
OperationMessage.new(true, "Added #{name} for removal.", object)
end
end
def checkout(commit_hash)
last_commit = @branch.get_commit(commit_hash)
unless last_commit
OperationMessage.new(false, "Commit #{commit_hash} does not exist.")
else
@branch.checkout_commit(last_commit)
OperationMessage.new(true, "HEAD is now at #{commit_hash}.", last_commit)
end
end
def log(branch = @branch.current)
message = @branch.log(branch)
unless message and not message.empty?
OperationMessage.new(false, "Branch #{branch} \
does not have any commits yet.")
else
OperationMessage.new(true, message)
end
end
def head
@branch.head
end
def get(name)
object = @branch.get_file(name)
unless object
OperationMessage.new(false, "Object #{name} is not committed.")
else
OperationMessage.new(true, "Found object #{name}.", object)
end
end
end

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

.......FFFFF..................

Failures:

  1) ObjectStore cannot show head for empty repository
     Failure/Error: expect(repo.head).to be_error("Branch master does not have any commits yet.")
       expected #<OperationMessage:0x007f52f98824a0 @successful=false, @message="Branch masterdoes not have any commits yet.", @result=nil> to be error "Branch master does not have any commits yet."
     # /tmp/d20160111-5693-uh5oot/spec.rb:74: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 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 #<OperationMessage:0x007f52f9867010 @successful=true, @message="Commit 9d1b0b5a505b08c7ae64f17547ea998a249b21c8\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!", @result=nil> to be success "Commit 020f94292ff683fc536310fe33c03adfbf64bbca\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!"
     # /tmp/d20160111-5693-uh5oot/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)>'

  3) 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 #<OperationMessage:0x007f52f9826f38 @successful=true, @message="Commit 9d1b0b5a505b08c7ae64f17547ea998a249b21c8\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!", @result=nil> to be success "Commit 020f94292ff683fc536310fe33c03adfbf64bbca\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSo cool!"
     # /tmp/d20160111-5693-uh5oot/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)>'

  4) 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 #<OperationMessage:0x007f52f9803060 @successful=true, @message="Commit aca5eacfff0e173c98936ef62a71b3472a7d45f9\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tSecond commit\n\nCommit 61b009cc3240619e563d880293d492a0e440ea7e\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit", @result=nil> 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-uh5oot/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)>'

  5) 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 #<OperationMessage:0x007f52f97f1298 @successful=true, @message="Commit 61b009cc3240619e563d880293d492a0e440ea7e\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit", @result=nil> to be success "Commit 9a97b358afe869ba1e523d99dd2101dfc0570dc0\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit"
     # /tmp/d20160111-5693-uh5oot/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)>'

Finished in 0.03282 seconds
30 examples, 5 failures

Failed examples:

rspec /tmp/d20160111-5693-uh5oot/spec.rb:72 # ObjectStore cannot show head for empty repository
rspec /tmp/d20160111-5693-uh5oot/spec.rb:77 # ObjectStore can show log of changes for a single commit
rspec /tmp/d20160111-5693-uh5oot/spec.rb:86 # ObjectStore can show log of changes for a single commit
rspec /tmp/d20160111-5693-uh5oot/spec.rb:95 # ObjectStore can show log of changes for multiple commits
rspec /tmp/d20160111-5693-uh5oot/spec.rb:111 # ObjectStore shows the log for the current branch only

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

Станимира обнови решението на 18.11.2015 23:13 (преди над 8 години)

+require 'digest/sha1'
+
+class OperationMessage
+ attr_reader :message, :result
+
+ def initialize(successful, message, result = nil)
+ @successful = successful
+ @message = message
+ @result = result
+ end
+
+ def success?
+ @successful
+ end
+
+ def error?
+ not @successful
+ end
+end
+
+class Commit
+ attr_reader :index, :date, :message, :hash, :files, :objects
+ @@commits_count = 0
+
+ def initialize(message, stage, repository_files)
+ @index = @@commits_count
+ @date = Time.now
+ @message = message
+ @hash = Digest::SHA1.hexdigest "#{date}#{message}"
+ @files = {
+ changed: stage[:changed].dup,
+ removed: stage[:removed].dup,
+ }
+ @objects = repository_files.values
+
+ @@commits_count += 1
+ end
+
+ def changed
+ @files[:changed]
+ end
+
+ def removed
+ @files[:removed]
+ end
+
+ def to_s
+ name = "Commit #{@hash}\n"
+ date = "Date: #{@date.strftime('%a %b %-d %H:%M %Y %z')}\n\n"
+ message = "\t#{@message}\n\n"
+
+ name << date << message
+ end
+end
+
+class Branch
+ attr_reader :current
+
+ def initialize
+ @current = :master
+ @branches = {@current => []}
+ @files = {@current => {}}
+ end
+
+ def create(name)
+ name = name.to_sym
+
+ if @branches.has_key?(name)
+ OperationMessage.new(false, "Branch #{name} already exists.")
+ else
+ @branches[name] = @branches[@current].dup
+ @files[name] = @files[@current].dup
+ OperationMessage.new(true, "Created branch #{name}.")
+ end
+ end
+
+ def checkout(name)
+ unless @branches.has_key?(name.to_sym)
+ OperationMessage.new(false, "Branch #{name} does not exist.")
+ else
+ @current = name.to_sym
+ OperationMessage.new(true, "Switched to branch #{name}.")
+ end
+ end
+
+ def remove(name)
+ if not @branches.has_key?(name.to_sym)
+ OperationMessage.new(false, "Branch #{name} does not exist.")
+ elsif name.to_sym == @current
+ OperationMessage.new(false, "Cannot remove current branch.")
+ else
+ @branches.delete(name.to_sym)
+ OperationMessage.new(true, "Removed branch #{name}.")
+ end
+ end
+
+ def list
+ message = ""
+ @branches.keys.sort.each do |name|
+ message << list_prefix(name)
+ message << name.to_s << "\n"
+ end
+ message.chop!
+
+ OperationMessage.new(true, message)
+ end
+
+ def commit(message, stage)
+ stage[:changed].each { |name, object| @files[@current][name] = object }
+ stage[:removed].each { |name, object| @files[@current].delete(name) }
+
+ new_commit = Commit.new(message, stage, @files[@current])
+ @branches[@current] << new_commit
+
+ new_commit
+ end
+
+ def head
+ if @branches[@current].length == 0
+ OperationMessage.new(false, "Branch #{@current}\
+does not have any commits yet.")
+ else
+ last_commit = @branches[@current].last
+ OperationMessage.new(true, last_commit.message, last_commit)
+ end
+ end
+
+ def get_file(name)
+ @files[@current][name.to_sym]
+ end
+
+ def get_commit(hash)
+ @branches[@current].find { |commit| commit.hash == hash }
+ end
+
+ def checkout_commit(last_commit)
+ @files[@current] = last_commit.objects
+ @branches[@current].select! { |c| c.index <= last_commit.index }
+ end
+
+ def log(branch)
+ message = ""
+ @branches[branch].sort_by { |commit| commit.index }.
+ reverse.
+ each { |commit| message << commit.to_s }
+
+ message.strip!
+ end
+
+ private
+ def list_prefix(branch_name)
+ branch_name == :master ? "* " : " "
+ end
+end
+
+class ObjectStore
+ attr_accessor :branch
+
+ class << self
+ def init(&block)
+ self.new &block
+ end
+ end
+
+ def initialize(&block)
+ @branch = Branch.new
+ @stage = {changed: {}, removed: {}}
+
+ if block_given?
+ instance_eval &block
+ end
+ end
+
+ def add(name, object)
+ @stage[:changed][name.to_sym] = object
+ OperationMessage.new(true, "Added #{name} to stage.", object)
+ end
+
+ def commit(message)
+ if @stage[:changed].length == 0 and @stage[:removed].length == 0
+ OperationMessage.new(false, "Nothing to commit, working directory clean.")
+ else
+ new_commit = @branch.commit(message, @stage)
+ changed_files = new_commit.changed.length + new_commit.removed.length
+ message = "#{message}\n\t#{changed_files} objects changed"
+
+ @stage[:changed].clear
+ @stage[:removed].clear
+
+ OperationMessage.new(true, message, new_commit)
+ end
+ end
+
+ def remove(name)
+ object = @branch.get_file(name)
+ unless object
+ OperationMessage.new(false, "Object #{name} is not committed.")
+ else
+ @stage[:removed][name.to_sym] = object
+ OperationMessage.new(true, "Added #{name} for removal.", object)
+ end
+ end
+
+ def checkout(commit_hash)
+ last_commit = @branch.get_commit(commit_hash)
+
+ unless last_commit
+ OperationMessage.new(false, "Commit #{commit_hash} does not exist.")
+ else
+ @branch.checkout_commit(last_commit)
+ OperationMessage.new(true, "HEAD is now at #{commit_hash}.", last_commit)
+ end
+ end
+
+ def log(branch = @branch.current)
+ message = @branch.log(branch)
+
+ unless message and not message.empty?
+ OperationMessage.new(false, "Branch #{branch} \
+does not have any commits yet.")
+ else
+ OperationMessage.new(true, message)
+ end
+ end
+
+ def head
+ @branch.head
+ end
+
+ def get(name)
+ object = @branch.get_file(name)
+ unless object
+ OperationMessage.new(false, "Object #{name} is not committed.")
+ else
+ OperationMessage.new(true, "Found object #{name}.", object)
+ end
+ end
+end