¶ ↑
Gibbler - v0.9Git-like hashes and history for Ruby objects for Ruby 1.8, 1.9 and JRuby.
Check out the screencast created by Alex Peuchert.
¶ ↑
Some things to keep in mind-
Digest calculation may change between minor releases (as it did between 0.6 and 0.7)
-
Gibbler history is not suitable for very large objects since it keeps complete copies of the object in memory. This is a very early implementation of this feature so don’t rely on it for production code.
-
Don’t forget to enjoy your life!
¶ ↑
Example 1 – Standalone Usagerequire 'gibbler' g = Gibbler.new 'id', 1001 # => f4fb3796ababa3788d1bded8fdc589ab1ccb1c3d g.base(36) # => sm71s7eam4hm5jlsuzlqkbuktwpe5h9 g == 'f4fb3796ababa3788d1bded8fdc589ab1ccb1c3d' # => true g === 'f4fb379' # => true
¶ ↑
Example 2 – Mixins Usagerequire 'gibbler/mixins' "kimmy".gibbler # => c8027100ecc54945ab15ddac529230e38b1ba6a1 :kimmy.gibbler # => 52be7494a602d85ff5d8a8ab4ffe7f1b171587df config = {} config.gibbler # => 4fdcadc66a38feb9c57faf3c5a18d5e76a6d29bf config.gibbled? # => false config[:server] = { :users => [:dave, :ali], :ports => [22, 80, 443] } config.gibbled? # => true config.gibbler # => ef23d605f8c4fc80a8e580f9a0e8dab8426454a8 config[:server][:users] << :yanni config.gibbler # => 4c558a56bc2abf5f8a845a69e47ceb5e0003683f config.gibbler.short # => 4c558a56 config.gibbler.base36 # => 8x00l83jov4j80i9vfzpaxr9jag23wf config.gibbler.base36.short # => 8x00l83j
¶ ↑
Example 3 – Object HistoryGibbler can also keep track of the history of changes to an object. By default Gibbler supports history for Hash, Array, and String objects. The gibbler_commit
method creates a clone of the current object and stores in an instance variable using the current hash digest as the key.
require 'gibbler/mixins' require 'gibbler/history' a = { :magic => :original } a.gibbler_commit # => d7049916ddb25e6cc438b1028fb957e5139f9910 a[:magic] = :updated a.gibbler_commit # => b668098e16d08898532bf3aa33ce2253a3a4150e a[:magic] = :changed a.gibbler_commit # => 0b11c377fccd44554a601e5d2b135c46dc1c4cb1 a.gibbler_history # => d7049916, b668098e, 0b11c377 a.gibbler_revert! 'd7049916' # Return to a specific commit a.gibbler # => d7049916ddb25e6cc438b1028fb957e5139f9910 a # => { :magic => :original } a.delete :magic a.gibbler_revert! # Return to the previous commit a.gibbler # => 0b11c377fccd44554a601e5d2b135c46dc1c4cb1 a # => { :magic => :changed } a.gibbler_object 'b668098e' # => { :magic => :updated } a.gibbler_stamp # => 2009-07-01 18:56:52 -0400
¶ ↑
Example 4 – Method AliasesIf you have control over the namespaces of your objects, you can use the method aliases to tighten up your code a bit. The “gibbler” and “gibbled?” methods can be accessed via “digest” and “changed?”, respectively. (The reason they’re not enabled by default is to avoid conflicts.)
require 'gibbler/aliases' "kimmy".digest # => c8027100ecc54945ab15ddac529230e38b1ba6a1 :kimmy.digest # => 52be7494a602d85ff5d8a8ab4ffe7f1b171587df a = [:a, :b, :c] a.digest # => e554061823b8f06367555d1ee4c25b4ffee61944 a << :d a.changed? # => true
The history methods also have aliases which remove the “gibbler_” prefix.
require 'gibbler/aliases' require 'gibbler/history' a = { :magic => :original } a.commit a.history a.revert! # etc...
¶ ↑
Example 5 – Different Digest typesBy default Gibbler creates SHA1 hashes. You can change this globally or per instance.
require 'gibbler/mixins' Gibbler.digest_type = Digest::MD5 :kimmy.gibbler # => 0c61ff17f46223f355759934154d5dcb :kimmy.gibbler(Digest::SHA1) # => 52be7494a602d85ff5d8a8ab4ffe7f1b171587df
In Jruby, you can grab the digest types from the openssl library.
require 'openssl' Gibbler.digest_type = OpenSSL::Digest::SHA256 :kimmy.gibbler # => 1069428e6273cf329436c3dce9b680d4d4e229d7b7...
¶ ↑
Example 6 – All your baserequire 'gibbler/mixins' :kimmy.gibbler # => 52be7494a602d85ff5d8a8ab4ffe7f1b171587df :kimmy.gibbler.base(16) # => 52be7494a602d85ff5d8a8ab4ffe7f1b171587df :kimmy.gibbler.base(36) # => 9nydr6mpv6w4k8ngo3jtx0jz1n97h7j :kimmy.gibbler.base(10) # => 472384540402900668368761869477227308873774630879 :kimmy.gibbler.to_i # => 472384540402900668368761869477227308873774630879
¶ ↑
Example 7 – Global secretGibbler can prepend all digest inputs with a global secret. You can set this once per project to ensure your project’s digests are unique.
require 'gibbler/mixins' :kimmy.gibbler # => 52be7494a602d85ff5d8a8ab4ffe7f1b171587df Gibbler.secret = "sUp0r5ekRu7" :kimmy.gibbler # => 6c5f5aff4d809cec7e7da091214a35a2698489f8
¶ ↑
Supported ClassesGibbler methods are available only to the classes which explicitly include them (see RDocs for details on which classes are supported by default). You can also extend custom objects:
class FullHouse include Gibbler::Complex attr_accessor :roles end a = FullHouse.new a.gibbler # => 4192d4cb59975813f117a51dcd4454ac16df6703 a.roles = [:jesse, :joey, :danny, :kimmy, :michelle, :dj, :stephanie] a.gibbler # => 6ea546919dc4caa2bab69799b71d48810a1b48fa
Gibbler::Complex creates a digest based on the name of the class and the names and values of the instance variables. See the RDocs for other Gibbler::* types.
If you want to support all Ruby objects, add the following to your application:
class Object include Gibbler::String end
Gibbler::String creates a digest based on the name of the class and the output of the to_s method. This is a reasonable default for most objects however any object that includes the object address in to_s (e.g. “Object:0x0x4ac9f0…”) will produce unreliable digests (because the address can change).
As of 0.7 all Proc objects have the same digest: 12075835e94be34438376cd7a54c8db7e746f15d
.
¶ ↑
Known Issues-
gibbler or gibbled? must be called at least once before gibbled? will be able to return a useful value (otherwise there is no previous digest value to compare to)
-
Digests for Bignum objects are different between Ruby and JRuby. Why?
-
Digests for Proc objects are different between Ruby 1.8 and 1.9 because Proc.arity returns different values and 1.8 has no lambda? method.
¶ ↑
InstallationVia Rubygems:
$ gem install gibbler
or via download:
¶ ↑
What People Are Saying-
“nice approach - everything is an object, every object is ‘gittish’” – @olgen_morten
-
“gibbler is just awesome” – @TomK32
-
“wie cool ist Gibbler eigentlich?” – @we5
-
“it’s nice idea and implementation!” – HristoHristov
¶ ↑
More Info¶ ↑
Thanks-
Kalin Harvey (krrh) for the early feedback and artistic direction.
-
Alex Peuchert (aaalex) for creating the screencast.
¶ ↑
Credits-
Delano Mandelbaum (delano)
¶ ↑
LicenseSee: LICENSE.txt