Решение на Пета задача от Ивайло Чернев

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

Към профила на Ивайло Чернев

Резултати

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

Код

require "time"
require 'digest/sha1'
class RepoResult
attr_accessor :message, :result
def initialize(message, status = false, result = nil)
@message = message
@status = status
@result = result
end
def success?
@status
end
def error?
not @status
end
end
class Commit
attr_accessor :objects_hash, :message, :date, :hash
def initialize(old_objects, new_objects, deleted_objects, message)
@message = message
@date = Time.new
hash_string = @date.strftime("%a %b %d %H:%M:%S %Y %z") + message
@hash = Digest::SHA1.hexdigest(hash_string)
@objects_hash = old_objects.dup
new_objects.each { |key, value| @objects_hash[key] = value }
deleted_objects.each { |key| @objects_hash.delete(key) }
end
def date_formated
@date.strftime("%a %b %d %H:%M %Y %z")
end
def objects
@objects_hash.values
end
end
class Branch
attr_accessor :commits, :new_changes, :name
def initialize(name, inherited_commits)
@commits = inherited_commits.dup
@name = name
@new_changes = {}
@deleted_objects = []
end
def add(name, object)
@new_changes[name] = object
end
def commit(message)
last_commit = @commits[-1]
state = last_commit != nil ? last_commit.objects_hash : {}
new_commit = Commit.new state, @new_changes, @deleted_objects, message
@commits << new_commit
size = @new_changes.size + @deleted_objects.size
@new_changes, @deleted_objects = {}, []
size
end
def remove(name)
@deleted_objects << name if @commits[-1].objects_hash[name] != nil
@commits[-1].objects_hash[name]
end
def get(name)
return nil if @commits.size == 0
commited_objects = @commits[-1].objects_hash
commited_objects[name]
end
def checkout(hash)
commit = @commits.select { |commit| commit.hash == hash }.first
return nil if commit == nil
index = @commits.find_index(commit)
remove_commits_count = @commits.size - index - 1
@commits.pop remove_commits_count
commit
end
end
class BranchManager
def initialize(store)
@store = store
end
def create(name)
branches = @store.branches
store_head = @store.head_branch
if branches[name] != nil
return RepoResult.new("Branch #{name} already exists.", false, nil)
end
new_branch = Branch.new name, branches[store_head].commits
branches[name] = new_branch
RepoResult.new("Created branch #{name}.", true, nil)
end
def checkout(branch_name)
branches = @store.branches
if branches[branch_name] == nil
return RepoResult.new("Branch #{branch_name} does not exist.", false, nil)
end
@store.head_branch = branch_name
RepoResult.new("Switched to branch #{branch_name}.", true, nil)
end
def remove(branch_name)
branches = @store.branches
if @store.head_branch == branch_name
return RepoResult.new("Cannot remove current branch.", false, nil)
elsif branches[branch_name] == nil
return RepoResult.new("Branch #{branch_name} does not exist.", false, nil)
end
branches.delete(branch_name)
RepoResult.new("Removed branch #{branch_name}.", true, nil)
end
def list
branches = @store.branches
head = @store.head_branch
format = -> (name) do
name == @store.branches[head].name ? ("* " + name) : (" " + name)
end
names = branches.map { |name, branch| name }.sort
message = names.map { |name| format.call name }.join("\n")
RepoResult.new(message, true, nil)
end
end
class ObjectStore
attr_accessor :branches, :head_branch
def initialize
master = Branch.new "master", []
@branches = {}
@head_branch = "master"
@branches[@head_branch] = master
end
def add(name, object)
@branches[@head_branch].add name, object
message = "Added #{name} to stage."
RepoResult.new(message, true, object)
end
def commit(message)
count = @branches[@head_branch].commit message
if count > 0
commit = @branches[@head_branch].commits[-1]
RepoResult.new("#{message}\n\t#{count} objects changed", true, commit)
else
RepoResult.new("Nothing to commit, working directory clean.")
end
end
def remove(name)
removed_object = @branches[@head_branch].remove name
if removed_object != nil
RepoResult.new("Added #{name} for removal.", true, removed_object)
else
RepoResult.new("Object #{name} is not committed.", false, nil)
end
end
def checkout(commit_hash)
commit = @branches[@head_branch].checkout commit_hash
if commit == nil
RepoResult.new("Commit #{commit_hash} does not exist.")
else
RepoResult.new("HEAD is now at #{commit_hash}.", true, commit)
end
end
def branch
BranchManager.new self
end
def log
commits, name = branches[@head_branch].commits, @head_branch
if commits.size == 0
return RepoResult.new("Branch #{name} does not have any commits yet.")
end
format = -> (commit) do
time = commit.date_formated
"Commit #{commit.hash}\nDate: #{time}\n\n\t#{commit.message}"
end
message = commits.reverse.map { |commit| format.call commit }.join("\n\n")
RepoResult.new(message, true)
end
def head
commits, name = branches[@head_branch].commits, @head_branch
if commits.size == 0
return RepoResult.new("Branch #{@name} does not have any commits yet.")
end
last_commit = commits[-1]
RepoResult.new(last_commit.message, true, last_commit)
end
def get(name)
needed_object = branches[@head_branch].get name
if needed_object == nil
RepoResult.new("Object #{name} is not committed.")
else
RepoResult.new("Found object #{name}.", true, needed_object)
end
end
def self.init(&block)
repo = ObjectStore.new
if block_given?
repo.instance_eval &block
end
repo
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 #<RepoResult:0x007fb11e894550 @message="Branch  does not have any commits yet.", @status=false, @result=nil> to be error "Branch master does not have any commits yet."
     # /tmp/d20160111-5693-166uwjh/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 #<RepoResult:0x007fb11e880c80 @message="Commit c37b43e59489a89b1b473bdbca810299a402d589\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tSo cool!", @status=true, @result=nil> to be success "Commit 381573fc6aa4a6bb947e617a74fc4e0a5e152245\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tSo cool!"
     # /tmp/d20160111-5693-166uwjh/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 #<RepoResult:0x007fb11e852380 @message="Commit c37b43e59489a89b1b473bdbca810299a402d589\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tSo cool!", @status=true, @result=nil> to be success "Commit 381573fc6aa4a6bb947e617a74fc4e0a5e152245\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tSo cool!"
     # /tmp/d20160111-5693-166uwjh/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 #<RepoResult:0x007fb11e8128e8 @message="Commit 216936f23824cf8aae17ab745091ca1bd3ebdd6b\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tSecond commit\n\nCommit 48e44060a740b5dff91925fc890689892c9c8e52\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tFirst commit", @status=true, @result=nil> to be success "Commit ffeb5391d1ec154dd4a821a1aeed876cad514a0d\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tSecond commit\n\nCommit 48bd765d675f355375408e84d12573236b16ddc2\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tFirst commit"
     # /tmp/d20160111-5693-166uwjh/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 #<RepoResult:0x007fb11e7f9190 @message="Commit 48e44060a740b5dff91925fc890689892c9c8e52\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tFirst commit", @status=true, @result=nil> to be success "Commit 48bd765d675f355375408e84d12573236b16ddc2\nDate: Mon Jan 11 11:54 2016 +0200\n\n\tFirst commit"
     # /tmp/d20160111-5693-166uwjh/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.03303 seconds
