junkfood 0.1.0

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 (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
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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 'delayed_job'
17
+ require 'json'
18
+
19
+ module Junkfood
20
+ module Ceb
21
+ module Executors
22
+
23
+ ##
24
+ # The actual job class that is serialized for DelayedJob runs. which
25
+ # is tasked to perform the commands.
26
+ #
27
+ # EXPERIMENTAL: This is untested, unfinished code.
28
+ #
29
+ class DelayedJobCommandExecutorJob < Struct(:message)
30
+
31
+ ##
32
+ # This method JSON parses the command data, instantiating the
33
+ # referenced Command class, and finally executes the command.
34
+ #
35
+ def perform
36
+ params = JSON.parse message
37
+ command_class = params['_type'].constantize
38
+ raise 'err' unless message_class.kind_of? ::Junkfood::Ceb::BaseCommand
39
+ command = command_class.new params
40
+ command.perform
41
+ end
42
+ end
43
+
44
+ ##
45
+ # An executor that queues up a DelayedJob to execute the command at
46
+ # a later point in time.
47
+ #
48
+ # EXPERIMENTAL: This is untested, unfinished code.
49
+ #
50
+ class DelayedJobExecutor
51
+
52
+ ##
53
+ # @param command (BaseCommand) the command to queue up.
54
+ #
55
+ def call(command)
56
+ Delayed::Job.enqueue DelayedJobExecutorJob.new(command.to_json)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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
+ module Junkfood
17
+ module Ceb
18
+ module Executors
19
+
20
+ ##
21
+ # Processes the event from the event_bus. The event is saved.
22
+ # TODO: emit json serialized event to other listeners.
23
+ #
24
+ class EventExecutor
25
+
26
+ ##
27
+ # @param event (BaseEvent) the event to save and perform.
28
+ #
29
+ def call(event)
30
+ event.save! if event.new_record?
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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
+ module Junkfood
17
+ module Ceb
18
+
19
+ ##
20
+ # Namespace for the Ceb executors.
21
+ #
22
+ module Executors
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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
+ module Junkfood
17
+
18
+ ##
19
+ # The Junkfood::Ceb module is the namespace for the Command-Query
20
+ # Responsibility Separation component of Junkfood.
21
+ module Ceb
22
+ end
23
+ end
24
+
25
+ require 'junkfood/ceb/base_command'
26
+ require 'junkfood/ceb/base_event'
27
+ require 'junkfood/ceb/bus'
@@ -0,0 +1,247 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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 'openssl'
17
+ require 'wrong'
18
+
19
+ module Junkfood
20
+
21
+ ##
22
+ # Implements HMAC One Time Passwords using SHA-1 digests.
23
+ #
24
+ # @example
25
+ #
26
+ # # Using the class methods to get OTP one at a time.
27
+ # key = '12345678901234567890'
28
+ # puts Junkfood::OneTime.hotp(key, 0) #=> 755224
29
+ # puts Junkfood::OneTime.hotp(key, 1) #=> 287082
30
+ #
31
+ # @example
32
+ #
33
+ # # Changing the length of the OTP
34
+ # key = '12345678901234567890'
35
+ # puts Junkfood::OneTime.hotp(key, 0, :digits => 8) #=> 84755224
36
+ #
37
+ # @example
38
+ #
39
+ # # Using the class methods to get multiple OTP at a time.
40
+ # key = '12345678901234567890'
41
+ # puts Junkfood::OneTime.hotp_multi(key, 0..1) #=> [755224, 287082]
42
+ #
43
+ # @example
44
+ #
45
+ # # Create a new OTP generator starting at counter 0.
46
+ # key = '12345678901234567890'
47
+ # one_time = Junkfood::OneTime.new key
48
+ # # Get an OTP, but don't advance the counter
49
+ # puts one_time.otp #=> 755224
50
+ # puts one_time.otp #=> 755224
51
+ # # Get a range of OTP
52
+ # puts one_time.otp :range => 2 #=> [755224, 287082]
53
+ # # Get an OTP, and advance the counter
54
+ # puts one_time.otp! #=> 755224
55
+ # puts one_time.otp! #=> 287082
56
+ # puts one_time.counter #=> 2
57
+ # puts one_time.otp! :range => 2 #=> [359152, 969429]
58
+ # puts one_time.counter #=> 4
59
+ #
60
+ # @example
61
+ #
62
+ # # The current Time based OTP for the current epoch step.
63
+ # key = '12345678901234567890'
64
+ # one_time = Junkfood::OneTime.new key
65
+ # puts one_time.totp
66
+ # # A bunch of OTPs preceding and following the current epoch step OTP.
67
+ # puts one_time.totp :radius => 2
68
+ #
69
+ # @example
70
+ #
71
+ # # Setting the length and counter of the OTP on a OneTime instance
72
+ # one_time = Junkfood::OneTime.new key, :digits => 8, :counter => 2
73
+ # puts one_time.otp! #=> 37359152
74
+ # puts one_time.otp! #=> 26969429
75
+ #
76
+ # @see http://tools.ietf.org/html/rfc4226
77
+ # @see http://tools.ietf.org/html/draft-mraihi-totp-timebased-06
78
+ #
79
+ class OneTime
80
+ include ::Wrong::Assert
81
+
82
+ attr_reader :counter
83
+
84
+ # Default number of digits for each OTP.
85
+ DEFAULT_DIGITS = 6
86
+ # Default number of seconds for each step in the Time Epoch calculation.
87
+ DEFAULT_STEP_SIZE = 30
88
+ # Max number of OTPs preceding and following the current Time based OTP
89
+ # allowed in the Time based OTP method.
90
+ MAX_RADIUS = 10
91
+
92
+ ##
93
+ # @param secret (String) the secret key used for the HMAC calculation.
94
+ # @option options [Fixnum] :counter (0) the htop counter to start at.
95
+ # @option options [Fixnum] :digits (6) size of each OTP.
96
+ # @option options [Fixnum] :time_digits (6) size of each Time Based OTP.
97
+ # @option options [Fixnum] :time_step_size (30) number of seconds for
98
+ # each block in calculating current counter in Time Based OTP.
99
+ def initialize(secret, options={})
100
+ @secret = secret
101
+ @counter = options[:counter] || 0
102
+ @digits = options[:digits] || DEFAULT_DIGITS
103
+ @time_digits = options[:time_digits] || @digits
104
+ @time_step_size = options[:time_step_size] || DEFAULT_STEP_SIZE
105
+ end
106
+
107
+ ##
108
+ # Generate counter based OTPs and advance the counter.
109
+ #
110
+ # @option options [Fixnum] :range (1) number of OTPs to generate.
111
+ # @return [Array<String>,String] the generated OTPs.
112
+ def otp!(options={})
113
+ range = options[:range] || 1
114
+ result = otp :range => range
115
+ @counter += range
116
+ return result
117
+ end
118
+
119
+ ##
120
+ # Generate counter based OTPs without advancing the counter.
121
+ #
122
+ # @option options [Fixnum] :range (1) number of OTPs to generate.
123
+ # @return [Array<String>,String] the generated OTPs.
124
+ def otp(options={})
125
+ range = options[:range] || 1
126
+ if range <= 1
127
+ return self.class.hotp(@secret, @counter, :digits => @digits)
128
+ else
129
+ return self.class.hotp_multi(
130
+ @secret,
131
+ @counter...(@counter + range),
132
+ :digits => @digits)
133
+ end
134
+ end
135
+
136
+ ##
137
+ # Generate Time Based OTPs based on the current time and time steps.
138
+ #
139
+ # @option options [Fixnum] :radius (0) number of additional OTPs
140
+ # preceding and following the current Time OTP to generate.
141
+ # @return [Array<String>,String] the generated OTPs.
142
+ def totp(options={})
143
+ radius = options[:radius] || 0
144
+ assert{radius.kind_of?(Fixnum) && radius >= 0 && radius <= MAX_RADIUS}
145
+ c = self.class.epoch_counter(:step_size => @time_step_size)
146
+ start_counter = max(c - radius, 0)
147
+ range = start_counter..(c+radius)
148
+ results = self.class.hotp_multi @secret, range, :digits => @time_digits
149
+ return results.size <= 1 ? results.first : results
150
+ end
151
+
152
+ ##
153
+ # Generate an individual OTP.
154
+ #
155
+ # @param secret (String) the secret key used for the HMAC.
156
+ # @param counter (Fixnum) the counter used to generate the OTP.
157
+ # @option options [Fixnum] :digits (6) size of each OTP.
158
+ # @return [String] the generated OTP.
159
+ def self.hotp(secret, counter=0, options={})
160
+ results = hotp_raw secret, counter, (options[:digits] || DEFAULT_DIGITS)
161
+ return results.first
162
+ end
163
+
164
+ ##
165
+ # Generate a set of OTPs.
166
+ #
167
+ # @param secret (String) the secret key used for the HMAC calculation.
168
+ # @param range (Fixnum,Range) counters for which to generate OTPs
169
+ # @option options [Fixnum] :digits (6) size of each OTP.
170
+ # @return [String] the generated OTPs.
171
+ def self.hotp_multi(secret, range, options={})
172
+ digits = options[:digits] || DEFAULT_DIGITS
173
+ range = range..range if range.kind_of? Fixnum
174
+ range.map do |c|
175
+ (hotp_raw secret, c, digits).first
176
+ end
177
+ end
178
+
179
+ ##
180
+ # Generate the OTP along with additional debug information.
181
+ #
182
+ # @param secret (String) the secret key used for the HMAC calculation.
183
+ # @param counter (Fixnum) the htop counter to use at.
184
+ # @param digits (Fixnum) size of each OTP.
185
+ # @return [Array<String,Fixnum,String>] The generated OTP, the Dynamic
186
+ # Binary Code, and the calculated HMAC digest for the OTP.
187
+ #
188
+ def self.hotp_raw(secret, counter=0, digits=DEFAULT_DIGITS)
189
+ # TODO: figure out a better way to turn fixnum into an 8byte buffer string
190
+ counter_bytes = []
191
+ x = counter
192
+ for i in 0..7
193
+ byte = x & 0xff
194
+ x >>= 8
195
+ counter_bytes.unshift byte
196
+ end
197
+ digest_data = counter_bytes.pack('C8')
198
+
199
+ # SHA1 digest is guaranteed to produce a 20 byte binary string.
200
+ # We unpack the string into an array of 8-bit bytes.
201
+ digest = OpenSSL::HMAC.digest(
202
+ OpenSSL::Digest::Digest.new('sha1'),
203
+ secret,
204
+ digest_data)
205
+ digest_array = digest.unpack('C20')
206
+
207
+ # Based on the HMAC OTP algorithm, we use the last 4 bits of the binary
208
+ # string to find the 'dbc' value. The 4 bits is the offset of the
209
+ # hmac bytes array. From which, we extract 4 bytes for the 'dbc'.
210
+ # This is the "Dynamic Truncation".
211
+ # We zero the most significant bit of the 'dbc' to get a 31-bit
212
+ # unsigned big-endian integer. This dbc (converted to a Ruby Fixnum).
213
+ # From the fix num, we modulo 10^digits to get the digits for the HOTP.
214
+ # This is the "Compute HOTP value" step
215
+ offset = digest_array.last & 0x0f
216
+ dbc = digest_array[offset..(offset+3)]
217
+ dbc[0] &= 0x7f
218
+ dbc = dbc.pack('C4').unpack('N').first
219
+ otp = (dbc % 10**digits).to_s.rjust(digits,'0')
220
+ return otp, dbc, digest
221
+ end
222
+
223
+ ##
224
+ # Generate the counter based on the time and step_size.
225
+ #
226
+ # @option options [Time] :time (Time.now) the time to use.
227
+ # @option options [Fixnum] :step_size (30) the step size.
228
+ # @return the time based counter.
229
+ def self.epoch_counter(options={})
230
+ time = options[:time] || Time.now.to_i
231
+ step_size = options[:step_size] || DEFAULT_STEP_SIZE
232
+ return time / step_size
233
+ end
234
+
235
+ private
236
+
237
+ ##
238
+ # Helper method to return the larger of two values.
239
+ #
240
+ # @param a (Object)
241
+ # @param b (Object)
242
+ # @return [Boolean] a &gt;= b ? a : b
243
+ def max(a, b)
244
+ return a >= b ? a : b
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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 'stringio'
17
+
18
+ module Junkfood
19
+
20
+ ##
21
+ # Adapter to save blobs of in-memory data into paperclip enabled
22
+ # ActiveRecord models without requiring the use of temporary files.
23
+ #
24
+ # @example
25
+ #
26
+ # class FaxDocument < ActiveRecord::Base
27
+ # has_attached_file :pdf
28
+ # end
29
+ #
30
+ # def incoming_fax_handler()
31
+ # attachment = 'Blob of Faxed Data in PDF form'
32
+ # fax_number = '555-1234'
33
+ #
34
+ # fax_document = FaxDocument.create(
35
+ # :caption => 'Look at this Document!',
36
+ # :pdf => PaperclipStringIo.new(
37
+ # attachment,
38
+ # :filename => "#{fax_number}.pdf",
39
+ # :content_type => 'application/pdf'))
40
+ # end
41
+ #
42
+ # @see http://rubygems.org/gems/paperclip
43
+ #
44
+ class PaperclipStringIo < StringIO
45
+ attr_reader :original_filename, :content_type
46
+
47
+ # Default filename
48
+ DEFAULT_FILENAME = 'unnamed'
49
+
50
+ # Default file content_type
51
+ DEFAULT_CONTENT_TYPE = 'application/octet-stream'
52
+
53
+ ##
54
+ # @param string (String) blob of to save into paperclip.
55
+ # @option options [String] :filename ('unnamed') set the filename
56
+ # component for the paperclip object.
57
+ # @option options [String] :content_type ('application/octet-stream')
58
+ # set the paperclip object's mime content type.
59
+ #
60
+ def initialize(string, options={})
61
+ super(string)
62
+ @original_filename = options[:filename] || DEFAULT_FILENAME
63
+ @content_type = options[:content_type] || DEFAULT_CONTENT_TYPE
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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 'active_support/core_ext/hash'
17
+ require 'singleton'
18
+ require 'yaml'
19
+
20
+ module Junkfood
21
+
22
+ ##
23
+ # A Global Settings Singleton class for Rails applications.
24
+ #
25
+ class Settings
26
+ include Singleton
27
+
28
+ attr_reader :config
29
+
30
+ ##
31
+ # Reads the settings.yml and settings_<env>.yml file for configuration
32
+ # options and merges them together. The env is the Rails.env,
33
+ # and the settings files are assumed to be in the Rails.root's config
34
+ # subdirectory.
35
+ #
36
+ def initialize
37
+ file = "#{Rails.root}/config/settings.yml"
38
+ env_file = "#{Rails.root}/config/settings_#{Rails.env}.yml"
39
+ @config = {}
40
+ if File.exist? file
41
+ base_cfg = YAML.load File.read(file)
42
+ @config.deep_merge! base_cfg if base_cfg.kind_of? Hash
43
+ end
44
+ if File.exist? env_file
45
+ env_cfg = YAML.load File.read(env_file)
46
+ @config.deep_merge! env_cfg if env_cfg.kind_of? Hash
47
+ end
48
+ end
49
+
50
+ ##
51
+ # @return (Hash) the singleton's configuration.
52
+ #
53
+ def self.config
54
+ instance.config
55
+ end
56
+
57
+ ##
58
+ # Looks up the configuration option.
59
+ #
60
+ # @param key (Object) the configuration option key.
61
+ # @return (Object) the configuration value.
62
+ #
63
+ def self.[](key)
64
+ config[key]
65
+ end
66
+ end
67
+ end
data/lib/junkfood.rb ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ # Copyright 2010 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
+ ##
17
+ # The Junkfood module is the namespace for all Junkfood components.
18
+ #
19
+ module Junkfood
20
+ end
21
+
22
+ require 'junkfood/adler32'
23
+ require 'junkfood/adler32_pure'
24
+ require 'junkfood/assert'
25
+ require 'junkfood/base32'
26
+ require 'junkfood/ceb'
27
+ require 'junkfood/one_time'
28
+ require 'junkfood/paperclip_string_io'
29
+ require 'junkfood/settings'
data/spec/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe 'Adler32' do
4
+
5
+ it 'should checksum Wikipedia example' do
6
+ adler32 = Junkfood::Adler32Pure.new('Wikipedia')
7
+ adler32.digest.should eql(300286872)
8
+ end
9
+
10
+ it 'should checksum Wikipedia example using update' do
11
+ adler32 = Junkfood::Adler32Pure.new
12
+ adler32.update('Wikipedia').should eql(300286872)
13
+ adler32.digest.should eql(300286872)
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe 'Adler32' do
4
+
5
+ it 'should checksum Wikipedia example' do
6
+ adler32 = Junkfood::Adler32.new('Wikipedia')
7
+ adler32.digest.should eql(300286872)
8
+ end
9
+
10
+ it 'should checksum Wikipedia example using update' do
11
+ adler32 = Junkfood::Adler32Pure.new
12
+ adler32.update('Wikipedia').should eql(300286872)
13
+ adler32.digest.should eql(300286872)
14
+ end
15
+
16
+ end
@@ -0,0 +1,84 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Assert" do
4
+
5
+ it 'should pass with various yielded results' do
6
+ x = Class.new do
7
+ include Junkfood::Assert
8
+ def test
9
+ assert { true }
10
+ assert { 1 }
11
+ assert { Array.new }
12
+ assert { Hash.new }
13
+ end
14
+ end
15
+ x.new.test
16
+ end
17
+
18
+ it 'should raise Assertion Error with false' do
19
+ x = Class.new do
20
+ include Junkfood::Assert
21
+ def test
22
+ assert { false }
23
+ end
24
+ end
25
+ lambda {
26
+ x.new.test
27
+ }.should raise_error(Junkfood::Assert::AssertionFailedError)
28
+ end
29
+
30
+ it 'should raise Assertion Error with nil' do
31
+ x = Class.new do
32
+ include Junkfood::Assert
33
+ def test
34
+ assert { nil }
35
+ end
36
+ end
37
+ lambda {
38
+ x.new.test
39
+ }.should raise_error(Junkfood::Assert::AssertionFailedError)
40
+ end
41
+
42
+ it 'should raise Assertion Error with custom message' do
43
+ x = Class.new do
44
+ include Junkfood::Assert
45
+ def test
46
+ assert('my custom error message') {
47
+ false
48
+ }
49
+ end
50
+ end
51
+ lambda {
52
+ x.new.test
53
+ }.should raise_error(
54
+ Junkfood::Assert::AssertionFailedError,
55
+ 'my custom error message')
56
+ end
57
+
58
+ it 'should call the parent class assert method when no block is given' do
59
+ x = Class.new do
60
+ def assert(*args)
61
+ return args.first
62
+ end
63
+ end
64
+ y = Class.new(x) do
65
+ include Junkfood::Assert
66
+ def test
67
+ result = assert true
68
+ assert { result }
69
+ end
70
+ end
71
+ y.new.test
72
+ end
73
+
74
+ it 'should raise an error on missing block and undefined parent assert' do
75
+ x = Class.new
76
+ y = Class.new(x) do
77
+ include Junkfood::Assert
78
+ def test
79
+ assert
80
+ end
81
+ end
82
+ lambda { y.new.test }.should raise_error
83
+ end
84
+ end