Skip to content

Commit ef9b61b

Browse files
committed
ternary_value_flag feature without tests
1 parent c28a287 commit ef9b61b

2 files changed

Lines changed: 298 additions & 57 deletions

File tree

TERNARY_UPDATE_README.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# FlagShihTzu_Ternary_flag_update
2+
3+
## Summary
4+
5+
The updated functionality of the gem allow flag(s) to be set as nil, i.e neither true nor false.
6+
7+
8+
### Defaults (Important)
9+
10+
* Due to the default of `0`, *all flags* are initially set to "false"). To set all flags to nil initially, assign default value to 2^(32-1)-1 i.e 2147483647.
11+
* The ternary update restricts the support of total no. of flags to 15.
12+
13+
14+
### Bit Fields: How it stores the three values
15+
16+
As said, FlagShihTzu uses a single integer column to store the values for all
17+
the defined flags as a [bit field][bitfield].
18+
19+
So, to accomodate 3 values(true, false and nil), a combination of 2 bits is used to store one of the three value via following mapping:
20+
21+
`---+---+---+---+
22+
| Value | Bits |
23+
| | |
24+
`---+---+---+---+
25+
| false | 00 |
26+
`---+---+---+---+
27+
| true | 10 |
28+
`---+---+---+---+
29+
| nil | 11 |
30+
`---+---+---+---+
31+
32+
The bit position of a flag corresponds to the given key.
33+
34+
This way, we can use [bitwise operators][bit_operation] on the stored integer value to set, unset
35+
and check individual flags.
36+
37+
`---+---+---+---+---+---+ +---+---+---+---+---+---`
38+
| | | | | | | |
39+
Flag position | 3 | 2 | 1 | | 3 | 2 | 1 |
40+
(flag key) | | | | | | | |
41+
`---+---+---+---+---+---+ +---+---+---+---+---+---`
42+
| e | s | w | | e | s | w |
43+
| l | h | a | | l | h | a |
44+
| e | i | r | | e | i | r |
45+
| c | e | p | | c | e | p |
46+
| t | l | d | | t | l | d |
47+
| r | d | r | | r | d | r |
48+
| o | s | i | | o | s | i |
49+
| l | | v | | l | | v |
50+
| y | | e | | y | | e |
51+
| t | | | | t | | |
52+
| e | | | | e | | |
53+
| s | | | | s | | |
54+
`---+---+---+---+---+---+ +---+---+---+---+---+---`
55+
| true | false | nil | | nil | true | false |
56+
Flag Value `---+---|---+---|---+---+ +---+---|---+---|---+---`
57+
| 0 1 | 0 0 | 1 1 | | 1 1 | 0 1 | 0 0 |
58+
`---+---+---+---|---+---+ +---+---|---+---|---+---`
59+
Bit Value | 32 16 | 8 4 | 2 1 | = 16 + 2 + 1 = 19 | 32 16 | 8 4 | 2 1 | = 32 + 16 + 4 = 52
60+
`---+---+---+---|---+---+ +---+---|---+---|---+---`
61+
62+
Read more about [bit fields][bit_field] here: http://en.wikipedia.org/wiki/Bit_field
63+
64+
65+
### Bang Method for nil value
66+
67+
When setting the `:bang_methods` option to true, the following method also gets defined:
68+
69+
Spaceship#electrolytes_nil! # will save the bitwise equivalent of electrolytes = nil on the record
70+
71+
which clears the current value of the electrolytes flag.
72+
73+
74+
### Generated named scope for nil flags
75+
76+
The following new named scope(s) become available:
77+
78+
```ruby
79+
Spaceship.warpdrive_nil # :conditions => "(spaceships.flags in (3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,71,75,79,83,87,91,95))"
80+
```
81+
82+
83+
### Support for manually building conditions
84+
85+
The following class method gets added for nil condition for supporting manually building
86+
ActiveRecord conditions:
87+
88+
```ruby
89+
Spaceship.warpdrive_nil_condition # :conditions => "(spaceships.flags in (3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,71,75,79,83,87,91,95))"
90+
```
91+
92+
93+
### Query mode
94+
95+
While the default way of building the SQL conditions uses an `IN()` list
96+
(as shown above) and the same is also used in flag_shih_tzu, this approach will not work well in this gem for higher number of flags,
97+
as the value list for `IN()` grows a lot faster.
98+
99+
So, in this gem, flag query mode is changed to `:bit_operator`
100+
from `:in_list`
101+
102+
This will modify the generated condition and named_scope methods to use bit
103+
operators in the SQL instead of an `IN()` list:
104+
105+
```ruby
106+
Spaceship.warpdrive_condition # "(spaceships.flags & 3 = 1)",
107+
Spaceship.not_warpdrive_condition # "(spaceships.flags & 3 = 0)",
108+
Spaceship.warpdrive_nil_condition # "(spaceships.flags & 3 = 3)",
109+
Spaceship.shields_condition # "(spaceships.flags & 12 = 4)",
110+
Spaceship.not_shields_condition # "(spaceships.flags & 12 = 0)",
111+
Spaceship.shields_nil_condition # "(spaceships.flags & 12 = 12)",
112+
113+
Spaceship.warpdrive # :conditions => "(spaceships.flags & 3 = 1)"
114+
Spaceship.not_warpdrive # :conditions => "(spaceships.flags & 3 = 0)"
115+
Spaceship.warpdrive_nil # :conditions => "(spaceships.flags & 3 = 3)"
116+
Spaceship.shields # :conditions => "(spaceships.flags & 12 = 4)"
117+
Spaceship.not_shields # :conditions => "(spaceships.flags & 12 = 0)"
118+
Spaceship.shields_nil # :conditions => "(spaceships.flags & 12 = 12)"
119+
```
120+
121+

0 commit comments

Comments
 (0)