banditmask 0.2.1 → 0.3.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 +4 -4
- data/README.md +28 -15
- data/lib/banditmask.rb +67 -13
- data/lib/banditmask/banditry.rb +71 -37
- data/lib/banditmask/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c07c68905cfe2a56b3ba19fa9192604e505fe06e
|
|
4
|
+
data.tar.gz: 5787ac69e4472405d2e0408203e788128eaabb19
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5535575ab548f020d6043df8927ba7da1fe90bf094c76894890894f1c9c153dabf6fab2501ed23be227c169a8d53af94c41b579a6631777b0c30611876a51c9e
|
|
7
|
+
data.tar.gz: b0a80aa7a44e9e02d32465d9bc4c200d697bb5fdefe63239328faad9255e3b387d06fbf5fe44717017ae239be4ec500915b23fc9a70ac3bc3cb8b5eb10e3b3a9
|
data/README.md
CHANGED
|
@@ -22,7 +22,9 @@ Or install it yourself as:
|
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
### BanditMask
|
|
26
|
+
|
|
27
|
+
Create a class which inherits from BanditMask, and declare the available bit
|
|
26
28
|
names and their corresponding values.
|
|
27
29
|
|
|
28
30
|
```ruby
|
|
@@ -47,25 +49,29 @@ mask = ChmodMask.new current_bitmask
|
|
|
47
49
|
Enable bits by name.
|
|
48
50
|
|
|
49
51
|
```ruby
|
|
50
|
-
mask << :read << :
|
|
52
|
+
mask << :read << :execute
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
Ask whether specific bits are enabled.
|
|
54
56
|
|
|
55
57
|
```ruby
|
|
56
|
-
mask.include? :read
|
|
57
|
-
mask.include? :write
|
|
58
|
-
mask.include? :execute
|
|
58
|
+
mask.include? :read # => true
|
|
59
|
+
mask.include? :write # => false
|
|
60
|
+
mask.include? :execute # => true
|
|
61
|
+
mask.include? :read, :write # => false
|
|
62
|
+
mask.include? :read, :execute # => true
|
|
59
63
|
```
|
|
60
64
|
|
|
61
65
|
Retrieve a list of all currently enabled bits.
|
|
62
66
|
|
|
63
67
|
```ruby
|
|
64
|
-
mask.bits # => [:read, :
|
|
68
|
+
mask.bits # => [:read, :execute]
|
|
65
69
|
```
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
### BanditMask::Banditry
|
|
72
|
+
|
|
73
|
+
In a class with a bitmask attribute, extend BanditMask::Banditry and call
|
|
74
|
+
BanditMask::Banditry.bandit_mask to add accessor methods for working with the
|
|
69
75
|
bitmask attribute.
|
|
70
76
|
|
|
71
77
|
```ruby
|
|
@@ -77,28 +83,35 @@ class ObjectWithBitmaskAttribute
|
|
|
77
83
|
end
|
|
78
84
|
|
|
79
85
|
obj = ObjectWithBitmaskAttribute.new
|
|
80
|
-
obj.bitmask =
|
|
86
|
+
obj.bitmask = 0b001
|
|
81
87
|
```
|
|
82
88
|
|
|
83
|
-
This gives you a reader method which
|
|
89
|
+
This gives you a reader method which returns the BanditMask representation
|
|
90
|
+
of the bitmask attribute.
|
|
84
91
|
|
|
85
92
|
```ruby
|
|
86
|
-
obj.bits # =>
|
|
93
|
+
obj.bits # => #<ChmodMask:0x007f941b9518c8 @bitmask=1>
|
|
87
94
|
```
|
|
88
95
|
|
|
89
|
-
It also gives you a writer method which lets you
|
|
96
|
+
It also gives you a writer method which lets you modify the bitmask. The
|
|
97
|
+
writer accepts BanditMask objects or an Array of bits.
|
|
90
98
|
|
|
91
99
|
```ruby
|
|
100
|
+
obj.bits |= :write
|
|
101
|
+
obj.bitmask # => 3
|
|
92
102
|
obj.bits = [:read, :execute]
|
|
93
103
|
obj.bitmask # => 5
|
|
94
104
|
```
|
|
95
105
|
|
|
96
|
-
Finally, it gives you a query method for checking whether
|
|
106
|
+
Finally, it gives you a query method for checking whether particular bits are
|
|
97
107
|
set on the bitmask.
|
|
98
108
|
|
|
99
109
|
```ruby
|
|
100
|
-
obj.
|
|
101
|
-
obj.
|
|
110
|
+
obj.bits? :read # => true
|
|
111
|
+
obj.bits? :write # => false
|
|
112
|
+
obj.bits? :execute # => true
|
|
113
|
+
obj.bits? :read, :write # => false
|
|
114
|
+
obj.bits? :read, :execute # => true
|
|
102
115
|
```
|
|
103
116
|
|
|
104
117
|
## Development
|
data/lib/banditmask.rb
CHANGED
|
@@ -4,8 +4,8 @@ require 'banditmask/banditry'
|
|
|
4
4
|
class BanditMask
|
|
5
5
|
attr_reader :bitmask
|
|
6
6
|
|
|
7
|
-
def initialize(bitmask =
|
|
8
|
-
@bitmask = bitmask
|
|
7
|
+
def initialize(bitmask = nil) # :nodoc:
|
|
8
|
+
@bitmask = bitmask || 0b0
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
##
|
|
@@ -42,12 +42,12 @@ class BanditMask
|
|
|
42
42
|
##
|
|
43
43
|
# Returns an array of names of the currently enabled bits.
|
|
44
44
|
#
|
|
45
|
-
# class BanditMask
|
|
45
|
+
# class MyMask < BanditMask
|
|
46
46
|
# bit :read, 0b01
|
|
47
47
|
# bit :write, 0b10
|
|
48
48
|
# end
|
|
49
49
|
#
|
|
50
|
-
# mask =
|
|
50
|
+
# mask = MyMask.new 0b01
|
|
51
51
|
# mask.bits # => [:read]
|
|
52
52
|
def bits
|
|
53
53
|
self.class.bits.select { |bit, _| include? bit }.keys
|
|
@@ -57,32 +57,83 @@ class BanditMask
|
|
|
57
57
|
##
|
|
58
58
|
# Enables the bit named +bit+. Returns +self+, so calls to #<< can be
|
|
59
59
|
# chained. (Think Array#<<.) Raises +ArgumentError+ if +bit+ does not
|
|
60
|
-
# correspond to a bit that was previously
|
|
60
|
+
# correspond to a bit that was previously defined with BanditMask.bit.
|
|
61
61
|
#
|
|
62
|
-
# class BanditMask
|
|
62
|
+
# class MyMask < BanditMask
|
|
63
63
|
# bit :read, 0b01
|
|
64
64
|
# bit :write, 0b10
|
|
65
65
|
# end
|
|
66
66
|
#
|
|
67
|
-
# mask =
|
|
68
|
-
# mask << :read << :write
|
|
67
|
+
# mask = MyMask.new # => #<MyMask:0x007f9ebd44ae40 @bitmask=0>
|
|
68
|
+
# mask << :read << :write # => #<MyMask:0x007f9ebd44ae40 @bitmask=3>
|
|
69
69
|
def <<(bit)
|
|
70
70
|
@bitmask |= bit_value(bit)
|
|
71
71
|
self
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
##
|
|
75
|
-
# Returns
|
|
76
|
-
#
|
|
77
|
-
#
|
|
75
|
+
# Returns a new instance with the current bitmask plus +bit+. Raises
|
|
76
|
+
# +ArgumentError+ if +bit+ does not correspond to a bit that was previously
|
|
77
|
+
# defined by BanditMask.bit.
|
|
78
|
+
#
|
|
79
|
+
# class MyMask < BanditMask
|
|
80
|
+
# bit :read, 0b01
|
|
81
|
+
# bit :write, 0b10
|
|
82
|
+
# end
|
|
78
83
|
#
|
|
79
|
-
#
|
|
84
|
+
# mask = MyMask.new 0b01
|
|
85
|
+
# mask | :write # => #<MyMask:0x007f9e0bcf5d90 @bitmask=3>
|
|
86
|
+
def |(bit)
|
|
87
|
+
self.class.new bitmask | bit_value(bit)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# Returns +true+ if +other+ is an instance of the same class as +self+ and
|
|
92
|
+
# they have the same bitmask.
|
|
93
|
+
#
|
|
94
|
+
# class MyMask < BanditMask
|
|
95
|
+
# bit :read, 0b01
|
|
96
|
+
# bit :write, 0b10
|
|
97
|
+
# end
|
|
98
|
+
#
|
|
99
|
+
# class MyOtherMask < BanditMask
|
|
100
|
+
# bit :chocolate, 0b01
|
|
101
|
+
# bit :vanilla, 0b10
|
|
102
|
+
# end
|
|
103
|
+
#
|
|
104
|
+
# a = MyMask.new 0b1
|
|
105
|
+
# b = MyMask.new 0b1
|
|
106
|
+
# c = MyMask.new 0b0
|
|
107
|
+
# d = MyOtherMask.new 0b1
|
|
108
|
+
#
|
|
109
|
+
# a == b # => true
|
|
110
|
+
# a == c # => false
|
|
111
|
+
# a == d # => false
|
|
112
|
+
def ==(other)
|
|
113
|
+
other.class == self.class && other.bitmask == bitmask
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
alias_method :eql?, :==
|
|
117
|
+
|
|
118
|
+
##
|
|
119
|
+
# Returns an object hash. Two BanditMask objects have identical hashes if
|
|
120
|
+
# they have identical bitmasks and are instances of the same class.
|
|
121
|
+
def hash
|
|
122
|
+
[bitmask, self.class].hash
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
##
|
|
126
|
+
# Returns true if every bit in +bits+ is enabled and false otherwise. Raises
|
|
127
|
+
# +ArgumentError+ if +bits+ is empty or if any element in +bits+ does not
|
|
128
|
+
# correspond to a bit that was previously defined with BanditMask.bit.
|
|
129
|
+
#
|
|
130
|
+
# class MyMask < BanditMask
|
|
80
131
|
# bit :read, 0b001
|
|
81
132
|
# bit :write, 0b010
|
|
82
133
|
# bit :execute, 0b100
|
|
83
134
|
# end
|
|
84
135
|
#
|
|
85
|
-
# mask =
|
|
136
|
+
# mask = MyMask.new 0b101
|
|
86
137
|
#
|
|
87
138
|
# mask.include? :read # => true
|
|
88
139
|
# mask.include? :write # => false
|
|
@@ -97,6 +148,9 @@ class BanditMask
|
|
|
97
148
|
|
|
98
149
|
private
|
|
99
150
|
|
|
151
|
+
##
|
|
152
|
+
# Returns the integer value for the bit named +bit+. Raises +ArgumentError+
|
|
153
|
+
# if +bit+ has not been previously defined with BanditMask.bit.
|
|
100
154
|
def bit_value(bit)
|
|
101
155
|
self.class.bits.fetch(bit) do
|
|
102
156
|
raise ArgumentError, "undefined bit: #{bit.inspect}"
|
data/lib/banditmask/banditry.rb
CHANGED
|
@@ -1,54 +1,88 @@
|
|
|
1
1
|
class BanditMask
|
|
2
|
+
class MethodCollisionError < StandardError
|
|
3
|
+
end
|
|
4
|
+
|
|
2
5
|
module Banditry
|
|
3
6
|
##
|
|
4
|
-
# Creates wrapper methods for reading and
|
|
5
|
-
# +attribute+ using the class +with+. +with+ defaults to
|
|
6
|
-
# you can (and probably
|
|
7
|
-
# +BanditMask+ to fill this role. The name of the accessor
|
|
8
|
-
# derived from +as+, e.g., if +as+ is +:foo+, the
|
|
9
|
-
#
|
|
7
|
+
# Creates wrapper methods for reading, writing, and querying the bitmask
|
|
8
|
+
# stored in +attribute+ using the class +with+. +with+ defaults to
|
|
9
|
+
# BanditMask, but you can (and probably should) define your own class
|
|
10
|
+
# inheriting from +BanditMask+ to fill this role. The name of the accessor
|
|
11
|
+
# methods will be derived from +as+, e.g., if +as+ is +:foo+, the methods
|
|
12
|
+
# will be named +:foo+, +:foo=+, and +:foo?+.
|
|
10
13
|
#
|
|
11
|
-
# The reader method will
|
|
12
|
-
# enabled bit names represented by +attribute+.
|
|
14
|
+
# The reader method will return a BanditMask representation of +attribute+.
|
|
13
15
|
#
|
|
14
|
-
# The writer method
|
|
15
|
-
#
|
|
16
|
+
# The writer method overwrites the current bitmask if with an Array of
|
|
17
|
+
# bits, or it updates the current bitmask if sent an individual bit, e.g.,
|
|
18
|
+
# using +#|+.
|
|
16
19
|
#
|
|
17
|
-
# In addition to the accessor methods, a method
|
|
18
|
-
#
|
|
20
|
+
# In addition to the accessor methods, a query method that delegates to
|
|
21
|
+
# BanditMask#include? will be added.
|
|
19
22
|
#
|
|
20
|
-
# class
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
23
|
+
# class FileMask < BanditMask
|
|
24
|
+
# bit :r, 0b001
|
|
25
|
+
# bit :w, 0b010
|
|
26
|
+
# bit :e, 0b100
|
|
24
27
|
# end
|
|
25
28
|
#
|
|
26
|
-
# class
|
|
27
|
-
# attr_accessor :
|
|
29
|
+
# class FileObject
|
|
30
|
+
# attr_accessor :mode_mask
|
|
28
31
|
#
|
|
29
32
|
# extend BanditMask::Banditry
|
|
30
|
-
# bandit_mask :
|
|
33
|
+
# bandit_mask :mode_mask, as: :mode, with: FileMask
|
|
31
34
|
# end
|
|
35
|
+
#
|
|
36
|
+
# file = FileObject.new
|
|
37
|
+
# file.mode_mask # => nil
|
|
38
|
+
# file.mode |= :r
|
|
39
|
+
# file.mode_mask # => 1
|
|
40
|
+
# file.mode |= :w
|
|
41
|
+
# file.mode_mask # => 3
|
|
42
|
+
# file.mode = [:r, :x]
|
|
43
|
+
# file.mode_mask # => 5
|
|
32
44
|
def bandit_mask(attribute, as:, with: BanditMask)
|
|
33
|
-
cls = with
|
|
34
|
-
wrapper = as
|
|
35
|
-
|
|
36
45
|
class_eval do
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
generate_reader attribute, as, with
|
|
47
|
+
generate_writer attribute, as, with
|
|
48
|
+
generate_query attribute, as, with
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def generate_reader(attr, virt, cls)
|
|
55
|
+
respond_to? virt and
|
|
56
|
+
raise MethodCollisionError, "method `#{virt}` already exists"
|
|
57
|
+
|
|
58
|
+
define_method virt do
|
|
59
|
+
instance_variable_get(:"@#{virt}") ||
|
|
60
|
+
instance_variable_set(:"@#{virt}", cls.new(send(attr)))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def generate_writer(attr, virt, cls)
|
|
65
|
+
respond_to? :"#{virt}=" and
|
|
66
|
+
raise MethodCollisionError, "method `#{virt}=` already exists"
|
|
67
|
+
|
|
68
|
+
define_method :"#{virt}=" do |bits|
|
|
69
|
+
mask = case bits
|
|
70
|
+
when BanditMask
|
|
71
|
+
bits
|
|
72
|
+
else
|
|
73
|
+
bits.inject(cls.new) { |bm, bit| bm << bit }
|
|
74
|
+
end
|
|
75
|
+
send :"#{attr}=", Integer(mask)
|
|
76
|
+
instance_variable_set :"@#{virt}", mask
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def generate_query(attr, virt, cls)
|
|
81
|
+
respond_to? :"#{virt}?" and
|
|
82
|
+
raise MethodCollisionError, "method `#{virt}?` already exists"
|
|
83
|
+
|
|
84
|
+
define_method :"#{virt}?" do |*bits|
|
|
85
|
+
cls.new(send(attr)).include? *bits
|
|
52
86
|
end
|
|
53
87
|
end
|
|
54
88
|
end
|
data/lib/banditmask/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: banditmask
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Parker
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-07-
|
|
11
|
+
date: 2015-07-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|