enums 1.3.0 → 1.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 21d675f9ace380c191b6ee58c484ab192dbdb440
4
- data.tar.gz: 42c0d89f1a150c48a432b3c2d1b1fbbe00ac1aa0
3
+ metadata.gz: 65a45b808ac04efdf1cf4b9b299b61882d691605
4
+ data.tar.gz: fc6259850c15fe3f81ee5d8e2bebf4d40f0a754f
5
5
  SHA512:
6
- metadata.gz: f990e4ab5fcc741b1226a3f4eb0d8f9e53f8b2b446d1c8175a4f8bd3464d6fcde42a59cc966735bd2216abc4ec397fd3f043c89254815209c7c61fd0464459ba
7
- data.tar.gz: 22ff3b44aea19efd814a45f3ad46184bfaf9df24bbb3e23bb306b91b9f068ff68381de7404293ecb47d5e8b8e6e8d669d92f184d2adcd36ff372740b2c35ce57
6
+ metadata.gz: f4875a80e70ac8099ce8b79b92ec6385edced9606a4e873c2ffd3709dd2d454d6057c4aab302c5fa6f4a78999dd79bf36a0fc910ee216af1bbdaaccdc764f25a
7
+ data.tar.gz: 38c9a7a44081ecad43ebd9431c3149f48632466499dfea0029532dd036013e8a59add6cd33996cd96cccd61c170e24d3b7ad8803fb41c5c39359d71e20556ba1
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Enums - Safe Enumeration Types
2
2
 
3
- enums library / gem - safe enumeration types - a set of symbolic keys bound to unique integer numbers
3
+ enums library / gem - safe enumeration types - a set of symbolic keys bound to unique integer numbers (incl. bit flags option)
4
4
 
5
5
  * home :: [github.com/s6ruby/enums](https://github.com/s6ruby/enums)
6
6
  * bugs :: [github.com/s6ruby/enums/issues](https://github.com/s6ruby/enums/issues)
@@ -50,7 +50,7 @@ enum :Color, :red, :green, :blue
50
50
  # or
51
51
  enum :Color, [:red, :green, :blue]
52
52
  # or
53
- enum :Color, { red: 0,
53
+ enum :Color, { red: 0,
54
54
  green: 1,
55
55
  blue: 2 }
56
56
 
@@ -149,8 +149,8 @@ enum :State, :fundraising, :expired_refund, :successful
149
149
  # or
150
150
  enum :State, [:fundraising, :expired_refund, :successful]
151
151
  # or
152
- enum :State, { fundraising: 0,
153
- expired_refund: 1,
152
+ enum :State, { fundraising: 0,
153
+ expired_refund: 1,
154
154
  successful: 2 }
155
155
 
156
156
 
@@ -231,21 +231,25 @@ end
231
231
 
232
232
  class FileAttrib < Flag
233
233
 
234
+ NONE = new( :none, 0 )
234
235
  READ_ONLY = new( :read_only, 1<<0 )
235
236
  HIDDEN = new( :hidden, 1<<1 )
236
237
  SYSTEM = new( :system, 1<<2 )
237
238
  ARCHIVE = new( :archive, 1<<3 )
239
+ ALL = new( :all, 1<<0|1<<1|1<<2|1<<3 )
238
240
 
241
+ def self.none() NONE; end
239
242
  def self.read_only() READ_ONLY; end
240
243
  def self.hidden() HIDDEN; end
241
244
  def self.system() SYSTEM; end
242
245
  def self.archive() ARCHIVE; end
246
+ def self.all() ALL; end
243
247
 
244
248
  def self.values() [1<<0,1<<1,1<<2,1<<3]; end
245
249
  def self.keys() [:read_only, :hidden, :system, :archive]; end
246
250
  def self.members() [READ_ONLY, HIDDEN, SYSTEM, ARCHIVE]; end
247
251
 
248
- def self.zero() @zero ||= new(0); end
252
+ def self.zero() NONE; end
249
253
 
250
254
  def self.key( key )
251
255
  @hash_by_key ||= Hash[ keys.zip( members ) ]
@@ -253,10 +257,12 @@ class FileAttrib < Flag
253
257
  end
254
258
  def self.[]( key ) self.key( key ); end
255
259
 
256
- def read_only?() member?( READ_ONLY ); end
257
- def hidden?() member?( HIDDEN ); end
258
- def system?() member?( SYSTEM ); end
259
- def archive?() member?( ARCHIVE ); end
260
+ def none? @value == 0; end
261
+ def read_only?() @value & 1<<0 == 1<<0; end
262
+ def hidden?() @value & 1<<1 == 1<<1; end
263
+ def system?() @value & 1<<2 == 1<<2; end
264
+ def archive?() @value & 1<<3 == 1<<3; end
265
+ def all?() @value == 1<<0|1<<1|1<<2|1<<3; end
260
266
 
261
267
  def member?( other ) @value & other.value == other.value; end
262
268
 
@@ -284,15 +290,11 @@ class FileAttrib < Flag
284
290
  alias_method :toggle, :bitwise_xor
285
291
 
286
292
  # ...
287
-
288
- def initialize( *args )
289
- # ...
290
- end
291
293
  end
292
294
 
293
295
 
294
296
  def FileAttrib( *args )
295
- FileAttrib.new( *args )
297
+ FileAttrib.convert( *args )
296
298
  end
297
299
  ```
298
300
 
@@ -306,20 +308,16 @@ FileAttrib.read_only #=> <FileAttrib @key=:read_only, @valu
306
308
  FileAttrib::READ_ONLY #=> <FileAttrib @key=:read_only, @value=1>
307
309
  FileAttribs[:read_only] #=> <FileAttrib @key=:read_only, @value=1>
308
310
 
309
- FileAttrib(0) #=> <FileAttrib @key=:0000, @value=0>
311
+ FileAttrib(0) #=> <FileAttrib @key=:none, @value=0>
310
312
  FileAttrib.read_only | FileAttrib.hidden #=> <FileAttrib @key=:0011, @value=3>
311
313
  # -or-
312
- FileAttrib.new( FileAttrib.read_only | FileAttrib.hidden )
313
- FileAttrib.new( FileAttrib::READ_ONLY | FileAttrib::HIDDEN )
314
- FileAttrib.new( :read_only, :hidden )
315
- # -or-
316
314
  FileAttrib( FileAttrib.read_only | FileAttrib.hidden )
317
315
  FileAttrib( FileAttrib::READ_ONLY | FileAttrib::HIDDEN )
318
316
  FileAttrib( :read_only, :hidden )
319
317
  #=> <FileAttrib @key=:0011, @value=3>
320
318
 
321
- attrib = FileAttrib.new #=> <FileAttrib @key=:0000, @value=0>
322
- attrib |= FileAttrib.read_only #=> <FileAttrib @key=:0001, @value=1>
319
+ attrib = FileAttrib.none #=> <FileAttrib @key=:none, @value=0>
320
+ attrib |= FileAttrib.read_only #=> <FileAttrib @key=:read_only, @value=1>
323
321
  attrib.read_only? #=> true
324
322
  # -or-
325
323
  attrib.member?( FileAttrib.read_only ) #=> true
@@ -327,12 +325,12 @@ attrib.member?( FileAttrib.READ_ONLY ) #=> true
327
325
  attrib.member?( :read_only ) #=> true
328
326
  attrib & FileAttrib.read_only == FileAttrib.read_only #=> true
329
327
 
330
- attrib ^= FileAttrib.read_only #=> <FileAttrib @key=:0000, @value=0>
328
+ attrib ^= FileAttrib.read_only #=> <FileAttrib @key=:none, @value=0>
331
329
  attrib.read_only? #=> false
332
- attrib ^= FileAttrib.read_only #=> <FileAttrib @key=:0001, @value=1>
330
+ attrib ^= FileAttrib.read_only #=> <FileAttrib @key=:read_ony, @value=1>
333
331
  attrib.read_only? #=> true
334
332
 
335
- attrib &= ~FileAttrib.read_only #=> <FileAttrib @key=:0000, @value=0>
333
+ attrib &= ~FileAttrib.read_only #=> <FileAttrib @key=:none, @value=0>
336
334
  attrib.read_only? #=> false
337
335
 
338
336
  attrib.is_a? Flag #=> true
@@ -340,6 +338,66 @@ attrib.is_a? FileAttrib #=> true
340
338
  # ...
341
339
  ```
342
340
 
341
+
342
+ Let's try another example:
343
+
344
+ ``` ruby
345
+ Flag.new( :TextStyle, :bold, :italic, :underline )
346
+ # -or -
347
+ enum :TextStyle, [:bold, :italic, :underline], flags: true
348
+ # -or -
349
+ enum :TextStyle, :bold, :italic, :underline, flags: true
350
+ # -or -
351
+ enum :TextStyle, { bold: 1<<0,
352
+ italic: 1<<1,
353
+ underline: 1<<2
354
+ },
355
+ flags: true
356
+
357
+
358
+ TextStyle.values #=> [1, 2, 4]
359
+ TextStyle.keys #=> [:bold, :italic, :underline]
360
+
361
+ TextStyle.bold #=> <TextStyle @key=:bold, @value=1>
362
+ TextStyle::BOLD #=> <TextStyle @key=:bold, @value=1>
363
+ TextStyle[:bold] #=> <TextStyle @key=:bold, @value=1>
364
+
365
+ TextStyle(0) #=> <TextStyle @key=:none, @value=0>
366
+ TextStyle.bold | TextStyle.italic #=> <TextStyle @key=:0011, @value=3>
367
+ # -or-
368
+ TextStyle( TextStyle.bold | TextStyle.italic )
369
+ TextStyle( TextStyle::BOLD | TextStyle::ITALIC )
370
+ TextStyle( :bold, :italic )
371
+ #=> <TextStyle @key=:0011, @value=3>
372
+
373
+ style = TextStyle.none #=> <TextStyle @key=:none, @value=0>
374
+ style |= TextStyle.bold #=> <TextStyle @key=:bold, @value=1>
375
+ style.bold? #=> true
376
+ # -or-
377
+ style.member?( TextStyle.bold ) #=> true
378
+ style.member?( TextStyle.BOLD ) #=> true
379
+ style.member?( :bold ) #=> true
380
+ style & TextStyle.bold == TextStyle.bold #=> true
381
+
382
+ style ^= TextStyle.bold #=> <TextStyle @key=:none, @value=0>
383
+ style.bold? #=> false
384
+ style ^= TextStyle.bold #=> <TextStyle @key=:bold, @value=1>
385
+ style.bold? #=> true
386
+
387
+ style &= ~TextStyle.bold #=> <TextStyle @key=:none, @value=0>
388
+ style.bold? #=> false
389
+
390
+ style = TextStyle.bold | TextStyle.italic | TextStyle.underline
391
+ #=> <TextStyle @key=:all, @value=7>
392
+ style & TextStyle.all == TextStyle.all #=> true
393
+ style & TextStyle.all != 0 #=> true
394
+ style.all? #=> true
395
+
396
+ style.is_a? Flag #=> true
397
+ style.is_a? TextStyle #=> true
398
+ # ...
399
+ ```
400
+
343
401
  and so on.
344
402
 
345
403
 
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ Hoe.spec 'enums' do
5
5
 
6
6
  self.version = Enums::VERSION
7
7
 
8
- self.summary = "enums - safe enumeration types - a set of symbolic keys bound to unique integer numbers"
8
+ self.summary = "enums - safe enumeration types - a set of symbolic keys bound to unique integer numbers (incl. bit flags option)"
9
9
  self.description = summary
10
10
 
11
11
  self.urls = ['https://github.com/s6ruby/enums']
@@ -10,47 +10,32 @@ class Flag
10
10
  attr_reader :key
11
11
  attr_reader :value
12
12
 
13
- def initialize( *args )
14
- fmt = "%08b"
15
-
16
- if args.size == 0
17
- @value = 0 ## same as new(0)
18
- @key = :"#{fmt % @value}" ## use :none for 0 key - why? why not?
19
- elsif args.size == 1 && args[0].is_a?(Integer)
20
- @value = args[0]
21
- @key = :"#{fmt % @value}" ## todo: lookup if value is a known flag (with key) - why? why not?
22
- elsif args.size == 2 && args[0].is_a?(Symbol) && args[1].is_a?(Integer)
23
- @key = args[0]
24
- @value = args[1]
25
- else
26
- ## assume flag object or symbols
27
- @value = 0
28
- args.each do |arg|
29
- flag = _typecast_flag!( arg )
30
- @value |= flag.value
31
- end
32
- @key = :"#{fmt % @value}" ## todo: lookup if value is a known flag (with key) - why? why not?
33
- end
34
- self.freeze ## make "immutable" - should be a value object like an integer number!!!
35
- self # return self for chaining
13
+ def initialize( key, value )
14
+ @key = key
15
+ @value = value
16
+ self.freeze
17
+ self
36
18
  end
37
19
 
38
-
39
- def _typecheck_flag!( o )
40
- if self.class == o.class
20
+ def self._typecheck_flag!( o )
21
+ if self == o.class
41
22
  o
42
23
  else
43
- raise TypeError.new( "[Flag] flag >#{self.class.name}< type expected; got >#{o.class.inspect}<" )
24
+ raise TypeError.new( "[Flag] flag >#{name}< type expected; got >#{o.class.inspect}<" )
44
25
  end
45
26
  end
46
27
 
47
- def _typecast_flag!( o )
28
+ def self._typecast_flag!( o )
48
29
  if o.is_a? Symbol ## auto-convert symbol to flag
49
- o = self.class.key( o ) ## lookup symbol in "parent" flags class
30
+ o = key( o ) ## lookup symbol in "parent" flags class
50
31
  end
51
32
  _typecheck_flag!( o )
52
33
  end
53
34
 
35
+ def _typecheck_flag!( o ) self.class._typecheck_flag!( o ); end
36
+ def _typecast_flag!( o ) self.class._typecast_flag!( o ); end
37
+
38
+
54
39
 
55
40
  def ==( other )
56
41
  if self.class == other.class
@@ -64,56 +49,58 @@ class Flag
64
49
  alias_method :eql?, :==
65
50
 
66
51
 
67
- def member?( other ) _member?(_typecast_flag!( other )); end
68
- def _member?( other ) @value & other.value == other.value; end
52
+ def member?( other )
53
+ other = _typecast_flag!( other )
54
+ @value & other.value == other.value
55
+ end
69
56
 
70
57
 
71
58
  def bitwise_or( other )
72
- self.class.new( @value | _typecheck_flag!( other ).value )
59
+ self.class.build( @value | _typecheck_flag!( other ).value )
73
60
  end
74
- alias_method :|, :bitwise_or
61
+ alias_method :|, :bitwise_or
75
62
 
76
63
  def bitwise_and( other )
77
- self.class.new( @value & _typecheck_flag!( other ).value )
64
+ self.class.build( @value & _typecheck_flag!( other ).value )
78
65
  end
79
66
  alias_method :&, :bitwise_and
80
67
 
81
68
  def bitwise_xor( other )
82
- self.class.new( @value ^ _typecheck_flag!( other ).value )
69
+ self.class.build( @value ^ _typecheck_flag!( other ).value )
83
70
  end
84
- alias_method :^, :bitwise_xor
71
+ alias_method :^, :bitwise_xor
85
72
 
86
73
  def bitwise_inverse
87
- self.class.new( ~@value )
74
+ self.class.build( ~@value )
88
75
  end
89
76
  alias_method :~, :bitwise_inverse
90
77
 
91
78
 
92
79
  def set( other ) ## note: typecast also allows symbol e.g (:read_only, etc.)
93
- self.class.new( @value | _typecast_flag!( other ).value )
80
+ self.class.build( @value | _typecast_flag!( other ).value )
94
81
  end
95
82
  alias_method :flag, :set
96
83
 
97
84
  def unset( other )
98
- self.class.new( @value & ~_typecast_flag!( other ).value )
85
+ self.class.build( @value & ~_typecast_flag!( other ).value )
99
86
  end
100
87
  alias_method :unflag, :unset
101
88
 
102
89
  def toggle( other )
103
- self.class.new( @value ^ _typecast_flag!( other ).value )
90
+ self.class.build( @value ^ _typecast_flag!( other ).value )
104
91
  end
105
92
 
106
93
 
107
94
 
108
-
109
95
  def self.keys()
110
- # note: does NOT include none - why? why not?
96
+ # note: does NOT include :none (and :all)
111
97
  @keys ||= members.map { |member| member.key }.freeze
112
98
  end
113
99
 
114
100
  def self.key( key )
115
- @hash ||= Hash[ keys.zip( members ) ].freeze
116
- @hash[key]
101
+ # note: does NOT include :none (and :all)
102
+ @hash_by_key ||= Hash[ keys.zip( members ) ].freeze
103
+ @hash_by_key[key]
117
104
  end
118
105
 
119
106
  def self.[]( key ) ## convenience alias for key
@@ -122,23 +109,50 @@ class Flag
122
109
 
123
110
 
124
111
  def self.values()
125
- # note: does NOT include none - why? why not?
112
+ # note: does NOT include :none (and :all)
126
113
  @values ||= members.map { |member| member.value }.freeze
127
114
  end
128
115
 
116
+ def self.value( value )
117
+ ## note: adds :none and :all for value lookup
118
+ @hash_by_value ||= Hash[ values.zip( members ) ].merge( self::NONE.value => self::NONE,
119
+ self::ALL.value => self::ALL ).freeze
120
+ @hash_by_value[value]
121
+ end
122
+
123
+ def self.build( value )
124
+ o = self.value( value ) # lookup if value is a known flag (with key)
125
+ o = new( :"#{'%08b' % value}", value ) if o.nil?
126
+ o
127
+ end
128
+
129
129
 
130
- def self.zero() @zero ||= new(0); end
130
+ def self.zero() @zero ||= self::NONE; end
131
131
  def zero?() @value == 0; end
132
132
 
133
+ def self.none() self::NONE; end
134
+ def none?() @value == 0; end
135
+ def self.all() self::ALL; end
136
+ def all?() @value & self.class::ALL.value == self.class::ALL.value; end
137
+
133
138
 
134
139
  def self.convert( *args )
135
- new( *args )
140
+ if args.size == 0
141
+ self::NONE
142
+ elsif args.size == 1 && args[0].is_a?(Integer)
143
+ build( args[0] )
144
+ else
145
+ ## assume flag object or symbols
146
+ value = 0
147
+ args.each do |arg|
148
+ flag = _typecast_flag!( arg )
149
+ value |= flag.value
150
+ end
151
+ build( value )
152
+ end
136
153
  end
137
154
 
138
-
139
155
  ## add size|length too why? why not?
140
- ## add value() lookup?
141
- ## not for now - why? combined values are undefined!! what to return??
142
156
 
143
157
  ## add to_i, to_int - why? why not?
144
158
  ## def to_i() @value; end
@@ -44,12 +44,15 @@ def self.build_class( class_name, *args, **kwargs )
44
44
  end
45
45
 
46
46
  def #{key}?
47
- _member?( #{key.upcase} )
47
+ @value & #{value} == #{value}
48
48
  end
49
49
  RUBY
50
50
  end
51
51
 
52
52
  klass.class_eval( <<RUBY )
53
+ NONE = new( :none, 0 )
54
+ ALL = new( :all, #{f.values.reduce( 0 ) { |sum, value| sum|value }} )
55
+
53
56
  def self.members
54
57
  @members ||= [#{f.keys.map {|key|key.upcase}.join(',')}].freeze
55
58
  end
@@ -6,7 +6,7 @@ module Enums
6
6
 
7
7
  MAJOR = 1
8
8
  MINOR = 3
9
- PATCH = 0
9
+ PATCH = 1
10
10
  VERSION = [MAJOR,MINOR,PATCH].join('.')
11
11
 
12
12
  def self.version
@@ -60,6 +60,19 @@ def test_attrib
60
60
  assert_equal :read_only, FileAttrib.read_only.key
61
61
  assert_equal 1<<0, FileAttrib::READ_ONLY.value
62
62
  assert_equal :read_only, FileAttrib::READ_ONLY.key
63
+
64
+ attrib = FileAttrib.read_only | FileAttrib.hidden
65
+ assert_equal false, attrib.none?
66
+ assert_equal false, attrib & FileAttrib.all == FileAttrib.all
67
+ assert_equal false, attrib.all?
68
+ assert_equal true, attrib.read_only?
69
+ assert_equal true, attrib.hidden?
70
+
71
+ attrib |= FileAttrib.system
72
+ attrib |= FileAttrib.archive
73
+ assert_equal true, attrib & FileAttrib.all == FileAttrib.all
74
+ assert_equal true, attrib.all?
75
+ assert_equal false, attrib.none?
63
76
  end
64
77
 
65
78
  def test_text_style
@@ -70,6 +83,9 @@ def test_text_style
70
83
 
71
84
  style = TextStyle(0)
72
85
  assert_equal true, style == 0
86
+ assert_equal true, style.zero?
87
+ assert_equal true, style.none?
88
+
73
89
  style |= TextStyle.bold
74
90
  assert_equal true, style.member?( :bold )
75
91
  assert_equal true, style.member?( TextStyle.bold )
@@ -83,6 +99,11 @@ def test_text_style
83
99
  assert_equal true, style.member?( TextStyle.italic )
84
100
  assert_equal true, style & TextStyle.italic == TextStyle.italic
85
101
  assert_equal true, style & TextStyle.italic != 0
102
+
103
+ style = TextStyle.bold | TextStyle.italic | TextStyle.underline
104
+ assert_equal true, style & TextStyle.all == TextStyle.all
105
+ assert_equal true, style & TextStyle.all != 0
106
+ assert_equal true, style.all?
86
107
  end
87
108
 
88
109
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enums
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-28 00:00:00.000000000 Z
11
+ date: 2019-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.16'
41
41
  description: enums - safe enumeration types - a set of symbolic keys bound to unique
42
- integer numbers
42
+ integer numbers (incl. bit flags option)
43
43
  email: wwwmake@googlegroups.com
44
44
  executables: []
45
45
  extensions: []
@@ -89,5 +89,5 @@ rubygems_version: 2.5.2
89
89
  signing_key:
90
90
  specification_version: 4
91
91
  summary: enums - safe enumeration types - a set of symbolic keys bound to unique integer
92
- numbers
92
+ numbers (incl. bit flags option)
93
93
  test_files: []