我有一个用于缓存断言值的宏。我没有写这个问题,但想修改它,在块中使用动态值,而不是静态的最小值/最大值。
# frozen_string_literal: true
# Provides a lightweight model-level DSL for defining conditions with
# Redis-backed configurable criteria.
#
# Example:
#
# class User
# include CriteriaCacheConcern
#
# # Each criterion has a default value (second argument) that can be overridden by
# # a cached value. When evaluating criteria, we read first from cache (Redis) and
# # fall back on the default value if no cached value is present. Values are cached
# # under a key of this composition: 'model_class-condition-attribute'; e.g.,
# # 'user-auto_reject-application-score'
#
# criteria_cache :auto_reject do
# range :application-score, [0, 20]
# range :user_age, [0, 18]
# end
# end
#
# # Set Redis-backed min/max
# User.auto_reject_post_application.applicant_percentile_score.configure(min: 1, max: 21)
#
# # Are all criteria satisfiable for the user for this condition?
# user.auto_reject_post_application?
module CriteriaCacheConcern
extend ActiveSupport::Concern
included do
def self.criteria_caches
@criteria_caches || []
end
def self.criteria_cache(condition, &block)
criteria_cache = CriteriaCache.new(condition, name).tap { |cc| cc.instance_eval(&block) }
# Access the criteria cache object from the class
#
# Example:
# User.auto_reject_post_application
singleton_class.send(:define_method, condition) do
criteria_cache
end
# Does the model meet the criteria?
#
# Example:
# user.auto_reject_post_application?
define_method("#{condition}?") do
criteria_cache.meets_criteria?(self)
end
@criteria_caches ||= []
@criteria_caches << criteria_cache
end
end
class ConfigurableCriterion
attr_reader :condition, :model_class, :attribute, :default_value
def initialize(condition, model_class, attribute, default_value)
@condition = condition
@model_class = model_class
@attribute = attribute
@default_value = default_value
end
def value
RedisHelper.cached_value(cache_key) || default_value
end
def configure(_params)
raise NotImplementedError, 'ConfigurableCriterion subclass must implement #configure'
end
def meets_criterion?(_model)
raise NotImplementedError, 'ConfigurableCriterion subclass must implement #meets_criterion?'
end
private
def cache_key
"#{model_class.underscore}-#{condition}-#{attribute}"
end
end
# ConfigurableCriterion subclasses
# --------------------------------
#
# All ConfigurableCriterion subclasses should implement the following interface:
#
# class ConfigurableCriterionSubclass < ConfigurableCriterion
# # Does the model satisfy the criterion?
# def meets_criterion?(model)
# end
#
# # Update cached values
# def configure(params)
# end
# end
class Range < ConfigurableCriterion
def min
value.min
end
def max
value.max
end
def meets_criterion?(model)
(min..max).cover?(model.send(attribute))
end
def configure(params)
min = params.fetch(:min) { default_value.min }.to_i
max = params.fetch(:max) { default_value.max }.to_i
raise ArgumentError, 'Maximum must be larger than minimum' if max <= min
RedisHelper.cache_value(cache_key, [min, max])
end
end
# ---------------------------------
class CriteriaCache
attr_reader :condition, :model_class, :criteria
def initialize(condition, model_class)
@condition = condition
@model_class = model_class
@criteria = []
end
# Define method for each configurable criterion type that adds
# criterion object to @criteria collection
#
# Example of resultant method:
# criteria_cache.range(attribute, default_value)
ConfigurableCriterion.descendants.each do |klass|
define_method(klass.name.demodulize.underscore) do |attribute, default_value|
criterion = klass.new(condition, model_class, attribute, default_value)
@criteria << criterion
# Return configurable criterion object
#
# Example:
# User.auto_reject_post_application.applicant_percentile_score
define_singleton_method(criterion.attribute) do
criterion
end
end
end
def meets_criteria?(model)
@criteria.all? { |c| c.meets_criterion?(model) }
end
end
end
并按原样使用
criteria_cache :auto_assign_user do
range :user_score, [80 , 100]
end
我想更改宏,以便能够根据计算值设置范围。例如
User
模型有一种方法
lowest_score_to_auto_assign
这将计算出在
auto_assign_user
块。
我还不够熟悉,不知道该如何将其传递给
CriteriaCacheConcern