gibbler 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.txt CHANGED
@@ -1,11 +1,21 @@
1
1
  GIBBLER, CHANGES
2
2
 
3
3
 
4
+ #### 0.6.0 (2009-07-20) #################################
5
+
6
+ NOTE: Digest calculation for Proc and Class objects have changed.
7
+ Digests created for these types will not match previous releases.
8
+
9
+ * FIXED: Proc digests no longer refer to Proc#binding
10
+ * CHANGE: The Gibbler module now raises an exception if it's included
11
+ * CHANGE: Module and Class now use the default Gibbler::Object digest
12
+ * ADDED: Gibbler::Object now contains a default digest method
13
+
14
+
4
15
  #### 0.5.4 (2009-07-17) #################################
5
16
 
6
17
  * FIXED: Improved support for Symbol and Fixnum objects with Attic 0.4
7
18
 
8
-
9
19
  #### 0.5.3 (2009-07-12) #################################
10
20
 
11
21
  * FIXED: Updated gemspec to fix missing files (aliases)
data/README.rdoc CHANGED
@@ -1,9 +1,8 @@
1
- = Gibbler - v0.5 ALPHA
1
+ = Gibbler - v0.6 ALPHA
2
2
 
3
- Git-like hashes and history for Ruby objects.
4
-
5
- NOTE: Gibbler supports Ruby 1.8, 1.9 and JRuby.
3
+ Git-like hashes and history for Ruby objects for Ruby 1.8, 1.9 and JRuby.
6
4
 
5
+ <b>NOTE: Digests changed in the 0.6 release for Class, Module, and Proc objects. See "News" below for more info.</b>
7
6
 
8
7
  == Example 1 -- Basic Usage
9
8
 
@@ -122,26 +121,34 @@ Gibbler::String creates a digest based on the name of the class and the output o
122
121
 
123
122
  == ALPHA Notice
124
123
 
125
- This code is hella fresh (est 2009-06-25). It's barely tested and the interface may change, but it's fun to play with. I'll happily accept patches.
124
+ This code is hella fresh (est 2009-06-25). It's barely tested and the interface may change, but it's fun to play with. I'll happily accept patches. Some things to keep in mind:
126
125
 
127
- NOTE: 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.
126
+ * 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.
127
+ * Digest calculation may change between non-trivial releases.
128
+ * There has been very little testing for concurrency issues. (Anyone interested?)
128
129
 
129
130
 
130
131
  == News
131
132
 
132
- === 2009-07-17: Improved support for Symbol and Fixnum
133
+ === 2009-07-20: Digest change for instances of Class, Module, and Proc
133
134
 
134
- With the upgrade to Attic 0.4, the gibbled? method and object history is now available for Symbol and Fixnum objects.
135
+ Digest calculation has changed for Class, Module, and Proc objects. Digests created with Gibbler 0.5.x and earlier will not match the ones created by 0.6.
135
136
 
137
+ * Class and Module objects were calculating digests based on the output of <tt>self.to_s</tt>. This was a problem because that string contains a memory address which can change arbitrarily. The new calculation is based on the object class, the length of name, and the name itself. e.g. <tt>"Class:6:Object" # => '5620e4a8b10ec6830fece61d33f5d3e9a349b4c2'</tt>
138
+ * Proc objects were including the return value of <tt>self.binding</tt> in the digest calculation. This is not reliable because the binding includes an arbitrary address. The new calculation is based on the class name, the arity, and whether it was created with a lambda.
136
139
 
137
- === 2009-07-13: Fixed Attic gem
140
+ Also note that this change affects the digests for Hashes and Arrays that contain instances of Class, Module, or Proc.
138
141
 
139
- Cripes! I added the Attic dependency but there was a problem with the attic gem (the gemspec was outdated). It's <i>all</i> good now, the attic-0.3.1 gem should be available on all Rubyforge mirrors and and gems.github.com soon.
142
+ === 2009-07-17: Improved support for Symbol and Fixnum
143
+
144
+ With the upgrade to Attic 0.4, the gibbled? method and object history is now available for Symbol and Fixnum objects.
140
145
 
