Gibbler - v0.10.0
Git-like hashes and history for Ruby objects for Ruby 3.1+.
Check out this post on RubyInside.
Installation
Install the gem and add to the application's Gemfile by executing:
$ bundle add gibbler
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install gibbler
Usage
Example 1 -- Standalone Usage
require 'gibbler'
g = Gibbler.new 'id', 1001
g.base(36)
g == 'f4fb3796ababa3788d1bded8fdc589ab1ccb1c3d'
g === 'f4fb379'
Example 2 -- Mixins Usage
require 'gibbler/mixins'
"kimmy".gibbler
:kimmy.gibbler
config = {}
config.gibbler
config.gibbled?
config[:server] = {
:users => [:dave, :ali],
:ports => [22, 80, 443]
}
config.gibbled?
config.gibbler
config[:server][:users] << :yanni
config.gibbler
config.gibbler.short
config.gibbler.base36
config.gibbler.base36.short
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
a[:magic] = :updated
a.gibbler_commit
a[:magic] = :changed
a.gibbler_commit
a.gibbler_history
a.gibbler_revert! 'd7049916'
a.gibbler
a
a.delete :magic
a.gibbler_revert!
a.gibbler
a
a.gibbler_object 'b668098e'
a.gibbler_stamp
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
:kimmy.digest
a = [:a, :b, :c]
a.digest
a << :d
a.changed?
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!
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
:kimmy.gibbler(Digest::SHA1)
In Jruby, you can grab the digest types from the openssl library.
require 'openssl'
Gibbler.digest_type = OpenSSL::Digest::SHA256
:kimmy.gibbler
Example 6 -- All your base
require 'gibbler/mixins'
:kimmy.gibbler
:kimmy.gibbler.base(16)
:kimmy.gibbler.base(36)
:kimmy.gibbler.base(10)
:kimmy.gibbler.to_i
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
Gibbler.secret = "sUp0r5ekRu7"
:kimmy.gibbler
Supported Classes
Gibbler methods are available only to the classes which explicitly include them [see docs'(https://delanotes.com/gibbler) 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
a.roles = [:jesse, :joey, :danny, :kimmy, :michelle, :dj, :stephanie]
a.gibbler
Gibbler::Complex
creates a digest based on the name of the class and the names and values of the instance variables. See the RDocs[http://delano.github.com/gibbler] 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
.
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!
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
Development
After checking out the repo, run bin/setup
to install dependencies. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome GitHub Issues. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
Thanks
Code of Conduct
Everyone interacting in the Gibbler project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
License
The gem is available as open source under the terms of the MIT License.