forked from fnando/simple_presenter
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
281 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,96 @@ | ||
module SimplePresenter | ||
class Base | ||
# Define how many subjects this presenter will receive. | ||
# Each subject will create a private method with the same name. | ||
# | ||
# The first subject name will be used as default, thus isn't required as <tt>:with</tt> | ||
# option on the SimplePresenter::Base.expose method. | ||
# | ||
# class CommentPresenter < Presenter | ||
# subjects :comment, :post | ||
# expose :body # will expose comment.body | ||
# expose :title, :with => :post # will expose post.title | ||
# end | ||
# | ||
def self.subjects(*names) | ||
@subjects ||= [:subject] | ||
@subjects = names unless names.empty? | ||
@subjects | ||
end | ||
|
||
# This method will return a presenter for each item of collection. | ||
# | ||
# users = UserPresenter.map(User.all) | ||
# | ||
# If your presenter accepts more than one subject, you can provided | ||
# them as following parameters. | ||
# | ||
# comments = CommentPresenter.map(post.comment.all, post) | ||
# | ||
def self.map(collection, *subjects) | ||
collection.map {|item| new(item, *subjects)} | ||
end | ||
|
||
# The list of attributes that will be exposed. | ||
# | ||
# class UserPresenter < Presenter | ||
# expose :name, :email | ||
# end | ||
# | ||
# You can also expose an attribute from a composition. | ||
# | ||
# class CommentPresenter < Presenter | ||
# expose :body, :created_at | ||
# expose :name, :with => :user | ||
# end | ||
# | ||
# The presenter above will expose the methods +body+, +created_at+, and +user_name+. | ||
# | ||
def self.expose(*attrs) | ||
options = attrs.pop if attrs.last.kind_of?(Hash) | ||
options ||= {} | ||
|
||
attrs.each do |attr_name| | ||
subject = options.fetch(:with, nil) | ||
method_name = [subject, attr_name].compact.join("_") | ||
|
||
class_eval <<-RUBY, __FILE__, __LINE__ + 1 | ||
def #{method_name} # def user_name | ||
proxy_message(#{subject.inspect}, "#{attr_name}") # proxy_message("user", "name") | ||
end # end | ||
RUBY | ||
end | ||
end | ||
|
||
# It assigns the subjects. | ||
# | ||
# user = UserPresenter.new(User.first) | ||
# | ||
# You can assign several subjects if you want. | ||
# | ||
# class CommentPresenter < Presenter | ||
# subject :comment, :post | ||
# expose :body | ||
# expose :title, :with => :post | ||
# end | ||
# | ||
# comment = CommentPresenter.new(Comment.first, Post.first) | ||
# | ||
# If the :with option specified to one of the subjects, then the default subject is bypassed. | ||
# Otherwise, it will be proxied to the default subject. | ||
# | ||
def initialize(*subjects) | ||
self.class.subjects.each_with_index do |name, index| | ||
instance_variable_set("@#{name}", subjects[index]) | ||
end | ||
end | ||
|
||
private | ||
def proxy_message(subject_name, method) | ||
subject_name ||= self.class.subjects.first | ||
subject = instance_variable_get("@#{subject_name}") | ||
subject = instance_variable_get("@#{self.class.subjects.first}").__send__(subject_name) unless subject || self.class.subjects.include?(subject_name) | ||
subject.respond_to?(method) ? subject.__send__(method) : nil | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
module SimplePresenter | ||
autoload :Base, "simple_presenter/base" | ||
autoload :Version, "simple_presenter/version" | ||
|
||
require "simple_presenter/rails" if defined?(Rails) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
module SimplePresenter | ||
class Base | ||
private | ||
def translate(*args, &block) | ||
I18n.t(*args, &block) | ||
end | ||
|
||
alias_method :t, :translate | ||
|
||
def localize(*args, &block) | ||
I18n.l(*args, &block) | ||
end | ||
|
||
alias_method :l, :localize | ||
|
||
def routes | ||
Rails.application.routes.url_helpers | ||
end | ||
|
||
alias_method :r, :routes | ||
|
||
def helpers | ||
ApplicationController.helpers | ||
end | ||
|
||
alias_method :h, :helpers | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
require "spec_helper" | ||
|
||
describe SimplePresenter::Base do | ||
describe ".expose" do | ||
context "not using :with option" do | ||
subject { UserPresenter.new } | ||
|
||
it { should respond_to(:name) } | ||
it { should respond_to(:email) } | ||
it { should_not respond_to(:password_hash) } | ||
it { should_not respond_to(:password_salt) } | ||
end | ||
|
||
context "using :with option" do | ||
subject { CommentPresenter.new } | ||
|
||
it { should respond_to(:user_name) } | ||
end | ||
end | ||
|
||
describe ".subjects" do | ||
context "using defaults" do | ||
let(:user) { stub :name => "John Doe", :email => "john@doe.com" } | ||
subject { UserPresenter.new(user) } | ||
|
||
its(:name) { should == "John Doe" } | ||
its(:email) { should == "john@doe.com" } | ||
end | ||
|
||
context "specifying several subjects" do | ||
let(:user) { stub :name => "John Doe" } | ||
let(:comment) { stub :body => "Some comment", :user => user } | ||
let(:post) { stub :title => "Some post" } | ||
subject { CommentPresenter.new(comment, post) } | ||
|
||
its(:body) { should == "Some comment" } | ||
its(:post_title) { should == "Some post" } | ||
its(:user_name) { should == "John Doe" } | ||
end | ||
|
||
context "when subjects are nil" do | ||
let(:comment) { stub :body => "Some comment" } | ||
subject { CommentPresenter.new(comment, nil) } | ||
|
||
its(:post_title) { should be_nil } | ||
end | ||
end | ||
|
||
describe ".map" do | ||
context "wraps a single subject" do | ||
let(:user) { stub :name => "John Doe" } | ||
subject { UserPresenter.map([user])[0] } | ||
|
||
it { should be_a(UserPresenter) } | ||
its(:name) { should == "John Doe" } | ||
end | ||
|
||
context "wraps several subjects" do | ||
let(:comment) { stub :body => "Some comment" } | ||
let(:post) { stub :title => "Some post" } | ||
let(:user) { stub :name => "John Doe" } | ||
subject { CommentPresenter.map([comment], post)[0] } | ||
|
||
it { should be_a(CommentPresenter) } | ||
its(:body) { should == "Some comment" } | ||
its(:post_title) { should == "Some post" } | ||
end | ||
end | ||
|
||
describe "#initialize" do | ||
let(:user) { mock } | ||
subject { UserPresenter.new(user) } | ||
|
||
it "assigns the subject" do | ||
subject.instance_variable_get("@subject").should == user | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,6 @@ | |
|
||
require "simple_presenter" | ||
|
||
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each do |file| | ||
require file | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class Comment | ||
attr_accessor :body, :created_at, :user | ||
|
||
def initialize(attrs = {}) | ||
attrs.each {|name, value| __send__("#{name}=", value)} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class CommentPresenter < Presenter | ||
expose :body | ||
expose :name, :with => :user | ||
expose :title, :with => :post | ||
|
||
subjects :comment, :post | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class User | ||
attr_accessor :name, :email, :password_salt, :password_hash | ||
|
||
def initialize(attrs = {}) | ||
attrs.each {|name, value| __send__("#{name}=", value)} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
class UserPresenter < Presenter | ||
expose :name, :email | ||
end |