141
146
 
142
147
  == Known Issues
143
148
 
144
149
  * 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)
150
+ * Digests for Bignum objects are different between (MRI) Ruby and JRuby. Does anyone know why?
151
+ * 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.
145
152
 
146
153
 
147
154
  == Installation
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.5.4"
4
+ s.version = "0.6.0"
5
5
  s.summary = "Gibbler: Git-like hashes for Ruby objects"
6
6
  s.description = s.summary
7
7
  s.author = "Delano Mandelbaum"
@@ -4,6 +4,11 @@ module Gibbler
4
4
 
5
5
  module Object
6
6
 
7
+ def self.included(obj)
8
+ obj.extend Attic
9
+ obj.attic :__gibbler_cache
10
+ end
11
+
7
12
  # Calculates a digest for the current object instance.
8
13
  # Objects that are a kind of Hash or Array are processed
9
14
  # recursively. The length of the returned String depends
@@ -31,6 +36,23 @@ module Gibbler
31
36
  p args
32
37
  end
33
38
 
39
+ # Creates a digest for the current state of self based on:
40
+ # * Object#class
41
+ # * Length of Object#name || ''
42
+ # * Object#name || ''
43
+ #
44
+ # e.g. Digest::SHA1.hexdigest "Class:6:Object" #=>
45
+ #
46
+ # <b>This is a default method appropriate for only the most
47
+ # basic objects like Class and Module.</b>
48
+ #
49
+ def __gibbler(h=self)
50
+ klass = h.class
51
+ nom = h.name || ''
52
+ a = Gibbler.digest '%s:%s:%s' % [klass, nom.size, nom]
53
+ gibbler_debug klass, a, [klass, nom.size, nom]
54
+ a
55
+ end
34
56
  end
35
57
 
36
58
  end
data/lib/gibbler.rb CHANGED
@@ -13,7 +13,7 @@ module Gibbler
13
13
  #include Attic
14
14
  extend Attic
15
15
 
16
- VERSION = "0.5.4"
16
+ VERSION = "0.6.0"
17
17
 
18
18
  require 'gibbler/object'
19
19
  require 'gibbler/digest'
@@ -53,6 +53,33 @@ module Gibbler
53
53
  p args
54
54
  end
55
55
 
56
+ # Raises an exception. The correct usage is to include a Gibbler::Object:
57
+ # * Gibbler::Complex
58
+ # * Gibbler::String
59
+ # * Gibbler::Object
60
+ # * etc ...
61
+ def self.included(obj)
62
+ raise "You probably want to include Gibbler::Complex or Gibbler::Object"
63
+ end
64
+
65
+ # Creates a digest based on:
66
+ # * An Array of instance variable names and values in the format: <tt>CLASS:LENGTH:VALUE</tt>
67
+ # * The gibbler method is called on each element so if it is a Hash or Array etc it
68
+ # will be parsed recursively according to the gibbler method for that class type.
69
+ # * Digest the Array of digests
70
+ # * Return the digest for <tt>class:length:value</tt> where:
71
+ # * "class" is equal to the current object class (e.g. FullHouse).
72
+ # * "length" is the size of the Array of digests (which should equal
73
+ # the number of instance variables in the object).
74
+ # * "value" is the Array of digests joined with a colon (":").
75
+ #
76
+ # This method can be used by any class which stores values in instance variables.
77
+ #
78
+ # class Episodes
79
+ # include Gibbler::Complex
80
+ # attr_accessor :season, :year, :cast
81
+ # end
82
+ #
56
83
  module Complex
57
84
  include Gibbler::Object
58
85
 
@@ -61,19 +88,7 @@ module Gibbler
61
88
  obj.attic :__gibbler_cache
62
89
  end
63
90
 
64
- # Creates a digest based on:
65
- # * An Array of instance variable names and values in the format: <tt>CLASS:LENGTH:VALUE</tt>
66
- # * The gibbler method is called on each element so if it is a Hash or Array etc it
67
- # will be parsed recursively according to the gibbler method for that class type.
68
- # * Digest the Array of digests
69
- # * Return the digest for <tt>class:length:value</tt> where:
70
- # * "class" is equal to the current object class (e.g. FullHouse).
71
- # * "length" is the size of the Array of digests (which should equal
72
- # the number of instance variables in the object).
73
- # * "value" is the Array of digests joined with a colon (":").
74
- #
75
- # This method can be used by any class which stores values in instance variables.
76
- #
91
+ # Creates a digest for the current state of self.
77
92
  def __gibbler(h=self)
78
93
  klass = h.class
79
94
  d = []
@@ -97,6 +112,21 @@ module Gibbler
97
112
 
98
113
  end
99
114
 
115
+ # Creates a digest based on: <tt>CLASS:LENGTH:VALUE</tt>.
116
+ # This method can be used for any class where the <tt>to_s</tt>
117
+ # method returns an appropriate unique value for this instance.
118
+ # It's used by default for Symbol, Class, Fixnum, and Bignum.
119
+ # e.g.
120
+ #
121
+ # "str" => String:3:str => 509a839ca1744c72e37759e7684ff0daa3b61427
122
+ # :sym => Symbol:3:sym => f3b7b3ca9529002c6826b1ef609d3583c356c8c8
123
+ #
124
+ # To use use method in other classes simply:
125
+ #
126
+ # class MyStringLikeClass
127
+ # include Gibbler::String
128
+ # end
129
+ #
100
130
  module String
101
131
  include Gibbler::Object
102
132
 
@@ -105,21 +135,7 @@ module Gibbler
105
135
  obj.attic :__gibbler_cache
106
136
  end
107
137
 
108
- # Creates a digest based on: <tt>CLASS:LENGTH:VALUE</tt>.
109
- # This method can be used for any class where the <tt>to_s</tt>
110
- # method returns an appropriate unique value for this instance.
111
- # It's used by default for Symbol, Class, Fixnum, and Bignum.
112
- # e.g.
113
- #
114
- # "str" => String:3:str => 509a839ca1744c72e37759e7684ff0daa3b61427
115
- # :sym => Symbol:3:sym => f3b7b3ca9529002c6826b1ef609d3583c356c8c8
116
- #
117
- # To use use method in other classes simply:
118
- #
119
- # class MyClass
120
- # include Gibbler::String
121
- # end
122
- #
138
+ # Creates a digest for the current state of self.
123
139
  def __gibbler(h=self)
124
140
  klass = h.class
125
141
  value = h.nil? ? "\0" : h.to_s
@@ -128,7 +144,24 @@ module Gibbler
128
144
  a
129
145
  end
130
146
  end
131
-
147
+
148
+ # Creates a digest based on:
149
+ # * parse each key, value pair into an Array containing keys: <tt>CLASS:KEY:VALUE.__gibbler</tt>
150
+ # * The gibbler method is called on each element so if it is a Hash or Array etc it
151
+ # will be parsed recursively according to the gibbler method for that class type.
152
+ # * Digest the Array of digests
153
+ # * Return the digest for <tt>class:length:value</tt> where:
154
+ # * "class" is equal to the current object class (e.g. Hash).
155
+ # * "length" is the size of the Array of digests (which should equal
156
+ # the number of keys in the original Hash object).
157
+ # * "value" is the Array of digests joined with a colon (":").
158
+ #
159
+ # This method can be used by any class with a <tt>keys</tt> method.
160
+ #
161
+ # class MyOrderedHash
162
+ # include Gibbler::Hash
163
+ # end
164
+ #
132
165
  module Hash
133
166
  include Gibbler::Object
134
167
 
@@ -137,25 +170,7 @@ module Gibbler
137
170
  obj.attic :__gibbler_cache
138
171
  end
139
172
 
