AvtiveOopish

Gem Version Build Status Code Climate Coverage Status Dependency Status

Simple tools for better OOP in Rails projects.

ActiveOopish::Inheritance

Instantiate a model instance as sub class's instance based on records value.

class Book < ActiveRecord::Base
  include ActiveOopish::Inheritance

  # If the record whose 'category_code' column equals `BIOGRAPHY` is fetched from
  # the database, it will be instantiated as Biography class instance.
  instantiate_as 'Biography', category_code: BIOGRAPHY
end

class Biography < Book
end

Why not STI?

Single table inheritance (STI) requires a string column which stores the instance's class name, but it is hard to prepare such thing in some cases. For example suppose your project came from another WAP to Rails, it may already have running DB and it does not satisfy the requirement by default. In addition, these columns are too Rails specific.

ActiveOopish::Validator

Encapsulates the responsibility of validating a model into a validator.

class BookValidator < ActiveOopish::Validator
  declear do
    validates :author, presence: true

    validates :title, length: { minimum: 3, maximum: 255 }

    validate :title_must_include_author_name, if: :biography?
  end

  def title_must_include_author_name(book)
    unless book.title.include?(book.author.name)
      book.errors.add(:author, "cannot write a biography for other people")
    end
  end

  def biography?(book)
    book.category == :biography
  end
end

class Book < ActiveRecord::Base
  belongs_to :author, class_name: 'User'

  BookValidator.monitor(self)
end

RSpec

require 'activeoopish/rspec_helper'
require 'shoulda-matchers'

describe Book do
  it { should be_monitored_by BookValidator }
end

describe BookValidator, :with_activeoopish_helper do
  include_context 'describe declaration' do
    it { should validate_presence_of(:author) }

    it { should validate_length_of(:title).is_at_least(3).is_at_most(255) }

    context 'when #biography? returns true' do
      before do
        allow_any_instance_of(described_class)
          .to receive(:biography?).and_return(true)
      end

      it 'calls #title_must_include_author_name' do
        expect_any_instance_of(described_class)
          .to receive(:title_must_include_author_name).with(subject).once
        subject.valid?
      end
    end
  end

  describe '#biography?' do
    # ...
  end

  describe '#title_must_include_author_name' do
    # ...
  end
end