Wednesday, February 08, 2017

Easily Typable Gemified and Updated to Support Rails

Easily Typable:

Although polymorphism is a recommended standard in Object-Oriented programming for invoking varied behavior in an inheritance hierarchy, sometimes it is still useful to verify if a particular model belongs to a certain type when the behavior concerned does not belong to the model and is too small to require a Design Pattern like Strategy.
A common example in Rails is checking user roles before rendering certain parts of the view:
<% if user.is_a?(Admin) %>
  <%= link_to 'Admin', admin_dashboard_path %>
<% end %>
To avoid the model.is_a?(CertainType) syntax, a more readable approach that developers resort to is to add an English-like method that hides the details of type checking model.certain_type?.
The Rails example above would then become:
<% if user.admin? %>
  <%= link_to 'Admin', admin_dashboard_path %>
<% end %>
Implementing such methods manually gets repetitive after a while, so an easier way to get these methods automatically is to mixin the EasilyTypable module.
This was originally released back in 2009 when I worked at Obtiva, but not in Gem form, so I've gemified it and updated to support Rails lazy-loading of Models.

Example:

require 'easily_typable'

class TypeA
  include EasilyTypable
end

class TypeB < TypeA
end

class TypeC < TypeB
end

## RSpec of Easily Typable
require 'spec_helper'

describe EasilyTypable do
  it "adds type_a? method to TypeA object" do
    expect(TypeA.new.type_a?).to be_truthy
  end
  it "adds type_b? method to TypeA object" do
    expect(TypeA.new.type_b?).to be_falsey
  end
  it "adds type_c? method to TypeA object" do
    expect(TypeA.new.type_c?).to be_falsey
  end
  it "adds type_a? method to TypeB object" do
    expect(TypeB.new.type_a?).to be_truthy
  end
  it "adds type_b? method to TypeB object" do
    expect(TypeB.new.type_b?).to be_truthy
  end
  it "adds type_c? method to TypeB object" do
    expect(TypeB.new.type_c?).to be_falsey
  end
  it "adds type_a? method to TypeC object" do
    expect(TypeC.new.type_a?).to be_truthy
  end
  it "adds type_b? method to TypeC object" do
    expect(TypeC.new.type_b?).to be_truthy
  end
  it "adds type_c? method to TypeC object" do
    expect(TypeC.new.type_c?).to be_truthy
  end
end