0.05
No release in over 3 years
Low commit activity in last 3 years
Gibbler: Git-like hashes for Ruby objects
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

>= 0.4.0
 Project Readme

Gibbler - v0.9¶ ↑

Git-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 Usage¶ ↑

require 'gibbler'

g = Gibbler.new 'id', 1001   # => f4fb3796ababa3788d1bded8fdc589ab1ccb1c3d
g.base(36)                   # => sm71s7eam4hm5jlsuzlqkbuktwpe5h9

g == 'f4fb3796ababa3788d1bded8fdc589ab1ccb1c3d'   # => true
g === 'f4fb379'              # => true

Example 2 – Mixins Usage¶ ↑

require '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 History ¶ ↑

Gibbler 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 Aliases¶ ↑

If 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 types¶ ↑

By 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 base¶ ↑

require '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 secret¶ ↑

Gibbler 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 Classes¶ ↑

Gibbler 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.

Installation¶ ↑

Via 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¶ ↑

License¶ ↑

See: LICENSE.txt