30 examples, 5 failures

Failed examples:

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

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

Ивайло обнови решението на 23.11.2015 17:27 (преди над 8 години)

+require "time"
+require 'digest/sha1'
+
+class RepoResult
+ attr_accessor :message, :result
+ def initialize(message, status = false, result = nil)
+ @message = message
+ @status = status
+ @result = result
+ end
+
+ def success?
+ @status
+ end
+
+ def error?
+ not @status
+ end
+end
+
+class Commit
+ attr_accessor :objects_hash, :message, :date, :hash
+ def initialize(old_objects, new_objects, deleted_objects, message)
+ @message = message
+ @date = Time.new
+ hash_string = @date.strftime("%a %b %d %H:%M:%S %Y %z") + message
+ @hash = Digest::SHA1.hexdigest(hash_string)
+ @objects_hash = old_objects.dup
+ new_objects.each { |key, value| @objects_hash[key] = value }
+ deleted_objects.each { |key| @objects_hash.delete(key) }
+ end
+
+ def date_formated
+ @date.strftime("%a %b %d %H:%M %Y %z")
+ end
+
+ def objects
+ @objects_hash.values
+ end
+end
+
+class Branch
+ attr_accessor :commits, :new_changes, :name
+ def initialize(name, inherited_commits)
+ @commits = inherited_commits.dup
+ @name = name
+ @new_changes = {}
+ @deleted_objects = []
+ end
+
+ def add(name, object)
+ @new_changes[name] = object
+ end
+
+ def commit(message)
+ last_commit = @commits[-1]
+ state = last_commit != nil ? last_commit.objects_hash : {}
+ new_commit = Commit.new state, @new_changes, @deleted_objects, message
+ @commits << new_commit
+ size = @new_changes.size + @deleted_objects.size
+ @new_changes, @deleted_objects = {}, []
+ size
+ end
+
+ def remove(name)
+ @deleted_objects << name if @commits[-1].objects_hash[name] != nil
+ @commits[-1].objects_hash[name]
+ end
+
+ def get(name)
+ return nil if @commits.size == 0
+ commited_objects = @commits[-1].objects_hash
+ commited_objects[name]
+ end
+
+ def checkout(hash)
+ commit = @commits.select { |commit| commit.hash == hash }.first
+ return nil if commit == nil
+ index = @commits.find_index(commit)
+ remove_commits_count = @commits.size - index - 1
+ @commits.pop remove_commits_count
+ commit
+ end
+end
+
+class BranchManager
+ def initialize(store)
+ @store = store
+ end
+
+ def create(name)
+ branches = @store.branches
+ store_head = @store.head_branch
+ if branches[name] != nil
+ return RepoResult.new("Branch #{name} already exists.", false, nil)
+ end
+ new_branch = Branch.new name, branches[store_head].commits
+ branches[name] = new_branch
+ RepoResult.new("Created branch #{name}.", true, nil)
+ end
+
+ def checkout(branch_name)
+ branches = @store.branches
+ if branches[branch_name] == nil
+ return RepoResult.new("Branch #{branch_name} does not exist.", false, nil)
+ end
+ @store.head_branch = branch_name
+ RepoResult.new("Switched to branch #{branch_name}.", true, nil)
+ end
+
+ def remove(branch_name)
+ branches = @store.branches
+ if @store.head_branch == branch_name
+ return RepoResult.new("Cannot remove current branch.", false, nil)
+ elsif branches[branch_name] == nil
+ return RepoResult.new("Branch #{branch_name} does not exist.", false, nil)
+ end
+ branches.delete(branch_name)
+ RepoResult.new("Removed branch #{branch_name}.", true, nil)
+ end
+
+ def list
+ branches = @store.branches
+ head = @store.head_branch
+ format = -> (name) do
+ name == @store.branches[head].name ? ("* " + name) : (" " + name)
+ end
+ names = branches.map { |name, branch| name }.sort
+ message = names.map { |name| format.call name }.join("\n")
+ RepoResult.new(message, true, nil)
+ end
+end
+
+class ObjectStore
+ attr_accessor :branches, :head_branch
+ def initialize
+ master = Branch.new "master", []
+ @branches = {}
+ @head_branch = "master"
+ @branches[@head_branch] = master
+ end
+
+ def add(name, object)
+ @branches[@head_branch].add name, object
+ message = "Added #{name} to stage."
+ RepoResult.new(message, true, object)
+ end
+
+ def commit(message)
+ count = @branches[@head_branch].commit message
+ if count > 0
+ commit = @branches[@head_branch].commits[-1]
+ RepoResult.new("#{message}\n\t#{count} objects changed", true, commit)
+ else
+ RepoResult.new("Nothing to commit, working directory clean.")
+ end
+ end
+
+ def remove(name)
+ removed_object = @branches[@head_branch].remove name
+ if removed_object != nil
+ RepoResult.new("Added #{name} for removal.", true, removed_object)
+ else
+ RepoResult.new("Object #{name} is not committed.", false, nil)
+ end
+ end
+
+ def checkout(commit_hash)
+ commit = @branches[@head_branch].checkout commit_hash
+ if commit == nil
+ RepoResult.new("Commit #{commit_hash} does not exist.")
+ else
+ RepoResult.new("HEAD is now at #{commit_hash}.", true, commit)
+ end
+ end
+
+ def branch
+ BranchManager.new self
+ end
+
+ def log
+ commits, name = branches[@head_branch].commits, @head_branch
+ if commits.size == 0
+ return RepoResult.new("Branch #{name} does not have any commits yet.")
+ end
+ format = -> (commit) do
+ time = commit.date_formated
+ "Commit #{commit.hash}\nDate: #{time}\n\n\t#{commit.message}"
+ end
+ message = commits.reverse.map { |commit| format.call commit }.join("\n\n")
+ RepoResult.new(message, true)
+ end
+
+ def head
+ commits, name = branches[@head_branch].commits, @head_branch
+ if commits.size == 0
+ return RepoResult.new("Branch #{@name} does not have any commits yet.")
+ end
+ last_commit = commits[-1]
+ RepoResult.new(last_commit.message, true, last_commit)
+ end
+
+ def get(name)
+ needed_object = branches[@head_branch].get name
+ if needed_object == nil
+ RepoResult.new("Object #{name} is not committed.")
+ else
+ RepoResult.new("Found object #{name}.", true, needed_object)
+ end
+ end
+
+ def self.init(&block)
+ repo = ObjectStore.new
+ if block_given?
+ repo.instance_eval &block
+ end
+ repo
+ end
+end

