Skip to content

Instantly share code, notes, and snippets.

@aganov
Created March 25, 2016 06:56
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 aganov/ea95dd45ebe3be567871 to your computer and use it in GitHub Desktop.
Save aganov/ea95dd45ebe3be567871 to your computer and use it in GitHub Desktop.
rails-completeness
module Completeness
extend ActiveSupport::Concern
included do
class_attribute :completeness_checks
class_attribute :completeness_attributes
attr_accessor :completeness_points
attr_accessor :incomplete_attributes
end
# Class methods
module ClassMethods
def define_completeness(&checks_block)
self.completeness_checks = Completeness::Builder.build(self, &checks_block)
self.completeness_attributes = self.completeness_checks.keys
end
end
# Instance methods
def complete?
self.completeness_points = {}
self.incomplete_attributes = []
self.class.completeness_checks.each do |attribute, check|
if (check[:unless].blank? && check[:if].blank?) || (check[:if] && check[:if].call(self)) || (check[:unless] && !check[:unless].call(self))
complete = check[:check].call(self.send(attribute))
self.completeness_points[attribute] = (complete ? 1 : 0) * check[:points]
unless check[:points_per_item].blank?
points = check[:points_per_item] * self.send(attribute).count
self.completeness_points[attribute] = (points >= check[:points]) ? check[:points] : points
end
self.incomplete_attributes << attribute unless complete
end
end
self.incomplete_attributes.empty?
end
class Builder < Struct.new(:completeness_checks, :model)
def self.build(model, &block)
builder = self.new({}, model)
builder.instance_eval(&block)
builder.completeness_checks
end
protected
def check(*attributes)
options = attributes.extract_options!
attributes.each do |attribute|
if options[:with].nil?
association = self.model.reflect_on_association(attribute)
unless association.nil?
case association.macro
when :has_many
with = lambda { |relation| relation.present? && relation.count >= 1 }
end
end
end
self.completeness_checks[attribute] = {
points: options[:points],
points_per_item: options[:points_per_item],
check: options[:with] || with || lambda { |a| a.present? },
unless: options[:unless],
if: options[:if]
}
end
end
end
end
user = User.first
user.complete?
user.incomplete_attributes
user.completeness_points
class User < ActiveRecord::Base
include Completeness
define_completeness do
check :name, points: 34
check :avatar, points: 33
check :role, points: 33, with: lambda { |role|
![nil, "", "not_set"].include?(role)
}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment