bitswitch 1.0.5 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bitswitch.gemspec +1 -1
- data/lib/bitswitch.rb +175 -64
- data/lib/bitswitch/version.rb +10 -2
- metadata +2 -2
data/bitswitch.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'bitswitch/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "bitswitch"
|
8
|
-
gem.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."
|
data/lib/bitswitch.rb
CHANGED
@@ -1,103 +1,176 @@
|
|
1
|
+
require 'bitswitch/version'
|
2
|
+
|
1
3
|
class BitSwitch
|
2
4
|
|
3
|
-
def initialize(
|
5
|
+
def initialize(input = 0, labels = {})
|
6
|
+
|
7
|
+
# Placeholder
|
8
|
+
@labels = {}
|
9
|
+
@val = 0
|
4
10
|
|
5
|
-
|
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
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
23
|
-
|
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
|
-
#
|
28
|
-
|
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
|
-
#
|
32
|
-
@labels = labels
|
33
|
-
@val =
|
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
|
-
|
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
|
-
#
|
42
|
-
bit = bit.
|
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
|
-
|
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
|
-
|
110
|
+
self
|
54
111
|
end
|
55
|
-
|
112
|
+
|
56
113
|
# Check a bit status
|
57
114
|
def [](bit)
|
58
115
|
|
59
|
-
#
|
60
|
-
bit
|
61
|
-
|
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
|
-
|
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
|
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=(
|
72
|
-
|
73
|
-
|
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
|
-
#
|
79
|
-
unless reset
|
80
|
-
|
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
|
-
|
158
|
+
self
|
89
159
|
end
|
90
|
-
|
91
|
-
#
|
160
|
+
|
161
|
+
# Get value
|
92
162
|
def to_i
|
93
163
|
@val
|
94
164
|
end
|
95
165
|
|
96
|
-
#
|
166
|
+
# Get hash
|
97
167
|
def to_hash
|
98
168
|
|
99
|
-
#
|
100
|
-
|
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
|
183
|
+
# Return serialization
|
111
184
|
serialized
|
112
185
|
end
|
113
186
|
|
114
|
-
# Method
|
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
|
-
|
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
|
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
|
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
|
-
#
|
180
|
-
|
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
|
-
|
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
|
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
|
data/lib/bitswitch/version.rb
CHANGED
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
|
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:
|
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
|