Module: Gibbler::History
- Extended by:
- Attic
- Defined in:
- lib/gibbler/aliases.rb,
lib/gibbler/history.rb
Overview
– Aliases for Gibbler::History methods
NOTE: we explicitly define the methods rather than use “alias” in the event that the require ‘gibbler/aliases’ appears before require ‘gibbler/history’ (alias complains about unknown methods) ++
Constant Summary collapse
- @@mutex =
Mutex.new
Class Method Summary collapse
Instance Method Summary collapse
- #commit ⇒ Object
- #find_long(*args, &b) ⇒ Object
-
#gibbler_commit ⇒ Object
Stores a clone of the current object instance using the current digest value.
-
#gibbler_find_long(g) ⇒ Object
Returns the long digest associated to the short digest
g
. -
#gibbler_history(short = false) ⇒ Object
Returns an Array of digests in the order they were committed.
-
#gibbler_history? ⇒ Boolean
Does the current object have any history?.
-
#gibbler_object(g = nil) ⇒ Object
Returns the object stored under the given digest
g
. -
#gibbler_revert!(g = nil) ⇒ Object
Revert this object to a previously known state.
-
#gibbler_stamp(g = nil) ⇒ Object
Returns the timestamp (a Time object) when the digest
g
was committed. -
#gibbler_valid?(g) ⇒ Boolean
Is the given digest
g
contained in the history for this object?. - #history(*args, &b) ⇒ Object
- #history? ⇒ Boolean
- #object(*args, &b) ⇒ Object
- #revert!(*args, &b) ⇒ Object
- #stamp(*args, &b) ⇒ Object
- #valid?(*args, &b) ⇒ Boolean
Class Method Details
.mutex ⇒ Object
22 |
# File 'lib/gibbler/history.rb', line 22 def self.mutex; @@mutex; end |
Instance Method Details
#commit ⇒ Object
24 |
# File 'lib/gibbler/aliases.rb', line 24 def commit; gibbler_commit; end |
#find_long(*args, &b) ⇒ Object
30 |
# File 'lib/gibbler/aliases.rb', line 30 def find_long(*args, &b); gibbler_find_long(*args, &b); end |
#gibbler_commit ⇒ Object
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?
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# 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) ⇒ Object
Returns the long digest associated to the short digest g
. If g is longer than 8 characters it returns the value of g
.
140 141 142 143 144 |
# 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) ⇒ Object
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.
27 28 29 30 31 32 33 34 35 36 37 38 39 |
# 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? ⇒ Boolean
Does the current object have any history?
134 135 136 |
# File 'lib/gibbler/history.rb', line 134 def gibbler_history? !gibbler_history.empty? end |
#gibbler_object(g = nil) ⇒ Object
Returns the object stored under the given digest g
. If g
is not a valid digest, returns nil.
43 44 45 46 47 48 49 |
# 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) ⇒ Object
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
).
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# 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) ⇒ Object
Returns the timestamp (a Time object) when the digest g
was committed. If g
is not a valid gibble, returns nil.
53 54 55 56 57 58 |
# 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) ⇒ Boolean
Is the given digest g
contained in the history for this object?
128 129 130 131 |
# 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) ⇒ Object
23 |
# File 'lib/gibbler/aliases.rb', line 23 def history(*args, &b); gibbler_history(*args, &b); end |
#history? ⇒ Boolean
28 |
# File 'lib/gibbler/aliases.rb', line 28 def history?; gibbler_history?; end |
#object(*args, &b) ⇒ Object
25 |
# File 'lib/gibbler/aliases.rb', line 25 def object(*args, &b); gibbler_object(*args, &b); end |
#revert!(*args, &b) ⇒ Object
27 |
# File 'lib/gibbler/aliases.rb', line 27 def revert!(*args, &b); gibbler_revert!(*args, &b); end |
#stamp(*args, &b) ⇒ Object
26 |
# File 'lib/gibbler/aliases.rb', line 26 def stamp(*args, &b); gibbler_stamp(*args, &b); end |
#valid?(*args, &b) ⇒ Boolean
29 |
# File 'lib/gibbler/aliases.rb', line 29 def valid?(*args, &b); gibbler_valid?(*args, &b); end |