Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class FlagSet
- class <<self
- # frozen flags
- attr_reader :flags
- # the amount of possible states
- attr_reader :states
- # If this flagset includes certain flag
- def include?(flag)
- @position.has_key?(flag)
- end
- # Get the Position of a flag
- def position(flag)
- @position[flag]
- end
- # Convert an integer to this kind of FlagSet
- def from(integer)
- raise ArgumentError, "Invalid State, maximum is #{states-1}" unless integer < states
- new(*@flags.select { |flag| integer[position(flag)] == 1 })
- end
- alias from_integer from
- # Example:
- # MyFlags = FlagSet.new(:a, :b, :c)
- # x = MyFlags.new(:a, :b)
- # x.a? # => true
- # x.b? # => true
- # x.c? # => false
- # x.c!
- # x.a!(false)
- # x.a? # => false
- # x.b? # => true
- # x.c? # => true
- def new(*flags)
- str_flags = flags.map { |flag| flag.to_s }
- sym_flags = []
- position = {}
- str_flags.each_with_index { |flag, index|
- raise ArgumentError, "Invalid flag #{flag}" unless flag =~ /\A[A-Za-z_][A-Za-z0-9_]*\z/ && !self.instance_methods.include?(flag)
- sym_flag = flag.to_sym
- position[sym_flag] = index
- sym_flags << sym_flag
- }
- flagset = Class.new(FlagSet)
- flagset.instance_variable_set("@flags", sym_flags)
- flagset.instance_variable_get("@flags").freeze
- flagset.instance_variable_set("@position", position)
- flagset.instance_variable_set("@states", 2**(str_flags.length))
- str_flags.each_with_index { |flag, position|
- flagset.class_eval("def #{flag}?; @value[#{position}] == 1; end")
- flagset.class_eval("def #{flag}!(set=true); if set then @value |= #{2**position} else @value &= #{2**position} end; end")
- }
- class <<flagset; define_method(:new, (class <<Object; instance_method(:new); end)); end # restore new-method
- flagset
- end
- end
- def initialize(*flags)
- flags = flags.map { |flag| flag.to_sym }
- @value = flags.inject(0) { |sum, flag|
- raise ArgumentError, "Invalid flag #{flag}" unless position = self.class.position(flag)
- sum + 2**position
- }
- end
- # Flagwise AND (returns a FlagSet with all Flags set in both)
- def &(other)
- self.class.from(other.to_i & self.to_i)
- end
- # Flagwise OR (returns a FlagSet with all Flags set in either)
- def |(other)
- self.class.from(other.to_i | self.to_i)
- end
- # Flagwise exclusive OR (returns a FlagSet with all Flags set in only one of either)
- def ^(other)
- self.class.from(other.to_i ^ self.to_i)
- end
- # An Integer-representation of the FlagSet
- def to_i
- @value
- end
- # The flags set in this FlagSet
- def flags
- flags = []
- self.class.flags.each_with_index { |flag, index| flags << flag if @value[index] == 1 }
- flags
- end
- end
- if __FILE__ == $0 then
- Permission = FlagSet.new(
- :owner_execute,
- :owner_read,
- :owner_write,
- :group_execute,
- :group_read,
- :group_write,
- :world_execute,
- :world_read,
- :world_write
- )
- p ["states", Permission.states] # => true
- p x = Permission.new(:owner_execute)
- p (x.methods - Object.methods).sort
- p ["owner_execute?", x.owner_execute?] # => true
- p ["world_read?", x.world_read?] # => false
- p ["world_read!", x.world_read!]
- p ["world_read?", x.world_read?] # => true
- p ["x.to_i", i = x.to_i] # => 1
- y = Permission.from_integer(i)
- p ["y", y]
- p ["y.flags", y.flags] # => [:owner_execute, :world_read]
- z = Permission.new(:group_write, :owner_execute)
- p ["(z | y).flags", (z | y).flags]
- p ["(z & y).flags", (z & y).flags]
- p ["(z ^ y).flags", (z ^ y).flags]
- end
Add Comment
Please, Sign In to add comment