bit_set 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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +54 -0
- data/.yardopts +9 -0
- data/Gemfile +25 -0
- data/HISTORY.md +6 -0
- data/LICENSE.md +15 -0
- data/README.md +435 -0
- data/Rakefile +48 -0
- data/bit_set.gemspec +61 -0
- data/lib/bit_set.rb +22 -0
- data/lib/god_object/bit_set.rb +43 -0
- data/lib/god_object/bit_set/bit_set.rb +316 -0
- data/lib/god_object/bit_set/configuration.rb +213 -0
- data/lib/god_object/bit_set/version.rb +30 -0
- data/spec/god_object/bit_set/bit_set_spec.rb +487 -0
- data/spec/god_object/bit_set/configuration_spec.rb +249 -0
- data/spec/spec_helper.rb +38 -0
- metadata +177 -0
@@ -0,0 +1,213 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
=begin
|
3
|
+
Copyright GodObject Team <dev@godobject.net>, 2012-2016
|
4
|
+
|
5
|
+
This file is part of BitSet.
|
6
|
+
|
7
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
8
|
+
purpose with or without fee is hereby granted, provided that the above
|
9
|
+
copyright notice and this permission notice appear in all copies.
|
10
|
+
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
12
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
13
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
14
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
15
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
16
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
17
|
+
PERFORMANCE OF THIS SOFTWARE.
|
18
|
+
=end
|
19
|
+
|
20
|
+
module GodObject
|
21
|
+
module BitSet
|
22
|
+
|
23
|
+
# A Configuration defines the digits of a BitSet. Additionally it can hold
|
24
|
+
# information on how to represent the digits in a String representation.
|
25
|
+
class Configuration
|
26
|
+
|
27
|
+
# @return [String] the default String representation for enabled digits
|
28
|
+
UNNAMED_ENABLED = '1'.freeze
|
29
|
+
|
30
|
+
# @return [String] the default String representation for disabled digits
|
31
|
+
UNNAMED_DISABLED = '0'.freeze
|
32
|
+
|
33
|
+
# @return [String] the default String representation for disabled digits
|
34
|
+
# which have a custom enabled representation
|
35
|
+
NAMED_DISABLED = '-'.freeze
|
36
|
+
|
37
|
+
class << self
|
38
|
+
|
39
|
+
# @overload build(configuration)
|
40
|
+
# Returns an existing instance of GodObject::BitSet::Configuration.
|
41
|
+
# @param [GodObject::BitSet::Configuration] configuration an already
|
42
|
+
# existing Configuration
|
43
|
+
# @return [GodObject::BitSet::Configuration] the same Configuration object
|
44
|
+
#
|
45
|
+
# @overload build(digits)
|
46
|
+
# Returns a new Configuration object with given attributes.
|
47
|
+
# @param [Array<Symbol>] digits a list of digit names
|
48
|
+
# @return [GodObject::PosixMode::Mode] a new Configuration object
|
49
|
+
#
|
50
|
+
# @overload build(enabled_representations_by_digits)
|
51
|
+
# Returns a new Configuration object with given attributes.
|
52
|
+
# @param [Hash<Symbol => String>] enabled_representations_by_digits
|
53
|
+
# digit names mapped to their enabled character representations
|
54
|
+
# @return [GodObject::PosixMode::Mode] a new Configuration object
|
55
|
+
#
|
56
|
+
# @overload build(representations_by_digits)
|
57
|
+
# Returns a new Configuration object with given attributes.
|
58
|
+
# @param [Hash<Symbol => Array<String>>] representations_by_digits
|
59
|
+
# digit names mapped to their enabled and disabled character
|
60
|
+
# representations
|
61
|
+
# @return [GodObject::PosixMode::Mode] a new Configuration object
|
62
|
+
def build(configuration)
|
63
|
+
if configuration.is_a?(Configuration)
|
64
|
+
configuration
|
65
|
+
else
|
66
|
+
new(configuration)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Range<Integer>] the Range in which an Integer representation of a
|
73
|
+
# BitSet with this Configuration can be.
|
74
|
+
attr_reader :valid_range
|
75
|
+
|
76
|
+
# Initializes a new BitSet::Configuration
|
77
|
+
#
|
78
|
+
# @overload initialize(digits)
|
79
|
+
# @param [Array<Symbol>] digits a list of digit names
|
80
|
+
#
|
81
|
+
# @overload initialize(enabled_representations_by_digits)
|
82
|
+
# @param [Hash<Symbol => String>] enabled_representations_by_digits
|
83
|
+
# digit names mapped to their enabled character representations
|
84
|
+
#
|
85
|
+
# @overload initialize(representations_by_digits)
|
86
|
+
# @param [Hash<Symbol => Array<String>>] representations_by_digits
|
87
|
+
# digit names mapped to their enabled and disabled character
|
88
|
+
# representations
|
89
|
+
def initialize(configuration)
|
90
|
+
@digits = {}
|
91
|
+
@enabled = {}
|
92
|
+
@disabled = {}
|
93
|
+
|
94
|
+
configuration.each do |digit, display|
|
95
|
+
digit = digit.to_sym
|
96
|
+
|
97
|
+
@digits[digit] = nil
|
98
|
+
|
99
|
+
case
|
100
|
+
when display.respond_to?(:all?) && display.all?{|s| s.respond_to?(:to_str) && s.to_str.length == 1}
|
101
|
+
@enabled[digit] = display.first.to_str.dup.freeze
|
102
|
+
@disabled[digit] = display.last.to_str.dup.freeze
|
103
|
+
when display.respond_to?(:to_str) && display.to_str.length == 1
|
104
|
+
@enabled[digit] = display.to_str.dup.freeze
|
105
|
+
@disabled[digit] = NAMED_DISABLED
|
106
|
+
when display.nil?
|
107
|
+
@enabled[digit] = UNNAMED_ENABLED
|
108
|
+
@disabled[digit] = UNNAMED_DISABLED
|
109
|
+
else
|
110
|
+
raise ArgumentError, 'Invalid configuration'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
raise ArgumentError, 'At least one digit must be configured' if digits.count < 1
|
115
|
+
|
116
|
+
@digits.keys.reverse.each_with_index{|digit, index| @digits[digit] = 2 ** index }
|
117
|
+
|
118
|
+
@valid_range = Range.new(0, (@digits.values.first * 2) - 1).freeze
|
119
|
+
|
120
|
+
@unique_characters = !@enabled.values.dup.uniq!
|
121
|
+
end
|
122
|
+
|
123
|
+
# Answers if all digits have unique enabled representations.
|
124
|
+
#
|
125
|
+
# @return [true, false] true if all digits have unique enabled
|
126
|
+
# representations, false otherwise
|
127
|
+
def unique_characters?
|
128
|
+
@unique_characters
|
129
|
+
end
|
130
|
+
|
131
|
+
# @attribute digits [readonly]
|
132
|
+
# @return [Array<Symbol>] an ordered list of all configured digit names
|
133
|
+
def digits
|
134
|
+
@digits.keys
|
135
|
+
end
|
136
|
+
|
137
|
+
# @param [Integer, Array<Symbol>] state either the octal state of the
|
138
|
+
# BitSet or a list of enabled digits
|
139
|
+
# @return [GodObject::BitSet] a new BitSet object with the current
|
140
|
+
# configuration
|
141
|
+
def new(*state)
|
142
|
+
BitSet.new(*state, self)
|
143
|
+
end
|
144
|
+
|
145
|
+
# @return [Integer] the Integer representation of a BitSet where
|
146
|
+
# only the given digit is enabled.
|
147
|
+
def binary_position(digit)
|
148
|
+
@digits[find_digit(digit)]
|
149
|
+
end
|
150
|
+
|
151
|
+
# @param [Symbol, Integer] digit the name or index of the digit
|
152
|
+
# @return [String] the String representation for the given digit when
|
153
|
+
# it is disabled
|
154
|
+
def disabled_character(digit)
|
155
|
+
@disabled[find_digit(digit)]
|
156
|
+
end
|
157
|
+
|
158
|
+
# @param [Symbol, Integer] digit the name or index of the digit
|
159
|
+
# @return [String] the String representation for the given digit when
|
160
|
+
# it is enabled
|
161
|
+
def enabled_character(digit)
|
162
|
+
@enabled[find_digit(digit)]
|
163
|
+
end
|
164
|
+
|
165
|
+
# @param [Symbol, Integer] index_or_digit the name or index of the digit
|
166
|
+
# @return [Symbol] the digit's name
|
167
|
+
def find_digit(index_or_digit)
|
168
|
+
case
|
169
|
+
when index_or_digit.respond_to?(:to_sym)
|
170
|
+
digit = index_or_digit.to_sym
|
171
|
+
|
172
|
+
raise ArgumentError, "Invalid digit name (#{index_or_digit})" unless @digits.keys.include?(digit)
|
173
|
+
else
|
174
|
+
digit = @digits.keys[index_or_digit.to_int]
|
175
|
+
end
|
176
|
+
|
177
|
+
raise ArgumentError, "Invalid index or digit (#{index_or_digit})" unless digit
|
178
|
+
|
179
|
+
digit
|
180
|
+
end
|
181
|
+
|
182
|
+
# Answers if another object is equal.
|
183
|
+
#
|
184
|
+
# Equality is defined as having the same ordered list of digits.
|
185
|
+
#
|
186
|
+
# @param [Object] other an object to be checked for equality
|
187
|
+
# @return [true, false] true if the object is considered equal, false
|
188
|
+
# otherwise
|
189
|
+
def ==(other)
|
190
|
+
digits == other.digits
|
191
|
+
rescue NoMethodError
|
192
|
+
false
|
193
|
+
end
|
194
|
+
|
195
|
+
# Answers if another object is equal and of the same type family.
|
196
|
+
#
|
197
|
+
# @see GodObject::Configuration#==
|
198
|
+
# @param [Object] other an object to be checked for equality
|
199
|
+
# @return [true, false] true if the object is considered equal and of
|
200
|
+
# the same type familiy, false otherwise
|
201
|
+
def eql?(other)
|
202
|
+
self == other && other.kind_of?(self.class)
|
203
|
+
end
|
204
|
+
|
205
|
+
# @return (see Hash#hash) identity hash for hash table usage
|
206
|
+
def hash
|
207
|
+
@digits.hash
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
=begin
|
3
|
+
Copyright GodObject Team <dev@godobject.net>, 2012-2016
|
4
|
+
|
5
|
+
This file is part of BitSet.
|
6
|
+
|
7
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
8
|
+
purpose with or without fee is hereby granted, provided that the above
|
9
|
+
copyright notice and this permission notice appear in all copies.
|
10
|
+
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
12
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
13
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
14
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
15
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
16
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
17
|
+
PERFORMANCE OF THIS SOFTWARE.
|
18
|
+
=end
|
19
|
+
|
20
|
+
module GodObject
|
21
|
+
module BitSet
|
22
|
+
|
23
|
+
# The currently loaded version.
|
24
|
+
#
|
25
|
+
# Using Semantic Versioning (2.0.0) rules
|
26
|
+
# @see http://semver.org/spec/v2.0.0.html
|
27
|
+
VERSION = '0.1.0'.freeze
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,487 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
=begin
|
3
|
+
Copyright GodObject Team <dev@godobject.net>, 2012-2016
|
4
|
+
|
5
|
+
This file is part of BitSet.
|
6
|
+
|
7
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
8
|
+
purpose with or without fee is hereby granted, provided that the above
|
9
|
+
copyright notice and this permission notice appear in all copies.
|
10
|
+
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
12
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
13
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
14
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
15
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
16
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
17
|
+
PERFORMANCE OF THIS SOFTWARE.
|
18
|
+
=end
|
19
|
+
|
20
|
+
module GodObject
|
21
|
+
module BitSet
|
22
|
+
|
23
|
+
describe BitSet do
|
24
|
+
let(:traffic_light_configuration) { Configuration.new(red: 'r', yellow: 'y', green: 'g') }
|
25
|
+
let(:generic_configuration) { Configuration.new([:a, :b, :c, :d, :e])}
|
26
|
+
|
27
|
+
describe ".new" do
|
28
|
+
it "should accept a configuration" do
|
29
|
+
result = BitSet.new(generic_configuration)
|
30
|
+
|
31
|
+
expect(result).to be_a(BitSet)
|
32
|
+
expect(result.to_i).to eql 0
|
33
|
+
expect(result.configuration).to eql generic_configuration
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should accept an Integer as initial state and a configuration" do
|
37
|
+
result = BitSet.new(0b01010, generic_configuration)
|
38
|
+
|
39
|
+
expect(result).to be_a(BitSet)
|
40
|
+
expect(result.to_i).to eql 0b01010
|
41
|
+
expect(result.configuration).to eql generic_configuration
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should accept multiple arguments of enabled digits as initial state and a configuration" do
|
45
|
+
result = BitSet.new(:red, :green, traffic_light_configuration)
|
46
|
+
|
47
|
+
expect(result).to be_a(BitSet)
|
48
|
+
expect(result.to_i).to eql 0b101
|
49
|
+
expect(result.configuration).to eql traffic_light_configuration
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should accept a list of enabled digits as initial state and a configuration" do
|
53
|
+
result = BitSet.new(Set[:red, :green], traffic_light_configuration)
|
54
|
+
|
55
|
+
expect(result).to be_a(BitSet)
|
56
|
+
expect(result.to_i).to eql 0b101
|
57
|
+
expect(result.configuration).to eql traffic_light_configuration
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should accept on-the-fly configurations" do
|
61
|
+
result = BitSet.new(Set[:symmetric, :transitive], symmetric: nil, transitive: 't', antisymmetric: ['a', 'x'])
|
62
|
+
|
63
|
+
configuration = Configuration.build(symmetric: nil, transitive: 't', antisymmetric: ['a', 'x'])
|
64
|
+
|
65
|
+
expect(result).to be_a(BitSet)
|
66
|
+
expect(result.to_i).to eql 0b110
|
67
|
+
expect(result.to_s).to eql "1tx"
|
68
|
+
expect(result.configuration).to eql configuration
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should complain about invalid digits" do
|
72
|
+
expect {
|
73
|
+
BitSet.new(Set[:white, :blue, :green], traffic_light_configuration)
|
74
|
+
}.to raise_error(ArgumentError, "Invalid digit(s): :white, :blue")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should complain about invalid state" do
|
78
|
+
expect {
|
79
|
+
BitSet.new(:invalid, traffic_light_configuration)
|
80
|
+
}.to raise_error(ArgumentError, "Invalid digit(s): :invalid")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should complain about invalid configuration" do
|
84
|
+
expect {
|
85
|
+
BitSet.new(3, invalid: 12)
|
86
|
+
}.to raise_error(ArgumentError, 'Invalid configuration')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "magic attributes" do
|
91
|
+
it "should allow accessing each digit's on/off state by name" do
|
92
|
+
bit_set = BitSet.new(0b001, traffic_light_configuration)
|
93
|
+
|
94
|
+
expect(bit_set.red).to eq false
|
95
|
+
expect(bit_set.yellow).to eq false
|
96
|
+
expect(bit_set.green).to eq true
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should allow accessing each digit's on/off state by a question mark method" do
|
100
|
+
bit_set = BitSet.new(0b01101, generic_configuration)
|
101
|
+
|
102
|
+
expect(bit_set.a?).to eq false
|
103
|
+
expect(bit_set.b?).to eq true
|
104
|
+
expect(bit_set.c?).to eq true
|
105
|
+
expect(bit_set.d?).to eq false
|
106
|
+
expect(bit_set.e?).to eq true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should complain about invalid methods as usual" do
|
110
|
+
expect {
|
111
|
+
BitSet.new(0b101, traffic_light_configuration).fnord
|
112
|
+
}.to raise_error(NoMethodError, /^undefined method `fnord'/)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
[:state, :attributes].each do |method_name|
|
117
|
+
describe "##{method_name}" do
|
118
|
+
it "should list all digits and their on/off state" do
|
119
|
+
bit_set = BitSet.new(0b10101, generic_configuration)
|
120
|
+
|
121
|
+
expect(bit_set.public_send(method_name)).to eql(
|
122
|
+
a: true,
|
123
|
+
b: false,
|
124
|
+
c: true,
|
125
|
+
d: false,
|
126
|
+
e: true
|
127
|
+
)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#to_i" do
|
133
|
+
it "should return the Integer state" do
|
134
|
+
bit_set = BitSet.new(6, traffic_light_configuration)
|
135
|
+
|
136
|
+
expect(bit_set.to_i).to eql 6
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#[]" do
|
141
|
+
it "should return true if the digit given by symbol is on" do
|
142
|
+
bit_set = BitSet.new(0b100, traffic_light_configuration)
|
143
|
+
|
144
|
+
expect(bit_set[:red]).to eq true
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should return true if the digit given by index is on" do
|
148
|
+
bit_set = BitSet.new(0b100, traffic_light_configuration)
|
149
|
+
|
150
|
+
expect(bit_set[0]).to eq true
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should return false if the digit given by symbol is off" do
|
154
|
+
bit_set = BitSet.new(0b11101, generic_configuration)
|
155
|
+
|
156
|
+
expect(bit_set[:d]).to eq false
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should return false if the digit given by index is off" do
|
160
|
+
bit_set = BitSet.new(0b11101, generic_configuration)
|
161
|
+
|
162
|
+
expect(bit_set[3]).to eq false
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#enabled_digits" do
|
167
|
+
it "should return the set of digits which are on" do
|
168
|
+
bit_set = BitSet.new(0b10101, generic_configuration)
|
169
|
+
|
170
|
+
expect(bit_set.enabled_digits).to eql Set[:a, :c, :e]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#disabled_digits" do
|
175
|
+
it "should return the set of digits which are off" do
|
176
|
+
bit_set = BitSet.new(0b001, traffic_light_configuration)
|
177
|
+
|
178
|
+
expect(bit_set.disabled_digits).to eql Set[:red, :yellow]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "#invert" do
|
183
|
+
it "should return a copy with every digit on/off state toggled" do
|
184
|
+
bit_set = BitSet.new(0b101, traffic_light_configuration)
|
185
|
+
|
186
|
+
result = bit_set.invert
|
187
|
+
expect(result).to be_a(BitSet)
|
188
|
+
expect(result.configuration).to eql traffic_light_configuration
|
189
|
+
expect(result.to_i).to eql 0b010
|
190
|
+
expect(result).not_to equal bit_set
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#+" do
|
195
|
+
it "should return a copy with all added digits switched to on (given a BitSet)" do
|
196
|
+
bit_set = BitSet.new(0b01000, generic_configuration)
|
197
|
+
|
198
|
+
result = bit_set + BitSet.new([:a, :d], generic_configuration)
|
199
|
+
|
200
|
+
expect(result).to be_a(BitSet)
|
201
|
+
expect(result.configuration).to eql generic_configuration
|
202
|
+
expect(result.to_i).to eql 0b11010
|
203
|
+
expect(result).not_to equal bit_set
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should return a copy with all added digits switched to on (given an Enumerable)" do
|
207
|
+
bit_set = BitSet.new(0b01010, generic_configuration)
|
208
|
+
|
209
|
+
result = bit_set + Set[:a, :d]
|
210
|
+
|
211
|
+
expect(result).to be_a(BitSet)
|
212
|
+
expect(result.configuration).to eql generic_configuration
|
213
|
+
expect(result.to_i).to eql 0b11010
|
214
|
+
expect(result).not_to equal bit_set
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "#-" do
|
219
|
+
it "should return a copy with all added digits switched to on (given a BitSet)" do
|
220
|
+
bit_set = BitSet.new(0b110, traffic_light_configuration)
|
221
|
+
|
222
|
+
result = bit_set - BitSet.new([:yellow, :green], traffic_light_configuration)
|
223
|
+
|
224
|
+
expect(result).to be_a(BitSet)
|
225
|
+
expect(result.configuration).to eql traffic_light_configuration
|
226
|
+
expect(result.to_i).to eql 0b100
|
227
|
+
expect(result).not_to equal bit_set
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should return a copy with all added digits switched to on (given an Enumerable)" do
|
231
|
+
bit_set = BitSet.new(0b101, traffic_light_configuration)
|
232
|
+
|
233
|
+
result = bit_set - [:red, :yellow]
|
234
|
+
|
235
|
+
expect(result).to be_a(BitSet)
|
236
|
+
expect(result.configuration).to eql traffic_light_configuration
|
237
|
+
expect(result.to_i).to eql 0b001
|
238
|
+
expect(result).not_to equal bit_set
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
[:union, :|].each do |method_name|
|
243
|
+
describe "##{method_name}" do
|
244
|
+
it "should return a copy with all enabled digits of both operands switched to on (given a BitSet)" do
|
245
|
+
bit_set = BitSet.new(0b01101, generic_configuration)
|
246
|
+
|
247
|
+
result = bit_set.public_send(method_name,
|
248
|
+
BitSet.new([:d, :e], generic_configuration))
|
249
|
+
|
250
|
+
expect(result).to be_a(BitSet)
|
251
|
+
expect(result.configuration).to eql generic_configuration
|
252
|
+
expect(result.to_i).to eql 0b01111
|
253
|
+
expect(result).not_to equal bit_set
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should return a copy with all enabled digits of both operands switched to on (given an Integer)" do
|
257
|
+
bit_set = BitSet.new(0b01101, generic_configuration)
|
258
|
+
|
259
|
+
result = bit_set.public_send(method_name, 0b00011)
|
260
|
+
|
261
|
+
expect(result).to be_a(BitSet)
|
262
|
+
expect(result.configuration).to eql generic_configuration
|
263
|
+
expect(result.to_i).to eql 0b01111
|
264
|
+
expect(result).not_to equal bit_set
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
[:intersection, :&].each do |method_name|
|
270
|
+
describe "##{method_name}" do
|
271
|
+
it "should return a copy with only those digits switched to on which are on in both operands (given a BitSet)" do
|
272
|
+
bit_set = BitSet.new(0b110, traffic_light_configuration)
|
273
|
+
|
274
|
+
result = bit_set.public_send(method_name,
|
275
|
+
BitSet.new([:yellow, :green], traffic_light_configuration))
|
276
|
+
|
277
|
+
expect(result).to be_a(BitSet)
|
278
|
+
expect(result.configuration).to eql traffic_light_configuration
|
279
|
+
expect(result.to_i).to eql 0b010
|
280
|
+
expect(result).not_to equal bit_set
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should return a copy with only those digits switched to on which are on in both operands (given an Integer)" do
|
284
|
+
bit_set = BitSet.new(0b110, traffic_light_configuration)
|
285
|
+
|
286
|
+
result = bit_set.public_send(method_name, 0b011)
|
287
|
+
|
288
|
+
expect(result).to be_a(BitSet)
|
289
|
+
expect(result.configuration).to eql traffic_light_configuration
|
290
|
+
expect(result.to_i).to eql 0b010
|
291
|
+
expect(result).not_to equal bit_set
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
[:symmetric_difference, :^].each do |method_name|
|
297
|
+
describe "##{method_name}" do
|
298
|
+
it "should return a copy with only those digits switched to on which are uniquely enabled in both operands (given a BitSet)" do
|
299
|
+
bit_set = BitSet.new(0b01101, generic_configuration)
|
300
|
+
|
301
|
+
result = bit_set.public_send(method_name,
|
302
|
+
BitSet.new([:d, :e], generic_configuration))
|
303
|
+
|
304
|
+
expect(result).to be_a(BitSet)
|
305
|
+
expect(result.configuration).to eql generic_configuration
|
306
|
+
expect(result.to_i).to eql 0b01110
|
307
|
+
expect(result).not_to equal bit_set
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should return a copy with only those digits switched to on which are uniquely enabled in both operands (given an Integer)" do
|
311
|
+
bit_set = BitSet.new(0b01101, generic_configuration)
|
312
|
+
|
313
|
+
result = bit_set.public_send(method_name, 0b00011)
|
314
|
+
|
315
|
+
expect(result).to be_a(BitSet)
|
316
|
+
expect(result.configuration).to eql generic_configuration
|
317
|
+
expect(result.to_i).to eql 0b01110
|
318
|
+
expect(result).not_to equal bit_set
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
describe "#==" do
|
324
|
+
let(:bit_set) { BitSet.new(0b110, traffic_light_configuration) }
|
325
|
+
|
326
|
+
it "should return true if state and configuration is equal" do
|
327
|
+
expect(bit_set).to eq(BitSet.new(0b110, traffic_light_configuration))
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should return true if state and configuration is equal (different class)" do
|
331
|
+
expect(bit_set).to eq(OpenStruct.new(integer_representation: 0b110, configuration: traffic_light_configuration))
|
332
|
+
end
|
333
|
+
|
334
|
+
it "should return false if state is equal but configuration differs" do
|
335
|
+
expect(bit_set).not_to eq(BitSet.new(0b110, generic_configuration))
|
336
|
+
end
|
337
|
+
|
338
|
+
it "should return false if configuration is equal but state differs" do
|
339
|
+
expect(bit_set).not_to eq(BitSet.new(0b010, traffic_light_configuration))
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should return false if both state and configuration differ" do
|
343
|
+
expect(bit_set).not_to eq(BitSet.new(0b010, generic_configuration))
|
344
|
+
end
|
345
|
+
|
346
|
+
it "should return false if compared to incompatible type" do
|
347
|
+
expect(bit_set).not_to eq(:incompatible)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe "#eql?" do
|
352
|
+
let(:bit_set) { BitSet.new(0b110, traffic_light_configuration) }
|
353
|
+
|
354
|
+
it "should return true if state and configuration is equal" do
|
355
|
+
expect(bit_set).to eql BitSet.new(0b110, traffic_light_configuration)
|
356
|
+
end
|
357
|
+
|
358
|
+
it "should return false if state and configuration is equal (different class)" do
|
359
|
+
expect(bit_set).not_to eql OpenStruct.new(integer_representation: 0b110, configuration: traffic_light_configuration)
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should return false if state is equal but configuration differs" do
|
363
|
+
expect(bit_set).not_to eql BitSet.new(0b110, generic_configuration)
|
364
|
+
end
|
365
|
+
|
366
|
+
it "should return false if configuration is equal but state differs" do
|
367
|
+
expect(bit_set).not_to eql BitSet.new(0b010, traffic_light_configuration)
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should return false if both state and configuration differ" do
|
371
|
+
expect(bit_set).not_to eql BitSet.new(0b010, generic_configuration)
|
372
|
+
end
|
373
|
+
|
374
|
+
it "should return false if compared to an incompatible object" do
|
375
|
+
expect(bit_set).not_to eql :incompatible
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
describe "#<=>" do
|
380
|
+
let(:bit_set) { BitSet.new(11, generic_configuration) }
|
381
|
+
|
382
|
+
it "should return -1 if state is lower than that of the compared" do
|
383
|
+
expect(bit_set <=> BitSet.new(12, generic_configuration)).to eql -1
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should return 0 if state is equal to that of the compared" do
|
387
|
+
expect(bit_set <=> BitSet.new(11, generic_configuration)).to eql 0
|
388
|
+
end
|
389
|
+
|
390
|
+
it "should return 1 if state is higher than that of the compared" do
|
391
|
+
expect(bit_set <=> BitSet.new(10, generic_configuration)).to eql 1
|
392
|
+
end
|
393
|
+
|
394
|
+
it "should return nil if configuration differs" do
|
395
|
+
expect(bit_set <=> BitSet.new(11, traffic_light_configuration)).to be_nil
|
396
|
+
end
|
397
|
+
|
398
|
+
it "should return nil if compared to an incompatible object" do
|
399
|
+
expect(bit_set <=> :incompatible).to be_nil
|
400
|
+
end
|
401
|
+
|
402
|
+
it "should make BitSet sortable" do
|
403
|
+
result = [BitSet.new(11, generic_configuration),
|
404
|
+
BitSet.new(10, generic_configuration),
|
405
|
+
BitSet.new(12, generic_configuration)].sort
|
406
|
+
|
407
|
+
expect(result).to eql [
|
408
|
+
BitSet.new(10, generic_configuration),
|
409
|
+
BitSet.new(11, generic_configuration),
|
410
|
+
BitSet.new(12, generic_configuration)
|
411
|
+
]
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
describe "#hash" do
|
416
|
+
let(:bit_set) { BitSet.new(0b01011, generic_configuration) }
|
417
|
+
|
418
|
+
it "should be stable over multiple calls" do
|
419
|
+
expect(bit_set.hash).to eql bit_set.hash
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should differ if state is equal but configuration differs" do
|
423
|
+
expect(bit_set.hash).not_to eql BitSet.new(0b01011, traffic_light_configuration).hash
|
424
|
+
end
|
425
|
+
|
426
|
+
it "should differ if configuration is equal but state differs" do
|
427
|
+
expect(bit_set.hash).not_to eql BitSet.new(0b00010, generic_configuration).hash
|
428
|
+
end
|
429
|
+
|
430
|
+
it "should differ if both state and configuration differ" do
|
431
|
+
expect(bit_set.hash).not_to eql BitSet.new(0b00010, traffic_light_configuration).hash
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
describe "#inspect" do
|
436
|
+
it "should return a decent string representation for debugging" do
|
437
|
+
result = BitSet.new(0b011, traffic_light_configuration).inspect
|
438
|
+
|
439
|
+
expect(result).to eql '#<GodObject::BitSet::BitSet: "-yg">'
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
describe "#to_s" do
|
444
|
+
it "should complain about invalid formats" do
|
445
|
+
expect {
|
446
|
+
BitSet.new(0b00101, generic_configuration).to_s(:medium)
|
447
|
+
}.to raise_error(ArgumentError, "Invalid format: :medium")
|
448
|
+
end
|
449
|
+
|
450
|
+
context "long mode" do
|
451
|
+
it "should by default display every digit as either 0 or 1" do
|
452
|
+
result = BitSet.new(0b00101, generic_configuration).to_s
|
453
|
+
|
454
|
+
expect(result).to eql "00101"
|
455
|
+
end
|
456
|
+
|
457
|
+
it "should display every digit as either it's assigned character or a dash if digits have assigned characters" do
|
458
|
+
result = BitSet.new(0b101, traffic_light_configuration).to_s
|
459
|
+
|
460
|
+
expect(result).to eql "r-g"
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
context "short mode" do
|
465
|
+
it "should not be available if configuration has no unique characters per digit" do
|
466
|
+
expect {
|
467
|
+
BitSet.new(3, generic_configuration).to_s(:short)
|
468
|
+
}.to raise_error(ArgumentError, 'Short format only available for configurations with unique characters for each digit')
|
469
|
+
end
|
470
|
+
|
471
|
+
it "should only display enabled digits" do
|
472
|
+
result = BitSet.new(0b110, traffic_light_configuration).to_s(:short)
|
473
|
+
|
474
|
+
expect(result).to eql "ry"
|
475
|
+
end
|
476
|
+
|
477
|
+
it "should diplay one dash when no digit is on" do
|
478
|
+
result = BitSet.new(0, traffic_light_configuration).to_s(:short)
|
479
|
+
|
480
|
+
expect(result).to eql "-"
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
end
|
487
|
+
end
|