Class: Cult::NamedArray
- Inherits:
-
Array
- Object
- Array
- Cult::NamedArray
- Defined in:
- lib/cult/named_array.rb
Defined Under Namespace
Modules: ArrayExtensions, ObjectExtensions
Constant Summary collapse
- PROXY_METHODS =
Wrap any non-mutating methods that can return an Array, and wrap the result with a NamedArray. This is why NamedArray.select results in a NamedArray instead of an Array
%i(& * + - << | collect compact flatten reject reverse rotate select shuffle slice sort uniq sort_by)
Class Method Summary collapse
Instance Method Summary collapse
-
#[](key) ⇒ Object
first matching item.
-
#all(key, method = :select) ⇒ Object
Returns all keys that match if method == :select, the first if method == :find.
- #extract_index(key) ⇒ Object
-
#fetch(key) ⇒ Object
first matching item, or raises KeyError.
- #fetch_by_index(ary, index) ⇒ Object
- #first(key = nil) ⇒ Object
- #key?(key) ⇒ Boolean (also: #exist?)
- #keys ⇒ Object
- #normal_key?(k) ⇒ Boolean
- #to_named_array ⇒ Object
- #values ⇒ Object
-
#with(**kw) ⇒ Object
(also: #where)
Takes a predicate in the form of: key: value And returns all items that both respond_to?(key), and predicate === the result of sending key.
Class Method Details
.indexable_wrapper(method_name) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/cult/named_array.rb', line 57 def self.indexable_wrapper(method_name) old_method_name = "#{method_name}_without_wrapper" alias_method old_method_name, method_name define_method(method_name) do |*a| if a.empty? return IndexWrapper.new(self, method_name) else return send(old_method_name, *a) end end end |
Instance Method Details
#[](key) ⇒ Object
first matching item
188 189 190 191 |
# File 'lib/cult/named_array.rb', line 188 def [](key) return super if normal_key?(key) all(key).first end |
#all(key, method = :select) ⇒ Object
Returns all keys that match if method == :select, the first if method == :find
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/cult/named_array.rb', line 169 def all(key, method = :select) return [self[key]] if normal_key?(key) return [] if key.nil? key, index = extract_index(key) predicate = (key) effective_method = index.nil? ? method : :select result = send(effective_method) do |v| predicate === v.named_array_identifier end result = fetch_by_index(result, index) if index Array(result).to_named_array end |
#extract_index(key) ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/cult/named_array.rb', line 132 def extract_index(key) re = /\[\s*([^\]]*)\s*\]$/ if key.is_a?(String) && (m = key.match(re)) subs, expr = m[0], m[1] index = case expr when /^(\-?\d+)$/; $1.to_i #.. $1.to_i when /^(\-?\d+)\s*\.\.\s*(\-?\d+)$/; $1.to_i .. $2.to_i when /^(\-?\d+)\s*\.\.\.\s*(\-?\d+)$/; $1.to_i ... $2.to_i when /^((?:\-?\d+\s*,?\s*)+)$/; $1.split(',').map(&:to_i) end # We return [predicate string with index removed, expanded index] [ key[0 ... key.size - subs.size], index ] else [ key, nil ] end end |
#fetch(key) ⇒ Object
first matching item, or raises KeyError
199 200 201 |
# File 'lib/cult/named_array.rb', line 199 def fetch(key) first(key) or raise KeyError, "Not found: #{key.inspect}" end |
#fetch_by_index(ary, index) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/cult/named_array.rb', line 149 def fetch_by_index(ary, index) case index when Array ary.values_at(*index).compact when Integer v = ary.at(index) v.nil? ? [] : [v] when Range ary[index] else fail ArgumentError, "weird index: #{index.inspect}" end end |
#first(key = nil) ⇒ Object
193 194 195 196 |
# File 'lib/cult/named_array.rb', line 193 def first(key = nil) return super() if key.nil? all(key, :find).first end |
#key?(key) ⇒ Boolean Also known as: exist?
204 205 206 |
# File 'lib/cult/named_array.rb', line 204 def key?(key) !! first(key) end |
#keys ⇒ Object
210 211 212 |
# File 'lib/cult/named_array.rb', line 210 def keys map(&:named_array_identifier) end |
#normal_key?(k) ⇒ Boolean
163 164 165 |
# File 'lib/cult/named_array.rb', line 163 def normal_key?(k) [Integer, Range].any?{|cls| k.is_a?(cls) } end |
#to_named_array ⇒ Object
70 71 72 |
# File 'lib/cult/named_array.rb', line 70 def to_named_array self end |
#values ⇒ Object
215 216 217 |
# File 'lib/cult/named_array.rb', line 215 def values self end |
#with(**kw) ⇒ Object Also known as: where
Takes a predicate in the form of:
key: value
And returns all items that both respond_to?(key), and predicate === the result of sending key.
Instances can override what predicates mean by defining “names_for_*” to override what is tested.
For example, if you have an Object that contains a list of “Foos”, but you want to select them by name, you’d do something like:
class Object
attr_reader :foos # Instances of Foo class
def names_for_foos # Now we can select by name
foos.map(&:name)
end
end
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/cult/named_array.rb', line 238 def with(**kw) fail ArgumentError, "with requires exactly one predicate" if kw.size != 1 key, predicate = kw.first predicate = (predicate) select do |candidate| methods = [key, "query_for_#{key}", "names_for_#{key}"].select do |m| candidate.respond_to?(m) end methods.any? do |method| Array(candidate.send(method)).any? do |r| begin predicate === r rescue # We're going to assume this is a result of a string # comparison to a custom #== false end end end end end |