gibbler 0.3 → 0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. data/CHANGES.txt +17 -0
  2. data/README.rdoc +51 -7
  3. data/gibbler.gemspec +1 -1
  4. data/lib/gibbler.rb +223 -46
  5. metadata +2 -2
data/CHANGES.txt CHANGED
@@ -1,6 +1,23 @@
1
1
  GIBBLER, CHANGES
2
2
 
3
3
 
4
+ #### 0.4 (2009-06-30) #################################
5
+
6
+ NOTE: Calculated gibbles have changed since 0.3. Most gibbles created with
7
+ 0.3 and earlier will not match those created in 0.4 for the same object
8
+
9
+ * FIXED: Hash and Array now use the class of the value for hashing
10
+ rather than Hash or Array (respectively).
11
+ * FIXED: __gibbler methods now return a digest based on their own class.
12
+ Previously, all digests were created by String.__gibbler so the class
13
+ name from the original object got lost.
14
+ * CHANGE: Gibbler methods are no longer available to all Ruby classes
15
+ by default. The default list is now: String, Hash, Array, Symbol,
16
+ Class, Fixnum, Bignum.
17
+ * CHANGE: Renamed Gibbler.gibbler_digest_type to Gibbler.digest_type
18
+ * ADDED: Custom objects can now "include Gibbler::Complex"
19
+
20
+
4
21
  #### 0.3 (2009-06-29) #################################
5
22
 
6
23
  * CHANGE: Renamed to_gibble -> gibble
data/README.rdoc CHANGED
@@ -1,30 +1,74 @@
1
- = Gibbler - v0.2
1
+ = Gibbler - v0.4
2
2
 
3
3
  Git-like hashes for Ruby objects.
4
4
 
5
-
5
+ == Examples
6
+
6
7
  config = {}
7
- config.gibble # => 57589e9811fe00c307ed3ab740cdac516c9975cb
8
+ config.gibble # => 4fdcadc66a38feb9c57faf3c5a18d5e76a6d29bf
9
+ config.gibbled? # => false
8
10
 
9
11
  config[:server] = {
10
12
  :users => [:dave, :ali],
11
13
  :ports => [22, 80, 443]
12
14
  }
13
- config.gibble # => 87d792aefceb893b2d966828827c61636b0ace3e
15
+ config.gibbled? # => true
16
+ config.gibble # => ef23d605f8c4fc80a8e580f9a0e8dab8426454a8
14
17
 
15
18
  config[:server][:users] << :yanni
16
19
 
