Permalink
Browse files

Initial build

  • Loading branch information...
jcasimir committed May 29, 2011
1 parent a6a2d4e commit bc0b0a29e71d08bd2f3cb3bd48f900f8a1e3e273
View
@@ -0,0 +1,56 @@
+Rails Decorators
+================
+
+This gem makes it easy to apply the decorator pattern to the models in a Rails application.
+
+## Why?
+
+Helpers, as they're commonly used, are a bit odd. In both Ruby and Rails we approach everything from an Object-Oriented perspective, then with helpers we get procedural.
+
+The job of a helper is to take in data or a data object and output presentation-ready results. We can do that job in an OO fashion with a decorator.
+
+In general, a decorator wraps an object with presentation-related accessor methods. For instance, if you had an `Article` object, then a decorator might add instance methods like `.formatted_published_at` or `.formatted_title` that output actual HTML.
+
+## How?
+
+Here are the steps to utilizing this pattern:
+
+Add the dependency to your `Gemfile`:
+
+```
+gem "rails_decorators"
+```
+
+Run bundle:
+
+```
+bundle
+```
+
+Run the setup generator to create a decorators folder and an initializer to connect your decorators with your models:
+
+```
+rails generate decorator:setup
+```
+
+Create a decorator for your model (ex: `Article`)
+
+```
+rails generate decorator:model Article
+```
+
+Open the decorator module (ex: `app/decorators/article_decorator.rb`)
+
+Add your new formatting methods inside the `instance_methods` module
+
+If you need access to the Rails helpers like `link_to` and `content_tag`, include the appropriate modules (commented out in the generated decorator)
+
+Use the new methods in your views like any other model method (ex: `@article.formatted_published_at`)
+
+## Uses
+
+Here are some ideas of what you might do in decorator methods:
+
+* Implement output formatting for `to_csv`, `to_json`, or `to_xml`
+* Format dates and times using `strftime`
+* Implement a commonly used representation of the data object like a `.name` method that combines `first_name` and `last_name` attributes
@@ -1,15 +0,0 @@
-require 'rails/generators/base'
-
-module Decorator
- module Generators
- class Base < Rails::Generators::Base #:nodoc:
- def self.source_root
- @_decorator_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'decorator', generator_name, 'templates'))
- end
-
- def self.banner
- "rails generate decorator:#{generator_name} #{self.arguments.map{ |a| a.usage }.join(' ')} [options]"
- end
- end
- end
-end
@@ -0,0 +1,8 @@
+Description:
+ The decorator:model generator creates a decorator module in /app/decorators
+ setup to interact with the named model.
+
+Examples:
+ rails generate decorator:model Article
+
+ file: app/decorators/article_decorator.rb
@@ -0,0 +1,9 @@
+module Decorator
+ class ModelGenerator < Rails::Generators::NamedBase
+ source_root File.expand_path('../templates', __FILE__)
+
+ def build_module
+ template 'module.rb', "app/decorators/#{singular_name}_decorator.rb"
+ end
+ end
+end
@@ -0,0 +1,15 @@
+module <%= singular_name.camelize %>Decorator
+ extend ActiveSupport::Concern
+
+ # Uncomment this line to have access to the Rails view helpers like link_to and content_tag:
+ # include ActionView::Helpers
+
+ module InstanceMethods
+ # Add your instance methods here
+
+ # Example:
+ # def formatted_created_at
+ # content_tag :span, created_at.strftime("%A")
+ # end
+ end
+end
@@ -1,5 +1,5 @@
Description:
- The decorators_setup generator creates an /app/decorators folder and
+ The setup generator creates an /app/decorators folder and
a /config/initializers/load_decorators.rb initializer.
Any decorator module in /app/decorators that matches a model name
@@ -1,11 +1,14 @@
-require 'generators/decorator'
-
module Decorator
- module Generators
- class SetupGenerator < Base
- def create_setup
- directory "app/decorators"
- copy_file "load_decorators.rb", "config/initializers/load_decorators.rb"
+ class SetupGenerator < Rails::Generators::Base
+ source_root File.expand_path('../templates', __FILE__)
+
+ def create_directory
+ empty_directory "app/decorators"
+ end
+
+ def build_initializer
+ initializer("load_decorators.rb") do
+ "RailsDecorators::Loader.load"
end
end
end
@@ -1,16 +0,0 @@
-ActionController::Dispatcher.to_prepare do
- models = Dir.glob(File.join(Rails.root, '/app/models/*.rb')).map do |file|
- file.match(/(\w*).rb/)[1].split('_').map do |class_part|
- class_part.capitalize
- end.join('')
- end
-
- models.each do |model|
- begin
- decorator = (model + "Decorator").constantize
- model.constantize.send :include, decorator
- rescue NameError
- # No Decorator Exists
- end
- end
-end
View
@@ -0,0 +1 @@
+require 'rails_decorators/loader'
@@ -0,0 +1,22 @@
+module RailsDecorators
+ class Loader
+ def self.load
+ ActionController::Dispatcher.to_prepare do
+ models = Dir.glob(File.join(Rails.root, '/app/models/*.rb')).map do |file|
+ file.match(/(\w*).rb/)[1].split('_').map do |class_part|
+ class_part.capitalize
+ end.join('')
+ end
+
+ models.each do |model|
+ begin
+ decorator = (model + "Decorator").constantize
+ model.constantize.send :include, decorator
+ rescue NameError
+ # No Decorator Exists
+ end
+ end
+ end
+ end
+ end
+end
View
Binary file not shown.
View
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "rails_decorators"
- s.version = "0.0.1"
+ s.version = "0.0.3"
s.author = "Jeff Casimir"
s.email = "jeff@jumpstartlab.com"
s.homepage = "http://github.com/jcasimir/rails_decorators"

0 comments on commit bc0b0a2

Please sign in to comment.