class ActiveRegistry
Constants
- DEFAULT_INDEX
- VERSION
Public Class Methods
new(*args, indexes: [])
click to toggle source
Calls superclass method
# File lib/active_registry.rb, line 9 def initialize(*args, indexes: []) @indexed = {} super(*args) reindex!(indexes) end
Public Instance Methods
add(item)
click to toggle source
Calls superclass method
# File lib/active_registry.rb, line 41 def add(item) @indexed.each do |idx, store| watch_setter(item, idx) unless include?(item) begin idx_value = item.send(idx) (store[idx_value] ||= Set.new) << (item) rescue NoMethodError => e raise "#{item.name} cannot be added because indexable attribute (#{idx}) is missing." end end super(item) end
Also aliased as: <<
delete(item)
click to toggle source
Calls superclass method
# File lib/active_registry.rb, line 27 def delete(item) @indexed.each do |idx, store| ignore_setter(item, idx) if include?(item) begin idx_value = item.send(idx) (store[idx_value] ||= Set.new).delete(item) store.delete(idx_value) if store[idx_value].empty? rescue NoMethodError => e raise "#{item.name} cannot be added because indexable attribute (#{idx}) is missing." end end super(item) end
find(search_criteria)
click to toggle source
# File lib/active_registry.rb, line 59 def find(search_criteria) _find(search_criteria) { warn "There were more than 1 records found" } end
find!(search_criteria)
click to toggle source
# File lib/active_registry.rb, line 55 def find!(search_criteria) _find(search_criteria) { raise MoreThanOneRecordFound, "There were more than 1 records found" } end
index(*indexes)
click to toggle source
# File lib/active_registry.rb, line 74 def index(*indexes) indexes.each do |idx| warn "Index #{idx} already exists!" and next if @indexed.key?(idx) each { |item| watch_setter(item, idx) } indexed_records = group_by { |a| a.send(idx) } indexed_sets = Hash[indexed_records.keys.zip(indexed_records.values.map { |e| Set.new(e) })] @indexed[idx] = indexed_sets end end
indexes()
click to toggle source
# File lib/active_registry.rb, line 23 def indexes @indexed.keys - [:object_id] end
inspect()
click to toggle source
# File lib/active_registry.rb, line 15 def inspect to_a.inspect end
reindex!(indexes = [])
click to toggle source
# File lib/active_registry.rb, line 84 def reindex!(indexes = []) @indexed = {} index(*([DEFAULT_INDEX] | indexes)) end
to_h()
click to toggle source
# File lib/active_registry.rb, line 19 def to_h @indexed end
where(search_criteria)
click to toggle source
# File lib/active_registry.rb, line 63 def where(search_criteria) sets = search_criteria.inject([]) do |sets, (idx, value)| raise "No '#{idx}' index! Add it with '.index(:#{idx})'" unless @indexed.include?(idx) sets << (@indexed.dig(idx, value) || Set.new) end subset_records = sets.reduce(sets.first, &:&) subset_registry = ActiveRegistry.new(subset_records, indexes: indexes) subset_registry end
Protected Instance Methods
reindex(idx, item, old_value, new_value)
click to toggle source
# File lib/active_registry.rb, line 91 def reindex(idx, item, old_value, new_value) if (new_value != old_value) @indexed[idx][old_value].delete item (@indexed[idx][new_value] ||= Set.new).add item end end
Private Instance Methods
_find(search_criteria) { || ... }
click to toggle source
# File lib/active_registry.rb, line 100 def _find(search_criteria) results = where(search_criteria) yield if block_given? && results.count > 1 results.first end
ignore_setter(item, idx)
click to toggle source
# File lib/active_registry.rb, line 127 def ignore_setter(item, idx) return if item.frozen? item.public_methods.select { |m| m.match(/^#{idx}=$/) }.each do |original_method| watched_method = "__watched_#{original_method}".to_sym renamed_method = "__unwatched_#{original_method}".to_sym next unless item.methods.include?(watched_method) item.singleton_class.class_eval do alias_method original_method, renamed_method remove_method(watched_method) remove_method(renamed_method) end end end
watch_setter(item, idx)
click to toggle source
# File lib/active_registry.rb, line 106 def watch_setter(item, idx) return if item.frozen? __registry__ = self item.public_methods.select { |m| m.match(/^#{idx}=$/) }.each do |original_method| watched_method = "__watched_#{original_method}".to_sym renamed_method = "__unwatched_#{original_method}".to_sym next if item.methods.include?(watched_method) item.singleton_class.class_eval do define_method(watched_method) do |*args| old_value = item.send(idx) send(renamed_method, *args).tap do |new_value| __registry__.send(:reindex, idx, item, old_value, new_value) end end alias_method renamed_method, original_method alias_method original_method, watched_method end end end