17
- config.gibble # => 126ea10af73149ae4e69b0e036aa1d47a7651f07
20
+ config.gibble # => 4c558a56bc2abf5f8a845a69e47ceb5e0003683f
21
+
22
+
23
+ == Supported Classes
24
+
25
+ Gibbler methods are available only to the classes which explicitly include them (see RDocs[http://delano.github.com/gibbler] for details on which classes are supported by default). You can also extend custom objects:
26
+
27
+ class FullHouse
28
+ include Gibbler::Complex
29
+ attr_accessor :roles
30
+ end
31
+
32
+ a = FullHouse.new
33
+ a.gibble # => 4192d4cb59975813f117a51dcd4454ac16df6703
34
+
35
+ a.roles = [:jesse, :joey, :danny, :kimmy, :michelle, :dj, :stephanie]
36
+ a.gibble # => 6ea546919dc4caa2bab69799b71d48810a1b48fa
37
+
38
+ 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.
39
+
40
+ If you want to support all Ruby objects, add the following to your application:
18
41
 
42
+ class Object
43
+ include Gibbler::String
44
+ end
19
45
 
20
- == ALPHA NOTICE
46
+ Gibbler::String creates a digest based on the output of the to_s method. This is a reasonable default for more objects however any object that includes the object address in to_s (e.g. "<Object:0x0x4ac9f0...") will produce unreliable gibbles (because the address can change).
47
+
48
+
49
+ == ALPHA NOTICE (2009-06-30)
21
50
 
22
51
  This code is hella fresh. It's ugly and barely tested, but it's fun to play with. I'll happily accept patches.
23
52
 
53
+ NOTE: Gibbles have changed between 0.3 and 0.4. Ones created with 0.3 and earlier will not match ones created with 0.4 for the same object.
54
+
55
+
56
+ == Known Issues
57
+
58
+ * The gibble method or gibbled? must be called at least once before gibbled? will be able to return a useful value (otherwise there is no previous gibble value to compare to)
59
+
60
+
61
+ == More Info
62
+
63
+ * Codes[http://github.com/delano/gibbler]
64
+ * RDocs[http://delano.github.com/gibbler]
65
+ * Sponsor[http://solutious.com/]
66
+ * Inspiration[http://www.youtube.com/watch?v=fipD4DdV48g]
67
+
24
68
 
25
69
  == Credits
26
70
 
27
- * Delano Mandelbaum (delano@solutious.com)
71
+ * Delano (@solutious.com)
28
72
 
29
73
 
30
74
  == License
data/gibbler.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "gibbler"
3
3
  s.rubyforge_project = "gibbler"
4
- s.version = "0.3"
4
+ s.version = "0.4"
5
5
  s.summary = "Gibbler: Git-like hashes for Ruby objects"
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
data/lib/gibbler.rb CHANGED
@@ -6,7 +6,7 @@ require 'digest/sha1'
6
6
  # "Hola, Tanneritos"
7
7
  #
8
8
  module Gibbler
9
- VERSION = "0.3.0"
9
+ VERSION = "0.4.0"
10
10
 
11
11
  @@gibbler_debug = false
12
12
  @@gibbler_digest_type = Digest::SHA1
@@ -16,15 +16,15 @@ module Gibbler
16
16
  #
17
17
  # Object.gibbler_digest_type = Digest::SHA256
18
18
  #
19
- def self.gibbler_digest_type=(v)
19
+ def self.digest_type=(v)
20
20
  @@gibbler_digest_type = v
21
21
  end
22
22
  # Returns the current debug status (true or false)
23
- def self.gibbler_debug?; @@gibbler_debug; end
24
- # Enable debugging with a true value
25
- def self.gibbler_debug=(v); @@gibbler_debug = v; end
23
+ def self.debug?; @@gibbler_debug; end
24
+ def self.enable_debug; @@gibbler_debug = true; end
25
+ def self.disable_debug; @@gibbler_debug = false; end
26
26
  # Returns the current digest class.
27
- def self.gibbler_digest_type; @@gibbler_digest_type; end
27
+ def self.digest_type; @@gibbler_digest_type; end
28
28
 
29
29
  # Calculates a digest for the current object instance.
30
30
  # Objects that are a kind of Hash or Array are processed
@@ -37,64 +37,241 @@ module Gibbler
37
37
  # gibbler_debug [klass, a]
38
38
  # a
39
39
  #end
40
- gibbler_debug [:GIBBLER, self.class, self]
40
+ gibbler_debug :GIBBLER, self.class, self
41
41
  @__gibble__ = self.__gibbler
42
42
  end
43
43
 
44
+ # Sends +str+ to Digest::SHA1.hexdigest. If another digest class
45
+ # has been specified, that class will be used instead.
46
+ # See: digest_type
47
+ def self.digest(str)
48
+ @@gibbler_digest_type.hexdigest str
49
+ end
50
+
44
51
  # Has this object been modified?
52
+ #
53
+ # This method compares the return value from gibble with the
54
+ # previous value returned by gibble (the value is stored in
55
+ # <tt>@__gibble__</tt>)
45
56
  def gibbled?
57
+ @__gibble__ ||= self.gibble
46
58
  was, now = @__gibble__.clone, self.gibble
47
- gibbler_debug [:gibbled?, was, now]
59
+ gibbler_debug :gibbled?, was, now
48
60
  was != now
49
61
  end
50
62
 
51
63
  def gibbler_debug(*args)
52
- return unless @@gibbler_debug == true
53
- p *args
64
+ return unless Gibbler.debug?
65
+ p args
66
+ end
67
+ def self.gibbler_debug(*args)
68
+ return unless Gibbler.debug?
69
+ p args
54
70
  end
55
- end
56
-
57
- class Hash
58
- include Gibbler
59
71
 
60
- def __gibbler(h=self)
61
- klass = h.class
62
- d = h.keys.sort { |a,b| a.inspect <=> b.inspect }
63
- d.collect! do |name|
64
- '%s:%s:%s' % [klass, name, h[name].__gibbler]
65
- end
66
- a = d.join($/).__gibbler
67
- gibbler_debug [klass, a]
68
- a
72
+ # Gets the list of instance variables from the standard implementation
73
+ # of the instance_variables method and removes <tt>@__gibble__</tt>.
74
+ # Any class the includes Gibbler or Gibbler::* will use this version of
75
+ # instance_variables. It's important because we don't want the current
76
+ # gibble value to affect the next gibble.
77
+ def instance_variables
78
+ vars = super
79
+ vars.reject! { |x| x.to_s == '@__gibble__' }
80
+ vars
69
81
  end
70
82
 
71
- end
72
-
73
- class Array
74
- extend Gibbler
83
+ module Complex
84
+ include Gibbler
85
+ # Creates a gibble based on:
86
+ # * An Array of instance variable names and values in the format: <tt>CLASS:LENGTH:VALUE</tt>
87
+ # * The gibble method is called on each element so if it is a Hash or Array etc it
88
+ # will be parsed recursively according to the gibbler method for that class type.
89
+ # * Gibble the Array of gibbles
90
+ # * Return the digest for <tt>class:length:value</tt> where:
91
+ # * "class" is equal to the current object class (e.g. FullHouse).
92
+ # * "length" is the size of the Array of gibbles (which should equal
93
+ # the number of instance variables in the object).
94
+ # * "value" is the Array of gibbles joined with a colon (":").
95
+ #
96
+ # This method can be used by any class which stores values in instance variables.
97
+ #
98
+ def __gibbler(h=self)
99
+ klass = h.class
100
+ d = []
101
+ instance_variables.each do |n|
102
+ value = instance_variable_get(n)
103
+ d << '%s:%s:%s' % [value.class, n, value.__gibbler]
104
+ end
105
+ d = d.join(':').__gibbler
106
+ a = Gibbler.digest "%s:%d:%s" % [klass, d.size, d]
107
+ gibbler_debug klass, a, [klass, d.size, d]
108
+ a
109
+ end
110
+ end
75
111
 
76
- def __gibbler(h=self)
77
- klass = h.class
78
- d, index = [], 0
79
- h.each do |value|
80
- d << '%s:%s:%s' % [h.class, index, value.__gibbler]
81
- index += 1
112
+ module String
113
+ include Gibbler
114
+ # Creates a gibble based on: <tt>CLASS:LENGTH:VALUE</tt>.
115
+ # This method can be used for any class where the <tt>to_s</tt>
116
+ # method returns an appropriate unique value for this instance.
117
+ # It's used by default for Symbol, Class, Fixnum, and Bignum.
118
+ # e.g.
119
+ #
120
+ # "str" => String:3:str => 509a839ca1744c72e37759e7684ff0daa3b61427
121
+ # :sym => Symbol:3:sym => f3b7b3ca9529002c6826b1ef609d3583c356c8c8
122
+ #
123
+ # To use use method in other classes simply:
124
+ #
125
+ # class MyClass
126
+ # include Gibbler::String
127
+ # end
128
+ #
129
+ def __gibbler(h=self)
130
+ klass = h.class
131
+ value = h.nil? ? "\0" : h.to_s
132
+ a = Gibbler.digest "%s:%d:%s" % [klass, value.size, value]
133
+ gibbler_debug klass, a, [klass, value.size, value]
134
+ a
82
135
  end
83
- a = d.join($/).__gibbler
84
- gibbler_debug [klass, a]
85
- a
86
136
  end
137
+
138
+ module Hash
139
+ include Gibbler
140
+
141
+ # Creates a gibble based on:
142
+ # * parse each key, value pair into an Array containing keys: <tt>CLASS:KEY:VALUE.__gibbler</tt>
143
+ # * The gibble method is called on each element so if it is a Hash or Array etc it
144
+ # will be parsed recursively according to the gibbler method for that class type.
145
+ # * Gibble the Array of gibbles
146
+ # * Return the digest for <tt>class:length:value</tt> where:
147
+ # * "class" is equal to the current object class (e.g. Hash).
148
+ # * "length" is the size of the Array of gibbles (which should equal
149
+ # the number of keys in the original Hash object).
150
+ # * "value" is the Array of gibbles joined with a colon (":").
151
+ #
152
+ # This method can be used by any class with a <tt>keys</tt> method.
153
+ #
154
+ # e.g.
155
+ #
156
+ # class OrderedHash
157
+ # include Gibbler::Hash
158
+ # end
159
+ #
160
+ def __gibbler(h=self)
161
+ klass = h.class
162
+ d = h.keys.sort { |a,b| a.inspect <=> b.inspect }
163
+ d.collect! do |name|
164
+ value = h[name]
165
+ '%s:%s:%s' % [value.class, name, value.__gibbler]
166
+ end
167
+ d = d.join(':').__gibbler
168
+ a = Gibbler.digest '%s:%s:%s' % [klass, d.size, d]
169
+ gibbler_debug klass, a, [klass, d.size, d]
170
+ a
171
+ end
172
+ end
173
+
174
+ module Array
175
+ include Gibbler
176
+
177
+ # Creates a gibble based on:
178
+ # * parse each element into an Array of gibbles like: <tt>CLASS:INDEX:VALUE.__gibbler</tt>
179
+ # * The gibble method is called on each element so if it is a Hash or Array etc it
180
+ # will be parsed recursively according to the gibbler method for that class type.
181
+ # * Gibble the Array of gibbles
182
+ # * Return the digest for <tt>class:length:value</tt> where:
183
+ # * "class" is equal to the current object class (e.g. Array).
184
+ # * "length" is the size of the Array of gibbles (which should equal
185
+ # the number of elements in the original Array object).
186
+ # * "value" is the Array of gibbles joined with a colon (":").
187
+ #
188
+ # This method can be used by any class with an <tt>each</tt> method.
189
+ #
190
+ # e.g.
191
+ #
192
+ # class NamedArray
193
+ # include Gibbler::Array
194
+ # end
195
+ #
196
+ def __gibbler(h=self)
197
+ klass = h.class
198
+ d, index = [], 0
199
+ h.each do |value|
200
+ d << '%s:%s:%s' % [value.class, index, value.__gibbler]
201
+ index += 1
202
+ end
203
+ d = d.join(':').__gibbler
204
+ a = Gibbler.digest '%s:%s:%s' % [klass, d.size, d]
205
+ gibbler_debug klass, a, [klass, d.size, d]
206
+ a
207
+ end
208
+ end
209
+
210
+
211
+ ##--
212
+ ## NOTE: this was used when Gibbler supported "include Gibbler". We
213
+ ## now recommend the "include Gibbler::String" approach. This was an
214
+ ## interesting approach so I'm keeping the code here for reference.
215
+ ##def self.included(klass)
216
+ ## # Find the appropriate Gibbler::* module for the inheriting class
217
+ ## gibbler_module = Gibbler.const_get("#{klass}") rescue Gibbler::String
218
+ ##
219
+ ## # If a Gibbler module is not defined, const_get bubbles up
220
+ ## # through the stack to find the constant. This will return
221
+ ## # the global class (likely itself) so we enforce a default.
222
+ ## gibbler_module = Gibbler::String if gibbler_module == klass
223
+ ## gibbler_debug :constant, klass, gibbler_module
224
+ ##
225
+ ## klass.module_eval do
226
+ ## include gibbler_module
227
+ ## end
228
+ ##
229
+ ##end
230
+ ##++
231
+
87
232
 
88
233
  end
89
234
 
90
- class Object
91
- include Gibbler
92
-
93
- def __gibbler(h=self)
94
- klass = h.class
95
- value = h.nil? ? "\0" : h.to_s
96
- a=@@gibbler_digest_type.hexdigest "%s:%d:%s" % [klass, value.size, value]
97
- gibbler_debug [klass, value.size, value, a]
98
- a
99
- end
235
+ class Hash
236
+ include Gibbler::Hash
100
237
  end
238
+
239
+ class Array
240
+ include Gibbler::Array
241
+ end
242
+
243
+ class String
244
+ include Gibbler::String
245
+ end
246
+
247
+ class Symbol
248
+ include Gibbler::String
249
+ end
250
+
251
+ class Class
252
+ include Gibbler::String
253
+ end
254
+
255
+ class Fixnum
256
+ include Gibbler::String
257
+ end
258
+
259
+ class Bignum
260
+ include Gibbler::String
261
+ end
262
+
263
+ class TrueClass
264
+ include Gibbler::String
265
+ end
266
+
267
+ class FalseClass
268
+ include Gibbler::String
269
+ end
270
+
271
+ class Float
272
+ include Gibbler::String
273
+ end
274
+
275
+
276
+
277
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gibbler
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.3"
4
+ version: "0.4"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-29 00:00:00 -04:00
12
+ date: 2009-06-30 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15