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