Skip to content

Instantly share code, notes, and snippets.

@prdanelli
Created November 15, 2019 19:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prdanelli/47ef0b4e4cc1f7f54bee8e8e629b03b7 to your computer and use it in GitHub Desktop.
Save prdanelli/47ef0b4e4cc1f7f54bee8e8e629b03b7 to your computer and use it in GitHub Desktop.
Module, metaprogramming, dynamic instance/class method definition
# Usage:
# class YourClass < ApplicationRecord
# denormalizable_collection :my_collection
# ...
#
# def self.my_collection_data
# self.where(...).limit(5)
# end
# end
# View:
# <%= News.my_collection.each do ... %>
module DenormalizableCollection
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def denormalizable_collection(*actions)
actions.each do |action|
generate_class_methods(action)
generate_instance_methods(action)
generate_callbacks(action)
end
end
def generate_class_methods(action)
self.class_eval do |klass|
klass.define_singleton_method "#{action}" do
collection = Redis.current.get(send("#{action}_key"))
return [] unless collection.present?
JSON.parse(collection).map { |h| DenormalizedHash.new(h) }
end
klass.define_singleton_method "set_#{action}" do
Redis.current.set(send("#{action}_key"), send("#{action}_data").to_json)
end
klass.define_singleton_method "#{action}_data" do
raise NotImplementedError, "#{action}_data is required"
end
klass.define_singleton_method "#{action}_key" do
"#{name.underscore}_#{action}".to_sym
end
end
end
def generate_isntance_methods(action)
self.class_eval do |klass|
klass.define_method "resync_#{action}" do
self.class.send("set_#{action}".to_sym)
end
end
end
def generate_callbacks(action)
self.class_eval do
after_commit "resync_#{action}".to_sym
after_destroy "resync_#{action}".to_sym
# ... or
# after_commit -> { self.class.send("set_#{action}".to_sym) }
# after_destroy -> { self.class.send("set_#{action}".to_sym) }
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment