bitswitch 1.0.5 → 1.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.
@@ -5,7 +5,7 @@ require 'bitswitch/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "bitswitch"
8
- gem.version = Bitswitch::VERSION
8
+ gem.version = KellyLSB::BitSwitch::VERSION
9
9
  gem.authors = ["Kelly Becker"]
10
10
  gem.email = ["kellylsbkr@gmail.com"]
11
11
  gem.description = "Have you ever wanted to store multiple true/false values in your database, but annoyed with how many fields your tables have, then BitSwitcher is good for you. By assigning a bit for each true/false you can store all your fields in one integer."
@@ -1,103 +1,176 @@
1
+ require 'bitswitch/version'
2
+
1
3
  class BitSwitch
2
4
 
3
- def initialize(n = 0, labels = {})
5
+ def initialize(input = 0, labels = {})
6
+
7
+ # Placeholder
8
+ @labels = {}
9
+ @val = 0
4
10
 
5
- if n.is_a?(Hash)
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
6
16
 
7
- # Set default values
8
- @labels = {}
9
- @val = 0
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
10
22
 
11
- if labels.empty?
12
- # Loop through the hash and set the switches
13
- i=0; n.each do |label, tf|
14
- self[i] = tf ? 1 : 0
15
- @labels[i] = label.to_s
16
- i += 1
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."
17
31
  end
18
- else
19
- # Set the switches
20
- @labels = labels
21
32
 
22
- n.each do |label, tf|
23
- self[label.to_s] = tf ? 1 : 0
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."
24
37
  end
25
38
  end
39
+ end
40
+
41
+ # Validate label hash format
42
+ labels.each do |bit, label|
26
43
 
27
- # Return the BitSwitch object
28
- return self
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
29
55
  end
30
56
 
31
- # Set labels and initial number
32
- @labels = labels
33
- @val = n
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
34
76
  end
35
77
 
36
- # Set a bit
78
+ # Set a bit (or label)
37
79
  def []=(bit, val)
38
- val = val == true if val.is_a?(TrueClass)
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
39
94
  val = val > 0 if val.is_a?(Fixnum)
40
95
 
41
- # If a string representation of a bit was provided get the numerical
42
- bit = bit.to_s if bit.is_a?(Symbol)
43
- bit = @labels.invert[bit] if bit.is_a?(String)
96
+ # Get the numerical representation of the label
97
+ bit = @labels.invert[bit.to_sym] unless bit.is_a?(Fixnum)
44
98
 
45
99
  # If nil return false
46
- return false if bit.nil?
47
-
100
+ if bit.nil?
101
+ raise KellyLSB::BitSwitch::Error,
102
+ "BitSwitch (#{__method__}): There was no bit to match the requested label."
103
+ end
104
+
48
105
  # Set/Unset the bits
49
106
  @val |= 2 ** bit if val
50
107
  @val &= ~(2 ** bit) if !val && self[bit]
51
108
 
52
109
  # Return self
53
- return self
110
+ self
54
111
  end
55
-
112
+
56
113
  # Check a bit status
57
114
  def [](bit)
58
115
 
59
- # If a string representation of a bit was provided get the numerical
60
- bit = bit.to_s if bit.is_a?(Symbol)
61
- bit = @labels.invert[bit] if bit.is_a?(String)
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)
62
124
 
63
125
  # If nil return false
64
- return false if bit.nil?
126
+ if bit.nil?
127
+ raise KellyLSB::BitSwitch::Error,
128
+ "BitSwitch (#{__method__}): There was no bit to match the requested label."
129
+ end
65
130
 
66
- # Check if the bit it set
131
+ # Check if the bit was set
67
132
  (2 ** bit) & @val > 0
68
133
  end
69
-
134
+
70
135
  # Set an integer
71
- def set=(n)
72
- return false unless n.is_a?(Fixnum)
73
- @val = n
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
74
149
  end
75
150
 
76
151
  def labels(hash = {}, reset = false)
77
152
 
78
- # If reset is false then merge the labels
79
- unless reset
80
- @labels.merge!(hash)
81
- return self
82
- end
83
-
84
- # Set a whole new label hash
85
- @labels = hash
153
+ # Either merge or overwrite labels
154
+ @labels.merge!(hash) unless reset
155
+ @labels = hash if reset
86
156
 
87
157
  # Return self
88
- return self
158
+ self
89
159
  end
90
-
91
- # Convert to integer
160
+
161
+ # Get value
92
162
  def to_i
93
163
  @val
94
164
  end
95
165
 
96
- # Convert to hash
166
+ # Get hash
97
167
  def to_hash
98
168
 
99
- # Raise an error if no labels are set
100
- raise StandardError, "No labels were set!" if @labels.empty?
169
+ # Make sure labels are set
170
+ if @labels.empty?
171
+ raise KellyLSB::BitSwitch::Error,
172
+ "BitSwitch (#{__method__}): No labels were set!"
173
+ end
101
174
 
102
175
  # Prepare new hash
103
176
  serialized = Hash.new
@@ -107,17 +180,20 @@ class BitSwitch
107
180
  serialized[label] = self[bit]
108
181
  end
109
182
 
110
- # Return the serialized BitSwitch
183
+ # Return serialization
111
184
  serialized
112
185
  end
113
186
 
114
- # Method missing for args access
187
+ # Method access
115
188
  def method_missing(method, *args)
189
+
190
+ # Handle setting values
116
191
  if method[-1] == '='
117
192
  method = method[0..-2]
118
193
  return self[method] = args.first
119
194
  end
120
-
195
+
196
+ # Return a value
121
197
  self[method]
122
198
  end
123
199
  end
@@ -132,7 +208,15 @@ end
132
208
  # Convert hash of booleans to Switch
133
209
  class Hash
134
210
  def to_switch(labels = {})
135
- cleaned = self.delete_if{|k,v| ![true, false].include?(v)}
211
+
212
+ # Remove any non boolean values
213
+ cleaned = self.delete_if{|k,v| ![true, false, 1, 0, '1', '0'].include?(v)}
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)}
218
+
219
+ # Return new BitSwitch
136
220
  return BitSwitch.new(0, labels) if cleaned.empty?
137
221
  return BitSwitch.new(cleaned, labels)
138
222
  end
@@ -148,7 +232,7 @@ if defined? ActiveRecord::Base
148
232
  def bitswitch(column, hash = {})
149
233
  columne = column.to_s + '='
150
234
  send(:include, Module.new {
151
- send(:define_method, column.to_sym) do |*args|
235
+ send(:define_method, column) do |*args|
152
236
  val = read_attribute(column)
153
237
 
154
238
  # If nil make 0
@@ -167,19 +251,46 @@ if defined? ActiveRecord::Base
167
251
  return val
168
252
  end
169
253
 
170
- send(:define_method, columne.to_sym) do |input|
254
+ send(:define_method, columne) do |args|
171
255
  val = read_attribute(column)
172
256
 
173
257
  # If nil make 0
174
258
  val = 0 if val.nil?
175
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
+
176
269
  # Make sure the value is an integer
177
270
  raise KellyLSB::BitSwitch::Error, "Column: #{column} is not an integer!" unless val.is_a?(Fixnum)
178
271
 
179
- # Get the BitSwitch
180
- val = val.to_switch(hash).to_hash.merge(input).to_switch(hash)
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
181
280
 
182
- # Dont save if it cant save
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
183
294
  return false if read_attribute(:id).nil?
184
295
 
185
296
  # Write the updated value
@@ -191,7 +302,7 @@ if defined? ActiveRecord::Base
191
302
  })
192
303
 
193
304
  send(:extend, Module.new {
194
- send(:define_method, column.to_sym) do |*args|
305
+ send(:define_method, column) do |*args|
195
306
  raise KellyLSB::BitSwitch::Error, "Missing arguments!" if args.empty?
196
307
  bits = hash.invert
197
308
 
@@ -231,4 +342,4 @@ if defined? ActiveRecord::Base
231
342
  end
232
343
 
233
344
  ActiveRecord::Base.send(:include, KellyLSB::BitSwitch)
234
- end
345
+ end
@@ -1,3 +1,11 @@
1
- module Bitswitch
2
- VERSION = "1.0.5"
1
+ module KellyLSB
2
+ module BitSwitch
3
+
4
+ # Error class
5
+ class Error < StandardError
6
+ end
7
+
8
+ # Version of the gem
9
+ VERSION = "1.1.0"
10
+ end
3
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.0.5
4
+ version: 1.1.0
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: 2012-12-09 00:00:00.000000000 Z
12
+ date: 2013-01-29 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