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

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

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

Резултати

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

Код

require 'digest/sha1'
require 'forwardable'
module Resultable
def result(message, status, result = nil)
Result.new(message, status, result)
end
end
class Result
attr_reader :message, :result
def initialize(message, status, result)
@message, @status, @result = message, status, result
end
def error?
not success?
end
def success?
@status
end
end
class Commit
DATE_FORMAT = '%a %b %-d %H:%M %Y %z'
attr_accessor :adds, :removals, :message, :date
def initialize(message, changes, branch)
@message = message
@adds = changes[:add]
@removals = changes[:remove]
@date = Time.now
@branch = branch
end
def hash
Digest::SHA1.hexdigest("#{@date.strftime(DATE_FORMAT)}#{@message}")
end
def objects
@branch.objects
end
def to_s
"Commit #{hash}\n" +
"Date: #{@date.strftime(DATE_FORMAT)}\n\n\t" +
@message
end
end
class Branch
include Resultable
def initialize(name)
@name = name
@commits = []
@current_commit = -1
@unstaged = { :add => [], :remove => [] }
end
def to_s
@name
end
def head
last = @commits[@current_commit]
result(last.message, true, last)
end
def add(name, object)
@unstaged[:add] << { :name => name, :object => object }
result("Added #{name} to stage.", true, object)
end
def remove(name)
search = get(name)
return result("Object #{name} is not committed.", false) if search.error?
@unstaged[:remove] << { :name => name, :object => search.result }
result("Object #{name} is not committed.", false)
end
def commit(message)
if @unstaged[:add].empty? && @unstaged[:remove].empty?
return result('Nothing to commit, working directory clean.', false)
end
commit = Commit.new(message, @unstaged, self)
@current_commit += 1
@commits.insert(@current_commit, commit)
@unstaged = { :add => [], :remove => [] }
changes_count = commit.adds.size + commit.removals.size
result("#{message}\n\t#{changes_count} objects changed", true, commit)
end
def checkout(hash)
prev_commit = @commits.find { |commit| commit.hash == hash }
return result("Commit #{hash} does not exist.", false) unless prev_commit
@current_commit = @commits.index(prev_commit)
result("HEAD is now at #{hash}.", true, prev_commit)
end
def get(name)
added = nil
@current_commit.downto(0) do |index|
removed = @commits[index].removals.find { |object| object[:name] == name }
break if removed
added = @commits[index].adds.find { |object| object[:name] == name }
break if added
end
return result("Found object #{name}.", true, added[:object]) if added
result("Object #{name} is not committed.", false)
end
def objects
objects = []
@commits.each do |commit|
objects += commit.adds
objects -= commit.removals
break if commit.hash == @commits[@current_commit].hash
end
objects
end
def log
if @commits.empty?
return result("Branch #{@name} does not have any commits yet.", false)
end
message = []
@current_commit.downto(0) do |index|
message << @commits[index].to_s
end
result(message.join("\n\n"), true)
end
end
class BranchStore
extend Forwardable
include Resultable
def_delegator :current, :add
def_delegator :current, :commit
def_delegator :current, :remove
def_delegator :current, :get
def_delegator :current, :head
def_delegator :current, :log
def initialize
@current_branch = 'master'
@branches = { @current_branch => Branch.new('master') }
end
def list
message = @branches.values.map(&:to_s).map do |name|
(name == @current_branch ? '* %s' : ' %s') % name
end.join('\n')
result(message, true)
end
def create(name)
return result("Branch #{name} already exists.", false) if @branches[name]
@branches[name] = Branch.new(name)
result("Created branch #{name}.", true)
end
def checkout(name)
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@current_branch = name
result("Switched to branch #{@current_branch}.", true)
end
def remove(name)
if name == @current_branch
return result('Cannot remove current branch.', false)
end
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@branches.delete name
result("Removed branch #{name}.", true)
end
def current
@branches[@current_branch]
end
end
class ObjectStore
extend Forwardable
def_delegator :@branch_store, :add
def_delegator :@branch_store, :commit
def_delegator :@branch_store, :get
def_delegator :@branch_store, :head
def_delegator :@branch_store, :log
# can not delegate this bad boy...
# def_delegator :@branch_store, :remove
def self.init(&block)
instance = self.new
instance.instance_eval(&block) if block_given?
instance
end
def initialize
@branch_store = BranchStore.new
end
def branch
@branch_store
end
def remove(name)
@branch_store.current.remove(name)
end
def checkout(hash)
@branch_store.current.checkout(hash)
end
end

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

