bitswitch 1.1.0 → 1.1.1

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 (3) hide show
  1. data/lib/bitswitch.rb +357 -325
  2. data/lib/bitswitch/version.rb +7 -7
  3. metadata +3 -2
@@ -2,344 +2,376 @@ require 'bitswitch/version'
2
2
 
3
3
  class BitSwitch
4
4
 
5
- def initialize(input = 0, labels = {})
6
-
7
- # Placeholder
8
- @labels = {}
9
- @val = 0
10
-
11
- # Validate the value input
12
- unless input.is_a?(Fixnum) || input.is_a?(Hash)
13
- raise KellyLSB::BitSwitch::Error,
14
- "BitSwitch: BitSwitch can only accept an instance of `Fixnum` or `Hash` as the first argument"
15
- end
16
-
17
- # Validate the labels input
18
- unless labels.is_a?(Hash)
19
- raise KellyLSB::BitSwitch::Error,
20
- "BitSwitch: BitSwitch expected the second argument to be a `Hash`"
21
- end
22
-
23
- # Validate hash value input
24
- if input.is_a?(Hash)
25
- input.each do |label, value|
26
-
27
- # Require a String, Symbol or Fixnum value for input hash keys
28
- unless label.is_a?(String) || label.is_a?(Symbol) || label.is_a?(Fixnum)
29
- raise KellyLSB::BitSwitch::Error,
30
- "BitSwitch: Input Hash keys must be a String, Symbol or Fixnum representation of the bit."
31
- end
32
-
33
- # Require input hash values to be true or false
34
- unless value === true || value === false
35
- raise KellyLSB::BitSwitch::Error,
36
- "BitSwitch: Input Hash values must be either true or false."
37
- end
38
- end
39
- end
40
-
41
- # Validate label hash format
42
- labels.each do |bit, label|
43
-
44
- # Require label bits to be Fixnum
45
- unless bit.is_a?(Fixnum)
46
- raise KellyLSB::BitSwitch::Error,
47
- "BitSwitch: Label Hash keys must be instances of Fixnum"
48
- end
49
-
50
- # Require labels to be Strings or Symbols
51
- unless label.is_a?(String) || label.is_a?(Symbol)
52
- raise KellyLSB::BitSwitch::Error,
53
- "BitSwitch: Label Hash values must be either Symbols or Strings"
54
- end
55
- end
56
-
57
- # Apply label hash into the instance variable and assume 0
58
- @labels = labels.inject({}){|h, (k, v)|h.merge(k => v.to_sym)}
59
- @val = input.is_a?(Hash) ? 0 : input
60
-
61
- # Handle hash input
62
- if input.is_a?(Hash)
63
-
64
- # If no labels are set
65
- # Loop through the input and set the values
66
- input.each_with_index { |(label, value), index|
67
- @labels[index] = label.to_sym
68
- self[index] = value
69
- } if @labels.empty?
70
-
71
- # Otherwise just set
72
- input.each { |label, value|
73
- self[label] = value
74
- } unless @labels.empty?
75
- end
76
- end
77
-
78
- # Set a bit (or label)
79
- def []=(bit, val)
80
-
81
- # Validate input label / bit
82
- unless bit.is_a?(Symbol) || bit.is_a?(String) || bit.is_a?(Fixnum)
83
- raise KellyLSB::BitSwitch::Error,
84
- "BitSwitch (#{__method__}): Expected the key to be a Symbol, String or Fixnum"
85
- end
86
-
87
- # Validate input value
88
- unless val === true || val === false || val.is_a?(Fixnum)
89
- raise KellyLSB::BitSwitch::Error,
90
- "BitSwitch (#{__method__}): Expected the value to be true, false or Fixnum"
91
- end
92
-
93
- # Convert numerical to boolean
94
- val = val > 0 if val.is_a?(Fixnum)
95
-
96
- # Get the numerical representation of the label
97
- bit = @labels.invert[bit.to_sym] unless bit.is_a?(Fixnum)
98
-
99
- # If nil return false
100
- if bit.nil?
101
- raise KellyLSB::BitSwitch::Error,
102
- "BitSwitch (#{__method__}): There was no bit to match the requested label."
103
- end
104
-
105
- # Set/Unset the bits
106
- @val |= 2 ** bit if val
107
- @val &= ~(2 ** bit) if !val && self[bit]
108
-
109
- # Return self
110
- self
111
- end
112
-
113
- # Check a bit status
114
- def [](bit)
115
-
116
- # Validate input label / bit
117
- unless bit.is_a?(Symbol) || bit.is_a?(String) || bit.is_a?(Fixnum)
118
- raise KellyLSB::BitSwitch::Error,
119
- "BitSwitch (#{__method__}): Expected the key to be a Symbol, String or Fixnum"
120
- end
121
-
122
- # Get the numerical representation of the label
123
- bit = @labels.invert[bit.to_sym] unless bit.is_a?(Fixnum)
124
-
125
- # If nil return false
126
- if bit.nil?
127
- raise KellyLSB::BitSwitch::Error,
128
- "BitSwitch (#{__method__}): There was no bit to match the requested label."
129
- end
130
-
131
- # Check if the bit was set
132
- (2 ** bit) & @val > 0
133
- end
134
-
135
- # Set an integer
136
- def set=(input)
137
-
138
- # Validate input
139
- unless input.is_a?(Fixnum)
140
- raise KellyLSB::BitSwitch::Error,
141
- "BitSwitch (#{__method__}): Expected value to be a Fixnum"
142
- end
143
-
144
- # Set the value
145
- @val = input
146
-
147
- # Return self
148
- self
149
- end
150
-
151
- def labels(hash = {}, reset = false)
152
-
153
- # Either merge or overwrite labels
154
- @labels.merge!(hash) unless reset
155
- @labels = hash if reset
156
-
157
- # Return self
158
- self
159
- end
160
-
161
- # Get value
162
- def to_i
163
- @val
164
- end
165
-
166
- # Get hash
167
- def to_hash
168
-
169
- # Make sure labels are set
170
- if @labels.empty?
171
- raise KellyLSB::BitSwitch::Error,
172
- "BitSwitch (#{__method__}): No labels were set!"
173
- end
174
-
175
- # Prepare new hash
176
- serialized = Hash.new
177
-
178
- # Loop through the labels
179
- @labels.each do |bit, label|
180
- serialized[label] = self[bit]
181
- end
182
-
183
- # Return serialization
184
- serialized
185
- end
186
-
187
- # Method access
188
- def method_missing(method, *args)
189
-
190
- # Handle setting values
191
- if method[-1] == '='
192
- method = method[0..-2]
193
- return self[method] = args.first
194
- end
195
-
196
- # Return a value
197
- self[method]
198
- end
5
+ def initialize(input = 0, labels = {})
6
+
7
+ # Placeholder
8
+ @labels = {}
9
+ @val = 0
10
+
11
+ # Validate the value input
12
+ unless input.is_a?(Fixnum) || input.is_a?(Hash)
13
+ raise KellyLSB::BitSwitch::Error,
14
+ "BitSwitch: BitSwitch can only accept an instance of `Fixnum` or `Hash` as the first argument"
15
+ end
16
+
17
+ # Validate the labels input
18
+ unless labels.is_a?(Hash)
19
+ raise KellyLSB::BitSwitch::Error,
20
+ "BitSwitch: BitSwitch expected the second argument to be a `Hash`"
21
+ end
22
+
23
+ # Validate hash value input
24
+ if input.is_a?(Hash)
25
+ input.each do |label, value|
26
+
27
+ # Require a String, Symbol or Fixnum value for input hash keys
28
+ unless label.is_a?(String) || label.is_a?(Symbol) || label.is_a?(Fixnum)
29
+ raise KellyLSB::BitSwitch::Error,
30
+ "BitSwitch: Input Hash keys must be a String, Symbol or Fixnum representation of the bit."
31
+ end
32
+
33
+ # Require input hash values to be true or false
34
+ unless value === true || value === false
35
+ raise KellyLSB::BitSwitch::Error,
36
+ "BitSwitch: Input Hash values must be either true or false."
37
+ end
38
+ end
39
+ end
40
+
41
+ # Validate label hash format
42
+ labels.each do |bit, label|
43
+
44
+ # Require label bits to be Fixnum
45
+ unless bit.is_a?(Fixnum)
46
+ raise KellyLSB::BitSwitch::Error,
47
+ "BitSwitch: Label Hash keys must be instances of Fixnum"
48
+ end
49
+
50
+ # Require labels to be Strings or Symbols
51
+ unless label.is_a?(String) || label.is_a?(Symbol)
52
+ raise KellyLSB::BitSwitch::Error,
53
+ "BitSwitch: Label Hash values must be either Symbols or Strings"
54
+ end
55
+ end
56
+
57
+ # Apply label hash into the instance variable and assume 0
58
+ @labels = labels.inject({}){|h, (k, v)|h.merge(k => v.to_sym)}
59
+ @val = input.is_a?(Hash) ? 0 : input
60
+
61
+ # Handle hash input
62
+ if input.is_a?(Hash)
63
+
64
+ # If no labels are set
65
+ # Loop through the input and set the values
66
+ input.each_with_index { |(label, value), index|
67
+ @labels[index] = label.to_sym
68
+ self[index] = value
69
+ } if @labels.empty?
70
+
71
+ # Otherwise just set
72
+ input.each { |label, value|
73
+ self[label] = value
74
+ } unless @labels.empty?
75
+ end
76
+ end
77
+
78
+ # Set a bit (or label)
79
+ def []=(bit, val)
80
+
81
+ # Validate input label / bit
82
+ unless bit.is_a?(Symbol) || bit.is_a?(String) || bit.is_a?(Fixnum)
83
+ raise KellyLSB::BitSwitch::Error,
84
+ "BitSwitch (#{__method__}): Expected the key to be a Symbol, String or Fixnum"
85
+ end
86
+
87
+ # Validate input value
88
+ unless val === true || val === false || val.is_a?(Fixnum)
89
+ raise KellyLSB::BitSwitch::Error,
90
+ "BitSwitch (#{__method__}): Expected the value to be true, false or Fixnum"
91
+ end
92
+
93
+ # Convert numerical to boolean
94
+ val = val > 0 if val.is_a?(Fixnum)
95
+
96
+ # Get the numerical representation of the label
97
+ bit = @labels.invert[bit.to_sym] unless bit.is_a?(Fixnum)
98
+
99
+ # If nil return false
100
+ if bit.nil?
101
+ raise KellyLSB::BitSwitch::Error,
102
+ "BitSwitch (#{__method__}): There was no bit to match the requested label."
103
+ end
104
+
105
+ # Set/Unset the bits
106
+ @val |= 2 ** bit if val
107
+ @val &= ~(2 ** bit) if !val && self[bit]
108
+
109
+ # Return self
110
+ self
111
+ end
112
+
113
+ # Check a bit status
114
+ def [](bit)
115
+
116
+ # Validate input label / bit
117
+ unless bit.is_a?(Symbol) || bit.is_a?(String) || bit.is_a?(Fixnum)
118
+ raise KellyLSB::BitSwitch::Error,
119
+ "BitSwitch (#{__method__}): Expected the key to be a Symbol, String or Fixnum"
120
+ end
121
+
122
+ # Get the numerical representation of the label
123
+ bit = @labels.invert[bit.to_sym] unless bit.is_a?(Fixnum)
124
+
125
+ # If nil return false
126
+ if bit.nil?
127
+ raise KellyLSB::BitSwitch::Error,
128
+ "BitSwitch (#{__method__}): There was no bit to match the requested label."
129
+ end
130
+
131
+ # Check if the bit was set
132
+ (2 ** bit) & @val > 0
133
+ end
134
+
135
+ # Set an integer
136
+ def set=(input)
137
+
138
+ # Validate input
139
+ unless input.is_a?(Fixnum)
140
+ raise KellyLSB::BitSwitch::Error,
141
+ "BitSwitch (#{__method__}): Expected value to be a Fixnum"
142
+ end
143
+
144
+ # Set the value
145
+ @val = input
146
+
147
+ # Return self
148
+ self
149
+ end
150
+
151
+ def labels(hash = {}, reset = false)
152
+
153
+ # Either merge or overwrite labels
154
+ @labels.merge!(hash) unless reset
155
+ @labels = hash if reset
156
+
157
+ # Return self
158
+ self
159
+ end
160
+
161
+ # Get value
162
+ def to_i
163
+ @val
164
+ end
165
+
166
+ # Get hash
167
+ def to_hash
168
+
169
+ # Make sure labels are set
170
+ if @labels.empty?
171
+ raise KellyLSB::BitSwitch::Error,
172
+ "BitSwitch (#{__method__}): No labels were set!"
173
+ end
174
+
175
+ # Prepare new hash
176
+ serialized = Hash.new
177
+
178
+ # Loop through the labels
179
+ @labels.each do |bit, label|
180
+ serialized[label] = self[bit]
181
+ end
182
+
183
+ # Return serialization
184
+ serialized
185
+ end
186
+
187
+ # Method access
188
+ def method_missing(method, *args)
189
+
190
+ # Handle setting values
191
+ if method[-1] == '='
192
+ method = method[0..-2]
193
+ return self[method] = args.first
194
+ end
195
+
196
+ # Return a value
197
+ self[method]
198
+ end
199
199
  end
200
200
 
201
201
  # Convert Fixnum to Switch
202
202
  class Fixnum
203
- def to_switch(labels = {})
204
- BitSwitch.new(self, labels)
205
- end
203
+ def to_switch(labels = {})
204
+ BitSwitch.new(self, labels)
205
+ end
206
206
  end
207
207
 
208
208
  # Convert hash of booleans to Switch
209
209
  class Hash
210
- def to_switch(labels = {})
210
+ def to_switch(labels = {})
211
211
 
212
- # Remove any non boolean values
213
- cleaned = self.delete_if{|k,v| ![true, false, 1, 0, '1', '0'].include?(v)}
212
+ # Remove any non boolean values
213
+ cleaned = self.delete_if{|k,v| ![true, false, 1, 0, '1', '0'].include?(v)}
214
214
 
215
- # Convert Numerical Booleans
216
- cleaned.collect!{|k,v|(v.is_a?(String) ? v.to_i : v)}
217
- cleaned.collect!{|k,v|(v.is_a?(Fixnum) ? !v.zero? : v)}
215
+ # Convert Numerical Booleans
216
+ cleaned.collect!{|k,v|(v.is_a?(String) ? v.to_i : v)}
217
+ cleaned.collect!{|k,v|(v.is_a?(Fixnum) ? !v.zero? : v)}
218
218
 
