Class: Safe::Flag
- Inherits:
-
Object
- Object
- Safe::Flag
- Defined in:
- lib/enums/flag.rb,
lib/enums/flag_builder.rb
Instance Attribute Summary collapse
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#value ⇒ Object
readonly
Returns the value of attribute value.
Class Method Summary collapse
- ._typecast_flag!(o) ⇒ Object
- ._typecheck_flag!(o) ⇒ Object
- .all ⇒ Object
- .build(value) ⇒ Object
-
.build_class(class_name, *args, **kwargs) ⇒ Object
(also: new)
meta-programming “macro” - build class (on the fly).
- .convert(*args) ⇒ Object
- .key(key) ⇒ Object (also: [])
- .keys ⇒ Object
- .none ⇒ Object
- .value(value) ⇒ Object
- .values ⇒ Object
- .zero ⇒ Object
Instance Method Summary collapse
- #==(other) ⇒ Object (also: #eql?)
- #_typecast_flag!(o) ⇒ Object
- #_typecheck_flag!(o) ⇒ Object
- #all? ⇒ Boolean
- #bitwise_and(other) ⇒ Object (also: #&)
- #bitwise_inverse ⇒ Object (also: #~)
- #bitwise_or(other) ⇒ Object (also: #|)
- #bitwise_xor(other) ⇒ Object (also: #^)
-
#initialize(key, value) ⇒ Flag
constructor
A new instance of Flag.
- #member?(other) ⇒ Boolean
- #none? ⇒ Boolean
-
#parse_bool ⇒ Object
(also: #to_bool)
nonzero == true, zero == false like numbers.
-
#set(other) ⇒ Object
(also: #flag)
note: typecast also allows symbol e.g (:read_only, etc.).
- #to_b ⇒ Object
-
#to_i ⇒ Object
add to_i, to_int - why? why not?.
-
#to_int ⇒ Object
allows Integer( .. ).
- #toggle(other) ⇒ Object
- #unset(other) ⇒ Object (also: #unflag)
- #zero? ⇒ Boolean
Constructor Details
#initialize(key, value) ⇒ Flag
Returns a new instance of Flag.
13 14 15 16 17 18 |
# File 'lib/enums/flag.rb', line 13 def initialize( key, value ) @key = key @value = value self.freeze self end |
Instance Attribute Details
#key ⇒ Object (readonly)
Returns the value of attribute key.
10 11 12 |
# File 'lib/enums/flag.rb', line 10 def key @key end |
#value ⇒ Object (readonly)
Returns the value of attribute value.
11 12 13 |
# File 'lib/enums/flag.rb', line 11 def value @value end |
Class Method Details
._typecast_flag!(o) ⇒ Object
28 29 30 31 32 33 |
# File 'lib/enums/flag.rb', line 28 def self._typecast_flag!( o ) if o.is_a? Symbol ## auto-convert symbol to flag o = key( o ) ## lookup symbol in "parent" flags class end _typecheck_flag!( o ) end |
._typecheck_flag!(o) ⇒ Object
20 21 22 23 24 25 26 |
# File 'lib/enums/flag.rb', line 20 def self._typecheck_flag!( o ) if o.instance_of?( self ) o else raise TypeError.new( "[Flag] flag >#{name}< type expected; got >#{o.class.inspect}<" ) end end |
.all ⇒ Object
133 |
# File 'lib/enums/flag.rb', line 133 def self.all() self::ALL; end |
.build(value) ⇒ Object
121 122 123 124 125 |
# File 'lib/enums/flag.rb', line 121 def self.build( value ) o = self.value( value ) # lookup if value is a known flag (with key) o = new( :"#{'%08b' % value}", value ) if o.nil? o end |
.build_class(class_name, *args, **kwargs) ⇒ Object Also known as: new
meta-programming “macro” - build class (on the fly)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/enums/flag_builder.rb', line 7 def self.build_class( class_name, *args, **kwargs ) if args.size > 0 keys = args values = (0...keys.size).to_a # note: use ... (exclusive) range values = values.map { |value| 1<<value } ## use power of twos (e.g. 2^0, 2^1, etc.) f = Hash[ keys.zip( values ) ] else ## assume kwargs f = kwargs end ## todo/fix: ## check class name MUST start with uppercase letter ## check if all keys are symbols and follow the ruby id(entifier) naming rules f.keys.each do |key| if key.is_a?( Symbol ) && key =~ /\A[a-z][a-zA-Z0-9_]*\z/ else raise ArgumentError.new( "[Flag] arguments to Flag.new must be all symbols following the ruby id naming rules; >#{key}< failed" ) end end klass = Class.new( Flag ) ## add self.new too - note: call/forward to "old" orginal self.new of Event (base) class klass.define_singleton_method( :new ) do |*new_args| old_new( *new_args ) end f.each do |key,value| klass.class_eval( <<RUBY ) #{key.upcase} = new( :#{key}, #{value} ) def self.#{key} #{key.upcase} end def #{key}? @value & #{value} == #{value} end RUBY end klass.class_eval( <<RUBY ) NONE = new( :none, 0 ) ALL = new( :all, #{f.values.reduce( 0 ) { |sum, value| sum|value }} ) def self.members @members ||= [#{f.keys.map {|key|key.upcase}.join(',')}].freeze end RUBY ## note: use Kernel for "namespacing" ## make all enums Kernel convenience converters (always) global ## including uppercase methods (e.g. State(), Color(), etc.) does NOT work otherwise (with other module includes) ## add global convenience converter function ## e.g. State(0) is same as State.convert(0) ## Color(0) is same as Color.convert(0) Kernel.class_eval( <<RUBY ) def #{class_name}( arg ) #{class_name}.convert( arg ) end RUBY ## note: use Safe (module) and NO Object for namespacing ## use include Safe to make all enums constants and machinery global Safe.const_set( class_name, klass ) ## returns klass (plus sets global constant class name) end |
.convert(*args) ⇒ Object
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/enums/flag.rb', line 137 def self.convert( *args ) if args.size == 0 self::NONE elsif args.size == 1 && args[0].is_a?(Integer) build( args[0] ) else ## assume flag object or symbols value = 0 args.each do |arg| flag = _typecast_flag!( arg ) value |= flag.value end build( value ) end end |
.key(key) ⇒ Object Also known as: []
98 99 100 101 102 |
# File 'lib/enums/flag.rb', line 98 def self.key( key ) # note: does NOT include :none (and :all) @hash_by_key ||= Hash[ keys.zip( members ) ].freeze @hash_by_key[key] end |
.keys ⇒ Object
93 94 95 96 |
# File 'lib/enums/flag.rb', line 93 def self.keys() # note: does NOT include :none (and :all) @keys ||= members.map { |member| member.key }.freeze end |
.none ⇒ Object
131 |
# File 'lib/enums/flag.rb', line 131 def self.none() self::NONE; end |
.value(value) ⇒ Object
114 115 116 117 118 119 |
# File 'lib/enums/flag.rb', line 114 def self.value( value ) ## note: adds :none and :all for value lookup @hash_by_value ||= Hash[ values.zip( members ) ].merge( self::NONE.value => self::NONE, self::ALL.value => self::ALL ).freeze @hash_by_value[value] end |
.values ⇒ Object
109 110 111 112 |
# File 'lib/enums/flag.rb', line 109 def self.values() # note: does NOT include :none (and :all) @values ||= members.map { |member| member.value }.freeze end |
.zero ⇒ Object
128 |
# File 'lib/enums/flag.rb', line 128 def self.zero() @zero ||= self::NONE; end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
40 41 42 43 44 45 46 |
# File 'lib/enums/flag.rb', line 40 def ==( other ) if other.is_a?( Integer ) && other == 0 ## note: only allow compare by zero (0) integer - why? why not? @value == 0 else @value == _typecheck_flag!( other ).value end end |
#_typecast_flag!(o) ⇒ Object
36 |
# File 'lib/enums/flag.rb', line 36 def _typecast_flag!( o ) self.class._typecast_flag!( o ); end |
#_typecheck_flag!(o) ⇒ Object
35 |
# File 'lib/enums/flag.rb', line 35 def _typecheck_flag!( o ) self.class._typecheck_flag!( o ); end |
#all? ⇒ Boolean
134 |
# File 'lib/enums/flag.rb', line 134 def all?() @value & self.class::ALL.value == self.class::ALL.value; end |
#bitwise_and(other) ⇒ Object Also known as: &
61 62 63 |
# File 'lib/enums/flag.rb', line 61 def bitwise_and( other ) self.class.build( @value & _typecheck_flag!( other ).value ) end |
#bitwise_inverse ⇒ Object Also known as: ~
71 72 73 |
# File 'lib/enums/flag.rb', line 71 def bitwise_inverse self.class.build( ~@value ) end |
#bitwise_or(other) ⇒ Object Also known as: |
56 57 58 |
# File 'lib/enums/flag.rb', line 56 def bitwise_or( other ) self.class.build( @value | _typecheck_flag!( other ).value ) end |
#bitwise_xor(other) ⇒ Object Also known as: ^
66 67 68 |
# File 'lib/enums/flag.rb', line 66 def bitwise_xor( other ) self.class.build( @value ^ _typecheck_flag!( other ).value ) end |
#member?(other) ⇒ Boolean
50 51 52 53 |
# File 'lib/enums/flag.rb', line 50 def member?( other ) other = _typecast_flag!( other ) @value & other.value == other.value end |
#none? ⇒ Boolean
132 |
# File 'lib/enums/flag.rb', line 132 def none?() @value == 0; end |
#parse_bool ⇒ Object Also known as: to_bool
nonzero == true, zero == false like numbers
161 |
# File 'lib/enums/flag.rb', line 161 def parse_bool() @value != 0; end |
#set(other) ⇒ Object Also known as: flag
note: typecast also allows symbol e.g (:read_only, etc.)
77 78 79 |
# File 'lib/enums/flag.rb', line 77 def set( other ) ## note: typecast also allows symbol e.g (:read_only, etc.) self.class.build( @value | _typecast_flag!( other ).value ) end |
#to_b ⇒ Object
160 |
# File 'lib/enums/flag.rb', line 160 def to_b() parse_bool(); end |
#to_i ⇒ Object
add to_i, to_int - why? why not?
157 |
# File 'lib/enums/flag.rb', line 157 def to_i() @value; end |
#to_int ⇒ Object
allows Integer( .. )
158 |
# File 'lib/enums/flag.rb', line 158 def to_int() @value; end |
#toggle(other) ⇒ Object
87 88 89 |
# File 'lib/enums/flag.rb', line 87 def toggle( other ) self.class.build( @value ^ _typecast_flag!( other ).value ) end |
#unset(other) ⇒ Object Also known as: unflag
82 83 84 |
# File 'lib/enums/flag.rb', line 82 def unset( other ) self.class.build( @value & ~_typecast_flag!( other ).value ) end |
#zero? ⇒ Boolean
129 |
# File 'lib/enums/flag.rb', line 129 def zero?() @value == 0; end |