gibbler 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
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