...F...F...F.F..............FF

Failures:

  1) ObjectStore can remove objects
     Failure/Error: expect(repo.remove("object1")).to be_success("Added object1 for removal.", "content1")
       expected #<Result:0x007fd55eac4f78 @message="Object object1 is not committed.", @status=false, @result=nil> to be success "Added object1 for removal." and "content1"
     # /tmp/d20160111-5693-1tlisk1/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 cannot show head for empty repository
     Failure/Error: expect(repo.head).to be_error("Branch master does not have any commits yet.")
     NoMethodError:
       undefined method `message' for nil:NilClass
     # /tmp/d20160111-5693-1tlisk1/solution.rb:74:in `head'
     # /tmp/d20160111-5693-1tlisk1/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)>'

  3) 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 #<Result:0x007fd55e944680 @message="Branch develop does not have any commits yet.", @status=false, @result=nil> to be success "Commit 9a97b358afe869ba1e523d99dd2101dfc0570dc0\nDate: Mon Jan 11 11:55 2016 +0200\n\n\tFirst commit"
     # /tmp/d20160111-5693-1tlisk1/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)>'

  4) ObjectStore can list branches
     Failure/Error: expect(repo.branch.list).to be_success("  develop\n  feature\n* master")
       expected #<Result:0x007fd55e906bf0 @message="* master\\n  develop\\n  feature", @status=true, @result=nil> to be success "  develop\n  feature\n* master"
     # /tmp/d20160111-5693-1tlisk1/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)>'

  5) ObjectStore can show the objects in a repo after overwriting an object
     Failure/Error: expect(first_commit.objects).to match_array(["content1"])
       expected collection contained:  ["content1"]
       actual collection contained:    [{:name=>"object1", :object=>"content1"}]
       the missing elements were:      ["content1"]
       the extra elements were:        [{:name=>"object1", :object=>"content1"}]
     # /tmp/d20160111-5693-1tlisk1/spec.rb:243: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 the objects of a repo after removing an object
     Failure/Error: expect(first_commit.objects).to match_array(["content1", "content2", "content3"])
       expected collection contained:  ["content1", "content2", "content3"]
       actual collection contained:    [{:name=>"object1", :object=>"content1"}, {:name=>"object2", :object=>"content2"}, {:name=>"object3", :object=>"content3"}]
       the missing elements were:      ["content1", "content2", "content3"]
       the extra elements were:        [{:name=>"object1", :object=>"content1"}, {:name=>"object2", :object=>"content2"}, {:name=>"object3", :object=>"content3"}]
     # /tmp/d20160111-5693-1tlisk1/spec.rb:259: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.03245 seconds
30 examples, 6 failures

Failed examples:

rspec /tmp/d20160111-5693-1tlisk1/spec.rb:38 # ObjectStore can remove objects
rspec /tmp/d20160111-5693-1tlisk1/spec.rb:72 # ObjectStore cannot show head for empty repository
rspec /tmp/d20160111-5693-1tlisk1/spec.rb:111 # ObjectStore shows the log for the current branch only
rspec /tmp/d20160111-5693-1tlisk1/spec.rb:136 # ObjectStore can list branches
rspec /tmp/d20160111-5693-1tlisk1/spec.rb:239 # ObjectStore can show the objects in a repo after overwriting an object
rspec /tmp/d20160111-5693-1tlisk1/spec.rb:253 # ObjectStore can show the objects of a repo after removing an object

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

Владимир обнови решението на 15.11.2015 22:13 (преди над 8 години)

+require 'digest/sha1'
+require 'forwardable'
+
+module Resultable
+
+ def result(message, status, result = nil)
+ Result.new(message, status, result)
+ end
+end
+
+class Result
+
+ attr_reader :message, :result
+
+ def initialize(message, status, result)
+ @message, @status, @result = message, status, result
+ end
+
+ def error?
+ not success?
+ end
+
+ def success?
+ @status
+ end
+end
+
+class Commit
+
+ attr_accessor :adds, :removals, :message, :date
+
+ def initialize(message, changes, branch)
+ @message = message
+ @adds = changes[:add]
+ @removals = changes[:remove]
+ @date = Time.now
+ @branch = branch
+ end
+
+ def hash
+ @hash ||= Digest::SHA1.hexdigest("#{@date.to_s}#{@message}")
+ end
+
+ def objects
+ @branch.objects
+ end
+
+ def to_s
+ "Commit #{hash}\n" +
+ "Date: #{@date.strftime('%a %b %-d %H:%M %Y %z')}\n\n\t" +
+ @message
+ end
+end
+
+class Branch
+
+ include Resultable
+
+ def initialize(name)
+ @name = name
+ @commits = []
+ @current_commit = -1
+ @unstaged = { :add => [], :remove => [] }
+ end
+
+ def to_s
+ @name
+ end
+
+ def head
+ last = @commits[@current_commit]
+ result(last.message, true, last)
+ end
+
+ def add(name, object)
+ @unstaged[:add] << { :name => name, :object => object }
+ result("Added #{name} to stage.", true, object)
+ end
+
+ def remove(name)
+ search = get(name)
+ return result("Object #{name} is not committed.", false) if search.error?
+ @unstaged[:remove] << { :name => name, :object => search.result }
+ result("Object #{name} is not committed.", false)
+ end
+
+ def commit(message)
+ if @unstaged[:add].empty? && @unstaged[:remove].empty?
+ return result('Nothing to commit, working directory clean.', false)
+ end
+ commit = Commit.new(message, @unstaged, self)
+ @current_commit += 1
+ @commits.insert(@current_commit, commit)
+ @unstaged = { :add => [], :remove => [] }
+ changes_count = commit.adds.size + commit.removals.size
+ result("#{message}\n\t#{changes_count} objects changed", true, commit)
+ end
+
+ def checkout(hash)
+ prev_commit = @commits.find { |commit| commit.hash == hash }
+ return result("Commit #{hash} does not exist.", false) unless prev_commit
+ @current_commit = @commits.index(prev_commit)
+ result("Head is now at #{hash}", true, prev_commit)
+ end
+
+ def get(name)
+ added = nil
+ @current_commit.downto(0) do |index|
+ removed = @commits[index].removals.find { |object| object[:name] == name }
+ break if removed
+ added = @commits[index].adds.find { |object| object[:name] == name }
+ break if added
+ end
+ return result("Found object #{name}.", true, added[:object]) if added
+ result("Object #{name} is not committed.", false)
+ end
+
+ def objects
+ objects = []
+ @commits.each do |commit|
+ objects += commit.adds
+ objects -= commit.removals
+ break if commit.hash == @commits[@current_commit].hash
+ end
+ objects
+ end
+
+ def log
+ if @commits.empty?
+ return result("Branch #{@name} does not have any commits yet.", false)
+ end
+ message = []
+ @current_commit.downto(0) do |index|
+ message << @commits[index].to_s
+ end
+ result(message.join("\n\n"), true)
+ end
+end
+
+class BranchStore
+
+ extend Forwardable
+ include Resultable
+
+ def_delegator :current, :add
+ def_delegator :current, :commit
+ def_delegator :current, :remove
+ def_delegator :current, :get
+ def_delegator :current, :head
+ def_delegator :current, :log
+
+ def initialize
+ @current_branch = 'master'
+ @branches = { @current_branch => Branch.new('master') }
+ end
+
+ def list
+ message = @branches.values.map(&:to_s).map do |name|
+ (name == @current_branch ? ' *%s' : ' %s') % name
+ end.join('\n')
+ result(message, true)
+ end
+
+ def create(name)
+ return result("Branch #{name} already exists.", false) if @branches[name]
+ @branches[name] = Branch.new(name)
+ result("Created branch #{name}.", true)
+ end
+
+ def checkout(name)
+ unless @branches[name]
+ return result("Branch #{name} does not exist.", false)
+ end
+ @current_branch = name
+ result("Switched to branch #{@current_branch}.", true)
+ end
+
+ def remove(name)
+ if name == @current_branch
+ return result('Cannot remove current branch.', false)
+ end
+ unless @branches[name]
+ return result("Branch #{name} does not exist.", false)
+ end
+ @branches.delete name
+ result("Removed branch #{name}.", true)
+ end
+
+ def current
+ @branches[@current_branch]
+ end
+end
+
+class ObjectStore
+
+ extend Forwardable
+
+ def_delegator :@branch_store, :add
+ def_delegator :@branch_store, :commit
+ def_delegator :@branch_store, :get
+ def_delegator :@branch_store, :head
+ def_delegator :@branch_store, :log
+ # can not delegate this bad boy...
+ # def_delegator :@branch_store, :remove
+
+ def self.init(&block)
+ instance = self.new
+ instance.instance_eval(&block) if block_given?
+ instance
+ end
+
+ def initialize
+ @branch_store = BranchStore.new
+ end
+
+ def branch
+ @branch_store
+ end
+
+ def remove(name)
+ @branch_store.current.remove(name)
+ end
+
+ def checkout(hash)
+ @branch_store.current.checkout(hash)
+ end
+end

