simple_presenter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg
3
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://gems.simplesideias.com.br"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ simple_presenter (0.1.0)
5
+
6
+ GEM
7
+ remote: http://gems.simplesideias.com.br/
8
+ specs:
9
+ coderay (0.9.8)
10
+ diff-lcs (1.1.3)
11
+ method_source (0.6.6)
12
+ ruby_parser (~> 2.0.5)
13
+ pry (0.9.6.2)
14
+ coderay (~> 0.9.8)
15
+ method_source (~> 0.6.5)
16
+ ruby_parser (~> 2.0.5)
17
+ slop (~> 2.1.0)
18
+ rake (0.9.2)
19
+ rspec (2.7.0)
20
+ rspec-core (~> 2.7.0)
21
+ rspec-expectations (~> 2.7.0)
22
+ rspec-mocks (~> 2.7.0)
23
+ rspec-core (2.7.0)
24
+ rspec-expectations (2.7.0)
25
+ diff-lcs (~> 1.1.2)
26
+ rspec-mocks (2.7.0)
27
+ ruby_parser (2.0.6)
28
+ sexp_processor (~> 3.0)
29
+ sexp_processor (3.0.7)
30
+ slop (2.1.0)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ pry
37
+ rake
38
+ rspec (~> 2.7)
39
+ simple_presenter!
data/README.rdoc ADDED
@@ -0,0 +1,76 @@
1
+ = simple_presenter
2
+
3
+ Some description
4
+
5
+ == Installation
6
+
7
+ gem install simple_presenter
8
+
9
+ == Usage
10
+
11
+ class User < ActiveRecord::Base
12
+ # implements the following attributes: name, email, password_hash, password_salt
13
+ end
14
+
15
+ class UserPresenter < Presenter
16
+ expose :name, :email
17
+ end
18
+
19
+ user = UserPresenter.new(User.first)
20
+ users = UserPresenter.map(User.all)
21
+
22
+ If you're using Simple Presenter within Rails, presenters also have access to:
23
+
24
+ * route helpers: just use the <tt>routes</tt> or <tt>r</tt> methods
25
+ * view helpers: just use the <tt>helpers</tt> or <tt>h</tt> methods
26
+ * I18n methods: just use the <tt>translate</tt>, <tt>t</tt>, <tt>localize</tt> or <tt>l</tt> methods
27
+
28
+ For additional usage, check the specs.
29
+
30
+ == TO-DO
31
+
32
+ * Recognize ActiveRecord objects and automatically expose attributes used by url and form helpers (like <tt>Model.model_name</tt>, <tt>Model#to_key</tt>, and <tt>Model#to_param</tt>).
33
+ * Override <tt>respond_to?</tt> to reflect exposed attributes.
34
+
35
+ == Troubleshooting
36
+
37
+ If you're having problems because already have a class/module called Presenter that is conflicting with this gem, you can require the namespace and inherit from <tt>SimplePresenter::Base</tt>.
38
+
39
+ require "simple_presenter/namespace"
40
+
41
+ class UserPresenter < SimplePresenter::Base
42
+ end
43
+
44
+ If you're using Rails/Bundler or something like that, remember to override the <tt>:require</tt> option.
45
+
46
+ # Gemfile
47
+ source :rubygems
48
+
49
+ gem "simple_presenter", :require => "simple_presenter/namespace"
50
+
51
+ == Maintainer
52
+
53
+ * Nando Vieira (http://nandovieira.com.br)
54
+
55
+ == License
56
+
57
+ (The MIT License)
58
+
59
+ Permission is hereby granted, free of charge, to any person obtaining
60
+ a copy of this software and associated documentation files (the
61
+ 'Software'), to deal in the Software without restriction, including
62
+ without limitation the rights to use, copy, modify, merge, publish,
63
+ distribute, sublicense, and/or sell copies of the Software, and to
64
+ permit persons to whom the Software is furnished to do so, subject to
65
+ the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be
68
+ included in all copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
71
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
73
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
74
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
75
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
76
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,96 @@
1
+ module SimplePresenter
2
+ class Base
3
+ # Define how many subjects this presenter will receive.
4
+ # Each subject will create a private method with the same name.
5
+ #
6
+ # The first subject name will be used as default, thus isn't required as <tt>:with</tt>
7
+ # option on the SimplePresenter::Base.expose method.
8
+ #
9
+ # class CommentPresenter < Presenter
10
+ # subjects :comment, :post
11
+ # expose :body # will expose comment.body
12
+ # expose :title, :with => :post # will expose post.title
13
+ # end
14
+ #
15
+ def self.subjects(*names)
16
+ @subjects ||= [:subject]
17
+ @subjects = names unless names.empty?
18
+ @subjects
19
+ end
20
+
21
+ # This method will return a presenter for each item of collection.
22
+ #
23
+ # users = UserPresenter.map(User.all)
24
+ #
25
+ # If your presenter accepts more than one subject, you can provided
26
+ # them as following parameters.
27
+ #
28
+ # comments = CommentPresenter.map(post.comment.all, post)
29
+ #
30
+ def self.map(collection, *subjects)
31
+ collection.map {|item| new(item, *subjects)}
32
+ end
33
+
34
+ # The list of attributes that will be exposed.
35
+ #
36
+ # class UserPresenter < Presenter
37
+ # expose :name, :email
38
+ # end
39
+ #
40
+ # You can also expose an attribute from a composition.
41
+ #
42
+ # class CommentPresenter < Presenter
43
+ # expose :body, :created_at
44
+ # expose :name, :with => :user
45
+ # end
46
+ #
47
+ # The presenter above will expose the methods +body+, +created_at+, and +user_name+.
48
+ #
49
+ def self.expose(*attrs)
50
+ options = attrs.pop if attrs.last.kind_of?(Hash)
51
+ options ||= {}
52
+
53
+ attrs.each do |attr_name|
54
+ subject = options.fetch(:with, nil)
55
+ method_name = [subject, attr_name].compact.join("_")
56
+
57
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
58
+ def #{method_name} # def user_name
59
+ proxy_message(#{subject.inspect}, "#{attr_name}") # proxy_message("user", "name")
60
+ end # end
61
+ RUBY
62
+ end
63
+ end
64
+
65
+ # It assigns the subjects.
66
+ #
67
+ # user = UserPresenter.new(User.first)
68
+ #
69
+ # You can assign several subjects if you want.
70
+ #
71
+ # class CommentPresenter < Presenter
72
+ # subject :comment, :post
73
+ # expose :body
74
+ # expose :title, :with => :post
75
+ # end
76
+ #
77
+ # comment = CommentPresenter.new(Comment.first, Post.first)
78
+ #
79
+ # If the :with option specified to one of the subjects, then the default subject is bypassed.
80
+ # Otherwise, it will be proxied to the default subject.
81
+ #
82
+ def initialize(*subjects)
83
+ self.class.subjects.each_with_index do |name, index|
84
+ instance_variable_set("@#{name}", subjects[index])
85
+ end
86
+ end
87
+
88
+ private
89
+ def proxy_message(subject_name, method)
90
+ subject_name ||= self.class.subjects.first
91
+ subject = instance_variable_get("@#{subject_name}")
92
+ subject = instance_variable_get("@#{self.class.subjects.first}").__send__(subject_name) unless subject || self.class.subjects.include?(subject_name)
93
+ subject.respond_to?(method) ? subject.__send__(method) : nil
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,6 @@
1
+ module SimplePresenter
2
+ autoload :Base, "simple_presenter/base"
3
+ autoload :Version, "simple_presenter/version"
4
+
5
+ require "simple_presenter/rails" if defined?(Rails)
6
+ end
@@ -0,0 +1,28 @@
1
+ module SimplePresenter
2
+ class Base
3
+ private
4
+ def translate(*args, &block)
5
+ I18n.t(*args, &block)
6
+ end
7
+
8
+ alias_method :t, :translate
9
+
10
+ def localize(*args, &block)
11
+ I18n.l(*args, &block)
12
+ end
13
+
14
+ alias_method :l, :localize
15
+
16
+ def routes
17
+ Rails.application.routes.url_helpers
18
+ end
19
+
20
+ alias_method :r, :routes
21
+
22
+ def helpers
23
+ ApplicationController.helpers
24
+ end
25
+
26
+ alias_method :h, :helpers
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ module SimplePresenter
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ require "simple_presenter/namespace"
2
+ Presenter = SimplePresenter::Base
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "simple_presenter/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "simple_presenter"
7
+ s.version = SimplePresenter::Version::STRING
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Nando Vieira"]
10
+ s.email = ["fnando.vieira@gmail.com"]
11
+ s.homepage = "http://rubygems.org/gems/simple_presenter"
12
+ s.summary = "A simple presenter/facade/decorator/whatever implementation."
13
+ s.description = s.summary
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency "rake"
21
+ s.add_development_dependency "rspec", "~> 2.7"
22
+ s.add_development_dependency "pry"
23
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,78 @@
1
+ require "spec_helper"
2
+
3
+ describe SimplePresenter::Base do
4
+ describe ".expose" do
5
+ context "not using :with option" do
6
+ subject { UserPresenter.new }
7
+
8
+ it { should respond_to(:name) }
9
+ it { should respond_to(:email) }
10
+ it { should_not respond_to(:password_hash) }
11
+ it { should_not respond_to(:password_salt) }
12
+ end
13
+
14
+ context "using :with option" do
15
+ subject { CommentPresenter.new }
16
+
17
+ it { should respond_to(:user_name) }
18
+ end
19
+ end
20
+
21
+ describe ".subjects" do
22
+ context "using defaults" do
23
+ let(:user) { stub :name => "John Doe", :email => "john@doe.com" }
24
+ subject { UserPresenter.new(user) }
25
+
26
+ its(:name) { should == "John Doe" }
27
+ its(:email) { should == "john@doe.com" }
28
+ end
29
+
30
+ context "specifying several subjects" do
31
+ let(:user) { stub :name => "John Doe" }
32
+ let(:comment) { stub :body => "Some comment", :user => user }
33
+ let(:post) { stub :title => "Some post" }
34
+ subject { CommentPresenter.new(comment, post) }
35
+
36
+ its(:body) { should == "Some comment" }
37
+ its(:post_title) { should == "Some post" }
38
+ its(:user_name) { should == "John Doe" }
39
+ end
40
+
41
+ context "when subjects are nil" do
42
+ let(:comment) { stub :body => "Some comment" }
43
+ subject { CommentPresenter.new(comment, nil) }
44
+
45
+ its(:post_title) { should be_nil }
46
+ end
47
+ end
48
+
49
+ describe ".map" do
50
+ context "wraps a single subject" do
51
+ let(:user) { stub :name => "John Doe" }
52
+ subject { UserPresenter.map([user])[0] }
53
+
54
+ it { should be_a(UserPresenter) }
55
+ its(:name) { should == "John Doe" }
56
+ end
57
+
58
+ context "wraps several subjects" do
59
+ let(:comment) { stub :body => "Some comment" }
60
+ let(:post) { stub :title => "Some post" }
61
+ let(:user) { stub :name => "John Doe" }
62
+ subject { CommentPresenter.map([comment], post)[0] }
63
+
64
+ it { should be_a(CommentPresenter) }
65
+ its(:body) { should == "Some comment" }
66
+ its(:post_title) { should == "Some post" }
67
+ end
68
+ end
69
+
70
+ describe "#initialize" do
71
+ let(:user) { mock }
72
+ subject { UserPresenter.new(user) }
73
+
74
+ it "assigns the subject" do
75
+ subject.instance_variable_get("@subject").should == user
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ describe SimplePresenter do
4
+ it "assigns SimplePresenter::Base" do
5
+ ::Presenter.should be(SimplePresenter::Base)
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ require "bundler"
2
+ Bundler.setup(:default, :development)
3
+ Bundler.require
4
+
5
+ require "simple_presenter"
6
+
7
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each do |file|
8
+ require file
9
+ end
@@ -0,0 +1,7 @@
1
+ class Comment
2
+ attr_accessor :body, :created_at, :user
3
+
4
+ def initialize(attrs = {})
5
+ attrs.each {|name, value| __send__("#{name}=", value)}
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class CommentPresenter < Presenter
2
+ expose :body
3
+ expose :name, :with => :user
4
+ expose :title, :with => :post
5
+
6
+ subjects :comment, :post
7
+ end
@@ -0,0 +1,7 @@
1
+ class User
2
+ attr_accessor :name, :email, :password_salt, :password_hash
3
+
4
+ def initialize(attrs = {})
5
+ attrs.each {|name, value| __send__("#{name}=", value)}
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ class UserPresenter < Presenter
2
+ expose :name, :email
3
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_presenter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nando Vieira
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70350773036040 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70350773036040
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70350773035120 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.7'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70350773035120
36
+ - !ruby/object:Gem::Dependency
37
+ name: pry
38
+ requirement: &70350773034520 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70350773034520
47
+ description: A simple presenter/facade/decorator/whatever implementation.
48
+ email:
49
+ - fnando.vieira@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - .rspec
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - README.rdoc
59
+ - Rakefile
60
+ - lib/simple_presenter.rb
61
+ - lib/simple_presenter/base.rb
62
+ - lib/simple_presenter/namespace.rb
63
+ - lib/simple_presenter/rails.rb
64
+ - lib/simple_presenter/version.rb
65
+ - simple_presenter.gemspec
66
+ - spec/base_spec.rb
67
+ - spec/simple_presenter_spec.rb
68
+ - spec/spec_helper.rb
69
+ - spec/support/comment.rb
70
+ - spec/support/comment_presenter.rb
71
+ - spec/support/user.rb
72
+ - spec/support/user_presenter.rb
73
+ homepage: http://rubygems.org/gems/simple_presenter
74
+ licenses: []
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ segments:
86
+ - 0
87
+ hash: -2912702022117065425
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ segments:
95
+ - 0
96
+ hash: -2912702022117065425
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 1.8.10
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: A simple presenter/facade/decorator/whatever implementation.
103
+ test_files:
104
+ - spec/base_spec.rb
105
+ - spec/simple_presenter_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/support/comment.rb
108
+ - spec/support/comment_presenter.rb
109
+ - spec/support/user.rb
110
+ - spec/support/user_presenter.rb