Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ source :rubygems

gemspec


gem 'capybara'
gem 'pry'
gem 'rails', '~> 3.2.0'
gem 'rspec-rails'
gem 'capybara'
gem 'sqlite3'
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ You can use the generator for doing this ( `% rails g decorator user` )
# first_name:string last_name:string website:string
end

# Implicit decorator. Works without configuration.
# app/decorators/user_decorator.rb
module UserDecorator
def full_name
Expand All @@ -47,6 +48,18 @@ You can use the generator for doing this ( `% rails g decorator user` )
link_to full_name, website
end
end

# Explicit decorator. Allows you to use a different
# decorator for other contexts. Overrides the
# implicit decorator.
# app/decorators/user_json_decorator.rb
module UserJsonDecorator
def as_json(opts={})
{ :id => id,
:first_name => first_name }
end
end


# app/controllers/users_controller.rb
class UsersController < ApplicationController
Expand All @@ -55,10 +68,21 @@ You can use the generator for doing this ( `% rails g decorator user` )
end
end

# app/controllers/remote_users_controller.rb
class RemoteUsersController < ApplicationController
decorate :user, :with => UserJsonDecorator # or :user_json_decorator
def show
@user = User.find(params[:id])
respond_with @user
end
end

# app/views/users/index.html.erb
<% @users.each do |user| %>
<%= user.link %><br>
<% end %>




## Contributing to ActiveDecorator ##
Expand Down
2 changes: 1 addition & 1 deletion gemfiles/Gemfile-rails.3.0.x
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source :rubygems

gem 'active_decorator', :path => '..'

gem 'pry-rails'
gem 'rails', '~> 3.0.0'
gem 'rspec-rails'
gem 'capybara'
Expand Down
2 changes: 1 addition & 1 deletion gemfiles/Gemfile-rails.3.1.x
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source :rubygems

gem 'active_decorator', :path => '..'

gem 'pry-rails'
gem 'rails', '~> 3.1.0'
gem 'rspec-rails'
gem 'capybara'
Expand Down
20 changes: 14 additions & 6 deletions lib/active_decorator/decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ def initialize

def decorate(obj)
return if obj.nil?

if obj.is_a? Array
obj.each do |r|
decorate r
Expand All @@ -27,19 +26,28 @@ def to_a_with_decorator
end
else
d = decorator_for obj.class

return obj unless d
obj.extend d unless obj.is_a? d
obj.extend d unless obj.is_a? d # do the include of the decorator
end
end

private
def decorator_for(model_class)
return @@decorators[model_class] if @@decorators.has_key? model_class

decorator_name = "#{model_class.name}Decorator"
d = decorator_name.constantize
d.send :include, ActiveDecorator::Helpers
@@decorators[model_class] = d
decorator = whos_my_decorator(model_class)
decorator.send :include, ActiveDecorator::Helpers
@@decorators[model_class] = decorator

end

def whos_my_decorator(model_class)
if model_class.respond_to? :decorated_with
return model_class.decorated_with
else
return "#{model_class.name}Decorator".constantize
end
rescue NameError
@@decorators[model_class] = nil
end
Expand Down
14 changes: 7 additions & 7 deletions lib/active_decorator/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ module Helpers
def method_missing(method, *args, &block)
super
#TODO need to make sure who raised the error?
rescue NoMethodError, NameError => original_error
begin
ActiveDecorator::ViewContext.current.send method, *args, &block
rescue NoMethodError, NameError
raise original_error
end
end
rescue NoMethodError, NameError => original_error
begin
ActiveDecorator::ViewContext.current.send method, *args, &block
rescue NoMethodError, NameError
raise original_error
end
end
end
end
21 changes: 20 additions & 1 deletion lib/active_decorator/monkey/abstract_controller/rendering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,26 @@ def view_assigns_with_decorator
end
hash
end

alias_method_chain :view_assigns, :decorator

module ClassMethods
def decorate model_name, opts={}
raise ArgumentError unless opts.keys.include? :with
klass = model_name.to_s.camelize.constantize
class << klass
attr_accessor :decorated_with
end
klass.decorated_with = decorator_class_with_unknown_input(opts[:with])
end

private
def decorator_class_with_unknown_input(symbol_or_constant)
if symbol_or_constant.is_a? Module
symbol_or_constant
else
symbol_or_constant.to_s.camelize.constantize
end
end
end
end
end
26 changes: 26 additions & 0 deletions lib/active_decorator/rspec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module RSpec::Rails
module DecoratorExampleGroup
extend ActiveSupport::Concern
include RSpec::Rails::RailsExampleGroup
include ActionView::TestCase::Behavior

def decorate(obj)
ActiveDecorator::Decorator.instance.decorate(obj)
obj
end

included do
metadata[:type] = :decorator

before do
ActiveDecorator::ViewContext.current = controller.view_context
end
end
end
end

RSpec::configure do |c|
c.include RSpec::Rails::DecoratorExampleGroup, :type => :decorator, :example_group => {
:file_path => c.escaped_path(%w[spec decorators])
}
end
1 change: 1 addition & 0 deletions spec/fake_app/authors/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<%= @author.name %>
<%= @author.capitalized_name %>
<%= @author.fancy_name %>
26 changes: 26 additions & 0 deletions spec/fake_app/fake_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ class Application < Rails::Application
# models
class Author < ActiveRecord::Base
has_many :books

#decorated_with ArbitraryDecorator

def self.decorated_with
ArbitraryDecorator
end

end

class Book < ActiveRecord::Base
belongs_to :author
end
Expand Down Expand Up @@ -60,11 +68,28 @@ def cover_image
end
end

module ArbitraryDecorator
def fancy_name
name.insert(0, 'Awesome he is, ')
end

def reverse_name
name.reverse
end

def capitalized_name
name.capitalize
end
end

# controllers
class ApplicationController < ActionController::Base
self.append_view_path File.dirname(__FILE__)
end

class AuthorsController < ApplicationController
decorate :author, :with => ArbitraryDecorator

def index
if params[:variable_type] == 'array'
@authors = Author.all
Expand All @@ -83,6 +108,7 @@ def show
end
end


# migrations
class CreateAllTables < ActiveRecord::Migration
def self.up
Expand Down
15 changes: 15 additions & 0 deletions spec/requests/controller_ivar_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@matz = Author.create! :name => 'matz'
Author.create! :name => 'takahashim'
end

after do
Author.delete_all
end
Expand All @@ -26,4 +27,18 @@
page.should have_content 'takahashim'
page.should have_content 'takahashim'.reverse
end

scenario "decorating Model with arbitrary decorator" do
visit "/authors/#{@matz.id}"
page.should have_content @matz.name.insert(0, 'Awesome he is, ')
end

scenario "throw ArgumentError when no :with is passed" do
lambda { BooksController.decorate :book }.should raise_error ArgumentError
end

scenario "should accept symbol for decorator class" do
BooksController.decorate :book, :with => :arbitrary_decorator
Book.decorated_with.should == ArbitraryDecorator
end
end
8 changes: 8 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@
# needs to load the app before loading rspec/rails => capybara
require 'fake_app/fake_app'
require 'rspec/rails'

# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}

module ::RSpec::Core
class ExampleGroup
include Capybara::DSL
include Capybara::RSpecMatchers
end
end

RSpec.configure do |config|
config.before :all do
CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'authors'
Expand Down