140
- # Creates a digest based on:
141
- # * parse each key, value pair into an Array containing keys: <tt>CLASS:KEY:VALUE.__gibbler</tt>
142
- # * The gibbler method is called on each element so if it is a Hash or Array etc it
143
- # will be parsed recursively according to the gibbler method for that class type.
144
- # * Digest the Array of digests
145
- # * Return the digest for <tt>class:length:value</tt> where:
146
- # * "class" is equal to the current object class (e.g. Hash).
147
- # * "length" is the size of the Array of digests (which should equal
148
- # the number of keys in the original Hash object).
149
- # * "value" is the Array of digests joined with a colon (":").
150
- #
151
- # This method can be used by any class with a <tt>keys</tt> method.
152
- #
153
- # e.g.
154
- #
155
- # class OrderedHash
156
- # include Gibbler::Hash
157
- # end
158
- #
173
+ # Creates a digest for the current state of self.
159
174
  def __gibbler(h=self)
160
175
  klass = h.class
161
176
  d = h.keys.sort { |a,b| a.inspect <=> b.inspect }
@@ -170,6 +185,23 @@ module Gibbler
170
185
  end
171
186
  end
172
187
 
188
+ # Creates a digest based on:
189
+ # * parse each element into an Array of digests like: <tt>CLASS:INDEX:VALUE.__gibbler</tt>
190
+ # * The gibbler method is called on each element so if it is a Hash or Array etc it
191
+ # will be parsed recursively according to the gibbler method for that class type.
192
+ # * Digest the Array of digests
193
+ # * Return the digest for <tt>class:length:value</tt> where:
194
+ # * "class" is equal to the current object class (e.g. Array).
195
+ # * "length" is the size of the Array of digests (which should equal
196
+ # the number of elements in the original Array object).
197
+ # * "value" is the Array of digests joined with a colon (":").
198
+ #
199
+ # This method can be used by any class with an <tt>each</tt> method.
200
+ #
201
+ # class MyNamedArray
202
+ # include Gibbler::Array
203
+ # end
204
+ #
173
205
  module Array
174
206
  include Gibbler::Object
175
207
 
@@ -178,25 +210,7 @@ module Gibbler
178
210
  obj.attic :__gibbler_cache
179
211
  end
180
212
 
181
- # Creates a digest based on:
182
- # * parse each element into an Array of digests like: <tt>CLASS:INDEX:VALUE.__gibbler</tt>
183
- # * The gibbler method is called on each element so if it is a Hash or Array etc it
184
- # will be parsed recursively according to the gibbler method for that class type.
185
- # * Digest the Array of digests
186
- # * Return the digest for <tt>class:length:value</tt> where:
187
- # * "class" is equal to the current object class (e.g. Array).
188
- # * "length" is the size of the Array of digests (which should equal
189
- # the number of elements in the original Array object).
190
- # * "value" is the Array of digests joined with a colon (":").
191
- #
192
- # This method can be used by any class with an <tt>each</tt> method.
193
- #
194
- # e.g.
195
- #
196
- # class NamedArray
197
- # include Gibbler::Array
198
- # end
199
- #
213
+ # Creates a digest for the current state of self.
200
214
  def __gibbler(h=self)
201
215
  klass = h.class
202
216
  d, index = [], 0
@@ -214,7 +228,7 @@ module Gibbler
214
228
  # Return the digest for <tt>class:arity:binding</tt>, where:
215
229
  # * class is the current class name (e.g. Proc)
216
230
  # * arity is the value returned by <tt>Proc#arity</tt>
217
- # * binding is the value returned by <tt>Proc#binding</tt>
231
+ # * value of lambda? if available (Ruby 1.9) or false otherwise
218
232
  #
219
233
  # This method can be used by any subclass of Proc.
220
234
  #
@@ -235,14 +249,17 @@ module Gibbler
235
249
  obj.attic :__gibbler_cache
236
250
  end
237
251
 
252
+ # Creates a digest for the current state of self.
238
253
  def __gibbler(h=self)
239
254
  klass = h.class
