Initial commit. Add all of DecoratesBeforeRendering.

This commit is contained in:
Rob Hanlon 2012-07-13 10:39:23 -07:00
commit 02325470e3
9 changed files with 261 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
.rspec

4
Gemfile Normal file
View File

@ -0,0 +1,4 @@
source 'https://rubygems.org'
# Specify your gem's dependencies in decorates_before_rendering.gemspec
gemspec

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2012 Rob Hanlon
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

31
README.md Normal file
View File

@ -0,0 +1,31 @@
# DecoratesBeforeRendering
A small add-on for [Draper](http://github.com/jcasimir/draper) that automatically decorates
specified controller instance variables before rendering. Currently only works on objects
that respond to ```model_name````, but this could easily be expanded upon.
## Installation
Add this line to your application's Gemfile:
gem 'decorates_before_rendering'
And then execute:
$ bundle
Or install it yourself as:
$ gem install decorates_before_rendering
## Usage
See ```lib/decorates_before_rendering.rb``` for usage instructions.
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

2
Rakefile Normal file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env rake
require "bundler/gem_tasks"

View File

@ -0,0 +1,22 @@
# -*- encoding: utf-8 -*-
require File.expand_path('../lib/decorates_before_rendering/version', __FILE__)
Gem::Specification.new do |gem|
gem.authors = ["Rob Hanlon"]
gem.email = ["rob@mediapiston.com"]
gem.description = %q{Small add-on for Draper that decorates models before rendering.}
gem.summary = %q{Small add-on for Draper that decorates models before rendering.}
gem.homepage = "http://github.com/ohwillie/decorates_before_rendering"
gem.files = `git ls-files`.split($\)
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.name = "decorates_before_rendering"
gem.require_paths = ["lib"]
gem.version = DecoratesBeforeRendering::VERSION
gem.add_development_dependency 'rspec', '>= 2.10.0'
gem.add_development_dependency 'rbx-require-relative', '>= 0.0.9'
gem.add_dependency 'activesupport', '>= 3.2.6'
end

View File

@ -0,0 +1,63 @@
# -*- encoding : utf-8 -*-
require "decorates_before_rendering/version"
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/class/attribute'
# Decorates the specified fields. For instance, if you have
#
# class StuffController < ApplicationController
# include DecoratesBeforeRendering
#
# decorates :thing_1, :thing_2
# end
#
# @thing_1 and @thing_2 will be decorated right before a rendering occurs.
#
module DecoratesBeforeRendering
module ClassMethods
def decorates(*unsigiled_ivar_names)
self.__ivars_to_decorate__ = unsigiled_ivar_names.map { |i| "@#{i}" }
end
end
def render(*args)
__decorate_ivars__
super(*args)
end
private
def __decorate_ivars__
ivars_to_decorate = self.class.__ivars_to_decorate__
return if ivars_to_decorate.nil?
ivars_to_decorate.each do |ivar_name|
ivar = instance_variable_get(ivar_name)
instance_variable_set(ivar_name, __decorator_for__(ivar)) unless ivar.nil?
end
end
def __decorator_for__(ivar)
__decorator_name_for__(ivar).constantize.decorate(ivar)
end
def __decorator_name_for__(ivar)
"#{__model_name_for__(ivar)}Decorator"
end
def __model_name_for__(ivar)
if ivar.respond_to?(:model_name)
ivar
elsif ivar.class.respond_to?(:model_name)
ivar.class
else
raise ArgumentError, "#{ivar} does not have an associated model"
end.model_name
end
def self.included(base)
base.class_attribute :__ivars_to_decorate__, :instance_accessor => false
base.extend ClassMethods
end
end

View File

@ -0,0 +1,3 @@
module DecoratesBeforeRendering
VERSION = "0.0.1"
end

View File

@ -0,0 +1,96 @@
require_relative '../lib/decorates_before_rendering'
class MyCompletelyFakeModelDecorator; end
describe DecoratesBeforeRendering do
# NOTE: these are married together, so they're tested together.
describe '::decorates + #render' do
let(:sentinel) { double(:sentinel) }
let(:ivar) { double('@ivar') }
# NOTE: This superclass is here so we know that the correct render gets
# called. It can't be defined in the subclass, or else that one
# will be the one that's used, as modules sit above their includers
# in the class hierarchy.
let(:superclass) do
Class.new do
def initialize(sentinel)
@sentinel = sentinel
end
def render(*args)
@sentinel.render(*args)
end
end
end
let(:klass) do
Class.new(superclass) do
include DecoratesBeforeRendering
attr_reader :ivar
def initialize(sentinel, ivar)
super(sentinel)
@ivar = ivar
end
end
end
let(:instance) { klass.new(sentinel, ivar) }
let(:args) { double('*args') }
context "no ivars" do
it 'should render' do
sentinel.should_receive(:render).with(args)
instance.render(args)
end
end
context "ivar is not present" do
it 'should render' do
sentinel.should_receive(:render).with(args)
instance.render(args)
end
end
context "cannot find model name for ivar" do
it 'should raise an ArgumentError' do
klass.decorates(:ivar)
expect {
instance.render(args)
}.to raise_error(ArgumentError)
end
end
context "ivar responds to model name" do
it "should decorate and render" do
sentinel.should_receive(:render).with(args)
MyCompletelyFakeModelDecorator.should_receive(:decorate).with(ivar)
ivar.stub(:model_name => 'MyCompletelyFakeModel')
klass.decorates(:ivar)
instance.render(args)
end
end
context "ivar's class responds to model name" do
it "should decorate and render" do
sentinel.should_receive(:render).with(args)
MyCompletelyFakeModelDecorator.should_receive(:decorate).with(ivar)
ivar.stub_chain(:class, :model_name => 'MyCompletelyFakeModel')
klass.decorates(:ivar)
instance.render(args)
end
end
context "subclass inherits attributes" do
it "should function correctly" do
klass.decorates(:ivar)
subclass_instance = Class.new(klass).new(sentinel, ivar)
sentinel.should_receive(:render).with(args)
MyCompletelyFakeModelDecorator.should_receive(:decorate).with(ivar)
ivar.stub_chain(:class, :model_name => 'MyCompletelyFakeModel')
subclass_instance.render(args)
end
end
end
end