Gibbler::History

Public Class Methods

mutex() click to toggle source
# File lib/gibbler/history.rb, line 22
def self.mutex; @@mutex; end

Public Instance Methods

commit() click to toggle source
# File lib/gibbler/aliases.rb, line 24
def commit; gibbler_commit; end
find_long(*args, &b) click to toggle source
# File lib/gibbler/aliases.rb, line 30
def find_long(*args, &b); gibbler_find_long(*args, &b); end
gibbler_commit() click to toggle source

Stores a clone of the current object instance using the current digest value. If the object was not changed, this method does nothing but return the gibble.

NOTE: This method is not fully thread safe. It uses a Mutex.synchronize but there's a race condition where two threads can attempt to commit at near the same time. The first will get the lock and create the commit. The second will get the lock and create another commit immediately after. What we probably want is for the second thread to return the digest for that first snapshot, but how do we know this was a result of the race conditioon rather than two legitimate calls for a snapshot?

# File lib/gibbler/history.rb, line 71
def gibbler_commit
  now, digest, point = nil,nil,nil
  
  if self.__gibbler_history.nil?
    @@mutex.synchronize {
      self.__gibbler_history ||= { :history => [], :objects => {}, :stamp => {} }
    }
  end
  
  @@mutex.synchronize {
    now, digest, point = ::Time.now, self.gibbler, self.clone
    self.__gibbler_history[:history] << digest
    self.__gibbler_history[:stamp][digest] = now
    self.__gibbler_history[:objects][digest] = point
  }
  
  digest
end
gibbler_find_long(g) click to toggle source

Returns the long digest associated to the short digest g. If g is longer than 8 characters it returns the value of g.

# File lib/gibbler/history.rb, line 140
def gibbler_find_long(g)
  return if g.nil?
  return g if g.size > 8
  gibbler_history.select { |d| d.match /\A#{g}/ }.first
end
gibbler_history(short=false) click to toggle source

Returns an Array of digests in the order they were committed. If short is anything but false, the digests will be converted to the short 8 character digests.

# File lib/gibbler/history.rb, line 27
def gibbler_history(short=false)
  # Only a single thread should attempt to initialize the store.
  if self.__gibbler_history.nil?
    @@mutex.synchronize {
      self.__gibbler_history ||= { :history => [], :objects => {}, :stamp => {} }
    }
  end
  if short == false
    self.__gibbler_history[:history]
  else
    self.__gibbler_history[:history].collect { |g| g.short }
  end
end
gibbler_history?() click to toggle source

Does the current object have any history?

# File lib/gibbler/history.rb, line 134
def gibbler_history?
  !gibbler_history.empty?
end
gibbler_object(g=nil) click to toggle source

Returns the object stored under the given digest g. If g is not a valid digest, returns nil.

# File lib/gibbler/history.rb, line 43
def gibbler_object(g=nil) 
  g = gibbler_find_long g
  g = self.gibbler_history.last if g.nil?

  return unless gibbler_valid? g
  self.__gibbler_history[:objects][ g ]
end
gibbler_revert!(g=nil) click to toggle source

Revert this object to a previously known state. If called without arguments it will revert to the most recent commit. If a digest is specified g, it will revert to that point.

Ruby does not support replacing self (self = previous_self) so each object type needs to implement its own __gibbler_revert! method. This default run some common checks and then defers to self.__gibbler_revert!.

Raise the following exceptions:

  • NoRevert: if this object doesn't have a __gibbler_revert! method

  • NoHistory: This object has no commits

  • BadDigest: The given digest is not in the history for this object

If g matches the current digest value this method does nothing.

Returns the new digest (g).

# File lib/gibbler/history.rb, line 106
def gibbler_revert!(g=nil)
  raise NoRevert unless self.respond_to? :__gibbler_revert!
  raise NoHistory, self.class unless gibbler_history?
  raise BadDigest, g if !g.nil? && !gibbler_valid?(g)
  
  g = self.gibbler_history.last if g.nil?
  g = gibbler_find_long g 
  
  # Do nothing if the given digest matches the current gibble. 
  # NOTE: We use __gibbler b/c it doesn't update self.gibbler_cache.
  unless self.__gibbler == g
    @@mutex.synchronize {
      # Always make sure self.gibbler_digest is a Gibbler::Digest 
      self.gibbler_cache = g.is_a?(Gibbler::Digest) ? g : Gibbler::Digest.new(g)
      self.__gibbler_revert!
    }
  end
  
  self.gibbler_cache
end
gibbler_stamp(g=nil) click to toggle source

Returns the timestamp (a Time object) when the digest g was committed. If g is not a valid gibble, returns nil.

# File lib/gibbler/history.rb, line 53
def gibbler_stamp(g=nil)
  g = gibbler_find_long g
  g = self.gibbler_history.last if g.nil?
  return unless gibbler_valid? g
  self.__gibbler_history[:stamp][ g ]
end
gibbler_valid?(g) click to toggle source

Is the given digest g contained in the history for this object?

# File lib/gibbler/history.rb, line 128
def gibbler_valid?(g)
  return false unless gibbler_history?
  gibbler_history.member? gibbler_find_long(g)
end
history(*args, &b) click to toggle source
# File lib/gibbler/aliases.rb, line 23
def history(*args, &b); gibbler_history(*args, &b); end
history?() click to toggle source
# File lib/gibbler/aliases.rb, line 28
def history?; gibbler_history?; end
object(*args, &b) click to toggle source
# File lib/gibbler/aliases.rb, line 25
def object(*args, &b); gibbler_object(*args, &b); end
revert!(*args, &b) click to toggle source
# File lib/gibbler/aliases.rb, line 27
def revert!(*args, &b); gibbler_revert!(*args, &b); end
stamp(*args, &b) click to toggle source
# File lib/gibbler/aliases.rb, line 26
def stamp(*args, &b); gibbler_stamp(*args, &b); end
valid?(*args, &b) click to toggle source
# File lib/gibbler/aliases.rb, line 29
def valid?(*args, &b); gibbler_valid?(*args, &b); end

[Validate]

Generated with the Darkfish Rdoc Generator 2.