Class: Module
- Inherits:
-
Object
- Object
- Module
- Defined in:
- lib/everythingrb/module.rb
Overview
Extensions to Ruby’s core Module class
Provides:
-
#attr_predicate: Create boolean-style accessor methods
Instance Method Summary collapse
-
#attr_predicate(*attributes, **opts) ⇒ nil
Creates predicate (boolean) methods that return true/false based on an attribute’s value.
Instance Method Details
#attr_predicate(*attributes, **opts) ⇒ nil
Creates predicate (boolean) methods that return true/false based on an attribute’s value. Similar to attr_reader, attr_writer, etc. Designed to work with regular classes, Struct, and Data objects.
Values are evaluated as follows:
-
nil and false are always false
-
With ActiveSupport: uses
present?(empty strings, arrays, hashes are false) -
Without ActiveSupport: checks
empty?if available, otherwise uses truthiness
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/everythingrb/module.rb', line 94 def attr_predicate(*attributes, **opts) from = opts[:from] private_method = !!opts[:private] if from && attributes.size > 1 raise ArgumentError, "Cannot use from: option with multiple attributes - each predicate needs its own source mapping" end attributes.each do |attribute| if method_defined?(:"#{attribute}?") raise ArgumentError, "Cannot create predicate method on #{self.class} - #{attribute}? is already defined. Please choose a different name or remove the existing method." end signature = "def #{attribute}?" signature.prepend("private ") if private_method # Performance note: # This was originally checked if an instance variable or method was defined, both of which are sllllooooowwwww # Now as of 1.0.0, this assumes an instance variable (with exceptions) by default getter = if from from.to_s.start_with?("@") ? from : "self.#{from}" elsif self < Struct || self < OpenStruct || self < Data "self.#{attribute}" else "@#{attribute}" end checker = if defined?(ActiveSupport) "!!value.presence" else # Handle empty arrays/hashes/strings "value.respond_to?(:empty?) ? !value.empty? : !!value" end module_eval <<~RUBY, __FILE__, __LINE__ + 1 #{signature} value = #{getter} return false if value.nil? #{checker} end RUBY end nil end |