bitty 0.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/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bitty.gemspec +55 -0
- data/lib/bitty/bit_proxy.rb +152 -0
- data/lib/bitty.rb +45 -0
- data/test/bitty_test.rb +91 -0
- data/test/proxy_test.rb +196 -0
- data/test/support/models.rb +3 -0
- data/test/support/schema.rb +9 -0
- data/test/test_helper.rb +17 -0
- metadata +71 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 oleg dashevskii
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "bitty"
|
8
|
+
gem.summary = %Q{ActiveRecord plugin for rich bitfields}
|
9
|
+
gem.email = "olegdashevskii@gmail.com"
|
10
|
+
gem.homepage = "http://github.com/be9/bitty"
|
11
|
+
gem.authors = ["oleg dashevskii"]
|
12
|
+
gem.files.exclude '.gitignore', '.document'
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
end
|
15
|
+
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/**/*_test.rb'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
require 'rcov/rcovtask'
|
29
|
+
Rcov::RcovTask.new do |test|
|
30
|
+
test.libs << 'test'
|
31
|
+
test.pattern = 'test/**/*_test.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
task :rcov do
|
36
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
task :default => :test
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
if File.exist?('VERSION.yml')
|
45
|
+
config = YAML.load(File.read('VERSION.yml'))
|
46
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
47
|
+
else
|
48
|
+
version = ""
|
49
|
+
end
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "bitty #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
56
|
+
|
57
|
+
Jeweler::GemcutterTasks.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bitty.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{bitty}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["oleg dashevskii"]
|
12
|
+
s.date = %q{2009-12-08}
|
13
|
+
s.email = %q{olegdashevskii@gmail.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE",
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"LICENSE",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"bitty.gemspec",
|
24
|
+
"lib/bitty.rb",
|
25
|
+
"lib/bitty/bit_proxy.rb",
|
26
|
+
"test/bitty_test.rb",
|
27
|
+
"test/proxy_test.rb",
|
28
|
+
"test/support/models.rb",
|
29
|
+
"test/support/schema.rb",
|
30
|
+
"test/test_helper.rb"
|
31
|
+
]
|
32
|
+
s.homepage = %q{http://github.com/be9/bitty}
|
33
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = %q{1.3.5}
|
36
|
+
s.summary = %q{ActiveRecord plugin for rich bitfields}
|
37
|
+
s.test_files = [
|
38
|
+
"test/bitty_test.rb",
|
39
|
+
"test/support/schema.rb",
|
40
|
+
"test/support/models.rb",
|
41
|
+
"test/proxy_test.rb",
|
42
|
+
"test/test_helper.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
50
|
+
else
|
51
|
+
end
|
52
|
+
else
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Bitty
|
2
|
+
# This class acts like a proxy. It presents you with all these
|
3
|
+
# bitfield methods, but it doesn't store the value itself.
|
4
|
+
def true?(val)
|
5
|
+
case val
|
6
|
+
when true, 1, /1|y|yes/i then true
|
7
|
+
else false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module_function :true?
|
12
|
+
|
13
|
+
class BitProxy
|
14
|
+
# this will be redefined in self.column=
|
15
|
+
def initialize(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
class <<self
|
19
|
+
def power2(name)
|
20
|
+
@power2[name.to_sym]
|
21
|
+
end
|
22
|
+
|
23
|
+
def bit_names=(names)
|
24
|
+
@power2 = {}
|
25
|
+
p = 1
|
26
|
+
|
27
|
+
names.each do |name|
|
28
|
+
n = name.to_sym
|
29
|
+
|
30
|
+
if @power2.include?(n)
|
31
|
+
raise ArgumentError, "Bit name #{n} repeated more that once!"
|
32
|
+
else
|
33
|
+
@power2[n] = p
|
34
|
+
p <<= 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
@power2.each do |name, bitmask|
|
39
|
+
inv = ~bitmask
|
40
|
+
class_eval <<-RUBY
|
41
|
+
def #{name}
|
42
|
+
(value & #{bitmask}) != 0
|
43
|
+
end
|
44
|
+
|
45
|
+
alias #{name}? #{name}
|
46
|
+
|
47
|
+
def #{name}=(val)
|
48
|
+
self.value = Bitty.true?(val) ? (value | #{bitmask}) : (value & #{inv})
|
49
|
+
end
|
50
|
+
RUBY
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
attr_reader :column
|
55
|
+
|
56
|
+
def column=(column)
|
57
|
+
@column = column
|
58
|
+
|
59
|
+
class_eval <<-RUBY
|
60
|
+
attr_accessor :model_object
|
61
|
+
|
62
|
+
def initialize(model_object)
|
63
|
+
self.model_object = model_object
|
64
|
+
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
def value
|
69
|
+
model_object[:#{column}]
|
70
|
+
end
|
71
|
+
|
72
|
+
def value=(newval)
|
73
|
+
model_object[:#{column}] = newval
|
74
|
+
end
|
75
|
+
RUBY
|
76
|
+
end
|
77
|
+
|
78
|
+
def named_scope(*args)
|
79
|
+
bits = args.extract_options!
|
80
|
+
args.each { |arg| bits[arg] = true }
|
81
|
+
|
82
|
+
masks = [0, 0]
|
83
|
+
|
84
|
+
bits.each do |name, val|
|
85
|
+
mask = power2(name)
|
86
|
+
raise ArgumentError, "invalid bit name #{name}" unless mask
|
87
|
+
|
88
|
+
masks[Bitty.true?(val) ? 1 : 0] |= mask
|
89
|
+
end
|
90
|
+
|
91
|
+
cond = [nil, nil]
|
92
|
+
|
93
|
+
if masks[0] != 0
|
94
|
+
cond[0] = "#{column} & #{masks[0]} = 0"
|
95
|
+
end
|
96
|
+
|
97
|
+
if masks[1] != 0
|
98
|
+
cond[1] = "#{column} & #{masks[1]} = #{masks[1]}"
|
99
|
+
end
|
100
|
+
|
101
|
+
{ :conditions => cond.compact.map { |c| "(#{c})" } * ' AND ' }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def [](key)
|
106
|
+
bitmask = power2(key)
|
107
|
+
|
108
|
+
if bitmask
|
109
|
+
(value & bitmask) != 0
|
110
|
+
else
|
111
|
+
nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def []=(key, val)
|
116
|
+
bitmask = power2(key)
|
117
|
+
raise ArgumentError, "unknown bitname: #{key}" unless bitmask
|
118
|
+
|
119
|
+
self.value = Bitty.true?(val) ? (value | bitmask) : (value & ~bitmask)
|
120
|
+
end
|
121
|
+
|
122
|
+
def set!(value)
|
123
|
+
case value
|
124
|
+
when Array
|
125
|
+
value.each { |key| self[key] = true }
|
126
|
+
when Hash
|
127
|
+
value.each { |key, val| self[key] = val }
|
128
|
+
when Fixnum
|
129
|
+
self.value = value
|
130
|
+
else
|
131
|
+
raise ArgumentError, "invalid value (must be Array/Hash/Fixnum)"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
protected
|
136
|
+
|
137
|
+
# this will be redefined in self.column=
|
138
|
+
def value
|
139
|
+
raise
|
140
|
+
end
|
141
|
+
|
142
|
+
# this will be redefined in self.column=
|
143
|
+
def value=(newval)
|
144
|
+
raise
|
145
|
+
end
|
146
|
+
|
147
|
+
# power of 2, corresponding to key
|
148
|
+
def power2(key)
|
149
|
+
self.class.power2(key)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/lib/bitty.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'bitty', 'bit_proxy')
|
2
|
+
|
3
|
+
module Bitty
|
4
|
+
module ActiveRecordExtensions
|
5
|
+
def bitty(field, *args)
|
6
|
+
field = field.to_sym
|
7
|
+
|
8
|
+
opts = args.extract_options!
|
9
|
+
|
10
|
+
proxy = Class.new(Bitty::BitProxy)
|
11
|
+
proxy.bit_names = args
|
12
|
+
proxy.column = opts[:column] || field
|
13
|
+
|
14
|
+
# TODO: opts[:default]
|
15
|
+
# TODO: opts[:named_scope]
|
16
|
+
# TODO: check if field has already been defined in superclass
|
17
|
+
write_inheritable_hash(:_bitty_fields, { field => proxy } )
|
18
|
+
|
19
|
+
class_eval <<-RUBY
|
20
|
+
def #{field}
|
21
|
+
@_bitty_#{field} ||=
|
22
|
+
self.class.read_inheritable_attribute(:_bitty_fields)[:#{field}].new(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def #{field}=(value)
|
26
|
+
#{field}.set!(value)
|
27
|
+
end
|
28
|
+
RUBY
|
29
|
+
end
|
30
|
+
|
31
|
+
def bitty_named_scope(name, bitty_field, *args)
|
32
|
+
proxy_class = read_inheritable_attribute(:_bitty_fields)[bitty_field]
|
33
|
+
|
34
|
+
if proxy_class
|
35
|
+
named_scope name, proxy_class.named_scope(*args)
|
36
|
+
else
|
37
|
+
raise ArgumentError, "There's no bitfield '#{bitty_field}' defined!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if defined? ActiveRecord::Base
|
44
|
+
ActiveRecord::Base.send(:extend, Bitty::ActiveRecordExtensions)
|
45
|
+
end
|
data/test/bitty_test.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'support/models'
|
3
|
+
load 'support/schema.rb'
|
4
|
+
|
5
|
+
class Foo < ActiveRecord::Base
|
6
|
+
bitty :bitval, :uno, :dos, :tres, :quatro
|
7
|
+
end
|
8
|
+
|
9
|
+
class BittyTest < Test::Unit::TestCase
|
10
|
+
context "Foo" do
|
11
|
+
before { @foo = Foo.new }
|
12
|
+
|
13
|
+
it "should have :bitval attribute" do
|
14
|
+
@foo.should respond_to :bitval
|
15
|
+
@foo.should respond_to :bitval=
|
16
|
+
end
|
17
|
+
|
18
|
+
it "attribute method should return an instance of BitProxy" do
|
19
|
+
@foo.bitval.should be_kind_of(Bitty::BitProxy)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "proxy value should correspond to model object column value" do
|
23
|
+
@foo2 = Foo.new
|
24
|
+
[0, 1, 200].each do |ival|
|
25
|
+
@foo[:bitval] = ival
|
26
|
+
@foo.bitval.send(:value).should == ival
|
27
|
+
@foo2.bitval.send(:value).should be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "proxy :value= should set model object's value" do
|
32
|
+
[0, 1, 200].each do |ival|
|
33
|
+
@foo.bitval.send(:value=, ival)
|
34
|
+
@foo[:bitval].should == ival
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it "proxy :value= should not spoil other objects of the same type" do
|
39
|
+
@foo2 = Foo.new
|
40
|
+
@foo2.bitval.send(:value=, 333)
|
41
|
+
@foo.bitval.send(:value=, 1000)
|
42
|
+
@foo2.bitval.value.should == 333
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class FooWithScope < Foo
|
48
|
+
bitty_named_scope :with_uno, :bitval, :uno
|
49
|
+
bitty_named_scope :without_4, :bitval, :quatro => 0
|
50
|
+
bitty_named_scope :with_110_, :bitval, :quatro => 1, :tres => 1, :dos => 0
|
51
|
+
end
|
52
|
+
|
53
|
+
class BittyNamedScopeTest < Test::Unit::TestCase
|
54
|
+
before :all do
|
55
|
+
@foos = (0..15).to_a.map do |v|
|
56
|
+
FooWithScope.create!(:bitval => v)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it ".with_uno should find values with :uno set" do
|
61
|
+
FooWithScope.with_uno.all.should == fs(1,3,5,7,9,11,13,15)
|
62
|
+
end
|
63
|
+
|
64
|
+
it ".with_4 should find values with :quatro unset" do
|
65
|
+
FooWithScope.without_4.all.should == fs(*(0..7).to_a)
|
66
|
+
end
|
67
|
+
|
68
|
+
it ".with_110_ should find by bit prefix 110" do
|
69
|
+
FooWithScope.with_110_.all.should == fs(12,13)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "raises ArgumentError given invalid bitfield" do
|
73
|
+
lambda do
|
74
|
+
FooWithScope.class_eval do
|
75
|
+
bitty_named_scope :test_1, :nonexistent, :foo
|
76
|
+
end
|
77
|
+
end.should raise_error(ArgumentError)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "raises ArgumentError given invalid bitname" do
|
81
|
+
lambda do
|
82
|
+
FooWithScope.class_eval do
|
83
|
+
bitty_named_scope :test_2, :bitval, :foo
|
84
|
+
end
|
85
|
+
end.should raise_error(ArgumentError)
|
86
|
+
end
|
87
|
+
|
88
|
+
def fs(*args)
|
89
|
+
args.map { |i| @foos[i] }
|
90
|
+
end
|
91
|
+
end
|
data/test/proxy_test.rb
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ValueTester < Hash
|
4
|
+
def value; self[:value] end
|
5
|
+
def value=(newval)
|
6
|
+
self[:value] = newval
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class BittyProxyTest < Test::Unit::TestCase
|
11
|
+
before :all do
|
12
|
+
@proxy_class = Class.new(Bitty::BitProxy)
|
13
|
+
@proxy_class.bit_names = [:uno, :dos, :tres, :quatro]
|
14
|
+
@proxy_class.column = :value
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
@mobject = ValueTester.new
|
19
|
+
@mobject.value = 0b1010
|
20
|
+
@foo = @proxy_class.new(@mobject)
|
21
|
+
end
|
22
|
+
|
23
|
+
[:to_sym, :to_s].each do |conv|
|
24
|
+
it "should allow to query values with [bitname.#{conv}]" do
|
25
|
+
@foo['uno'.send(conv)].should == false
|
26
|
+
@foo['dos'.send(conv)].should == true
|
27
|
+
@foo['tres'.send(conv)].should == false
|
28
|
+
@foo['quatro'.send(conv)].should == true
|
29
|
+
end
|
30
|
+
|
31
|
+
[true, '1', 1, 'yes', 'y', 'YES'].each do |yesval|
|
32
|
+
it "should set 1st bit with bitval['uno'.#{conv}] = #{yesval.inspect}" do
|
33
|
+
@foo['uno'.send(conv)] = yesval
|
34
|
+
@mobject.value.should == 0b1011
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should set 2nd bit with bitval['dos'.#{conv}] = #{yesval.inspect}" do
|
38
|
+
@foo['dos'.send(conv)] = yesval
|
39
|
+
@mobject.value.should == 0b1010
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should set 3rd bit with bitval['tres'.#{conv}] = #{yesval.inspect}" do
|
43
|
+
@foo['tres'.send(conv)] = yesval
|
44
|
+
@mobject.value.should == 0b1110
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
[false, '0', 0, 'no', 'n', 'NO'].each do |noval|
|
49
|
+
it "should reset 1st bit with bitval['uno'.#{conv}] = #{noval.inspect}" do
|
50
|
+
@foo['uno'.send(conv)] = noval
|
51
|
+
@mobject.value.should == 0b1010
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should reset 2nd bit with bitval['dos'.#{conv}] = #{noval.inspect}" do
|
55
|
+
@foo['dos'.send(conv)] = noval
|
56
|
+
@mobject.value.should == 0b1000
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should reset 4th bit with bitval['quatro'.#{conv}] = #{noval.inspect}" do
|
60
|
+
@foo['quatro'.send(conv)] = noval
|
61
|
+
@mobject.value.should == 0b0010
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#set!" do
|
67
|
+
it "should set value given integer" do
|
68
|
+
@foo.set! 0b1111
|
69
|
+
@mobject.value.should == 0b1111
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should set value given a hash of values" do
|
73
|
+
@mobject.value = 0
|
74
|
+
@foo.set! :uno => 1, :quatro => 'yeah'
|
75
|
+
@mobject.value.should == 0b1001
|
76
|
+
|
77
|
+
@mobject.value = 0b1111
|
78
|
+
@foo.set! :dos => 0, :tres => 'N'
|
79
|
+
@mobject.value.should == 0b1001
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should raise ArgumentError given hash with unknown bitname" do
|
83
|
+
@mobject.value = 0
|
84
|
+
lambda do
|
85
|
+
@foo.set! :uno => 1, :unknown => 'yeah'
|
86
|
+
end.should raise_error(ArgumentError)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should set value given an array of set bits" do
|
90
|
+
@mobject.value = 0
|
91
|
+
@foo.set! [:uno, :quatro]
|
92
|
+
@mobject.value.should == 0b1001
|
93
|
+
|
94
|
+
@mobject.value = 0
|
95
|
+
@foo.set! %w(dos tres)
|
96
|
+
@mobject.value.should == 0b0110
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should raise ArgumentError given array with unknown bitnames" do
|
100
|
+
@mobject.value = 0
|
101
|
+
lambda do
|
102
|
+
@foo.set! [:uno, :unknown]
|
103
|
+
end.should raise_error(ArgumentError)
|
104
|
+
end
|
105
|
+
|
106
|
+
["yeah", 123.321, nil, true, false, 1..10].each do |crap|
|
107
|
+
it "should raise ArgumentError given unsupported type (#{crap.inspect})" do
|
108
|
+
lambda do
|
109
|
+
@foo.set! crap
|
110
|
+
end.should raise_error(ArgumentError)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "named access" do
|
116
|
+
it "should allow to query bits directly" do
|
117
|
+
@foo.uno.should == false
|
118
|
+
@foo.dos.should == true
|
119
|
+
@foo.tres.should == false
|
120
|
+
@foo.quatro.should == true
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should allow to query bits with question mark methods" do
|
124
|
+
@foo.uno?.should == false
|
125
|
+
@foo.dos?.should == true
|
126
|
+
@foo.tres?.should == false
|
127
|
+
@foo.quatro?.should == true
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should allow to set bits directly" do
|
131
|
+
@mobject.value = 0b1010
|
132
|
+
@foo.uno = true
|
133
|
+
@mobject.value.should == 0b1011
|
134
|
+
|
135
|
+
@mobject.value = 0b1010
|
136
|
+
@foo.dos = 1
|
137
|
+
@mobject.value.should == 0b1010
|
138
|
+
|
139
|
+
@mobject.value = 0b1010
|
140
|
+
@foo.tres = 'YES'
|
141
|
+
@mobject.value.should == 0b1110
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should allow to reset bits directly" do
|
145
|
+
@mobject.value = 0b1010
|
146
|
+
@foo.uno = false
|
147
|
+
@mobject.value.should == 0b1010
|
148
|
+
|
149
|
+
@mobject.value = 0b1010
|
150
|
+
@foo.dos = 'N'
|
151
|
+
@mobject.value.should == 0b1000
|
152
|
+
|
153
|
+
@mobject.value = 0b1010
|
154
|
+
@foo.quatro = 0
|
155
|
+
@mobject.value.should == 0b0010
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "#named_scope" do
|
160
|
+
it "should generate valid condition for 0 bits" do
|
161
|
+
ns(:uno => 0).should == cond("(value & 1 = 0)")
|
162
|
+
ns(:uno => 0, :quatro => 0).should == cond("(value & 9 = 0)")
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should generate valid condition for 1 bits" do
|
166
|
+
ns(:uno => 1).should == cond("(value & 1 = 1)")
|
167
|
+
ns(:uno => 1, :quatro => 1).should == cond("(value & 9 = 9)")
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should generate valid condition for 1 bits given as array" do
|
171
|
+
ns(:uno).should == cond("(value & 1 = 1)")
|
172
|
+
ns(:uno, :quatro).should == cond("(value & 9 = 9)")
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should generate valid condition for mixed bit values" do
|
176
|
+
ns(:uno => 1, :dos => 0, :tres => 1, :quatro => 0).should ==
|
177
|
+
cond("(value & 10 = 0) AND (value & 5 = 5)")
|
178
|
+
ns(:uno, :tres, :dos => 0, :quatro => 0).should ==
|
179
|
+
cond("(value & 10 = 0) AND (value & 5 = 5)")
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should raise ArgumentError given invalid bitnames" do
|
183
|
+
lambda { ns(:bzz) }.should raise_error(ArgumentError)
|
184
|
+
lambda { ns(:bzz => 0) }.should raise_error(ArgumentError)
|
185
|
+
lambda { ns(:foo, :bzz => 0) }.should raise_error(ArgumentError)
|
186
|
+
end
|
187
|
+
|
188
|
+
def ns(*args)
|
189
|
+
@proxy_class.named_scope(*args)
|
190
|
+
end
|
191
|
+
|
192
|
+
def cond(str)
|
193
|
+
{ :conditions => str }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'context'
|
4
|
+
require 'matchy'
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_record'
|
7
|
+
|
8
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
9
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
10
|
+
require 'bitty'
|
11
|
+
|
12
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :dbfile => 'test.sqlite3')
|
13
|
+
|
14
|
+
#class Test::Unit::TestCase
|
15
|
+
#end
|
16
|
+
|
17
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bitty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- oleg dashevskii
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-08 00:00:00 +06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: olegdashevskii@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- bitty.gemspec
|
31
|
+
- lib/bitty.rb
|
32
|
+
- lib/bitty/bit_proxy.rb
|
33
|
+
- test/bitty_test.rb
|
34
|
+
- test/proxy_test.rb
|
35
|
+
- test/support/models.rb
|
36
|
+
- test/support/schema.rb
|
37
|
+
- test/test_helper.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/be9/bitty
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: ActiveRecord plugin for rich bitfields
|
66
|
+
test_files:
|
67
|
+
- test/bitty_test.rb
|
68
|
+
- test/support/schema.rb
|
69
|
+
- test/support/models.rb
|
70
|
+
- test/proxy_test.rb
|
71
|
+
- test/test_helper.rb
|