Browse files

decorators registered on inclusion

  • Loading branch information...
0 parents commit b78a1b300764c854ddb3456b25f6dce5ffe313c6 @moonmaster9000 committed Apr 29, 2012
Showing with 174 additions and 0 deletions.
  1. +1 −0 lib/frill.rb
  2. +13 −0 lib/frill/frill.rb
  3. +131 −0 readme.markdown
  4. +29 −0 spec/frill_spec.rb
1 lib/frill.rb
@@ -0,0 +1 @@
+require 'frills/frill'
13 lib/frill/frill.rb
@@ -0,0 +1,13 @@
+module Frill
+ def self.included(base)
+ self.decorators << base
+ end
+
+ def self.decorators
+ @decorators ||= []
+ end
+
+ def self.reset!
+ @decorators = nil
+ end
+end
131 readme.markdown
@@ -0,0 +1,131 @@
+# Frill
+
+Simple decoration of objects for presentation. If you don't know what I'm talking
+about, reading up on presenters / decorators and their role in MVC.
+
+Out of the box integration with Rails.
+
+## Installation
+
+Throw this in your Gemfile:
+
+```ruby
+gem "frill"
+```
+
+If you're placing this in a Rails app, run the following command:
+
+ $ rails g frill:install
+
+## Usage
+
+(For the purposes of this tutorial, I'm going to assume you're using
+`frill` inside a Rails app. Checkout the `Usage outside Rails` section
+below for information about how to use this outside of a Rails app.)
+
+Imagine you're creating a web application that includes both a
+JSON API and an HTML frontend, and you've decided to always present a
+timestamp as YEAR/MONTH/DAY. Furthermore, when presented in HTML, you
+always want your timestamps wrapped in `<bold>` tags.
+
+This is a perfect fit for the GoF decorator pattern.
+
+Create a new TimestampFrill module in `app/frills/timestamp_frill`:
+
+```ruby
+module TimestampFrill
+ include Frill
+
+ def self.frill? object, context
+ object.respond_to? :created_at
+ end
+
+ def created_at
+ time = super
+ "#{time.year}/#{time.month}/#{time.day}"
+ end
+end
+```
+
+The first method `self.frill?` tells `Frill` what kind of objects this
+decorator is applicable to. In our case, it's any object that responds
+to `created_at`.
+
+Next, let's create an `HtmlTimestampFrill` module:
+
+```ruby
+require_relative 'timestamp_frill'
+
+module HtmlTimestampFrill
+ include Frill
+ decorate after: TimestampFrill
+
+ def self.frill? object, context
+ object.respond_to?(:created_at) && context.format == "html"
+ end
+
+ def created_at
+ helper.content_tag :b, super
+ end
+end
+```
+
+Two things to note: the `HtmlTimestampFrill` is only applicable to
+objects that respond to `created_at` when presented in "html". Also, we
+tell `Frill` to decorate after `TimestampFrill` is applied (so that
+`super` in `created_at` returns our `TimestampFrill` response).
+
+Next, in our controller, we need to decorate our objects with frills:
+
+```ruby
+class PostsController < ApplicationController
+ respond_to :json, :html
+
+ def show
+ @article = frill Article.find(params[:id])
+ respond_with @article
+ end
+end
+```
+
+Notice that we've wrapped our article in a `frill`.
+
+In your html view, you simply call `@article.created_at`:
+
+```erb
+<%= @article.created_at %>
+```
+
+The same goes for your JSON view.
+
+## Usage outside of Rails
+
+There are really just two integrations in a Rails app: the `frill`
+method inside of your controller, plus the ability to call
+`ActionView::Helper` methods inside of your module methods.
+
+To kickoff the decoration of an object outside of a Rails application,
+simply call `Frill.decorate`:
+
+```ruby
+Frill.decorate my_object, my_context
+```
+
+If you want to replicate the `helper` behavior you get for free in a
+Rails app, consider how simple it was to make that `helper` method
+possible:
+
+```ruby
+module ActionViewFrill
+ include Frill
+ decorate before: :all
+
+ def helper
+ @helper ||= Object.new.extend ActionView::Helpers
+ end
+end
+```
+
+## License
+
+MIT.
29 spec/frill_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../lib/frill/frill'
+
+describe Frill do
+ before do
+ Frill.reset!
+ end
+
+ describe ".reset" do
+ before do
+ Frill.decorators << Module.new
+ Frill.decorators.should_not be_empty
+ end
+
+ it "should wipe out all decorators" do
+ Frill.reset!
+ Frill.decorators.should be_empty
+ end
+ end
+
+ describe ".included" do
+ let(:test_module) { double :module }
+
+ subject { Frill.decorators }
+
+ before { Frill.included test_module }
+
+ it { should include test_module }
+ end
+end

0 comments on commit b78a1b3

Please sign in to comment.