bit_set 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
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
+ require 'bundler/gem_tasks'
21
+ require 'rake'
22
+ require 'pathname'
23
+ require 'yard'
24
+ require 'rspec/core/rake_task'
25
+
26
+ RSpec::Core::RakeTask.new
27
+
28
+ YARD::Rake::YardocTask.new('doc')
29
+
30
+ desc "Removes temporary project files"
31
+ task :clean do
32
+ %w{doc/api coverage pkg .yardoc .rbx Gemfile.lock}.map{|name| Pathname.new(name) }.each do |path|
33
+ path.rmtree if path.exist?
34
+ end
35
+
36
+ Pathname.glob('*.gem').each &:delete
37
+ Pathname.glob('**/*.rbc').each &:delete
38
+ end
39
+
40
+ desc "Opens an interactive console with the project code loaded"
41
+ task :console do
42
+ Bundler.setup
43
+ require 'pry'
44
+ require 'bit_set'
45
+ Pry.start(GodObject::BitSet)
46
+ end
47
+
48
+ task default: :spec
@@ -0,0 +1,61 @@
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
+ require File.expand_path('../lib/god_object/bit_set/version', __FILE__)
21
+
22
+ Gem::Specification.new do |gem|
23
+ gem.name = "bit_set"
24
+ gem.version = GodObject::BitSet::VERSION.dup
25
+ gem.authors = ["Oliver Feldt", "Alexander E. Fischer", "Axel Sorge", "Andreas Wurm"]
26
+ gem.email = ["of@godobject.net", "aef@godobject.net", "as@godobject.net", "aw@godobject.net"]
27
+ gem.description = <<-DESCRIPTION
28
+ BitSet is a Ruby library implementing a bit set structure with labeled digits
29
+ and binary logic operators. Additionally it allows to create precached
30
+ configurations of BitSets which also allow the String representation to be
31
+ customized easily.
32
+ DESCRIPTION
33
+ gem.summary = "Easy bit sets with named digits and binary logic operators for Ruby."
34
+ gem.homepage = "https://www.godobject.net/"
35
+ gem.license = "ISC"
36
+ gem.has_rdoc = "yard"
37
+ gem.extra_rdoc_files = ["HISTORY.md", "LICENSE.md"]
38
+ gem.rubyforge_project = nil
39
+
40
+ `git ls-files 2> /dev/null`
41
+
42
+ if $?.success?
43
+ gem.files = `git ls-files`.split($\)
44
+ else
45
+ gem.files = `ls -1`.split($\)
46
+ end
47
+
48
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
49
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
50
+ gem.require_paths = ["lib"]
51
+
52
+ gem.required_ruby_version = '>= 1.9.3'
53
+
54
+ gem.add_development_dependency('rake')
55
+ gem.add_development_dependency('bundler')
56
+ gem.add_development_dependency('rspec')
57
+ gem.add_development_dependency('simplecov')
58
+ gem.add_development_dependency('pry')
59
+ gem.add_development_dependency('yard')
60
+ gem.add_development_dependency('kramdown')
61
+ end
@@ -0,0 +1,22 @@
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
+ # Helper file to allow loading by gem name.
21
+
22
+ require 'god_object/bit_set'
@@ -0,0 +1,43 @@
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
+ require 'set'
21
+ require 'forwardable'
22
+
23
+ # Namespace for projects of the GodObject team <dev@godobject.net>.
24
+ #
25
+ # If you want to be able to simply type Example instead of GodObject::Example
26
+ # to address classes in this namespace simply write the following before using
27
+ # the classes.
28
+ #
29
+ # @example Including the namespace
30
+ # include GodObject
31
+ # @see https://www.godobject.net/
32
+ module GodObject
33
+
34
+ # Namespace for components of the "bit_set" library
35
+ module BitSet
36
+
37
+ end
38
+
39
+ end
40
+
41
+ require 'god_object/bit_set/version'
42
+ require 'god_object/bit_set/configuration'
43
+ require 'god_object/bit_set/bit_set'
@@ -0,0 +1,316 @@
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 bit set with named digits and numeric internal value
24
+ class BitSet
25
+
26
+ # @return [Array<Symbol>] list of valid String representation formats
27
+ #
28
+ # @private
29
+ STRING_FORMAT = Set[:long, :short].freeze
30
+
31
+ # @return [GodObject::BitSet::Configuration] the configuration for the
32
+ # BitSet
33
+ attr_reader :configuration
34
+
35
+ # @return [Integer] the BitSet as binary number
36
+ attr_reader :integer_representation
37
+
38
+ extend Forwardable
39
+ include Comparable
40
+
41
+ # Initializes a new BitSet
42
+ #
43
+ # @param [Integer, Array<Symbol>] state either the octal state of the
44
+ # BitSet or a list of enabled digits
45
+ #
46
+ # @param [GodObject::BitSet::Configuration] configuration the configuration
47
+ # which defines the digits of the BitSet
48
+ def initialize(*state, configuration)
49
+ @configuration = Configuration.build(configuration)
50
+
51
+ create_attribute_readers
52
+
53
+ if state.size == 1 && state.first.respond_to?(:to_int)
54
+ @integer_representation = state.first.to_int
55
+ else
56
+ state = state.first if state.size == 1 && state.first.is_a?(Enumerable)
57
+
58
+ state, invalid_tokens = state.flatten.partition do |token|
59
+ digits.include?(token)
60
+ end
61
+
62
+ if invalid_tokens.any?
63
+ string = invalid_tokens.map(&:inspect).join(', ')
64
+ raise ArgumentError, "Invalid digit(s): #{string}"
65
+ end
66
+
67
+ @integer_representation = 0
68
+
69
+ state.each do |digit|
70
+ @integer_representation |= binary_position(digit)
71
+ end
72
+ end
73
+ end
74
+
75
+ # @return [{Symbol => true, false}] all digits and their current state
76
+ def state
77
+ state = {}
78
+
79
+ digits.each do |digit|
80
+ state[digit] = self[digit]
81
+ end
82
+
83
+ state
84
+ end
85
+
86
+ alias attributes state
87
+
88
+ # @overload [](index)
89
+ # Returns the state of a digit selected by index.
90
+ # @param [Integer] index a digit index
91
+ # @return [true, false] the digit's current state
92
+ #
93
+ # @overload [](digit)
94
+ # Returns the state of a digit selected by name.
95
+ # @param [Symbol] digit a digit name
96
+ # @return [true, false] the digit's current state
97
+ def [](index_or_digit)
98
+ digit = find_digit(index_or_digit)
99
+
100
+ case (@integer_representation & binary_position(digit)) >> digits.reverse.index(digit)
101
+ when 1 then true
102
+ else
103
+ false
104
+ end
105
+ end
106
+
107
+ # @return [Array<Symbol>] a list of all digits which are enabled
108
+ def enabled_digits
109
+ set = Set[]
110
+
111
+ digits.each {|digit| set << digit if self[digit] }
112
+
113
+ set
114
+ end
115
+
116
+ # @return [Array<Symbol>] a list of all digits which are disabled
117
+ def disabled_digits
118
+ set = Set[]
119
+
120
+ digits.each {|digit| set << digit unless self[digit] }
121
+
122
+ set
123
+ end
124
+
125
+ # @return [GodObject::BitSet] a new BitSet of the same configuration with
126
+ # all digit states inverted
127
+ def invert
128
+ @configuration.new(@configuration.valid_range.max - @integer_representation)
129
+ end
130
+
131
+ # @param [GodObject::BitSet, Array<Symbol>] other another
132
+ # BitSet
133
+ # @return [GodObject::BitSet] a new BitSet with the enabled
134
+ # digits of the current and other
135
+ def +(other)
136
+ other = other.enabled_digits if other.respond_to?(:enabled_digits)
137
+
138
+ @configuration.new(enabled_digits + other)
139
+ end
140
+
141
+ # @param [GodObject::BitSet, Array<Symbol>] other another
142
+ # BitSet
143
+ # @return [GodObject::BitSet] a new BitSet with the enabled
144
+ # digits of the current without the enabled of other
145
+ def -(other)
146
+ other = other.enabled_digits if other.respond_to?(:enabled_digits)
147
+
148
+ @configuration.new(enabled_digits - other)
149
+ end
150
+
151
+ # @param [GodObject::BitSet, Integer] other another BitSet
152
+ # @return [GodObject::BitSet] a new BitSet with the enabled
153
+ # digits of the current and other
154
+ def union(other)
155
+ other = other.to_i if other.respond_to?(:to_i)
156
+
157
+ @configuration.new(@integer_representation | other)
158
+ end
159
+
160
+ alias | union
161
+
162
+ # @param [GodObject::BitSet, Integer] other another BitSet
163
+ # @return [GodObject::BitSet] a new BitSet with only those
164
+ # digits enabled which are enabled in both the current and other
165
+ def intersection(other)
166
+ other = other.to_i if other.respond_to?(:to_i)
167
+
168
+ @configuration.new(@integer_representation & other)
169
+ end
170
+
171
+ alias & intersection
172
+
173
+ # @param [GodObject::BitSet, Integer] other another BitSet
174
+ # @return [GodObject::BitSet] a new BitSet with only those enabled
175
+ # digits which are enabled in only one of current and other
176
+ def symmetric_difference(other)
177
+ other = other.to_i if other.respond_to?(:to_i)
178
+
179
+ @configuration.new(@integer_representation ^ other)
180
+ end
181
+
182
+ alias ^ symmetric_difference
183
+
184
+ # Compares the BitSet to another to determine its relative position.
185
+ #
186
+ # BitSets are only comparable if their configuration is equal. Relative
187
+ # position is then defined by comparing the Integer representation.
188
+ #
189
+ # @param [GodObject::BitSet] other a BitSet
190
+ # @return [-1, 0, 1, nil] -1 if other is greater, 0 if other is equal and
191
+ # 1 if other is lesser than self, nil if comparison is impossible
192
+ def <=>(other)
193
+ if @configuration == other.configuration
194
+ @integer_representation <=> other.integer_representation
195
+ else
196
+ nil
197
+ end
198
+ rescue NoMethodError
199
+ nil
200
+ end
201
+
202
+ # Answers if another object is equal and of the same type family.
203
+ #
204
+ # @see GodObject::BitSet#<=>
205
+ # @param [Object] other an object to be checked for equality
206
+ # @return [true, false] true if the object is considered equal and of the
207
+ # same type familiy, false otherwise
208
+ def eql?(other)
209
+ self == other && other.kind_of?(self.class)
210
+ end
211
+
212
+ # @return [see Array#hash] identity hash for hash table usage
213
+ def hash
214
+ [@configuration, @integer_representation].hash
215
+ end
216
+
217
+ # Represents a BitSet as String for debugging.
218
+ #
219
+ # @return [String] a String representation for debugging
220
+ def inspect
221
+ "#<#{self.class}: #{self.to_s.inspect}>"
222
+ end
223
+
224
+ # Represents a BitSet as a binary Integer.
225
+ #
226
+ # @return [Integer] an Integer representation
227
+ def to_i
228
+ @integer_representation
229
+ end
230
+
231
+ # Represents a BitSet as String.
232
+ #
233
+ # @param [:long, :short] format the String format
234
+ # @return [String] a String representation
235
+ def to_s(format = :long)
236
+ unless STRING_FORMAT.include?(format)
237
+ raise ArgumentError, "Invalid format: #{format.inspect}"
238
+ end
239
+
240
+ if format == :short && !@configuration.unique_characters?
241
+ raise ArgumentError, 'Short format only available for configurations with unique characters for each digit'
242
+ end
243
+
244
+ output = ''
245
+
246
+ attributes.each do |digit, value|
247
+ case value
248
+ when true
249
+ output << enabled_character(digit)
250
+ else
251
+ output << disabled_character(digit) if format == :long
252
+ end
253
+ end
254
+
255
+ if @integer_representation == 0 && format == :short
256
+ output << '-'
257
+ end
258
+
259
+ output
260
+ end
261
+
262
+ protected
263
+
264
+ # @!method digits
265
+ # @attribute digits [readonly]
266
+ # @return (see GodObject::BitSet::Configuration#digits)
267
+ # @private
268
+ #
269
+ # @!method binary_position
270
+ # @return (see GodObject::BitSet::Configuration#binary_position)
271
+ # @private
272
+ #
273
+ # @!method enabled_character
274
+ # @return (see GodObject::BitSet::Configuration#enabled_character)
275
+ # @private
276
+ #
277
+ # @!method disabled_character
278
+ # @return (see GodObject::BitSet::Configuration#disabled_character)
279
+ # @private
280
+ #
281
+ # @!method find_digit
282
+ # @return (see GodObject::BitSet::Configuration#find_digit)
283
+ # @private
284
+ #
285
+ # @!method valid_range
286
+ # @attribute valid_range [readonly]
287
+ # @return (see GodObject::BitSet::Configuration#valid_range)
288
+ # @private
289
+ def_delegators :@configuration,
290
+ :digits, :binary_position, :enabled_character,
291
+ :disabled_character, :find_digit, :valid_range
292
+
293
+ # For each configured digit name, a reader method and a reader method with
294
+ # a question mark suffix is generated to easily ask for the state of a
295
+ # single digit.
296
+ #
297
+ # @private
298
+ # @return [void]
299
+ def create_attribute_readers
300
+ bit_set = self
301
+
302
+ singleton_class.class_eval do
303
+ bit_set.digits.each do |digit|
304
+ define_method("#{digit}?") do
305
+ bit_set[digit]
306
+ end
307
+
308
+ alias :"#{digit}" :"#{digit}?"
309
+ end
310
+ end
311
+ end
312
+
313
+ end
314
+
315
+ end
316
+ end