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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 89f4119902ba1674931d97b169c39ce1037ae2ae
4
- data.tar.gz: a5db82f06d10b4bdc8ff6927d9cc872df3f89721
3
+ metadata.gz: c07c68905cfe2a56b3ba19fa9192604e505fe06e
4
+ data.tar.gz: 5787ac69e4472405d2e0408203e788128eaabb19
5
5
  SHA512:
6
- metadata.gz: ec236a1784b37496fde1b63972587ff6bd57249dd7e68b3ae57107b52092274172fc99b188b31e2a0b7b97f04cf4da1f955356c339fb4c47fdb0bb3c0a5a91ce
7
- data.tar.gz: 280fb89f74711b141be7a505e4f05756443276322407df26a326681a705116583089af90b4b66aa98349f35238fb9e101b0f775542fd4ece051ceb4d1a1629a2
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
- Create a class which inherits from `BanditMask`, and declare the available bit
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 << :write
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 # => true
57
- mask.include? :write # => true
58
- mask.include? :execute # => false
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, :write]
68
+ mask.bits # => [:read, :execute]
65
69
  ```
66
70
 
67
- In an class with a bitmask attribute, extend `BanditMask::Banditry` and call
68
- `BanditMask::Banditry.bandit_mask` to add accessor methods for working with the
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 = 0b011
86
+ obj.bitmask = 0b001
81
87
  ```
82
88
 
83
- This gives you a reader method which delegates to `BanditMask#bits`.
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 # => [:read, :write]
93
+ obj.bits # => #<ChmodMask:0x007f941b9518c8 @bitmask=1>
87
94
  ```
88
95
 
89
- It also gives you a writer method which lets you overwrite the bitmask.
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 a particular bit is
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.has? :read # => true
101
- obj.has? :write # => false
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 = 0b0) # :nodoc:
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 = BanditMask.new 0b01
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 declared with BanditMask.bit.
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 = BanditMask.new
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 false if any bit in +bits+ is not enabled. Returns true otherwise.
76
- # Raises +ArgumentError+ if +bits+ is empty or if any element in +bits+ does
77
- # not correspond to bit that was previously declared with BanditMask.bit.
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
- # class BanditMask
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 = BanditMask.new 0b101
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}"
@@ -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 writing the bitmask stored in
5
- # +attribute+ using the class +with+. +with+ defaults to BanditMask, but
6
- # you can (and probably) should define your own class descending from
7
- # +BanditMask+ to fill this role. The name of the accessor methods will be
8
- # derived from +as+, e.g., if +as+ is +:foo+, the reader method will be
9
- # +:foo+ and the writer will be +:foo=+.
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 call BanditMask#bits to get an array of the
12
- # enabled bit names represented by +attribute+.
14
+ # The reader method will return a BanditMask representation of +attribute+.
13
15
  #
14
- # The writer method will replace the current bitmask with an Integer
15
- # representation of a new BanditMask built up using BanditMask#<<.
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 named +has?+ will be added
18
- # which delegates to the BanditMask#include?.
20
+ # In addition to the accessor methods, a query method that delegates to
21
+ # BanditMask#include? will be added.
19
22
  #
20
- # class ThingMask < BanditMask
21
- # # ...
22
- # # bit :foo, 0b1
23
- # # ...
23
+ # class FileMask < BanditMask
24
+ # bit :r, 0b001
25
+ # bit :w, 0b010
26
+ # bit :e, 0b100
24
27
  # end
25
28
  #
26
- # class Thing
27
- # attr_accessor :bitmask
29
+ # class FileObject
30
+ # attr_accessor :mode_mask
28
31
  #
29
32
  # extend BanditMask::Banditry
30
- # bandit_mask :bitmask, as: :bits, with: ThingMask
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
- # A reader method which instances a new BanditMask object and calls
39
- # BanditMask#bits.
40
- define_method wrapper do
41
- cls.new(send(attribute)).bits
42
- end
43
-
44
- define_method :"#{wrapper}=" do |bits|
45
- mask = bits.reduce(cls.new) { |mask, bit| mask << bit }
46
- send :"#{attribute}=", Integer(mask)
47
- end
48
-
49
- define_method :has? do |*bits|
50
- cls.new(send(attribute)).include? *bits
51
- end
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
@@ -1,3 +1,3 @@
1
1
  class BanditMask
2
- VERSION = '0.2.1'
2
+ VERSION = '0.3.0'
3
3
  end
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.2.1
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-06 00:00:00.000000000 Z
11
+ date: 2015-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler