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
@@ -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