ActiveOopish
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