219
- # Return new BitSwitch
220
- return BitSwitch.new(0, labels) if cleaned.empty?
221
- return BitSwitch.new(cleaned, labels)
222
- end
219
+ # Return new BitSwitch
220
+ return BitSwitch.new(0, labels) if cleaned.empty?
221
+ return BitSwitch.new(cleaned, labels)
222
+ end
223
223
  end
224
224
 
225
225
  # Rails 3 Extension
226
226
  if defined? ActiveRecord::Base
227
- module KellyLSB
228
- module BitSwitch
229
- extend ActiveSupport::Concern
230
-
231
- module ClassMethods
232
- def bitswitch(column, hash = {})
233
- columne = column.to_s + '='
234
- send(:include, Module.new {
235
- send(:define_method, column) do |*args|
236
- val = read_attribute(column)
237
-
238
- # If nil make 0
239
- val = 0 if val.nil?
240
-
241
- # Make sure the value is an integer
242
- raise KellyLSB::BitSwitch::Error, "Column: #{column} is not an integer!" unless val.is_a?(Fixnum)
243
-
244
- # Get the BitSwitch
245
- val = val.to_switch hash
246
-
247
- # Return the value of a specific key
248
- return val[args.first.to_s] unless args[0].nil?
249
-
250
- # Return the switch
251
- return val
252
- end
253
-
254
- send(:define_method, columne) do |args|
255
- val = read_attribute(column)
256
-
257
- # If nil make 0
258
- val = 0 if val.nil?
259
-
260
- # Get the input data
261
- if args.is_a?(Array)
262
- input = args[0]
263
- truncate = args[1]
264
- else
265
- input = args
266
- truncate = false
267
- end
268
-
269
- # Make sure the value is an integer
270
- raise KellyLSB::BitSwitch::Error, "Column: #{column} is not an integer!" unless val.is_a?(Fixnum)
271
-
272
- # Make sure the first input is a hash
273
- raise KellyLSB::BitSwitch::Error, "Input: We are expecting at least one argument that is a Hash" unless input.is_a?(Hash)
274
-
275
- # Get the BitSwitch as a Hash
276
- val = val.to_switch(hash).to_hash
277
-
278
- # If a second argument was passed and was true set all other keys to false
279
- if truncate == true
280
-
281
- # Get list of unset keys
282
- remove = val.keys.collect(&:to_s) - input.keys.collect(&:to_s)
283
-
284
- # Set those keys to false
285
- for key in remove
286
- input[key] = false
287
- end
288
- end
289
-
290
- # Merge in the changes
291
- val = val.merge(input).to_switch(hash)
292
-
293
- # Dont save if this is a new model
294
- return false if read_attribute(:id).nil?
295
-
296
- # Write the updated value
297
- update_column(column, val.to_i)
298
-
299
- # Return the switch
300
- return self.send(column)
301
- end
302
- })
303
-
304
- send(:extend, Module.new {
305
- send(:define_method, column) do |*args|
306
- raise KellyLSB::BitSwitch::Error, "Missing arguments!" if args.empty?
307
- bits = hash.invert
308
-
309
- # Type of condition
310
- if args.first.is_a?(String) && ['AND', 'OR'].include?(args.first.upcase)
311
- delimiter = args.shift
312
- else
313
- delimiter = 'AND'
314
- end
315
-
316
- # Empty conditions
317
- conditions = Array.new
318
-
319
- # Build conditions
320
- if args.first.is_a?(Hash)
321
- args.first.each do |slug,tf|
322
- bit = bits[slug.to_s]
323
- conditions << "POW(2, #{bit}) & `#{self.table_name}`.`#{column}`" + (tf ? ' > 0' : ' <= 0')
324
- end
325
- else
326
- args.each do |slug|
327
- bit = bits[slug.to_s]
328
- conditions << "POW(2, #{bit}) & `#{self.table_name}`.`#{column}` > 0"
329
- end
330
- end
331
-
332
- # Run add query
333
- return self.where(conditions.join(" #{delimiter} ")) unless conditions.empty?
334
-
335
- # Return update query
336
- return query
337
- end
338
- })
339
- end
340
- end
341
- end
342
- end
343
-
344
- ActiveRecord::Base.send(:include, KellyLSB::BitSwitch)
227
+ module KellyLSB
228
+ module BitSwitch
229
+ extend ActiveSupport::Concern
230
+
231
+ module ClassMethods
232
+
233
+ # Generate switch methods
234
+ def bitswitch(column, hash = {})
235
+
236
+ # Set column method name
237
+ columne = column.to_s + '='
238
+
239
+ # Instance methods
240
+ send(:include, Module.new {
241
+
242
+ # BitSwitch access method
243
+ send(:define_method, column) do |*args|
244
+ val = read_attribute(column)
245
+
246
+ # If nil make 0
247
+ val = 0 if val.nil?
248
+
249
+ # Make sure the column value is a Fixnum
250
+ unless val.is_a?(Fixnum)
251
+ raise KellyLSB::BitSwitch::Error,
252
+ "Column: #{column} is not an integer!"
253
+ end
254
+
255
+ # Convert the Fixnum to a BitSwitch
256
+ val = val.to_switch hash
257
+
258
+ # Return the value of a specific key if requested
259
+ return val[args.first] unless args[0].nil?
260
+
261
+ # Return the switch
262
+ val
263
+ end
264
+
265
+ # BitSwitch set method
266
+ send(:define_method, columne) do |args|
267
+ val = read_attribute(column)
268
+
269
+ # If nil make 0
270
+ val = 0 if val.nil?
271
+
272
+ # Get the input data
273
+ if args.is_a?(Array)
274
+ input = args[0]
275
+ truncate = args[1]
276
+ else
277
+ input = args
278
+ truncate = false
279
+ end
280
+
281
+ # Make sure the value is an integer
282
+ unless val.is_a?(Fixnum)
283
+ raise KellyLSB::BitSwitch::Error,
284
+ "Column: #{column} is not an integer!"
285
+ end
286
+
287
+ # Make sure the first input is a hash
288
+ unless input.is_a?(Hash)
289
+ raise KellyLSB::BitSwitch::Error,
290
+ "Input: We are expecting at least one argument that is a Hash"
291
+ end
292
+
293
+ # Convert Fixnum -> BitSwitch -> Hash
294
+ val = val.to_switch(hash).to_hash
295
+
296
+ # Convert all keys to symbols
297
+ input.delete_if do |key, val|
298
+ if key.is_a?(String)
299
+ input[key.to_sym] = val
300
+ true
301
+ else
302
+ false
303
+ end
304
+ end
305
+
306
+ # If we are requested to truncate other keys
307
+ if truncate == true
308
+
309
+ # Get list of unset keys and set them to false
310
+ remove = val.keys.collect(&:to_sym) - input.keys.collect(&:to_sym)
311
+ remove.each { |key| input[key] = false }
312
+ end
313
+
314
+ # Merge in the changes then convert to BitSwitch
315
+ val = val.merge(input).to_switch(hash)
316
+
317
+ # Dont save if this is a new model
318
+ return false if new_record?
319
+
320
+ # Write the updated value
321
+ update_column(column, val.to_i)
322
+
323
+ # Return the switch
324
+ return self.send(column)
325
+ end
326
+ })
327
+
328
+ # Scoping methods
329
+ send(:extend, Module.new {
330
+ send(:define_method, column) do |*args|
331
+
332
+ # Require at least one argument
333
+ if args.empty?
334
+ raise KellyLSB::BitSwitch::Error,
335
+ "Missing arguments! We were expecing at least one label or bit to query by."
336
+ end
337
+
338
+ # Invert the label hash
339
+ bits = hash.invert
340
+
341
+ # Type of condition
342
+ if args.first.is_a?(String) && ['AND', 'OR'].include?(args.first.to_s.upcase)
343
+ delimiter = args.shift
344
+ else
345
+ delimiter = 'AND'
346
+ end
347
+
348
+ # Empty conditions
349
+ conditions = Array.new
350
+
351
+ # Build conditions
352
+ if args.first.is_a?(Hash)
353
+ args.first.each do |slug, tf|
354
+ bit = bits[slug.to_s]
355
+ conditions << "POW(2, #{bit}) & #{self.table_name}.#{column}" + (tf ? ' > 0' : ' <= 0')
356
+ end
357
+ else
358
+ args.each do |slug|
359
+ bit = bits[slug.to_s]
360
+ conditions << "POW(2, #{bit}) & #{self.table_name}.#{column} > 0"
361
+ end
362
+ end
363
+
364
+ # If we have query conditions go ahead and return the updated scope
365
+ return self.where(conditions.join(" #{delimiter} ")) unless conditions.empty?
366
+
367
+ # Return self
368
+ self
369
+ end
370
+ })
371
+ end
372
+ end
373
+ end
374
+ end
375
+
376
+ ActiveRecord::Base.send(:include, KellyLSB::BitSwitch)
345
377
  end
@@ -1,11 +1,11 @@
1
1
  module KellyLSB
2
- module BitSwitch
2
+ module BitSwitch
3
3
 
4
- # Error class
5
- class Error < StandardError
6
- end
4
+ # Error class
5
+ class Error < StandardError
6
+ end
7
7
 
8
- # Version of the gem
9
- VERSION = "1.1.0"
10
- end
8
+ # Version of the gem
9
+ VERSION = "1.1.1"
10
+ end
11
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitswitch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-29 00:00:00.000000000 Z
12
+ date: 2013-02-14 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Have you ever wanted to store multiple true/false values in your database,
15
15
  but annoyed with how many fields your tables have, then BitSwitcher is good for
@@ -55,3 +55,4 @@ specification_version: 3
55
55
  summary: Bitswitch lets you store multiple true/false values in an integer using boolean
56
56
  math.
57
57
  test_files: []
58
+ has_rdoc: