banditmask 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|