Владимир обнови решението на 15.11.2015 22:16 (преди над 8 години)

require 'digest/sha1'
require 'forwardable'
module Resultable
def result(message, status, result = nil)
Result.new(message, status, result)
end
end
class Result
attr_reader :message, :result
def initialize(message, status, result)
@message, @status, @result = message, status, result
end
def error?
not success?
end
def success?
@status
end
end
class Commit
+ DATE_FORMAT = '%a %b %-d %H:%M %Y %z'
+
attr_accessor :adds, :removals, :message, :date
def initialize(message, changes, branch)
@message = message
@adds = changes[:add]
@removals = changes[:remove]
@date = Time.now
@branch = branch
end
def hash
- @hash ||= Digest::SHA1.hexdigest("#{@date.to_s}#{@message}")
+ Digest::SHA1.hexdigest("#{@date.strftime(DATE_FORMAT)}#{@message}")
end
def objects
@branch.objects
end
def to_s
"Commit #{hash}\n" +
- "Date: #{@date.strftime('%a %b %-d %H:%M %Y %z')}\n\n\t" +
+ "Date: #{@date.strftime(DATE_FORMAT)}\n\n\t" +
@message
end
end
class Branch
include Resultable
def initialize(name)
@name = name
@commits = []
@current_commit = -1
@unstaged = { :add => [], :remove => [] }
end
def to_s
@name
end
def head
last = @commits[@current_commit]
result(last.message, true, last)
end
def add(name, object)
@unstaged[:add] << { :name => name, :object => object }
result("Added #{name} to stage.", true, object)
end
def remove(name)
search = get(name)
return result("Object #{name} is not committed.", false) if search.error?
@unstaged[:remove] << { :name => name, :object => search.result }
result("Object #{name} is not committed.", false)
end
def commit(message)
if @unstaged[:add].empty? && @unstaged[:remove].empty?
return result('Nothing to commit, working directory clean.', false)
end
commit = Commit.new(message, @unstaged, self)
@current_commit += 1
@commits.insert(@current_commit, commit)
@unstaged = { :add => [], :remove => [] }
changes_count = commit.adds.size + commit.removals.size
result("#{message}\n\t#{changes_count} objects changed", true, commit)
end
def checkout(hash)
prev_commit = @commits.find { |commit| commit.hash == hash }
return result("Commit #{hash} does not exist.", false) unless prev_commit
@current_commit = @commits.index(prev_commit)
result("Head is now at #{hash}", true, prev_commit)
end
def get(name)
added = nil
@current_commit.downto(0) do |index|
removed = @commits[index].removals.find { |object| object[:name] == name }
break if removed
added = @commits[index].adds.find { |object| object[:name] == name }
break if added
end
return result("Found object #{name}.", true, added[:object]) if added
result("Object #{name} is not committed.", false)
end
def objects
objects = []
@commits.each do |commit|
objects += commit.adds
objects -= commit.removals
break if commit.hash == @commits[@current_commit].hash
end
objects
end
def log
if @commits.empty?
return result("Branch #{@name} does not have any commits yet.", false)
end
message = []
@current_commit.downto(0) do |index|
message << @commits[index].to_s
end
result(message.join("\n\n"), true)
end
end
class BranchStore
extend Forwardable
include Resultable
def_delegator :current, :add
def_delegator :current, :commit
def_delegator :current, :remove
def_delegator :current, :get
def_delegator :current, :head
def_delegator :current, :log
def initialize
@current_branch = 'master'
@branches = { @current_branch => Branch.new('master') }
end
def list
message = @branches.values.map(&:to_s).map do |name|
(name == @current_branch ? ' *%s' : ' %s') % name
end.join('\n')
result(message, true)
end
def create(name)
return result("Branch #{name} already exists.", false) if @branches[name]
@branches[name] = Branch.new(name)
result("Created branch #{name}.", true)
end
def checkout(name)
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@current_branch = name
result("Switched to branch #{@current_branch}.", true)
end
def remove(name)
if name == @current_branch
return result('Cannot remove current branch.', false)
end
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@branches.delete name
result("Removed branch #{name}.", true)
end
def current
@branches[@current_branch]
end
end
class ObjectStore
extend Forwardable
def_delegator :@branch_store, :add
def_delegator :@branch_store, :commit
def_delegator :@branch_store, :get
def_delegator :@branch_store, :head
def_delegator :@branch_store, :log
# can not delegate this bad boy...
# def_delegator :@branch_store, :remove
def self.init(&block)
instance = self.new
instance.instance_eval(&block) if block_given?
instance
end
def initialize
@branch_store = BranchStore.new
end
def branch
@branch_store
end
def remove(name)
@branch_store.current.remove(name)
end
def checkout(hash)
@branch_store.current.checkout(hash)
end
end

Владимир обнови решението на 17.11.2015 14:12 (преди над 8 години)

require 'digest/sha1'
require 'forwardable'
module Resultable
def result(message, status, result = nil)
Result.new(message, status, result)
end
end
class Result
attr_reader :message, :result
def initialize(message, status, result)
@message, @status, @result = message, status, result
end
def error?
not success?
end
def success?
@status
end
end
class Commit
DATE_FORMAT = '%a %b %-d %H:%M %Y %z'
attr_accessor :adds, :removals, :message, :date
def initialize(message, changes, branch)
@message = message
@adds = changes[:add]
@removals = changes[:remove]
@date = Time.now
@branch = branch
end
def hash
Digest::SHA1.hexdigest("#{@date.strftime(DATE_FORMAT)}#{@message}")
end
def objects
@branch.objects
end
def to_s
"Commit #{hash}\n" +
"Date: #{@date.strftime(DATE_FORMAT)}\n\n\t" +
@message
end
end
class Branch
include Resultable
def initialize(name)
@name = name
@commits = []
@current_commit = -1
@unstaged = { :add => [], :remove => [] }
end
def to_s
@name
end
def head
last = @commits[@current_commit]
result(last.message, true, last)
end
def add(name, object)
@unstaged[:add] << { :name => name, :object => object }
result("Added #{name} to stage.", true, object)
end
def remove(name)
search = get(name)
return result("Object #{name} is not committed.", false) if search.error?
@unstaged[:remove] << { :name => name, :object => search.result }
result("Object #{name} is not committed.", false)
end
def commit(message)
if @unstaged[:add].empty? && @unstaged[:remove].empty?
return result('Nothing to commit, working directory clean.', false)
end
commit = Commit.new(message, @unstaged, self)
@current_commit += 1
@commits.insert(@current_commit, commit)
@unstaged = { :add => [], :remove => [] }
changes_count = commit.adds.size + commit.removals.size
result("#{message}\n\t#{changes_count} objects changed", true, commit)
end
def checkout(hash)
prev_commit = @commits.find { |commit| commit.hash == hash }
return result("Commit #{hash} does not exist.", false) unless prev_commit
@current_commit = @commits.index(prev_commit)
result("Head is now at #{hash}", true, prev_commit)
end
def get(name)
added = nil
@current_commit.downto(0) do |index|
removed = @commits[index].removals.find { |object| object[:name] == name }
break if removed
added = @commits[index].adds.find { |object| object[:name] == name }
break if added
end
return result("Found object #{name}.", true, added[:object]) if added
result("Object #{name} is not committed.", false)
end
def objects
objects = []
@commits.each do |commit|
objects += commit.adds
objects -= commit.removals
break if commit.hash == @commits[@current_commit].hash
end
objects
end
def log
if @commits.empty?
return result("Branch #{@name} does not have any commits yet.", false)
end
message = []
@current_commit.downto(0) do |index|
message << @commits[index].to_s
end
result(message.join("\n\n"), true)
end
end
class BranchStore
extend Forwardable
include Resultable
def_delegator :current, :add
def_delegator :current, :commit
def_delegator :current, :remove
def_delegator :current, :get
def_delegator :current, :head
def_delegator :current, :log
def initialize
@current_branch = 'master'
@branches = { @current_branch => Branch.new('master') }
end
def list
message = @branches.values.map(&:to_s).map do |name|
- (name == @current_branch ? ' *%s' : ' %s') % name
+ (name == @current_branch ? '* %s' : ' %s') % name
end.join('\n')
result(message, true)
end
def create(name)
return result("Branch #{name} already exists.", false) if @branches[name]
@branches[name] = Branch.new(name)
result("Created branch #{name}.", true)
end
def checkout(name)
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@current_branch = name
result("Switched to branch #{@current_branch}.", true)
end
def remove(name)
if name == @current_branch
return result('Cannot remove current branch.', false)
end
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@branches.delete name
result("Removed branch #{name}.", true)
end
def current
@branches[@current_branch]
end
end
class ObjectStore
extend Forwardable
def_delegator :@branch_store, :add
def_delegator :@branch_store, :commit
def_delegator :@branch_store, :get
def_delegator :@branch_store, :head
def_delegator :@branch_store, :log
# can not delegate this bad boy...
# def_delegator :@branch_store, :remove
def self.init(&block)
instance = self.new
instance.instance_eval(&block) if block_given?
instance
end
def initialize
@branch_store = BranchStore.new
end
def branch
@branch_store
end
def remove(name)
@branch_store.current.remove(name)
end
def checkout(hash)
@branch_store.current.checkout(hash)
end
end

Владимир обнови решението на 17.11.2015 14:14 (преди над 8 години)

require 'digest/sha1'
require 'forwardable'
module Resultable
def result(message, status, result = nil)
Result.new(message, status, result)
end
end
class Result
attr_reader :message, :result
def initialize(message, status, result)
@message, @status, @result = message, status, result
end
def error?
not success?
end
def success?
@status
end
end
class Commit
DATE_FORMAT = '%a %b %-d %H:%M %Y %z'
attr_accessor :adds, :removals, :message, :date
def initialize(message, changes, branch)
@message = message
@adds = changes[:add]
@removals = changes[:remove]
@date = Time.now
@branch = branch
end
def hash
Digest::SHA1.hexdigest("#{@date.strftime(DATE_FORMAT)}#{@message}")
end
def objects
@branch.objects
end
def to_s
"Commit #{hash}\n" +
"Date: #{@date.strftime(DATE_FORMAT)}\n\n\t" +
@message
end
end
class Branch
include Resultable
def initialize(name)
@name = name
@commits = []
@current_commit = -1
@unstaged = { :add => [], :remove => [] }
end
def to_s
@name
end
def head
last = @commits[@current_commit]
result(last.message, true, last)
end
def add(name, object)
@unstaged[:add] << { :name => name, :object => object }
result("Added #{name} to stage.", true, object)
end
def remove(name)
search = get(name)
return result("Object #{name} is not committed.", false) if search.error?
@unstaged[:remove] << { :name => name, :object => search.result }
result("Object #{name} is not committed.", false)
end
def commit(message)
if @unstaged[:add].empty? && @unstaged[:remove].empty?
return result('Nothing to commit, working directory clean.', false)
end
commit = Commit.new(message, @unstaged, self)
@current_commit += 1
@commits.insert(@current_commit, commit)
@unstaged = { :add => [], :remove => [] }
changes_count = commit.adds.size + commit.removals.size
result("#{message}\n\t#{changes_count} objects changed", true, commit)
end
def checkout(hash)
prev_commit = @commits.find { |commit| commit.hash == hash }
return result("Commit #{hash} does not exist.", false) unless prev_commit
@current_commit = @commits.index(prev_commit)
- result("Head is now at #{hash}", true, prev_commit)
+ result("HEAD is now at #{hash}", true, prev_commit)
end
def get(name)
added = nil
@current_commit.downto(0) do |index|
removed = @commits[index].removals.find { |object| object[:name] == name }
break if removed
added = @commits[index].adds.find { |object| object[:name] == name }
break if added
end
return result("Found object #{name}.", true, added[:object]) if added
result("Object #{name} is not committed.", false)
end
def objects
objects = []
@commits.each do |commit|
objects += commit.adds
objects -= commit.removals
break if commit.hash == @commits[@current_commit].hash
end
objects
end
def log
if @commits.empty?
return result("Branch #{@name} does not have any commits yet.", false)
end
message = []
@current_commit.downto(0) do |index|
message << @commits[index].to_s
end
result(message.join("\n\n"), true)
end
end
class BranchStore
extend Forwardable
include Resultable
def_delegator :current, :add
def_delegator :current, :commit
def_delegator :current, :remove
def_delegator :current, :get
def_delegator :current, :head
def_delegator :current, :log
def initialize
@current_branch = 'master'
@branches = { @current_branch => Branch.new('master') }
end
def list
message = @branches.values.map(&:to_s).map do |name|
(name == @current_branch ? '* %s' : ' %s') % name
end.join('\n')
result(message, true)
end
def create(name)
return result("Branch #{name} already exists.", false) if @branches[name]
@branches[name] = Branch.new(name)
result("Created branch #{name}.", true)
end
def checkout(name)
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@current_branch = name
result("Switched to branch #{@current_branch}.", true)
end
def remove(name)
if name == @current_branch
return result('Cannot remove current branch.', false)
end
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@branches.delete name
result("Removed branch #{name}.", true)
end
def current
@branches[@current_branch]
end
end
class ObjectStore
extend Forwardable
def_delegator :@branch_store, :add
def_delegator :@branch_store, :commit
def_delegator :@branch_store, :get
def_delegator :@branch_store, :head
def_delegator :@branch_store, :log
# can not delegate this bad boy...
# def_delegator :@branch_store, :remove
def self.init(&block)
instance = self.new
instance.instance_eval(&block) if block_given?
instance
end
def initialize
@branch_store = BranchStore.new
end
def branch
@branch_store
end
def remove(name)
@branch_store.current.remove(name)
end
def checkout(hash)
@branch_store.current.checkout(hash)
end
end