Знам, че няма консистентност на използването на дефаултните стойности - до половината код не се използват. Намерих си грешен тест и докато го оправя останаха 2 минути. Реших да не започвам промяна в такъв момент.

Ивайло, все още имаш проблеми с идентацията на кода, което за пета задача никак не е окей. Потърси как да си настроиш редактора така, че да ползва автоматично орпеделен начин за идентиране на кода – всеки по-нормален редактор го може това. Ако твоят редактор не го може, пробвай Sublime Text или Atom.

Виж и нашето примерно решение, както и хвърли едно око на решенията на другите студенти.

Здравей, Не можах да те намеря последната седмица на лекции, но се опитах да обясня на другите, че просто промених кода си от работния лаптоп 5 мин преди края на домашната и той ми прецака цялата идентация. В предните ми домашни съм я спазвал. Имаш ли други забележки по кода ми.

Като изключим идентацията, останалите ти конвенции са прилични. Има някои места, на които е добре да се слагат празни редове за разделяне на кода на по-ясни парчета, както и други дреболии от вида на return if commit == nil вместо return nil if commit == nil, да се ползва постфиксен if и т.н.

Останалото са имплементационни бележки, на които и сам можеш да си отговориш, като видиш нашето примерно решение, както и като разгледаш решения на колеги.