I've started using Code Climate to assess some of my code quality and ran into a situation that I can't seem to find a good solution for. In short, in trying to solve some code duplication that resulted in a low "grade" by using metaprogramming, I simply get a low grade for code complexity instead.
Anyone know a good a way out of this trap?
Code Quality Background Info
Here are some resources that point to the underlying libraries used by Code Climate to assess code quality. I think these are pretty standard in the ruby world so this isn't a Code Climate specific question.
Before Code (duplication problem)
Several associations on User
that have basically identical functionality.
has_many :user_conditions
has_many :conditions, :through => :user_conditions do
def <<(new_item) # disable duplicate addition
super( Array(new_item) - proxy_association.owner.conditions )
end
end
def activate_condition(condition)
ActiveRecord::Base.transaction do
self.conditions << condition
self.update_attribute(:active_conditions, (self.active_conditions | [condition.id.to_s]))
end
end
def deactivate_condition(condition)
self.update_attribute(:active_conditions, (self.active_conditions - [condition.id.to_s]))
end
has_many :user_symptoms
has_many :symptoms, :through => :user_symptoms do
def <<(new_item) # disable duplicate addition
super( Array(new_item) - proxy_association.owner.symptoms )
end
end
def activate_symptom(symptom)
ActiveRecord::Base.transaction do
self.symptoms << symptom
self.update_attribute(:active_symptoms, (self.active_symptoms | [symptom.id.to_s]))
end
end
def deactivate_symptom(symptom)
self.update_attribute(:active_symptoms, (self.active_symptoms - [symptom.id.to_s]))
end
has_many :user_treatments
has_many :treatments, :through => :user_treatments do
def <<(new_item) # disable duplicate addition
super( Array(new_item) - proxy_association.owner.treatments )
end
end
def activate_treatment(treatment)
ActiveRecord::Base.transaction do
self.treatments << treatment
self.update_attribute(:active_treatments, (self.active_treatments | [treatment.id.to_s]))
end
end
def deactivate_treatment(treatment)
self.update_attribute(:active_treatments, (self.active_treatments - [treatment.id.to_s]))
end
After Code (complexity problem)
Moved out of User
into a module, admittedly this code is hard to grasp.
module UserTrackables
extend ActiveSupport::Concern
included do |base|
%w( treatments conditions symptoms ).each do |trackable|
base.class_eval do
has_many "user_#{trackable}".to_sym
has_many trackable.to_sym, :through => "user_#{trackable}".to_sym do
# disable duplicate addition
def <<(new_item)
super( Array(new_item) - proxy_association.owner.send(proxy_association.reflection.plural_name.to_sym) )
end
end
end
define_method("activate_#{trackable.singularize}") do |trackable_object|
ActiveRecord::Base.transaction do
self.send(trackable) << trackable_object
self.update_attribute("active_#{trackable}".to_sym, (self.send("active_#{trackable}") | [trackable_object.id.to_s]))
end
end
define_method("deactivate_#{trackable.singularize}") do |trackable_object|
self.update_attribute("active_#{trackable}".to_sym, (self.send("active_#{trackable}") - [trackable_object.id.to_s]))
end
define_method("current_#{trackable}") do
trackable.singularize.capitalize.constantize.where(id: self.send("active_#{trackable}".to_sym).map(&:to_i))
end
end
end
end