Владимир обнови решението на 17.11.2015 16:08 (преди над 8 години)

require 'digest/sha1'
require 'forwardable'
module Resultable
def result(message, status, result = nil)
Result.new(message, status, result)
end
end
class Result
attr_reader :message, :result
def initialize(message, status, result)
@message, @status, @result = message, status, result
end
def error?
not success?
end
def success?
@status
end
end
class Commit
DATE_FORMAT = '%a %b %-d %H:%M %Y %z'
attr_accessor :adds, :removals, :message, :date
def initialize(message, changes, branch)
@message = message
@adds = changes[:add]
@removals = changes[:remove]
@date = Time.now
@branch = branch
end
def hash
Digest::SHA1.hexdigest("#{@date.strftime(DATE_FORMAT)}#{@message}")
end
def objects
@branch.objects
end
def to_s
"Commit #{hash}\n" +
"Date: #{@date.strftime(DATE_FORMAT)}\n\n\t" +
@message
end
end
class Branch
include Resultable
def initialize(name)
@name = name
@commits = []
@current_commit = -1
@unstaged = { :add => [], :remove => [] }
end
def to_s
@name
end
def head
last = @commits[@current_commit]
result(last.message, true, last)
end
def add(name, object)
@unstaged[:add] << { :name => name, :object => object }
result("Added #{name} to stage.", true, object)
end
def remove(name)
search = get(name)
return result("Object #{name} is not committed.", false) if search.error?
@unstaged[:remove] << { :name => name, :object => search.result }
result("Object #{name} is not committed.", false)
end
def commit(message)
if @unstaged[:add].empty? && @unstaged[:remove].empty?
return result('Nothing to commit, working directory clean.', false)
end
commit = Commit.new(message, @unstaged, self)
@current_commit += 1
@commits.insert(@current_commit, commit)
@unstaged = { :add => [], :remove => [] }
changes_count = commit.adds.size + commit.removals.size
result("#{message}\n\t#{changes_count} objects changed", true, commit)
end
def checkout(hash)
prev_commit = @commits.find { |commit| commit.hash == hash }
return result("Commit #{hash} does not exist.", false) unless prev_commit
@current_commit = @commits.index(prev_commit)
- result("HEAD is now at #{hash}", true, prev_commit)
+ result("HEAD is now at #{hash}.", true, prev_commit)
end
def get(name)
added = nil
@current_commit.downto(0) do |index|
removed = @commits[index].removals.find { |object| object[:name] == name }
break if removed
added = @commits[index].adds.find { |object| object[:name] == name }
break if added
end
return result("Found object #{name}.", true, added[:object]) if added
result("Object #{name} is not committed.", false)
end
def objects
objects = []
@commits.each do |commit|
objects += commit.adds
objects -= commit.removals
break if commit.hash == @commits[@current_commit].hash
end
objects
end
def log
if @commits.empty?
return result("Branch #{@name} does not have any commits yet.", false)
end
message = []
@current_commit.downto(0) do |index|
message << @commits[index].to_s
end
result(message.join("\n\n"), true)
end
end
class BranchStore
extend Forwardable
include Resultable
def_delegator :current, :add
def_delegator :current, :commit
def_delegator :current, :remove
def_delegator :current, :get
def_delegator :current, :head
def_delegator :current, :log
def initialize
@current_branch = 'master'
@branches = { @current_branch => Branch.new('master') }
end
def list
message = @branches.values.map(&:to_s).map do |name|
(name == @current_branch ? '* %s' : ' %s') % name
end.join('\n')
result(message, true)
end
def create(name)
return result("Branch #{name} already exists.", false) if @branches[name]
@branches[name] = Branch.new(name)
result("Created branch #{name}.", true)
end
def checkout(name)
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@current_branch = name
result("Switched to branch #{@current_branch}.", true)
end
def remove(name)
if name == @current_branch
return result('Cannot remove current branch.', false)
end
unless @branches[name]
return result("Branch #{name} does not exist.", false)
end
@branches.delete name
result("Removed branch #{name}.", true)
end
def current
@branches[@current_branch]
end
end
class ObjectStore
extend Forwardable
def_delegator :@branch_store, :add
def_delegator :@branch_store, :commit
def_delegator :@branch_store, :get
def_delegator :@branch_store, :head
def_delegator :@branch_store, :log
# can not delegate this bad boy...
# def_delegator :@branch_store, :remove
def self.init(&block)
instance = self.new
instance.instance_eval(&block) if block_given?
instance
end
def initialize
@branch_store = BranchStore.new
end
def branch
@branch_store
end
def remove(name)
@branch_store.current.remove(name)
end
def checkout(hash)
@branch_store.current.checkout(hash)
end
end