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.
@@ -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