classIsMatchesConditionsHash<Struct.new(:model_adapter,:subject,:conditions)defself.call(*args)new(*args).callenddefinitialize(model_adapter,subject,conditions)self.model_adapter=model_adapterself.subject=subjectself.conditions=conditionsend# ======== actual logicdefcallreturntrueifconditions.empty?ifmodel_adapter.override_conditions_hash_matching?(subject,conditions)returnmodel_adapter.matches_conditions_hash?(subject,conditions)endconditions.all?do|name,value|ifmodel_adapter.override_condition_matching?(subject,name,value)returnmodel_adapter.matches_condition?(subject,name,value)endcondition_match?(subject.send(name),value)endend# ========privatedefcondition_match?(attribute,value)casevaluewhenHashthenmatch_hash_value(attribute,value)whenEnumerablethen(!value.is_a?(String)&&value.include?(attribute))elseattribute==valueendenddefmatch_hash_value(attribute,value)ifattribute.kind_of?(Array)||(defined?(ActiveRecord)&&attribute.kind_of?(ActiveRecord::Relation))attribute.any?{|element|self.class.(model_adapter,element,value)}else!attribute.nil?&&self.class.(model_adapter,attribute,value)endendend
We can go deeper of course. Shave the yak completely. But that’s a good
start.
Actually, in this case, the implementation was moved back to the
original class with a few private methods extracted. But nice thing
about Method Object – it helps to understand all the dependencies this
beast have, so you can deal with it.