Simple gem to check hierarchically dependent "facts" about objects
Ruby
Switch branches/tags
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
spec
.gitignore
.ruby-gemset
.ruby-version
.travis.yml
Gemfile
README.md
Rakefile
fact_checker.gemspec

README.md

Fact Checker Build Status Code Climate

Simple ruby gem to define and check hierarchically dependent "facts" about objects.

Synopsys

class Person
  include FactChecker

  define_fact(:good_job)    { p.job.good? }
  define_fact(:good_family) { p.family.good? }
  define_fact(:is_healthy)  { p.health.good? }
  define_fact(:is_happy => [:is_healthy, :good_family, :good_job]) { ! p.too_clever? }

  ...
end

p = Person.new(job: good_job, family: good_family, health: :good, intellect: :too_clever)
p.good_job?                     # => true
p.good_family?                  # => true
p.is_healthy?                   # => true
p.is_happy.available?           # => true (dependency satisfied)
p.is_happy?                     # => false

Description

The gem is most usefull when you have something like a checklist, a list of tasks that your users should complete to achieve some goal.

For example, let's say that in order to publish an article a user has to:

  1. write the article
  2. name the article (user may complete steps 1 & 2 in any order)
  3. choose its category
  4. assign tags to the article (user may complete steps 3 & 4 in any order, but only after steps 1 & 2)
  5. mark article as "ready for review" (only after steps 1-3 are completed, but step 4 is not required)
  6. recieve approvement from one of moderators (all steps 1-5 are required)

Using fact_checker that logic could be implemented like this:

include FactChecker

define_fact(:step1)                     { content.present? }
define_fact(:step2)                     { name.present? }
define_fact(:step3 => [:step1, :step2]) { category.present? }
define_fact(:step4 => [:step1, :step2]) { tag_list.present? }
define_fact(:step5 => :step3)           { ready_for_approvement? }
define_fact(:step6 => [:step4, :step5]) { approved? }

def state_of(step)
  return 'completed'         if public_send(step).valid?
  return 'ready_for_action'  if public_send(step).available?
  return 'not_available'
end

Just to compare, a possible alternative implimentation without fact_checker:

def step1_available?
  true
end
def step1_valid?
  content.present?
end
def step2_available?
  true
end
def step2_valid?
  name.present?
end
def step3_available?
  step1? && step2?
end
def step3_valid?
  step3_available? && a.category.present?
end
def step4_available?
  step1? && step2?
end
def step4_valid?
  step4_available? && tag_list.present?
end
def step5_available?
  step3
end
def step5_valid?
  step5_available? && a.ready_for_approvement?
end
def step6_available?
  step4? && step5
end
def step6_valid?
  step6_available? && a.approved?
end

def state_of(step)
  return 'completed'         if self.public_send(step + '_valid?')
  return 'ready_for_action'  if self.public_send(step + '_available?')
  return 'not_available'
end

Installation

gem install fact_checker