bitfields 0.4.3 → 0.5.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.
- checksums.yaml +7 -0
- data/lib/bitfields.rb +15 -27
- data/lib/bitfields/rspec.rb +2 -3
- data/lib/bitfields/version.rb +1 -1
- metadata +94 -38
- data/.travis.yml +0 -19
- data/Appraisals +0 -9
- data/Gemfile +0 -9
- data/Gemfile.lock +0 -51
- data/Rakefile +0 -11
- data/benchmark/bit_operator_vs_in.rb +0 -137
- data/bitfields.gemspec +0 -12
- data/gemfiles/activerecord_2.3.gemfile +0 -12
- data/gemfiles/activerecord_2.3.gemfile.lock +0 -38
- data/gemfiles/activerecord_3.0.gemfile +0 -12
- data/gemfiles/activerecord_3.0.gemfile.lock +0 -49
- data/gemfiles/activerecord_3.1.gemfile +0 -12
- data/gemfiles/activerecord_3.1.gemfile.lock +0 -51
- data/gemfiles/activerecord_3.2.gemfile +0 -12
- data/gemfiles/activerecord_3.2.gemfile.lock +0 -51
- data/gemfiles/activerecord_4.0.gemfile +0 -12
- data/gemfiles/activerecord_4.0.gemfile.lock +0 -59
- data/spec/bitfields_spec.rb +0 -450
- data/spec/database.rb +0 -16
- data/spec/spec_helper.rb +0 -14
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fbae8863b34f3374742a6af0481aac9f284cf15b
|
4
|
+
data.tar.gz: 394e4e9db360d7eecfa030cf072047d3b687a768
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b32ed7e44546be81ae203e252564c3286bf80ba275de4b8a695ebe3b6d14017a4dca244469443f3edde593475ed89d97954a04314c0a3cca1f25167705c2c6b3
|
7
|
+
data.tar.gz: 7a63c7f78bb3d884fb9e88283ddc653d8963a1c347c17ec7b3f6a4efc27f345e8a8c5bf37027b4d5ff261e4cb65143c727532e6fc03e810625c95b4abe54af84
|
data/lib/bitfields.rb
CHANGED
@@ -38,19 +38,6 @@ module Bitfields
|
|
38
38
|
bitfields
|
39
39
|
end
|
40
40
|
|
41
|
-
def self.ar_3?
|
42
|
-
defined?(ActiveRecord::VERSION::MAJOR) and ActiveRecord::VERSION::MAJOR >= 3
|
43
|
-
end
|
44
|
-
|
45
|
-
# AR 3+ -> :scope, below :named_scope
|
46
|
-
def self.ar_scoping_method
|
47
|
-
if ar_3?
|
48
|
-
:scope
|
49
|
-
else
|
50
|
-
:named_scope
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
41
|
module ClassMethods
|
55
42
|
def bitfield(column, *args)
|
56
43
|
column = column.to_sym
|
@@ -99,9 +86,8 @@ module Bitfields
|
|
99
86
|
define_method("#{bit_name}=") { |value| set_bitfield_value(bit_name, value) }
|
100
87
|
|
101
88
|
if options[:scopes] != false
|
102
|
-
|
103
|
-
|
104
|
-
send scoping_method, "not_#{bit_name}", bitfield_scope_options(bit_name => false)
|
89
|
+
scope bit_name, bitfield_scope_options(bit_name => true)
|
90
|
+
scope "not_#{bit_name}", bitfield_scope_options(bit_name => false)
|
105
91
|
end
|
106
92
|
end
|
107
93
|
|
@@ -109,13 +95,7 @@ module Bitfields
|
|
109
95
|
end
|
110
96
|
|
111
97
|
def bitfield_scope_options(bit_values)
|
112
|
-
|
113
|
-
|
114
|
-
if Bitfields.ar_3?
|
115
|
-
lambda { where(sql) }
|
116
|
-
else
|
117
|
-
{:conditions => sql}
|
118
|
-
end
|
98
|
+
-> { where(bitfield_sql(bit_values)) }
|
119
99
|
end
|
120
100
|
|
121
101
|
def bitfield_sql_by_column(column, bit_values, options={})
|
@@ -167,6 +147,13 @@ module Bitfields
|
|
167
147
|
Hash[self.class.bitfields[column.to_sym].map{|bit_name, _| [bit_name, bitfield_value(bit_name)]}]
|
168
148
|
end
|
169
149
|
|
150
|
+
def bitfield_changes
|
151
|
+
self.class.bitfields.values.flat_map(&:keys).each_with_object({}) do |bit, changes|
|
152
|
+
old, current = bitfield_value_was(bit), bitfield_value(bit)
|
153
|
+
changes[bit.to_s] = [old, current] unless old == current
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
170
157
|
private
|
171
158
|
|
172
159
|
def bitfield_value(bit_name)
|
@@ -174,16 +161,17 @@ module Bitfields
|
|
174
161
|
current_value & bit != 0
|
175
162
|
end
|
176
163
|
|
164
|
+
def bitfield_value_was(bit_name)
|
165
|
+
column, bit, _ = bitfield_info(bit_name)
|
166
|
+
send("#{column}_was") & bit != 0
|
167
|
+
end
|
168
|
+
|
177
169
|
def set_bitfield_value(bit_name, value)
|
178
170
|
column, bit, current_value = bitfield_info(bit_name)
|
179
171
|
new_value = TRUE_VALUES.include?(value)
|
180
172
|
old_value = bitfield_value(bit_name)
|
181
173
|
return if new_value == old_value
|
182
174
|
|
183
|
-
if defined? changed_attributes
|
184
|
-
send(:changed_attributes).merge!(bit_name.to_s => old_value)
|
185
|
-
end
|
186
|
-
|
187
175
|
# 8 + 1 == 9 // 8 + 8 == 8 // 1 - 8 == 1 // 8 - 8 == 0
|
188
176
|
new_bits = if new_value then current_value | bit else (current_value | bit) - bit end
|
189
177
|
send("#{column}=", new_bits)
|
data/lib/bitfields/rspec.rb
CHANGED
@@ -6,16 +6,15 @@ RSpec::Matchers.define :have_a_bitfield do |field|
|
|
6
6
|
klass.respond_to?("#{field}=")
|
7
7
|
end
|
8
8
|
|
9
|
-
|
9
|
+
failure_message do |klass|
|
10
10
|
"expected #{expected.join} to be a bitfield property defined on #{klass}"
|
11
11
|
end
|
12
12
|
|
13
|
-
|
13
|
+
failure_message_when_negated do |klass|
|
14
14
|
"expected #{expected.join} to NOT be a bitfield property defined on #{klass}"
|
15
15
|
end
|
16
16
|
|
17
17
|
description do
|
18
18
|
"be a bitfield on #{expected}"
|
19
19
|
end
|
20
|
-
|
21
20
|
end
|
data/lib/bitfields/version.rb
CHANGED
metadata
CHANGED
@@ -1,75 +1,131 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitfields
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.5.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Michael Grosser
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
11
|
+
date: 2015-01-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: wwtd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bump
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
14
97
|
description:
|
15
98
|
email: michael@grosser.it
|
16
99
|
executables: []
|
17
100
|
extensions: []
|
18
101
|
extra_rdoc_files: []
|
19
102
|
files:
|
20
|
-
- .travis.yml
|
21
|
-
- Appraisals
|
22
|
-
- Gemfile
|
23
|
-
- Gemfile.lock
|
24
|
-
- Rakefile
|
25
103
|
- Readme.md
|
26
|
-
- benchmark/bit_operator_vs_in.rb
|
27
|
-
- bitfields.gemspec
|
28
|
-
- gemfiles/activerecord_2.3.gemfile
|
29
|
-
- gemfiles/activerecord_2.3.gemfile.lock
|
30
|
-
- gemfiles/activerecord_3.0.gemfile
|
31
|
-
- gemfiles/activerecord_3.0.gemfile.lock
|
32
|
-
- gemfiles/activerecord_3.1.gemfile
|
33
|
-
- gemfiles/activerecord_3.1.gemfile.lock
|
34
|
-
- gemfiles/activerecord_3.2.gemfile
|
35
|
-
- gemfiles/activerecord_3.2.gemfile.lock
|
36
|
-
- gemfiles/activerecord_4.0.gemfile
|
37
|
-
- gemfiles/activerecord_4.0.gemfile.lock
|
38
104
|
- lib/bitfields.rb
|
39
105
|
- lib/bitfields/rspec.rb
|
40
106
|
- lib/bitfields/version.rb
|
41
|
-
|
42
|
-
- spec/database.rb
|
43
|
-
- spec/spec_helper.rb
|
44
|
-
homepage: http://github.com/grosser/bitfields
|
107
|
+
homepage: https://github.com/grosser/bitfields
|
45
108
|
licenses:
|
46
109
|
- MIT
|
110
|
+
metadata: {}
|
47
111
|
post_install_message:
|
48
112
|
rdoc_options: []
|
49
113
|
require_paths:
|
50
114
|
- lib
|
51
115
|
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
-
none: false
|
53
116
|
requirements:
|
54
|
-
- -
|
117
|
+
- - ">="
|
55
118
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
57
|
-
segments:
|
58
|
-
- 0
|
59
|
-
hash: 950427918472941761
|
119
|
+
version: 1.9.3
|
60
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
121
|
requirements:
|
63
|
-
- -
|
122
|
+
- - ">="
|
64
123
|
- !ruby/object:Gem::Version
|
65
124
|
version: '0'
|
66
|
-
segments:
|
67
|
-
- 0
|
68
|
-
hash: 950427918472941761
|
69
125
|
requirements: []
|
70
126
|
rubyforge_project:
|
71
|
-
rubygems_version:
|
127
|
+
rubygems_version: 2.2.2
|
72
128
|
signing_key:
|
73
|
-
specification_version:
|
129
|
+
specification_version: 4
|
74
130
|
summary: Save migrations and columns by storing multiple booleans in a single integer
|
75
131
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
rvm:
|
2
|
-
- 1.8.7
|
3
|
-
- 1.9.3
|
4
|
-
- 2.0.0
|
5
|
-
gemfile:
|
6
|
-
- gemfiles/activerecord_2.3.gemfile
|
7
|
-
- gemfiles/activerecord_3.0.gemfile
|
8
|
-
- gemfiles/activerecord_3.1.gemfile
|
9
|
-
- gemfiles/activerecord_3.2.gemfile
|
10
|
-
- gemfiles/activerecord_4.0.gemfile
|
11
|
-
matrix:
|
12
|
-
exclude:
|
13
|
-
- rvm: 1.8.7
|
14
|
-
gemfile: gemfiles/activerecord_4.0.gemfile
|
15
|
-
- rvm: 2.0.0
|
16
|
-
gemfile: gemfiles/activerecord_2.3.gemfile
|
17
|
-
- rvm: 2.0.0
|
18
|
-
gemfile: gemfiles/activerecord_3.0.gemfile
|
19
|
-
script: rake spec
|
data/Appraisals
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
bitfields (0.4.3)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activemodel (3.2.11)
|
10
|
-
activesupport (= 3.2.11)
|
11
|
-
builder (~> 3.0.0)
|
12
|
-
activerecord (3.2.11)
|
13
|
-
activemodel (= 3.2.11)
|
14
|
-
activesupport (= 3.2.11)
|
15
|
-
arel (~> 3.0.2)
|
16
|
-
tzinfo (~> 0.3.29)
|
17
|
-
activesupport (3.2.11)
|
18
|
-
i18n (~> 0.6)
|
19
|
-
multi_json (~> 1.0)
|
20
|
-
appraisal (0.5.1)
|
21
|
-
bundler
|
22
|
-
rake
|
23
|
-
arel (3.0.2)
|
24
|
-
builder (3.0.4)
|
25
|
-
bump (0.3.9)
|
26
|
-
diff-lcs (1.1.3)
|
27
|
-
i18n (0.6.1)
|
28
|
-
multi_json (1.5.0)
|
29
|
-
rake (10.0.3)
|
30
|
-
rspec (2.12.0)
|
31
|
-
rspec-core (~> 2.12.0)
|
32
|
-
rspec-expectations (~> 2.12.0)
|
33
|
-
rspec-mocks (~> 2.12.0)
|
34
|
-
rspec-core (2.12.2)
|
35
|
-
rspec-expectations (2.12.1)
|
36
|
-
diff-lcs (~> 1.1.3)
|
37
|
-
rspec-mocks (2.12.1)
|
38
|
-
sqlite3 (1.3.7)
|
39
|
-
tzinfo (0.3.35)
|
40
|
-
|
41
|
-
PLATFORMS
|
42
|
-
ruby
|
43
|
-
|
44
|
-
DEPENDENCIES
|
45
|
-
activerecord
|
46
|
-
appraisal
|
47
|
-
bitfields!
|
48
|
-
bump
|
49
|
-
rake
|
50
|
-
rspec (~> 2)
|
51
|
-
sqlite3
|
data/Rakefile
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
bit_counts = [2,3,4,6,8,10,12,14]
|
2
|
-
record_counts = (1..10).to_a.map{|i| i * 100_000 }
|
3
|
-
use_index = true
|
4
|
-
database = ARGV[0]
|
5
|
-
|
6
|
-
puts "running#{' with index' if use_index} on #{database}"
|
7
|
-
|
8
|
-
$LOAD_PATH.unshift File.expand_path('lib')
|
9
|
-
require 'rubygems'
|
10
|
-
gem 'gchartrb'
|
11
|
-
require 'google_chart'
|
12
|
-
require 'active_record'
|
13
|
-
require 'bitfields'
|
14
|
-
|
15
|
-
def benchmark
|
16
|
-
t = Time.now.to_f
|
17
|
-
yield
|
18
|
-
Time.now.to_f - t
|
19
|
-
end
|
20
|
-
|
21
|
-
def create(bit_counts, count)
|
22
|
-
count.times do |i|
|
23
|
-
columns = bit_counts.map do |bits_count|
|
24
|
-
["bit_#{bits_count}", rand(2**(bits_count-1))]
|
25
|
-
end
|
26
|
-
User.create!(Hash[columns])
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def connect(db)
|
31
|
-
if db == 'mysql'
|
32
|
-
puts 'using mysql'
|
33
|
-
ActiveRecord::Base.establish_connection(
|
34
|
-
:adapter => "mysql",
|
35
|
-
:database => "bitfields_benchmark"
|
36
|
-
)
|
37
|
-
else
|
38
|
-
puts 'using sqlite'
|
39
|
-
ActiveRecord::Base.establish_connection(
|
40
|
-
:adapter => "sqlite3",
|
41
|
-
:database => ":memory:"
|
42
|
-
)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def create_model_table(bit_counts, use_index)
|
47
|
-
ActiveRecord::Schema.define(:version => 2) do
|
48
|
-
drop_table :users rescue nil
|
49
|
-
create_table :users do |t|
|
50
|
-
bit_counts.each do |bit_count|
|
51
|
-
t.integer "bit_#{bit_count}", :default => 0, :null => false
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
if use_index
|
56
|
-
bit_counts.each do |bit_count|
|
57
|
-
add_index :users, "bit_#{bit_count}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def create_model_fields(bit_counts)
|
64
|
-
puts "creating model"
|
65
|
-
User.class_eval do
|
66
|
-
include Bitfields
|
67
|
-
|
68
|
-
# this takes long for 15/20 bits, maybe needs to be optimized..
|
69
|
-
bit_counts.each do |bits_count|
|
70
|
-
bits = {}
|
71
|
-
0.upto(bits_count-1) do |bit|
|
72
|
-
bits[2**bit] = "bit_#{bits_count}_#{bit}"
|
73
|
-
end
|
74
|
-
|
75
|
-
bitfield "bit_#{bits_count}", bits
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_speed(bit_counts, query_mode)
|
81
|
-
result = bit_counts.map do |bit_count|
|
82
|
-
sql = User.bitfield_sql({"bit_#{bit_count}_1" => true}, :query_mode => query_mode)
|
83
|
-
sql = "select SQL_NO_CACHE count(*) from users where #{sql}"
|
84
|
-
# puts User.connection.select_all("EXPLAIN #{sql}").inspect
|
85
|
-
# puts sql[0..100]
|
86
|
-
time = benchmark do
|
87
|
-
User.connection.execute sql
|
88
|
-
end
|
89
|
-
puts "#{bit_count} -> #{time}"
|
90
|
-
[bit_count, time]
|
91
|
-
end
|
92
|
-
Hash[result]
|
93
|
-
end
|
94
|
-
|
95
|
-
connect(database)
|
96
|
-
create_model_table(bit_counts, use_index)
|
97
|
-
class User < ActiveRecord::Base
|
98
|
-
end
|
99
|
-
create_model_fields(bit_counts)
|
100
|
-
|
101
|
-
puts "creating test data"
|
102
|
-
last = 0
|
103
|
-
|
104
|
-
# collect graph data
|
105
|
-
graphs = {:bit => {}, :in => {}}
|
106
|
-
record_counts.each do |record_count|
|
107
|
-
create(bit_counts, record_count-last)
|
108
|
-
last = record_count
|
109
|
-
|
110
|
-
puts "testing with #{record_count} records -- bit_operator"
|
111
|
-
graphs[:bit][record_count] = test_speed(bit_counts, :bit_operator)
|
112
|
-
|
113
|
-
puts "testing with #{record_count} records -- in_list"
|
114
|
-
graphs[:in][record_count] = test_speed(bit_counts, :in_list)
|
115
|
-
end
|
116
|
-
|
117
|
-
# print them
|
118
|
-
colors = {:bit => 'xx0000', :in => '0000xx'}
|
119
|
-
alpha_num = (('0'..'9').to_a + ('a'..'f').to_a).reverse
|
120
|
-
title = "bit-operator vs IN -- #{use_index ? 'with' : 'without'} index"
|
121
|
-
url = GoogleChart::LineChart.new('600x500', title, false) do |line|
|
122
|
-
max_y = 0
|
123
|
-
graphs.each do |type, line_data|
|
124
|
-
bit_counts.each do |bit_count|
|
125
|
-
data = record_counts.map{|rc| line_data[rc][bit_count] }
|
126
|
-
name = "#{bit_count}bits (#{type})"
|
127
|
-
color = colors[type].sub('xx', alpha_num[bit_counts.index(bit_count)]*2)
|
128
|
-
line.data(name, data, color)
|
129
|
-
max_y = [data.max, max_y].max
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
line.axis :x, :labels => record_counts.map{|c|"#{c/1000}K"}
|
134
|
-
line.axis :y, :labels => ['0', "%.3fms" % [max_y*1000]]
|
135
|
-
end.to_url
|
136
|
-
|
137
|
-
puts url
|
data/bitfields.gemspec
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
-
name = "bitfields"
|
3
|
-
require "#{name}/version"
|
4
|
-
|
5
|
-
Gem::Specification.new name, Bitfields::VERSION do |s|
|
6
|
-
s.summary = "Save migrations and columns by storing multiple booleans in a single integer"
|
7
|
-
s.authors = ["Michael Grosser"]
|
8
|
-
s.email = "michael@grosser.it"
|
9
|
-
s.homepage = "http://github.com/grosser/#{name}"
|
10
|
-
s.files = `git ls-files`.split("\n")
|
11
|
-
s.license = 'MIT'
|
12
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/mgrosser/code/tools/bitfields
|
3
|
-
specs:
|
4
|
-
bitfields (0.4.2)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activerecord (2.3.15)
|
10
|
-
activesupport (= 2.3.15)
|
11
|
-
activesupport (2.3.15)
|
12
|
-
appraisal (0.5.1)
|
13
|
-
bundler
|
14
|
-
rake
|
15
|
-
bump (0.3.9)
|
16
|
-
diff-lcs (1.1.3)
|
17
|
-
rake (10.0.3)
|
18
|
-
rspec (2.12.0)
|
19
|
-
rspec-core (~> 2.12.0)
|
20
|
-
rspec-expectations (~> 2.12.0)
|
21
|
-
rspec-mocks (~> 2.12.0)
|
22
|
-
rspec-core (2.12.2)
|
23
|
-
rspec-expectations (2.12.1)
|
24
|
-
diff-lcs (~> 1.1.3)
|
25
|
-
rspec-mocks (2.12.1)
|
26
|
-
sqlite3 (1.3.7)
|
27
|
-
|
28
|
-
PLATFORMS
|
29
|
-
ruby
|
30
|
-
|
31
|
-
DEPENDENCIES
|
32
|
-
activerecord (~> 2.3.0)
|
33
|
-
appraisal
|
34
|
-
bitfields!
|
35
|
-
bump
|
36
|
-
rake
|
37
|
-
rspec (~> 2)
|
38
|
-
sqlite3
|
@@ -1,49 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/mgrosser/code/tools/bitfields
|
3
|
-
specs:
|
4
|
-
bitfields (0.4.2)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activemodel (3.0.19)
|
10
|
-
activesupport (= 3.0.19)
|
11
|
-
builder (~> 2.1.2)
|
12
|
-
i18n (~> 0.5.0)
|
13
|
-
activerecord (3.0.19)
|
14
|
-
activemodel (= 3.0.19)
|
15
|
-
activesupport (= 3.0.19)
|
16
|
-
arel (~> 2.0.10)
|
17
|
-
tzinfo (~> 0.3.23)
|
18
|
-
activesupport (3.0.19)
|
19
|
-
appraisal (0.5.1)
|
20
|
-
bundler
|
21
|
-
rake
|
22
|
-
arel (2.0.10)
|
23
|
-
builder (2.1.2)
|
24
|
-
bump (0.3.9)
|
25
|
-
diff-lcs (1.1.3)
|
26
|
-
i18n (0.5.0)
|
27
|
-
rake (10.0.3)
|
28
|
-
rspec (2.12.0)
|
29
|
-
rspec-core (~> 2.12.0)
|
30
|
-
rspec-expectations (~> 2.12.0)
|
31
|
-
rspec-mocks (~> 2.12.0)
|
32
|
-
rspec-core (2.12.2)
|
33
|
-
rspec-expectations (2.12.1)
|
34
|
-
diff-lcs (~> 1.1.3)
|
35
|
-
rspec-mocks (2.12.1)
|
36
|
-
sqlite3 (1.3.7)
|
37
|
-
tzinfo (0.3.35)
|
38
|
-
|
39
|
-
PLATFORMS
|
40
|
-
ruby
|
41
|
-
|
42
|
-
DEPENDENCIES
|
43
|
-
activerecord (~> 3.0.0)
|
44
|
-
appraisal
|
45
|
-
bitfields!
|
46
|
-
bump
|
47
|
-
rake
|
48
|
-
rspec (~> 2)
|
49
|
-
sqlite3
|
@@ -1,51 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/mgrosser/code/tools/bitfields
|
3
|
-
specs:
|
4
|
-
bitfields (0.4.2)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activemodel (3.1.8)
|
10
|
-
activesupport (= 3.1.8)
|
11
|
-
builder (~> 3.0.0)
|
12
|
-
i18n (~> 0.6)
|
13
|
-
activerecord (3.1.8)
|
14
|
-
activemodel (= 3.1.8)
|
15
|
-
activesupport (= 3.1.8)
|
16
|
-
arel (~> 2.2.3)
|
17
|
-
tzinfo (~> 0.3.29)
|
18
|
-
activesupport (3.1.8)
|
19
|
-
multi_json (>= 1.0, < 1.3)
|
20
|
-
appraisal (0.5.1)
|
21
|
-
bundler
|
22
|
-
rake
|
23
|
-
arel (2.2.3)
|
24
|
-
builder (3.0.4)
|
25
|
-
bump (0.3.9)
|
26
|
-
diff-lcs (1.1.3)
|
27
|
-
i18n (0.6.1)
|
28
|
-
multi_json (1.2.0)
|
29
|
-
rake (10.0.3)
|
30
|
-
rspec (2.12.0)
|
31
|
-
rspec-core (~> 2.12.0)
|
32
|
-
rspec-expectations (~> 2.12.0)
|
33
|
-
rspec-mocks (~> 2.12.0)
|
34
|
-
rspec-core (2.12.2)
|
35
|
-
rspec-expectations (2.12.1)
|
36
|
-
diff-lcs (~> 1.1.3)
|
37
|
-
rspec-mocks (2.12.1)
|
38
|
-
sqlite3 (1.3.7)
|
39
|
-
tzinfo (0.3.35)
|
40
|
-
|
41
|
-
PLATFORMS
|
42
|
-
ruby
|
43
|
-
|
44
|
-
DEPENDENCIES
|
45
|
-
activerecord (~> 3.1.0)
|
46
|
-
appraisal
|
47
|
-
bitfields!
|
48
|
-
bump
|
49
|
-
rake
|
50
|
-
rspec (~> 2)
|
51
|
-
sqlite3
|
@@ -1,51 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/mgrosser/code/tools/bitfields
|
3
|
-
specs:
|
4
|
-
bitfields (0.4.2)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activemodel (3.2.11)
|
10
|
-
activesupport (= 3.2.11)
|
11
|
-
builder (~> 3.0.0)
|
12
|
-
activerecord (3.2.11)
|
13
|
-
activemodel (= 3.2.11)
|
14
|
-
activesupport (= 3.2.11)
|
15
|
-
arel (~> 3.0.2)
|
16
|
-
tzinfo (~> 0.3.29)
|
17
|
-
activesupport (3.2.11)
|
18
|
-
i18n (~> 0.6)
|
19
|
-
multi_json (~> 1.0)
|
20
|
-
appraisal (0.5.1)
|
21
|
-
bundler
|
22
|
-
rake
|
23
|
-
arel (3.0.2)
|
24
|
-
builder (3.0.4)
|
25
|
-
bump (0.3.9)
|
26
|
-
diff-lcs (1.1.3)
|
27
|
-
i18n (0.6.1)
|
28
|
-
multi_json (1.5.0)
|
29
|
-
rake (10.0.3)
|
30
|
-
rspec (2.12.0)
|
31
|
-
rspec-core (~> 2.12.0)
|
32
|
-
rspec-expectations (~> 2.12.0)
|
33
|
-
rspec-mocks (~> 2.12.0)
|
34
|
-
rspec-core (2.12.2)
|
35
|
-
rspec-expectations (2.12.1)
|
36
|
-
diff-lcs (~> 1.1.3)
|
37
|
-
rspec-mocks (2.12.1)
|
38
|
-
sqlite3 (1.3.7)
|
39
|
-
tzinfo (0.3.35)
|
40
|
-
|
41
|
-
PLATFORMS
|
42
|
-
ruby
|
43
|
-
|
44
|
-
DEPENDENCIES
|
45
|
-
activerecord (~> 3.2.0)
|
46
|
-
appraisal
|
47
|
-
bitfields!
|
48
|
-
bump
|
49
|
-
rake
|
50
|
-
rspec (~> 2)
|
51
|
-
sqlite3
|
@@ -1,59 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/mgrosser/code/tools/bitfields
|
3
|
-
specs:
|
4
|
-
bitfields (0.4.2)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activemodel (4.0.0.rc1)
|
10
|
-
activesupport (= 4.0.0.rc1)
|
11
|
-
builder (~> 3.1.0)
|
12
|
-
activerecord (4.0.0.rc1)
|
13
|
-
activemodel (= 4.0.0.rc1)
|
14
|
-
activerecord-deprecated_finders (~> 1.0.2)
|
15
|
-
activesupport (= 4.0.0.rc1)
|
16
|
-
arel (~> 4.0.0)
|
17
|
-
activerecord-deprecated_finders (1.0.2)
|
18
|
-
activesupport (4.0.0.rc1)
|
19
|
-
i18n (~> 0.6, >= 0.6.4)
|
20
|
-
minitest (~> 4.2)
|
21
|
-
multi_json (~> 1.3)
|
22
|
-
thread_safe (~> 0.1)
|
23
|
-
tzinfo (~> 0.3.37)
|
24
|
-
appraisal (0.5.2)
|
25
|
-
bundler
|
26
|
-
rake
|
27
|
-
arel (4.0.0)
|
28
|
-
atomic (1.1.9)
|
29
|
-
builder (3.1.4)
|
30
|
-
bump (0.4.1)
|
31
|
-
diff-lcs (1.2.4)
|
32
|
-
i18n (0.6.4)
|
33
|
-
minitest (4.7.4)
|
34
|
-
multi_json (1.7.3)
|
35
|
-
rake (10.0.4)
|
36
|
-
rspec (2.13.0)
|
37
|
-
rspec-core (~> 2.13.0)
|
38
|
-
rspec-expectations (~> 2.13.0)
|
39
|
-
rspec-mocks (~> 2.13.0)
|
40
|
-
rspec-core (2.13.1)
|
41
|
-
rspec-expectations (2.13.0)
|
42
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
43
|
-
rspec-mocks (2.13.1)
|
44
|
-
sqlite3 (1.3.7)
|
45
|
-
thread_safe (0.1.0)
|
46
|
-
atomic
|
47
|
-
tzinfo (0.3.37)
|
48
|
-
|
49
|
-
PLATFORMS
|
50
|
-
ruby
|
51
|
-
|
52
|
-
DEPENDENCIES
|
53
|
-
activerecord (~> 4.0.0.rc)
|
54
|
-
appraisal
|
55
|
-
bitfields!
|
56
|
-
bump
|
57
|
-
rake
|
58
|
-
rspec (~> 2)
|
59
|
-
sqlite3
|
data/spec/bitfields_spec.rb
DELETED
@@ -1,450 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class User < ActiveRecord::Base
|
4
|
-
include Bitfields
|
5
|
-
bitfield :bits, 1 => :seller, 2 => :insane, 4 => :stupid
|
6
|
-
end
|
7
|
-
|
8
|
-
class UserWithBitfieldOptions < ActiveRecord::Base
|
9
|
-
include Bitfields
|
10
|
-
bitfield :bits, 1 => :seller, 2 => :insane, 4 => :stupid, :scopes => false
|
11
|
-
end
|
12
|
-
|
13
|
-
class MultiBitUser < ActiveRecord::Base
|
14
|
-
self.table_name = 'users'
|
15
|
-
include Bitfields
|
16
|
-
bitfield :bits, 1 => :seller, 2 => :insane, 4 => :stupid
|
17
|
-
bitfield :more_bits, 1 => :one, 2 => :two, 4 => :four
|
18
|
-
end
|
19
|
-
|
20
|
-
class UserWithoutScopes < ActiveRecord::Base
|
21
|
-
self.table_name = 'users'
|
22
|
-
include Bitfields
|
23
|
-
bitfield :bits, 1 => :seller, 2 => :insane, 4 => :stupid, :scopes => false
|
24
|
-
end
|
25
|
-
|
26
|
-
class UserWithoutSetBitfield < ActiveRecord::Base
|
27
|
-
self.table_name = 'users'
|
28
|
-
include Bitfields
|
29
|
-
end
|
30
|
-
|
31
|
-
class InheritedUser < User
|
32
|
-
end
|
33
|
-
|
34
|
-
class GrandchildInheritedUser < InheritedUser
|
35
|
-
end
|
36
|
-
|
37
|
-
# other children should not disturb the inheritance
|
38
|
-
class OtherInheritedUser < UserWithoutSetBitfield
|
39
|
-
self.table_name = 'users'
|
40
|
-
bitfield :bits, 1 => :seller_inherited
|
41
|
-
end
|
42
|
-
|
43
|
-
class InheritedUserWithoutSetBitfield < UserWithoutSetBitfield
|
44
|
-
end
|
45
|
-
|
46
|
-
class OverwrittenUser < User
|
47
|
-
bitfield :bits, 1 => :seller_inherited
|
48
|
-
end
|
49
|
-
|
50
|
-
class BitOperatorMode < ActiveRecord::Base
|
51
|
-
self.table_name = 'users'
|
52
|
-
include Bitfields
|
53
|
-
bitfield :bits, 1 => :seller, 2 => :insane, :query_mode => :bit_operator
|
54
|
-
end
|
55
|
-
|
56
|
-
class WithoutThePowerOfTwo < ActiveRecord::Base
|
57
|
-
self.table_name = 'users'
|
58
|
-
include Bitfields
|
59
|
-
bitfield :bits, :seller, :insane, :stupid, :query_mode => :bit_operator
|
60
|
-
end
|
61
|
-
|
62
|
-
class WithoutThePowerOfTwoWithoutOptions < ActiveRecord::Base
|
63
|
-
self.table_name = 'users'
|
64
|
-
include Bitfields
|
65
|
-
bitfield :bits, :seller, :insane
|
66
|
-
end
|
67
|
-
|
68
|
-
class CheckRaise < ActiveRecord::Base
|
69
|
-
self.table_name = 'users'
|
70
|
-
include Bitfields
|
71
|
-
end
|
72
|
-
|
73
|
-
class ManyBitsUser < User
|
74
|
-
self.table_name = 'users'
|
75
|
-
end
|
76
|
-
|
77
|
-
class InitializedUser < User
|
78
|
-
self.table_name = 'users'
|
79
|
-
bitfield :bits, 1 => :seller, 2 => :insane, 4 => :stupid, :scopes => false
|
80
|
-
|
81
|
-
after_initialize do
|
82
|
-
self.seller = true
|
83
|
-
self.insane = false
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
describe Bitfields do
|
88
|
-
before do
|
89
|
-
User.delete_all
|
90
|
-
end
|
91
|
-
|
92
|
-
def pending_if(condition, &block)
|
93
|
-
if condition
|
94
|
-
pending(&block)
|
95
|
-
else
|
96
|
-
yield
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe :bitfields do
|
101
|
-
it "parses them correctly" do
|
102
|
-
User.bitfields.should == {:bits => {:seller => 1, :insane => 2, :stupid => 4}}
|
103
|
-
end
|
104
|
-
|
105
|
-
it "is fast for huge number of bits" do
|
106
|
-
bits = {}
|
107
|
-
0.upto(20) do |bit|
|
108
|
-
bits[2**bit] = "my_bit_#{bit}"
|
109
|
-
end
|
110
|
-
|
111
|
-
Timeout.timeout(0.2) do
|
112
|
-
ManyBitsUser.class_eval{ bitfield :bits, bits }
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
describe :bitfield_options do
|
118
|
-
it "parses them correctly when not set" do
|
119
|
-
User.bitfield_options.should == {:bits => {}}
|
120
|
-
end
|
121
|
-
|
122
|
-
it "parses them correctly when set" do
|
123
|
-
UserWithBitfieldOptions.bitfield_options.should == {:bits => {:scopes => false}}
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe :bitfield_column do
|
128
|
-
it "raises a nice error when i use a unknown bitfield" do
|
129
|
-
lambda{
|
130
|
-
User.bitfield_column(:xxx)
|
131
|
-
}.should raise_error(RuntimeError, 'Unknown bitfield xxx')
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
describe :bitfield_values do
|
136
|
-
it "contains all bits with values" do
|
137
|
-
User.new.bitfield_values(:bits).should == {:insane=>false, :stupid=>false, :seller=>false}
|
138
|
-
User.new(:bits => 15).bitfield_values(:bits).should == {:insane=>true, :stupid=>true, :seller=>true}
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
describe 'attribute accessors' do
|
143
|
-
it "has everything on false by default" do
|
144
|
-
User.new.seller.should == false
|
145
|
-
User.new.seller?.should == false
|
146
|
-
end
|
147
|
-
|
148
|
-
it "is true when set to true" do
|
149
|
-
User.new(:seller => true).seller.should == true
|
150
|
-
end
|
151
|
-
|
152
|
-
it "is true when set to truthy" do
|
153
|
-
User.new(:seller => 1).seller.should == true
|
154
|
-
end
|
155
|
-
|
156
|
-
it "is false when set to false" do
|
157
|
-
User.new(:seller => false).seller.should == false
|
158
|
-
end
|
159
|
-
|
160
|
-
it "is false when set to falsy" do
|
161
|
-
User.new(:seller => 'false').seller.should == false
|
162
|
-
end
|
163
|
-
|
164
|
-
it "stays true when set to true twice" do
|
165
|
-
u = User.new
|
166
|
-
u.seller = true
|
167
|
-
u.seller = true
|
168
|
-
u.seller.should == true
|
169
|
-
u.bits.should == 1
|
170
|
-
end
|
171
|
-
|
172
|
-
it "stays false when set to false twice" do
|
173
|
-
u = User.new(:bits => 3)
|
174
|
-
u.seller = false
|
175
|
-
u.seller = false
|
176
|
-
u.seller.should == false
|
177
|
-
u.bits.should == 2
|
178
|
-
end
|
179
|
-
|
180
|
-
it "changes the bits when setting to false" do
|
181
|
-
user = User.new(:bits => 7)
|
182
|
-
user.seller = false
|
183
|
-
user.bits.should == 6
|
184
|
-
end
|
185
|
-
|
186
|
-
it "does not get negative when unsetting high bits" do
|
187
|
-
user = User.new(:seller => true)
|
188
|
-
user.stupid = false
|
189
|
-
user.bits.should == 1
|
190
|
-
end
|
191
|
-
|
192
|
-
it "changes the bits when setting to true" do
|
193
|
-
user = User.new(:bits => 2)
|
194
|
-
user.seller = true
|
195
|
-
user.bits.should == 3
|
196
|
-
end
|
197
|
-
|
198
|
-
it "does not get too high when setting high bits" do
|
199
|
-
user = User.new(:bits => 7)
|
200
|
-
user.seller = true
|
201
|
-
user.bits.should == 7
|
202
|
-
end
|
203
|
-
|
204
|
-
describe 'changes' do
|
205
|
-
it "has no changes by defaut" do
|
206
|
-
User.new.changes.should == {}
|
207
|
-
end
|
208
|
-
|
209
|
-
it "records a change when setting" do
|
210
|
-
User.new(:seller => true).changes.should == {'seller' => [false, true], 'bits' => [0,1]}
|
211
|
-
end
|
212
|
-
|
213
|
-
it "records a change when unsetting" do
|
214
|
-
u = User.create!(:seller => true)
|
215
|
-
u.seller = false
|
216
|
-
u.changes.should == {'seller' => [true, false], 'bits' => [1,0]}
|
217
|
-
end
|
218
|
-
|
219
|
-
it "does not track duplicate changes" do
|
220
|
-
User.create!(:seller => false).changes.should == {}
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
describe :bitfield_sql do
|
226
|
-
it "includes true states" do
|
227
|
-
User.bitfield_sql({:insane => true}, :query_mode => :in_list).should == 'users.bits IN (2,3,6,7)' # 2, 1+2, 2+4, 1+2+4
|
228
|
-
end
|
229
|
-
|
230
|
-
it "includes invalid states" do
|
231
|
-
User.bitfield_sql({:insane => false}, :query_mode => :in_list).should == 'users.bits IN (0,1,4,5)' # 0, 1, 4, 4+1
|
232
|
-
end
|
233
|
-
|
234
|
-
it "can combine multiple fields" do
|
235
|
-
User.bitfield_sql({:seller => true, :insane => true}, :query_mode => :in_list).should == 'users.bits IN (3,7)' # 1+2, 1+2+4
|
236
|
-
end
|
237
|
-
|
238
|
-
it "can combine multiple fields with different values" do
|
239
|
-
User.bitfield_sql({:seller => true, :insane => false}, :query_mode => :in_list).should == 'users.bits IN (1,5)' # 1, 1+4
|
240
|
-
end
|
241
|
-
|
242
|
-
it "combines multiple columns into one sql" do
|
243
|
-
sql = MultiBitUser.bitfield_sql({:seller => true, :insane => false, :one => true, :four => true}, :query_mode => :in_list)
|
244
|
-
sql.should == 'users.bits IN (1,5) AND users.more_bits IN (5,7)' # 1, 1+4 AND 1+4, 1+2+4
|
245
|
-
end
|
246
|
-
|
247
|
-
it "produces working sql" do
|
248
|
-
u1 = MultiBitUser.create!(:seller => true, :one => true)
|
249
|
-
u2 = MultiBitUser.create!(:seller => true, :one => false)
|
250
|
-
u3 = MultiBitUser.create!(:seller => false, :one => false)
|
251
|
-
conditions = MultiBitUser.bitfield_sql({:seller => true, :one => false}, :query_mode => :in_list)
|
252
|
-
result = if Bitfields.ar_3?
|
253
|
-
MultiBitUser.where(conditions)
|
254
|
-
else
|
255
|
-
MultiBitUser.all(:conditions => conditions)
|
256
|
-
end
|
257
|
-
result.should == [u2]
|
258
|
-
end
|
259
|
-
|
260
|
-
describe 'with bit operator mode' do
|
261
|
-
it "generates bit-operator sql" do
|
262
|
-
BitOperatorMode.bitfield_sql(:seller => true).should == '(users.bits & 1) = 1'
|
263
|
-
end
|
264
|
-
|
265
|
-
it "generates sql for each bit" do
|
266
|
-
BitOperatorMode.bitfield_sql(:seller => true, :insane => false).should == '(users.bits & 3) = 1'
|
267
|
-
end
|
268
|
-
|
269
|
-
it "generates working sql" do
|
270
|
-
u1 = BitOperatorMode.create!(:seller => true, :insane => true)
|
271
|
-
u2 = BitOperatorMode.create!(:seller => true, :insane => false)
|
272
|
-
u3 = BitOperatorMode.create!(:seller => false, :insane => false)
|
273
|
-
|
274
|
-
conditions = MultiBitUser.bitfield_sql(:seller => true, :insane => false)
|
275
|
-
result = if Bitfields.ar_3?
|
276
|
-
BitOperatorMode.where(conditions)
|
277
|
-
else
|
278
|
-
BitOperatorMode.all(:conditions => conditions)
|
279
|
-
end
|
280
|
-
result.should == [u2]
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
describe 'without the power of two' do
|
285
|
-
it 'uses correct bits' do
|
286
|
-
u = WithoutThePowerOfTwo.create!(:seller => false, :insane => true, :stupid => true)
|
287
|
-
u.bits.should == 6
|
288
|
-
end
|
289
|
-
|
290
|
-
it 'has all fields' do
|
291
|
-
u = WithoutThePowerOfTwo.create!(:seller => false, :insane => true)
|
292
|
-
u.seller.should == false
|
293
|
-
u.insane.should == true
|
294
|
-
WithoutThePowerOfTwo.bitfield_options.should == {:bits=>{:query_mode=>:bit_operator}}
|
295
|
-
end
|
296
|
-
|
297
|
-
it "can e built without options" do
|
298
|
-
u = WithoutThePowerOfTwoWithoutOptions.create!(:seller => false, :insane => true)
|
299
|
-
u.seller.should == false
|
300
|
-
u.insane.should == true
|
301
|
-
WithoutThePowerOfTwoWithoutOptions.bitfield_options.should == {:bits=>{}}
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
it "checks that bitfields are unique" do
|
306
|
-
lambda{
|
307
|
-
CheckRaise.class_eval do
|
308
|
-
bitfield :foo, :bar, :baz, :bar
|
309
|
-
end
|
310
|
-
}.should raise_error(Bitfields::DuplicateBitNameError)
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
describe :set_bitfield_sql do
|
315
|
-
it "sets a single bit" do
|
316
|
-
User.set_bitfield_sql(:seller => true).should == 'bits = (bits | 1) - 0'
|
317
|
-
end
|
318
|
-
|
319
|
-
it "unsets a single bit" do
|
320
|
-
User.set_bitfield_sql(:seller => false).should == 'bits = (bits | 1) - 1'
|
321
|
-
end
|
322
|
-
|
323
|
-
it "sets multiple bits" do
|
324
|
-
User.set_bitfield_sql(:seller => true, :insane => true).should == 'bits = (bits | 3) - 0'
|
325
|
-
end
|
326
|
-
|
327
|
-
it "unsets multiple bits" do
|
328
|
-
User.set_bitfield_sql(:seller => false, :insane => false).should == 'bits = (bits | 3) - 3'
|
329
|
-
end
|
330
|
-
|
331
|
-
it "sets and unsets in one command" do
|
332
|
-
User.set_bitfield_sql(:seller => false, :insane => true).should == 'bits = (bits | 3) - 1'
|
333
|
-
end
|
334
|
-
|
335
|
-
it "sets and unsets for multiple columns in one sql" do
|
336
|
-
sql = MultiBitUser.set_bitfield_sql(:seller => false, :insane => true, :one => true, :two => false)
|
337
|
-
sql.should == "bits = (bits | 3) - 1, more_bits = (more_bits | 3) - 2"
|
338
|
-
end
|
339
|
-
|
340
|
-
it "produces working sql" do
|
341
|
-
u = MultiBitUser.create!(:seller => true, :insane => true, :stupid => false, :one => true, :two => false, :four => false)
|
342
|
-
sql = MultiBitUser.set_bitfield_sql(:seller => false, :insane => true, :one => true, :two => false)
|
343
|
-
MultiBitUser.update_all(sql)
|
344
|
-
u.reload
|
345
|
-
u.seller.should == false
|
346
|
-
u.insane.should == true
|
347
|
-
u.stupid.should == false
|
348
|
-
u.one.should == true
|
349
|
-
u.two.should == false
|
350
|
-
u.four.should == false
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
describe 'named scopes' do
|
355
|
-
before do
|
356
|
-
@u1 = User.create!(:seller => true, :insane => false)
|
357
|
-
@u2 = User.create!(:seller => true, :insane => true)
|
358
|
-
end
|
359
|
-
|
360
|
-
it "creates them when nothing was passed" do
|
361
|
-
User.respond_to?(:seller).should == true
|
362
|
-
User.respond_to?(:not_seller).should == true
|
363
|
-
end
|
364
|
-
|
365
|
-
it "does not create them when false was passed" do
|
366
|
-
UserWithoutScopes.respond_to?(:seller).should == false
|
367
|
-
UserWithoutScopes.respond_to?(:not_seller).should == false
|
368
|
-
end
|
369
|
-
|
370
|
-
it "produces working positive scopes" do
|
371
|
-
User.insane.seller.to_a.should == [@u2]
|
372
|
-
end
|
373
|
-
|
374
|
-
it "produces working negative scopes" do
|
375
|
-
User.not_insane.seller.to_a.should == [@u1]
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
|
-
describe 'overwriting' do
|
380
|
-
it "does not change base class" do
|
381
|
-
OverwrittenUser.bitfields[:bits][:seller_inherited].should_not == nil
|
382
|
-
User.bitfields[:bits][:seller_inherited].should == nil
|
383
|
-
end
|
384
|
-
|
385
|
-
it "has inherited methods" do
|
386
|
-
User.respond_to?(:seller).should == true
|
387
|
-
OverwrittenUser.respond_to?(:seller).should == true
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
describe 'inheritance' do
|
392
|
-
it "knows overwritten values and normal" do
|
393
|
-
User.bitfields.should == {:bits=>{:seller=>1, :insane=>2, :stupid=>4}}
|
394
|
-
OverwrittenUser.bitfields.should == {:bits=>{:seller_inherited=>1}}
|
395
|
-
end
|
396
|
-
|
397
|
-
it "knows overwritten values when overwriting" do
|
398
|
-
OverwrittenUser.bitfield_column(:seller_inherited).should == :bits
|
399
|
-
end
|
400
|
-
|
401
|
-
it "does not know old values when overwriting" do
|
402
|
-
expect{
|
403
|
-
OverwrittenUser.bitfield_column(:seller)
|
404
|
-
}.to raise_error
|
405
|
-
end
|
406
|
-
|
407
|
-
it "knows inherited values without overwriting" do
|
408
|
-
InheritedUser.bitfield_column(:seller).should == :bits
|
409
|
-
end
|
410
|
-
|
411
|
-
it "has inherited scopes" do
|
412
|
-
InheritedUser.should respond_to(:not_seller)
|
413
|
-
end
|
414
|
-
|
415
|
-
it "has inherited methods" do
|
416
|
-
InheritedUser.new.should respond_to(:seller?)
|
417
|
-
end
|
418
|
-
|
419
|
-
it "knows grandchild inherited values without overwriting" do
|
420
|
-
GrandchildInheritedUser.bitfield_column(:seller).should == :bits
|
421
|
-
end
|
422
|
-
|
423
|
-
it "inherits no bitfields for a user without bitfields set" do
|
424
|
-
InheritedUserWithoutSetBitfield.bitfields.should be_nil
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
428
|
-
describe 'initializers' do
|
429
|
-
it "sets defaults" do
|
430
|
-
pending_if(ActiveRecord::VERSION::MAJOR == 2) do
|
431
|
-
InitializedUser.new.seller.should == true
|
432
|
-
InitializedUser.new.insane.should == false
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
it "can overwrite defaults in new" do
|
437
|
-
pending_if(ActiveRecord::VERSION::MAJOR != 2) do
|
438
|
-
InitializedUser.new(:seller => false).seller.should == false
|
439
|
-
InitializedUser.new(:insane => true).insane.should == true
|
440
|
-
end
|
441
|
-
end
|
442
|
-
end
|
443
|
-
|
444
|
-
describe "rspec matchers" do
|
445
|
-
subject { User.new }
|
446
|
-
|
447
|
-
it { should have_a_bitfield :seller }
|
448
|
-
it { should_not have_a_bitfield :pickle_eater }
|
449
|
-
end
|
450
|
-
end
|
data/spec/database.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
|
-
# connect
|
4
|
-
ActiveRecord::Base.establish_connection(
|
5
|
-
:adapter => "sqlite3",
|
6
|
-
:database => ":memory:"
|
7
|
-
)
|
8
|
-
|
9
|
-
# create tables
|
10
|
-
ActiveRecord::Schema.verbose = false
|
11
|
-
ActiveRecord::Schema.define(:version => 1) do
|
12
|
-
create_table :users do |t|
|
13
|
-
t.integer :bits, :default => 0, :null => false
|
14
|
-
t.integer :more_bits, :default => 0, :null => false
|
15
|
-
end
|
16
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
if ENV['VERSION']
|
3
|
-
gem 'activerecord', ENV['VERSION']
|
4
|
-
gem 'activesupport', ENV['VERSION']
|
5
|
-
end
|
6
|
-
$LOAD_PATH << 'lib'
|
7
|
-
require 'bitfields/rspec'
|
8
|
-
require 'bitfields'
|
9
|
-
require 'timeout'
|
10
|
-
|
11
|
-
require 'active_record'
|
12
|
-
puts "Using ActiveRecord #{ActiveRecord::VERSION::STRING}"
|
13
|
-
|
14
|
-
require File.expand_path('../database', __FILE__)
|