lib/rscm/revision.rb in rscm-0.4.5 vs lib/rscm/revision.rb in rscm-0.5.0
- old
+ new
@@ -1,206 +1,103 @@
require 'rscm/time_ext'
require 'rscm/revision_file'
+require 'yaml'
module RSCM
-
- # A collection of Revision.
- class Revisions
+ # Represents a collection of RevisionFile that were committed at the
+ # same time, or "more or less at the same time" for non-atomic
+ # SCMs (such as CVS and StarTeam). See Revisions for how to emulate
+ # atomicity for non-atomic SCMs.
+ class Revision
include Enumerable
- attr_accessor :revisions
-
- def initialize(revisions=[])
- @revisions = revisions
- end
+ attr_writer :identifier
+ attr_accessor :developer
+ attr_accessor :message
- # Accepts a visitor that will receive callbacks while
- # iterating over this instance's internal structure.
- # The visitor should respond to the following methods:
- #
- # * visit_revisions(revisions)
- # * visit_revision(revision)
- # * visit_file(file)
- #
- def accept(visitor)
- visitor.visit_revisions(self)
- self.each{|revision| revision.accept(visitor)}
+ def initialize(identifier=nil, time=nil)
+ @identifier = identifier
+ @time = time
+ @files = []
end
- def [](file)
- @revisions[file]
+ def add(file)
+ raise "Can't add #{file} to this revision" unless accept? file
+ @files << file
+ self.developer = file.developer if file.developer
+ self.message = file.message if file.message
end
-
- def each(&block)
- @revisions.each(&block)
- end
- def reverse
- r = clone
- r.revisions = @revisions.dup.reverse
- r
+ def identifier(min_or_max = :max)
+ @identifier || time(min_or_max)
end
- def length
- @revisions.length
+ # The time of this revision. Depending on the value of +min_or_max+,
+ # (should be :min or :max), returns the min or max time of this
+ # revision. (min or max only matters for non-transactional scms)
+ def time(min_or_max = :max)
+ @time || self.collect{|file| file.time}.__send__(min_or_max)
end
- def ==(other)
- return false if !other.is_a?(self.class)
- @revisions == other.revisions
+ # Sets the time for this revision. Should only be used by atomic SCMs.
+ # Non-atomic SCMs should <b>not</b> invoke this method, but instead create
+ # revisions by adding RscmFile objects to a Revisions object.
+ def time=(t)
+ raise "time must be a Time object - it was a #{t.class.name} with the string value #{t}" unless t.is_a?(Time)
+ raise "can't set time to an inferiour value than the previous value" if @time && (t < @time)
+ @time = t
end
- def empty?
- @revisions.empty?
- end
-
- # The set of developers that contributed to all of the contained Revision s.
- def developers
- result = []
- each do |revision|
- result << revision.developer unless result.index(revision.developer)
- end
- result
- end
-
- def first
- @revisions.first
- end
-
- def last
- @revisions.last
- end
-
- # The latest Revision (with the latest time)
- # or nil if there are none.
- def latest
- result = nil
- each do |revision|
- result = revision if result.nil? || result.time < revision.time
- end
- result
- end
+ # Whether +file+ can be added to this instance.
+ def accept?(file) #:nodoc:
+ return true if empty? || @time
- # Adds a File or a Revision.
- # If the argument is a File and no corresponding Revision exists,
- # a new Revision is created, added, and the File is added to that Revision -
- # and then finally the newly created Revision is returned.
- # Otherwise nil is returned.
- def add(file_or_revision)
- if(file_or_revision.is_a?(Revision))
- @revisions << file_or_revision
- return file_or_revision
- else
- revision = @revisions.find { |a_revision| a_revision.can_contain?(file_or_revision) }
- if(revision.nil?)
- revision = Revision.new
- @revisions << revision
- revision << file_or_revision
- return revision
- end
- revision << file_or_revision
- return nil
- end
- end
-
- def push(*file_or_revisions)
- file_or_revisions.each { |file_or_revision| self << (file_or_revision) }
- self
- end
+ close_enough_to_min = (time(:min) - file.time).abs <= 60
+ close_enough_to_max = (time(:max) - file.time).abs <= 60
+ close_enough = close_enough_to_min or close_enough_to_max
- # Sorts the revisions according to time
- def sort!
- @revisions.sort!
- self
+ close_enough and
+ self.developer == file.developer and
+ self.message == file.message
end
- end
-
- # Represents a collection of File that were committed at the same time.
- # Non-transactional SCMs (such as CVS and StarTeam) emulate Revision
- # by grouping File s that were committed by the same developer, with the
- # same commit message, and within a "reasonably" small timespan.
- class Revision
- include Enumerable
-
- attr_reader :files
- attr_accessor :identifier
- attr_accessor :developer
- attr_accessor :message
- attr_accessor :time
-
- def initialize(files=[])
- @files = files
+ def ==(other)
+ self.to_s == other.to_s
end
-
- def accept(visitor)
- visitor.visit_revision(self)
- @files.each{|file| file.accept(visitor)}
- end
- def << (file)
- @files << file
- if(self.time.nil? || self.time < file.time unless file.time.nil?)
- self.time = file.time
- self.identifier = self.time if(self.identifier.nil? || self.identifier.is_a?(Time))
+ # String representation that can be used for debugging.
+ def to_s
+ if(@to_s.nil?)
+ min = time(:min)
+ max = time(:max)
+ t = (min==max) ? min : "#{min}-#{max}"
+ @to_s = "#{identifier} | #{developer} | #{t} | #{message}\n"
+ self.each do |file|
+ @to_s << " " << file.to_s << "\n"
+ end
+ @to_s
end
- self.developer = file.developer if file.developer
- self.message = file.message if file.message
+ @to_s
end
- def [] (index)
- @files[index]
- end
-
- # Iterates over all the RevisionFile objects
def each(&block)
@files.each(&block)
end
-
- def pop
- @files.pop
+
+ def [](n)
+ @files[n]
end
-
+
def length
@files.length
end
- alias :size :length
- def time=(t)
- raise "time must be a Time object - it was a #{t.class.name} with the string value #{t}" unless t.is_a?(Time)
- raise "can't set time to an inferiour value than the previous value" if @time && (t < @time)
- @time = t
+ def pop
+ @files.pop
end
-
- def ==(other)
- other.is_a?(self.class) &&
- @developer == other.developer &&
- @identifier == other.identifier &&
- @message == other.message &&
- @time == other.time &&
- @files == other.files
- end
- def <=>(other)
- @time <=> other.time
+ def empty?
+ @files.empty?
end
- # Whether this instance can contain a File. Used
- # by non-transactional SCMs.
- def can_contain?(file) #:nodoc:
- self.developer == file.developer &&
- self.message == file.message &&
- (self.time - file.time).abs < 60
- end
-
- # String representation that can be used for debugging.
- def to_s
- result = "#{identifier} | #{developer} | #{time} | #{message}\n"
- self.each do |file|
- result << " " << file.to_s << "\n"
- end
- result
- end
-
end
-
end