lib/banditmask.rb in banditmask-0.2.1 vs lib/banditmask.rb in banditmask-0.3.0

- old
+ new

@@ -2,12 +2,12 @@ require 'banditmask/banditry' class BanditMask attr_reader :bitmask - def initialize(bitmask = 0b0) # :nodoc: - @bitmask = bitmask + def initialize(bitmask = nil) # :nodoc: + @bitmask = bitmask || 0b0 end ## # Returns a Hash mapping all defined names to their respective bits. # @@ -40,51 +40,102 @@ end ## # Returns an array of names of the currently enabled bits. # - # class BanditMask + # class MyMask < BanditMask # bit :read, 0b01 # bit :write, 0b10 # end # - # mask = BanditMask.new 0b01 + # mask = MyMask.new 0b01 # mask.bits # => [:read] def bits self.class.bits.select { |bit, _| include? bit }.keys end alias_method :to_a, :bits ## # Enables the bit named +bit+. Returns +self+, so calls to #<< can be # chained. (Think Array#<<.) Raises +ArgumentError+ if +bit+ does not - # correspond to a bit that was previously declared with BanditMask.bit. + # correspond to a bit that was previously defined with BanditMask.bit. # - # class BanditMask + # class MyMask < BanditMask # bit :read, 0b01 # bit :write, 0b10 # end # - # mask = BanditMask.new - # mask << :read << :write + # mask = MyMask.new # => #<MyMask:0x007f9ebd44ae40 @bitmask=0> + # mask << :read << :write # => #<MyMask:0x007f9ebd44ae40 @bitmask=3> def <<(bit) @bitmask |= bit_value(bit) self end ## - # Returns false if any bit in +bits+ is not enabled. Returns true otherwise. - # Raises +ArgumentError+ if +bits+ is empty or if any element in +bits+ does - # not correspond to bit that was previously declared with BanditMask.bit. + # Returns a new instance with the current bitmask plus +bit+. Raises + # +ArgumentError+ if +bit+ does not correspond to a bit that was previously + # defined by BanditMask.bit. # - # class BanditMask + # class MyMask < BanditMask + # bit :read, 0b01 + # bit :write, 0b10 + # end + # + # mask = MyMask.new 0b01 + # mask | :write # => #<MyMask:0x007f9e0bcf5d90 @bitmask=3> + def |(bit) + self.class.new bitmask | bit_value(bit) + end + + ## + # Returns +true+ if +other+ is an instance of the same class as +self+ and + # they have the same bitmask. + # + # class MyMask < BanditMask + # bit :read, 0b01 + # bit :write, 0b10 + # end + # + # class MyOtherMask < BanditMask + # bit :chocolate, 0b01 + # bit :vanilla, 0b10 + # end + # + # a = MyMask.new 0b1 + # b = MyMask.new 0b1 + # c = MyMask.new 0b0 + # d = MyOtherMask.new 0b1 + # + # a == b # => true + # a == c # => false + # a == d # => false + def ==(other) + other.class == self.class && other.bitmask == bitmask + end + + alias_method :eql?, :== + + ## + # Returns an object hash. Two BanditMask objects have identical hashes if + # they have identical bitmasks and are instances of the same class. + def hash + [bitmask, self.class].hash + end + + ## + # Returns true if every bit in +bits+ is enabled and false otherwise. Raises + # +ArgumentError+ if +bits+ is empty or if any element in +bits+ does not + # correspond to a bit that was previously defined with BanditMask.bit. + # + # class MyMask < BanditMask # bit :read, 0b001 # bit :write, 0b010 # bit :execute, 0b100 # end # - # mask = BanditMask.new 0b101 + # mask = MyMask.new 0b101 # # mask.include? :read # => true # mask.include? :write # => false # mask.include? :execute # => true # @@ -95,9 +146,12 @@ bits.all? { |bit| bitmask & bit_value(bit) != 0 } end private + ## + # Returns the integer value for the bit named +bit+. Raises +ArgumentError+ + # if +bit+ has not been previously defined with BanditMask.bit. def bit_value(bit) self.class.bits.fetch(bit) do raise ArgumentError, "undefined bit: #{bit.inspect}" end end