240
- a = Gibbler.digest '%s:%s:%s' % [klass, h.arity, h.binding]
241
- gibbler_debug klass, a, [klass, h.arity, h.binding]
255
+ is_lambda = h.respond_to?(:lambda?) ? h.lambda? : false
256
+ a = Gibbler.digest '%s:%s:%s' % [klass, h.arity, is_lambda]
257
+ gibbler_debug klass, a, [klass, h.arity, is_lambda]
242
258
  a
243
259
  end
244
260
  end
245
261
 
262
+
246
263
  ##--
247
264
  ## NOTE: this was used when Gibbler supported "include Gibbler". We
248
265
  ## now recommend the "include Gibbler::String" approach. This was an
@@ -288,7 +305,11 @@ class Symbol
288
305
  end
289
306
 
290
307
  class Class
291
- include Gibbler::String
308
+ include Gibbler::Object
309
+ end
310
+
311
+ class Module
312
+ include Gibbler::Object
292
313
  end
293
314
 
294
315
  class Fixnum
@@ -1,11 +1,17 @@
1
1
 
2
- library :gibbler, File.dirname(__FILE__), '..', 'lib'
2
+ library :gibbler, 'lib'
3
3
  group "Gibbler Gazette"
4
4
 
5
5
  Gibbler.enable_debug if Tryouts.verbose > 3
6
6
 
7
7
  tryouts "Basic syntax with SHA1" do
8
8
 
9
+ dream :exception, RuntimeError
10
+ drill "include Gibbler raises exception" do
11
+ a = Class.new
12
+ a.send :include, Gibbler
13
+ end
14
+
9
15
  dream :respond_to?, :gibbler
10
16
  dream :gibbler, '52be7494a602d85ff5d8a8ab4ffe7f1b171587df'
11
17
  drill "Symbol can gibbler", :kimmy
@@ -7,33 +7,33 @@ Gibbler.enable_debug if Tryouts.verbose > 3
7
7
 
8
8
  tryouts "Basic syntax with SHA256" do
9
9
 
10
- # NOTE: JRuby require that we use OpenSSL::Digest::SHA256
11
- if Tryouts.sysinfo.vm == :java
12
- drill "Can change Digest type", OpenSSL::Digest::SHA256 do
10
+ setup do
11
+ # NOTE: JRuby requires that we use OpenSSL::Digest::SHA256
12
+ if Tryouts.sysinfo.vm == :java
13
+ require 'openssl'
13
14
  Gibbler.digest_type = OpenSSL::Digest::SHA256
14
- end
15
- else
16
- drill "Can change Digest type", Digest::SHA256 do
15
+ else
17
16
  Gibbler.digest_type = Digest::SHA256
18
17
  end
18
+
19
+ end
20
+
21
+ clean do
22
+ Gibbler.digest_type = Digest::SHA1
19
23
  end
20
24
 
21
- dream :respond_to?, :gibbler
22
25
  dream :gibbler, '754f87ca720ec256633a286d9270d68478850b2abd7b0ae65021cb769ae70c08'
23
26
  drill "A Symbol can gibbler", :anything
24
27
 
25
- dream :respond_to?, :gibbler
26
28
  dream :gibbler, 'd345c0afb4e8da0133a3946d3bd9b2622b0acdd8d6cc1237470cc637a9e4777f'
27
29
  drill "Class can gibbler", Class
28
30
 
29
- dream :respond_to?, :gibbler
31
+ dream :gibbler, 'b7b874a9bff7825caa57750a900652354ac601b77497b694d313f658c69d25b4'
32
+ drill "TrueClass can gibbler", TrueClass
33
+
30
34
  dream :gibbler, '88d2bcbd68ce593fd2e0e06f276f7301357516291b95c0c53038e61a9bf091e5'
31
35
  drill "Empty Hash instance", {}
32
36
 
33
- drill "Can return Digest type", Digest::SHA1 do
34
- Gibbler.digest_type = Digest::SHA1
35
- end
36
-
37
37
  end
38
38
 
39
39
 
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.5.4
4
+ version: 0.6.0
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-07-17 00:00:00 -04:00
12
+ date: 2009-07-20 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency