junkfood 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.document +11 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +76 -0
  5. data/LICENSE +202 -0
  6. data/NOTICE +4 -0
  7. data/README.md +375 -0
  8. data/Rakefile +51 -0
  9. data/VERSION +1 -0
  10. data/junkfood.gemspec +147 -0
  11. data/lib/junkfood/adler32.rb +102 -0
  12. data/lib/junkfood/adler32_pure.rb +112 -0
  13. data/lib/junkfood/assert.rb +75 -0
  14. data/lib/junkfood/base32.rb +198 -0
  15. data/lib/junkfood/ceb/base_command.rb +62 -0
  16. data/lib/junkfood/ceb/base_event.rb +42 -0
  17. data/lib/junkfood/ceb/bus.rb +152 -0
  18. data/lib/junkfood/ceb/executors/command_executor.rb +44 -0
  19. data/lib/junkfood/ceb/executors/delayed_job_command_executor.rb +61 -0
  20. data/lib/junkfood/ceb/executors/event_executor.rb +35 -0
  21. data/lib/junkfood/ceb/executors.rb +25 -0
  22. data/lib/junkfood/ceb.rb +27 -0
  23. data/lib/junkfood/one_time.rb +247 -0
  24. data/lib/junkfood/paperclip_string_io.rb +66 -0
  25. data/lib/junkfood/settings.rb +67 -0
  26. data/lib/junkfood.rb +29 -0
  27. data/spec/.rspec +1 -0
  28. data/spec/junkfood/adler32_pure_spec.rb +16 -0
  29. data/spec/junkfood/adler32_spec.rb +16 -0
  30. data/spec/junkfood/assert_spec.rb +84 -0
  31. data/spec/junkfood/base32_spec.rb +39 -0
  32. data/spec/junkfood/ceb/base_command_spec.rb +73 -0
  33. data/spec/junkfood/ceb/base_event_spec.rb +67 -0
  34. data/spec/junkfood/ceb/bus_spec.rb +153 -0
  35. data/spec/junkfood/ceb/executors/command_executor_spec.rb +24 -0
  36. data/spec/junkfood/ceb/executors/delayed_job_command_executor_spec.rb +5 -0
  37. data/spec/junkfood/ceb/executors/event_executor_spec.rb +18 -0
  38. data/spec/junkfood/one_time_spec.rb +167 -0
  39. data/spec/junkfood/paperclip_string_io_spec.rb +40 -0
  40. data/spec/junkfood/settings_spec.rb +7 -0
  41. data/spec/junkfood_spec.rb +4 -0
  42. data/spec/spec_helper.rb +20 -0
  43. metadata +372 -0
data/README.md ADDED
@@ -0,0 +1,375 @@
1
+ Junkfood
2
+ ========
3
+
4
+ Junkfood is a mesh of different modules and classes that I found useful
5
+ for various projects. I combined them all into this all-in-one library
6
+ because each included component isn't big enough (or comprehensive
7
+ enough) to warrant its own fully managed gem library.
8
+
9
+ Components
10
+ ----------
11
+
12
+ * Adler32
13
+ * Assert
14
+ * Base32
15
+ * CEB - "Command-Event Busing" for Command-Query Responsibility Separation
16
+ * OneTime - HMAC One Time Passwords
17
+ * PaperclipStringIO
18
+ * Settings
19
+
20
+ Adler32
21
+ =======
22
+
23
+ [Adler-32](http://en.wikipedia.org/wiki/Adler-32) is a checksum algorithm
24
+ which was invented by Mark Adler. Compared to a cyclic redundancy check
25
+ of the same length, it trades reliability for speed. Adler-32 is more
26
+ reliable than Fletcher-16, and slightly less reliable than Fletcher-32.
27
+
28
+ Junkfood provides two implementations of Adler-32 in Ruby:
29
+
30
+ * Adler32 uses the Zlib library to do the checksum.
31
+ * Adler32Pure is a pure Ruby implementation of Adler-32 ported
32
+ from the [Pysync library](http://freshmeat.net/projects/pysync/).
33
+
34
+ Example:
35
+
36
+ adler32 = Junkfood::Adler32.new('Wikipedia') # Or Junkfood::Adler32Pure.new
37
+ puts adler32.digest #=> 300286872
38
+
39
+ adler32 = Junkfood::Adler32.new
40
+ digest = adler32.update 'Wikipedia' #=> 300286872
41
+ adler32.digest #=> 300286872
42
+
43
+ Assert
44
+ ======
45
+
46
+ A very simple assertions module to be a drop in "dumb down" replacement
47
+ for the 'wrong' assertion library. It is here just to be my own fallback
48
+ implementation for cases where I may not actually want to install the
49
+ [wrong gem](<http://rubygems.org/gems/wrong>) yet still like that
50
+ style of assertions.
51
+
52
+ require 'junkfood/assert'
53
+ class MyClass
54
+ include Junkfood::Assert
55
+
56
+ def my_method
57
+ testcase = true
58
+ assert { testcase == true } # This will flow through.
59
+ assert { testcase == false } # This will raise an error.
60
+ assert('My Custom Error Message') {
61
+ testcase == false
62
+ }
63
+ rescue Junkfood::Assert::AssertionFailedError => e
64
+ puts e
65
+ end
66
+ end
67
+
68
+ Base32
69
+ ======
70
+
71
+ A ruby implementation of [RFC4648](http://http://tools.ietf.org/html/rfc4648).
72
+ This class requires at least version Ruby 1.9 because it uses the new
73
+ String Encodings internally.
74
+
75
+ require 'junkfood/base32'
76
+
77
+ # Base32 uses StringIO objects by default.
78
+ io = Junkfood::Base32.encode 'MyBinaryStringData'
79
+ puts io.string
80
+ puts io.string.encoding #=> Encoding::ASCII
81
+
82
+ io = Junkfood::Base32.decode 'MyBase32StringData'
83
+ puts io.string
84
+ puts io.string.encoding #=> Encoding::BINARY
85
+
86
+ # The IO can be any object that conforms to Ruby IO.
87
+ # The returned io is the same file passed to output.
88
+ io = Junkfood::Base32.encode 'BinaryData', :output => open('out.b32', 'w')
89
+ io = Junkfood::Base32.decode 'Base32Data', :output => open('out.bin', 'w')
90
+
91
+ # Input is any object that conforms to #each_byte. This includes
92
+ # Strings and File IOs.
93
+ io = Junkfood::Base32.encode(
94
+ open('in.bin', 'r'),
95
+ :output => open('out.b32', 'w'))
96
+ io.close
97
+ io = Junkfood::Base32.decode(
98
+ open('in.b32', 'r'),
99
+ :output => open('out.bin', 'w'))
100
+ io.close
101
+
102
+
103
+ Command Event Busing (CEB)
104
+ ==========================
105
+
106
+ This component is meant to support Command-Query Responsibility Separation.
107
+
108
+ CEB is comprised of three major parts:
109
+
110
+ * The Base Models (BaseCommand, BaseEvent)
111
+ * The Bus (Bus)
112
+ * The Executors (CommandExecutor, EventExecutor)
113
+
114
+ The Base Models implement the foundation of Commands and Events in CQRS;
115
+ the Bus instantiates Command/Event from the parameters, validates
116
+ (using ActiveModel valid?) the Command/Event and drives its process with
117
+ the associated executors; executors (one per Command or Event bus) runs
118
+ the specific process to handle a command or event.
119
+
120
+ Commands are both data representation and handler code for its function.
121
+ Events are just statements of fact about changes in the system.
122
+
123
+ CEB Base Models
124
+ ---------------
125
+
126
+ BaseCommand and BaseEvent uses MongoDb via [mongoid](http://mongoid.org/).
127
+ Command and Event models SHOULD implement the ActiveModel interface; they
128
+ must at least implement the subset of features as described by the
129
+ RSpec tests in base_command_spec.rb and base_event_spec.rb.
130
+
131
+ These base models:
132
+
133
+ 1. Provide persistence for audit logs.
134
+ 2. Provide the base help to represent Commands and Events in our framework.
135
+ Users will subclass BaseCommand and BaseEvent to model their domain.
136
+ 3. Be the "standard contract" for others that want to implement their
137
+ base models. E.g. - Use ActiveRecord instead of Mongoid.
138
+
139
+ Subclasses of BaseCommand that implement their own `perform` method
140
+ SHOULD return the Event (or list of Events) published when said `perform`
141
+ method was executed.
142
+
143
+ CEB Executors
144
+ -------------
145
+
146
+ We implement helpers for the Command Bus and Event Bus part of CQRS.
147
+ So we have two default executors to handle the logic for those two buses.
148
+
149
+ * CommandExecutor
150
+ * EventExecutor
151
+
152
+ CommandExecutor is the default command bus executor that:
153
+
154
+ 1. just calls save! on the instantiated command, raising errors on failure.
155
+ 2. executes the command's perform method (with the assumption that
156
+ the bus validated the command beforehand).
157
+ 3. the return value from `perform` is passed back to the bus send_command
158
+ or send_event call.
159
+
160
+ Alternative CommandExecutors (e.g. - for DelayedJob) may just use its
161
+ own mechanisms to queue up the Command (most likely using the Command's
162
+ to_json serialization) for later execution. In this case, the executor's
163
+ call should return nil or false to the bus. This return value is convention
164
+ to signal this delayed execution to the requester.
165
+
166
+ EventExecutor is the default event bus executor that:
167
+
168
+ 1. just calls save! on the instantiated event, raising errors on failure.
169
+ 2. TODO: publishes the serialized Event (to_json) over a PubSub network such
170
+ as zeromq or webhooks.
171
+
172
+ CEB Example
173
+ -----------
174
+
175
+ class WidgetCreateCommand < Junkfood::Ceb::BaseCommand
176
+
177
+ field :color, :type => String, :default => 'red'
178
+
179
+ def perform
180
+ # Do creation. Update DDD aggregate root, or ActiveRecord State,
181
+ # or whatever is used to keep application state.
182
+ success = true
183
+
184
+ # Now we publish events based on what happened.
185
+ # Normally, there is a one-to-one relation between the number of
186
+ # commands performed to the number of event published.
187
+ if success
188
+ event, result = send_event(
189
+ 'widget_created',
190
+ :command_id => self.id,
191
+ :color => color,
192
+ :other_widget_info => 'to be determined')
193
+ else
194
+ event, result = send_event(
195
+ 'widget_creation_failed',
196
+ :command_id => self.id,
197
+ :error => 'some determined error',
198
+ :other_widget_info => 'to be determined')
199
+ end
200
+
201
+ # This is convention. Commands SHOULD return the event, or list of
202
+ # events, that it published in the execution of this perform method.
203
+ return event
204
+ end
205
+ end
206
+
207
+ class WidgetCreatedEvent < Junkfood::Ceb::BaseEvent
208
+ field :color, :type => String
209
+ field :other_widget_info, :type => String
210
+ end
211
+
212
+ class WidgetCreationFailedEvent < Junkfood::Ceb::BaseEvent
213
+ field :error_info, :type => String
214
+ field :other_widget_info, :type => String
215
+ end
216
+
217
+ class ApplicationController < ActionController::Base
218
+ include Junkfood::Ceb::Bus
219
+ acts_as_command_bus
220
+ end
221
+
222
+ class WidgetController < ApplicationController
223
+ def create
224
+ # params['widget'] is our posted form data that conforms to the Rails
225
+ # way of doing things for ActiveModel. This eliminates hassle for
226
+ # custom parsing, data handling.
227
+
228
+ # Create a command (WidgetCreateCommand) and puts it onto the bus
229
+ # for execution. The command created is returned along with
230
+ # published events by the command.
231
+ command, events = send_command 'widget_create', params['widget']
232
+
233
+ if command.valid?
234
+ # The command is correctly formed, so the backend executors will
235
+ # execute it in the future (or already has executed it).
236
+ end
237
+
238
+ # By convention, Commands SHOULD return the Event, or list of Events,
239
+ # that the command published when its `perform` method was called.
240
+ case result
241
+ when Junkfood::Ceb::BaseEvent
242
+ # The single published event.
243
+ # Can assume that the command was executed.
244
+ when Array
245
+ # An array of Events published.
246
+ # Can assume that the command was executed.
247
+ when nil, false
248
+ # No data was passed back. Nothing can be assumed about the
249
+ # execution of the command.
250
+ end
251
+ end
252
+ end
253
+
254
+ OneTime - HMAC One Time Passwords
255
+ =================================
256
+
257
+ OneTime implements [RFC4226](http://tools.ietf.org/html/rfc4226) and the
258
+ [Time Based](http://tools.ietf.org/html/draft-mraihi-totp-timebased-06)
259
+ version.
260
+
261
+ View the OneTime class docs to see all the options for setting the
262
+ initial counter, time steps, and number of digits each OneTime instance.
263
+
264
+ Example:
265
+
266
+ key = '12345678901234567890'
267
+
268
+ # Using the class methods to get OTP one at a time.
269
+ puts Junkfood::OneTime.hotp(key, 0) #=> 755224
270
+ puts Junkfood::OneTime.hotp(key, 1) #=> 287082
271
+
272
+ # Changing the length of the OTP
273
+ puts Junkfood::OneTime.hotp(key, 0, :digits => 8) #=> 84755224
274
+
275
+ # Using the class methods to get multiple OTP at a time.
276
+ puts Junkfood::OneTime.hotp_multi(key, 0..1) #=> [755224, 287082]
277
+
278
+ # Create a new OTP generator starting at counter 0.
279
+ one_time = Junkfood::OneTime.new key
280
+ # Get an OTP, but don't advance the counter
281
+ puts one_time.otp #=> 755224
282
+ puts one_time.otp #=> 755224
283
+ # Get a range of OTP
284
+ puts one_time.otp :range => 2 #=> [755224, 287082]
285
+
286
+ # Get an OTP, and advance the counter
287
+ puts one_time.otp! #=> 755224
288
+ puts one_time.otp! #=> 287082
289
+ puts one_time.counter #=> 2
290
+ puts one_time.otp! :range => 2 #=> [359152, 969429]
291
+ puts one_time.counter #=> 4
292
+
293
+ # The current Time based OTP for the current epoch step.
294
+ puts one_time.totp
295
+ # A bunch of OTPs preceding and following the current epoch step OTP.
296
+ puts one_time.totp :radius => 2
297
+
298
+ # Setting the length and counter of the OTP on a OneTime instance
299
+ one_time = Junkfood::OneTime.new key, :digits => 8, :counter => 2
300
+ puts one_time.otp! #=> 37359152
301
+ puts one_time.otp! #=> 26969429
302
+
303
+ PaperclipStringIO
304
+ =================
305
+
306
+ This class allows developers to save blobs of in-memory data into
307
+ [paperclip](http://rubygems.org/gems/paperclip) enabled ActiveRecord models
308
+ without requiring the use of temporary files.
309
+
310
+ Example:
311
+
312
+ class FaxDocument < ActiveRecord::Base
313
+ has_attached_file :pdf
314
+ end
315
+
316
+ def incoming_fax_handler()
317
+ attachment = 'Blob of Faxed Data in PDF form'
318
+ fax_number = '555-1234'
319
+
320
+ fax_document = FaxDocument.create(
321
+ :caption => 'Look at this Document!',
322
+ :pdf => PaperclipStringIo.new(
323
+ attachment,
324
+ :filename => "#{fax_number}.pdf",
325
+ :content_type => 'application/pdf'))
326
+ end
327
+
328
+
329
+ Settings
330
+ ========
331
+
332
+ A singleton to allow all parts of a Rails application use the same set
333
+ of settings, loaded from the same settings yaml file.
334
+
335
+ Testing
336
+ =======
337
+ This library uses [Bundler](http://gembundler.com/) for development and testing.
338
+
339
+ > bundle install
340
+ >
341
+ > rake spec
342
+ >
343
+ > rake rcov
344
+
345
+ Note on Patches/Pull Requests
346
+ =============================
347
+ * Fork the project.
348
+ * Make your feature addition or bug fix.
349
+ * Add tests for it. This is important so I don't break it in a
350
+ future version unintentionally.
351
+ * Commit, do not mess with rakefile, version, or history.
352
+ (if you want to have your own version, that is fine but bump version in a
353
+ commit by itself I can ignore when I pull)
354
+ * Send me a pull request. Bonus points for topic branches.
355
+
356
+ Authors
357
+ =======
358
+ * Benjamin Yu - <http://benjaminyu.org/>, <http://github.com/byu>
359
+
360
+ Copyright
361
+ =========
362
+
363
+ > Copyright 2009-2010 Benjamin Yu
364
+ >
365
+ > Licensed under the Apache License, Version 2.0 (the "License");
366
+ > you may not use this file except in compliance with the License.
367
+ > You may obtain a copy of the License at
368
+ >
369
+ > http://www.apache.org/licenses/LICENSE-2.0
370
+ >
371
+ > Unless required by applicable law or agreed to in writing, software
372
+ > distributed under the License is distributed on an "AS IS" BASIS,
373
+ > WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
374
+ > See the License for the specific language governing permissions and
375
+ > limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ gem.name = "junkfood"
15
+ gem.summary = %Q{My mesh of an all-in-one library for disjoint code.}
16
+ gem.description = %Q{My mesh of an all-in-one library for disjoint code.}
17
+ gem.email = "benjaminlyu@gmail.com"
18
+ gem.homepage = "http://github.com/byu/junkfood"
19
+ gem.authors = ["Benjamin Yu"]
20
+
21
+ gem.extra_rdoc_files << 'LICENSE'
22
+ gem.extra_rdoc_files << 'NOTICE'
23
+ gem.extra_rdoc_files << 'README.md'
24
+
25
+ gem.add_development_dependency "rspec", ">= 2.0.0.beta.19"
26
+ gem.add_development_dependency "yard", "~> 0.6.0"
27
+ gem.add_development_dependency "bundler", "~> 1.0.0"
28
+ gem.add_development_dependency "jeweler", "~> 1.5.0.pre3"
29
+ gem.add_development_dependency "rcov", ">= 0"
30
+
31
+ gem.add_runtime_dependency 'activesupport'
32
+ gem.add_runtime_dependency 'mongoid', '~> 2.0.0.beta.18'
33
+ gem.add_runtime_dependency 'wrong'
34
+ end
35
+ Jeweler::RubygemsDotOrgTasks.new
36
+
37
+ require 'rspec/core'
38
+ require 'rspec/core/rake_task'
39
+ RSpec::Core::RakeTask.new(:spec) do |spec|
40
+ spec.pattern = FileList['spec/**/*_spec.rb']
41
+ end
42
+
43
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
44
+ spec.pattern = 'spec/**/*_spec.rb'
45
+ spec.rcov = true
46
+ end
47
+
48
+ task :default => :spec
49
+
50
+ require 'yard'
51
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/junkfood.gemspec ADDED
@@ -0,0 +1,147 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{junkfood}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Benjamin Yu"]
12
+ s.date = %q{2010-09-30}
13
+ s.description = %q{My mesh of an all-in-one library for disjoint code.}
14
+ s.email = %q{benjaminlyu@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "NOTICE",
18
+ "README.md"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".gitignore",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE",
26
+ "NOTICE",
27
+ "README.md",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "junkfood.gemspec",
31
+ "lib/junkfood.rb",
32
+ "lib/junkfood/adler32.rb",
33
+ "lib/junkfood/adler32_pure.rb",
34
+ "lib/junkfood/assert.rb",
35
+ "lib/junkfood/base32.rb",
36
+ "lib/junkfood/ceb.rb",
37
+ "lib/junkfood/ceb/base_command.rb",
38
+ "lib/junkfood/ceb/base_event.rb",
39
+ "lib/junkfood/ceb/bus.rb",
40
+ "lib/junkfood/ceb/executors.rb",
41
+ "lib/junkfood/ceb/executors/command_executor.rb",
42
+ "lib/junkfood/ceb/executors/delayed_job_command_executor.rb",
43
+ "lib/junkfood/ceb/executors/event_executor.rb",
44
+ "lib/junkfood/one_time.rb",
45
+ "lib/junkfood/paperclip_string_io.rb",
46
+ "lib/junkfood/settings.rb",
47
+ "spec/.rspec",
48
+ "spec/junkfood/adler32_pure_spec.rb",
49
+ "spec/junkfood/adler32_spec.rb",
50
+ "spec/junkfood/assert_spec.rb",
51
+ "spec/junkfood/base32_spec.rb",
52
+ "spec/junkfood/ceb/base_command_spec.rb",
53
+ "spec/junkfood/ceb/base_event_spec.rb",
54
+ "spec/junkfood/ceb/bus_spec.rb",
55
+ "spec/junkfood/ceb/executors/command_executor_spec.rb",
56
+ "spec/junkfood/ceb/executors/delayed_job_command_executor_spec.rb",
57
+ "spec/junkfood/ceb/executors/event_executor_spec.rb",
58
+ "spec/junkfood/one_time_spec.rb",
59
+ "spec/junkfood/paperclip_string_io_spec.rb",
60
+ "spec/junkfood/settings_spec.rb",
61
+ "spec/junkfood_spec.rb",
62
+ "spec/spec_helper.rb"
63
+ ]
64
+ s.homepage = %q{http://github.com/byu/junkfood}
65
+ s.require_paths = ["lib"]
66
+ s.rubygems_version = %q{1.3.7}
67
+ s.summary = %q{My mesh of an all-in-one library for disjoint code.}
68
+ s.test_files = [
69
+ "spec/junkfood/adler32_pure_spec.rb",
70
+ "spec/junkfood/adler32_spec.rb",
71
+ "spec/junkfood/assert_spec.rb",
72
+ "spec/junkfood/base32_spec.rb",
73
+ "spec/junkfood/ceb/base_command_spec.rb",
74
+ "spec/junkfood/ceb/base_event_spec.rb",
75
+ "spec/junkfood/ceb/bus_spec.rb",
76
+ "spec/junkfood/ceb/executors/command_executor_spec.rb",
77
+ "spec/junkfood/ceb/executors/delayed_job_command_executor_spec.rb",
78
+ "spec/junkfood/ceb/executors/event_executor_spec.rb",
79
+ "spec/junkfood/one_time_spec.rb",
80
+ "spec/junkfood/paperclip_string_io_spec.rb",
81
+ "spec/junkfood/settings_spec.rb",
82
+ "spec/junkfood_spec.rb",
83
+ "spec/spec_helper.rb"
84
+ ]
85
+
86
+ if s.respond_to? :specification_version then
87
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
88
+ s.specification_version = 3
89
+
90
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
91
+ s.add_development_dependency(%q<bluecloth>, [">= 0"])
92
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
93
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
94
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
95
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
96
+ s.add_development_dependency(%q<rcov>, [">= 0"])
97
+ s.add_development_dependency(%q<activesupport>, [">= 0"])
98
+ s.add_development_dependency(%q<mongoid>, ["~> 2.0.0.beta.18"])
99
+ s.add_development_dependency(%q<wrong>, [">= 0"])
100
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
101
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
102
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
103
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
104
+ s.add_development_dependency(%q<rcov>, [">= 0"])
105
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
106
+ s.add_runtime_dependency(%q<mongoid>, ["~> 2.0.0.beta.18"])
107
+ s.add_runtime_dependency(%q<wrong>, [">= 0"])
108
+ else
109
+ s.add_dependency(%q<bluecloth>, [">= 0"])
110
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
111
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
112
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
113
+ s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
114
+ s.add_dependency(%q<rcov>, [">= 0"])
115
+ s.add_dependency(%q<activesupport>, [">= 0"])
116
+ s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.18"])
117
+ s.add_dependency(%q<wrong>, [">= 0"])
118
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
119
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
120
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
121
+ s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
122
+ s.add_dependency(%q<rcov>, [">= 0"])
123
+ s.add_dependency(%q<activesupport>, [">= 0"])
124
+ s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.18"])
125
+ s.add_dependency(%q<wrong>, [">= 0"])
126
+ end
127
+ else
128
+ s.add_dependency(%q<bluecloth>, [">= 0"])
129
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.22"])
130
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
131
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
132
+ s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
133
+ s.add_dependency(%q<rcov>, [">= 0"])
134
+ s.add_dependency(%q<activesupport>, [">= 0"])
135
+ s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.18"])
136
+ s.add_dependency(%q<wrong>, [">= 0"])
137
+ s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
138
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
139
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
140
+ s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre3"])
141
+ s.add_dependency(%q<rcov>, [">= 0"])
142
+ s.add_dependency(%q<activesupport>, [">= 0"])
143
+ s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.18"])
144
+ s.add_dependency(%q<wrong>, [">= 0"])
145
+ end
146
+ end
147
+
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+ # Copyright 2009 Benjamin Yu <http://benjaminyu.org/>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'zlib'
17
+
18
+ module Junkfood
19
+
20
+ ##
21
+ # A Ruby implementation of the Adler-32 checksum algorithm,
22
+ # which uses Ruby's own Zlib.adler32 class method.
23
+ #
24
+ # This Ruby implementation is a port of the Python adler32
25
+ # implementation found in the pysync project. The Python reference
26
+ # implementation, itself, was a port from zlib's adler32.c file.
27
+ #
28
+ # @see http://zlib.net/
29
+ # @see http://freshmeat.net/projects/pysync/
30
+ #
31
+ class Adler32
32
+
33
+ # largest prime smaller than 65536
34
+ BASE = 65521
35
+ # largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
36
+ NMAX = 5552
37
+ # default initial s1 offset
38
+ OFFS = 1
39
+
40
+ ##
41
+ # @param data (String) initial block of data to digest.
42
+ #
43
+ def initialize(data='')
44
+ value = Zlib.adler32(data, OFFS)
45
+ @s2, @s1 = (value >> 16) & 0xffff, value & 0xffff
46
+ @count = data.length
47
+ end
48
+
49
+ ##
50
+ # Adds another block of data to digest.
51
+ #
52
+ # @param data (String) block of data to digest.
53
+ # @return (Fixnum) the updated digest.
54
+ #
55
+ def update(data)
56
+ value = Zlib.adler32(data, (@s2 << 16) | @s1)
57
+ @s2, @s1 = (value >> 16) & 0xffff, value & 0xffff
58
+ @count = @count + data.length
59
+ return self.digest
60
+ end
61
+
62
+ ##
63
+ # @param x1 (Byte)
64
+ # @param xn (Byte)
65
+ # @return (Fixnum) the updated digest.
66
+ #
67
+ def rotate(x1, xn)
68
+ @s1 = (@s1 - x1 + xn) % BASE
69
+ @s2 = (@s2 - (@count * x1) + @s1 - OFFS) % BASE
70
+ return self.digest
71
+ end
72
+
73
+ ##
74
+ # @param b (Byte)
75
+ # @return (Fixnum) the updated digest.
76
+ #
77
+ def rollin(b)
78
+ @s1 = (@s1 + b) % BASE
79
+ @s2 = (@s2 + @s1) % BASE
80
+ @count = @count + 1
81
+ return self.digest
82
+ end
83
+
84
+ ##
85
+ # @param b (Byte)
86
+ # @return (Fixnum) the updated digest.
87
+ #
88
+ def rollout(b)
89
+ @s1 = (@s1 - b) % BASE
90
+ @s2 = (@s2 - @count * b) % BASE
91
+ @count = @count - 1
92
+ return self.digest
93
+ end
94
+
95
+ ##
96
+ # @return (Fixnum) the current Adler32 digest value.
97
+ #
98
+ def digest
99
+ return (@s2 << 16) | @s1
100
+ end
101
+ end
102
+ end