lulalala_presenter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +23 -0
  5. data/Gemfile +9 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +68 -0
  8. data/Rakefile +12 -0
  9. data/gemfiles/Gemfile-rails.3.0.x +16 -0
  10. data/gemfiles/Gemfile-rails.3.1.x +19 -0
  11. data/gemfiles/Gemfile-rails.3.2.x +20 -0
  12. data/gemfiles/Gemfile-rails.4.0.x +10 -0
  13. data/gemfiles/Gemfile-rails.4.1.x +9 -0
  14. data/gemfiles/Gemfile-rails.4.2.x +9 -0
  15. data/lib/active_decorator/config.rb +20 -0
  16. data/lib/active_decorator/helpers.rb +14 -0
  17. data/lib/active_decorator/monkey/action_controller/base/rescue_from.rb +11 -0
  18. data/lib/active_decorator/view_context.rb +44 -0
  19. data/lib/generators/rails/decorator_generator.rb +24 -0
  20. data/lib/generators/rails/templates/decorator.rb +2 -0
  21. data/lib/generators/rspec/decorator_generator.rb +9 -0
  22. data/lib/generators/rspec/templates/decorator_spec.rb +7 -0
  23. data/lib/generators/test_unit/decorator_generator.rb +9 -0
  24. data/lib/generators/test_unit/templates/decorator_test.rb +11 -0
  25. data/lib/lulalala_presenter.rb +4 -0
  26. data/lib/lulalala_presenter/active_model_bridge.rb +10 -0
  27. data/lib/lulalala_presenter/base.rb +14 -0
  28. data/lib/lulalala_presenter/railtie.rb +22 -0
  29. data/lib/lulalala_presenter/version.rb +3 -0
  30. data/lulalala_presenter.gemspec +18 -0
  31. data/spec/configuration_spec.rb +27 -0
  32. data/spec/controllers/fake_detection_spec.rb +7 -0
  33. data/spec/fake_app/app/views/authors/index.html.erb +16 -0
  34. data/spec/fake_app/app/views/authors/show.html.erb +2 -0
  35. data/spec/fake_app/app/views/authors/show.json.jbuilder +2 -0
  36. data/spec/fake_app/app/views/book_mailer/thanks.text.erb +1 -0
  37. data/spec/fake_app/app/views/books/_book.html.erb +2 -0
  38. data/spec/fake_app/app/views/books/_book.json.jbuilder +2 -0
  39. data/spec/fake_app/app/views/books/_book_locals.html.erb +2 -0
  40. data/spec/fake_app/app/views/books/error.html.erb +1 -0
  41. data/spec/fake_app/app/views/books/index.html.erb +4 -0
  42. data/spec/fake_app/app/views/books/purchase.html.erb +1 -0
  43. data/spec/fake_app/app/views/books/show.html.erb +4 -0
  44. data/spec/fake_app/app/views/movies/show.html.erb +1 -0
  45. data/spec/fake_app/fake_app.rb +194 -0
  46. data/spec/features/action_view_helpers_spec.rb +25 -0
  47. data/spec/features/controller_ivar_spec.rb +37 -0
  48. data/spec/features/jbuilder_spec.rb +12 -0
  49. data/spec/features/partial_spec.rb +25 -0
  50. data/spec/spec_helper.rb +27 -0
  51. metadata +114 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 83daef5e00861530f17904e67b427afb6398f4e6
4
+ data.tar.gz: 0da518f4274c4172cb51bdc47150062f77253404
5
+ SHA512:
6
+ metadata.gz: c5267a2f9ecec315bbf7f53e2feb755b9bfe598fc411d974af01ca6b19f59b65852e33d9dd4b59f13cde2dc6d7df3b7d76775dafffb9ce9f6c0e3e73a9807ec5
7
+ data.tar.gz: 06ef0a6c2b5270754543f25c080c6c332d2eed8b3f8694e48330f45fc601f991dd387edc454f504c8f75ef92243384de973e36414df631c0a8eb0daba75316e3
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ gemfiles/*.lock
5
+ pkg/*
6
+ log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,23 @@
1
+ language: ruby
2
+
3
+ script: bundle exec rake spec
4
+
5
+ rvm:
6
+ - 2.0.0
7
+ - 2.1
8
+ - 2.2.3
9
+ - ruby-head
10
+ gemfile:
11
+ - gemfiles/Gemfile-rails.3.2.x
12
+ - gemfiles/Gemfile-rails.4.0.x
13
+ - gemfiles/Gemfile-rails.4.1.x
14
+ - gemfiles/Gemfile-rails.4.2.x
15
+
16
+ sudo: false
17
+
18
+ matrix:
19
+ exclude:
20
+ - rvm: ruby-head
21
+ gemfile: gemfiles/Gemfile-rails.3.2.x
22
+ allow_failures:
23
+ - rvm: ruby-head
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 4.0.0'
6
+ gem 'rspec-rails'
7
+ gem 'capybara', '>= 2'
8
+ gem 'sqlite3'
9
+ gem 'jbuilder'
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Akira Matsuda
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,68 @@
1
+ # LulalalaPresenter - forked from ActiveDecorator
2
+
3
+ ...where you can put your view helpers if they are **very closely** related to ActiveModel.
4
+
5
+ This solves one very important computer science problem: naming your helper methods. All great programmers feels uneasy seeing:
6
+
7
+ * `auction_title(@auction)`
8
+ * `board_title(@board)`
9
+ * `category_title(@category)`
10
+
11
+ and this gem will solve it.
12
+
13
+
14
+ ## Usage ##
15
+
16
+ 1. put `gem 'lulalala_presenter', github:'lulalala/lulalala_presenter'` in Gemfile and then `bundle install`.
17
+ 2. create a presenter class for each AR model you wish to present. For example, a decorator for a model `User` should be named `UserPresenter`.
18
+ 3. access this presenter from the model like this: `record.presenter`, and from there call the helper methods.
19
+ 2. call any ActionView's helper methods using `h`, e.g. `h.content_tag` or `h.link_to`.
20
+
21
+
22
+ ## Examples ##
23
+
24
+ ```ruby
25
+ # app/models/user.rb
26
+ class User < ActiveRecord::Base
27
+ # first_name:string last_name:string website:string
28
+ end
29
+
30
+ # app/presenters/user_presenter.rb
31
+ module UserPresenter < LulalalaPresenter::Base
32
+ def full_name
33
+ "#{model.first_name} #{model.last_name}"
34
+ end
35
+
36
+ def link
37
+ h.link_to model.full_name, model.website
38
+ end
39
+ end
40
+
41
+ # app/controllers/users_controller.rb
42
+ class UsersController < ApplicationController
43
+ def index
44
+ @users = User.all
45
+ end
46
+ end
47
+ ```
48
+ ```erb
49
+ # app/views/users/index.html.erb
50
+ <% @users.each do |user| %>
51
+ <%= user.presenter.link %><br>
52
+ <% end %>
53
+ ```
54
+
55
+ ## Reason for fork ##
56
+
57
+ It's difficult to decorate models automatically. Leaky abstractions can happen easily. Having a presenter class that can be accessed from model would not have that issue at all.
58
+ Even though more typing is needed, I think it is good for establishing the awareness that presenter helpers are different to model methods.
59
+
60
+ ## Contribute ##
61
+
62
+ * Fork, fix, then send me a pull request.
63
+
64
+
65
+ ## Copyright ##
66
+
67
+ Copyright (c) 2011 Akira Matsuda. See MIT-LICENSE for further details.
68
+
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rspec/core'
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new(:spec) do |spec|
9
+ spec.pattern = FileList['spec/**/*_spec.rb']
10
+ end
11
+
12
+ task :default => :spec
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'active_decorator', :path => '..'
4
+
5
+ gem 'rails', '~> 3.0.0'
6
+ gem 'rspec-rails', '~> 2.14.0'
7
+ gem 'capybara', '~> 2.0.0'
8
+ # rubyzip >=1 doesn't support ruby 1.8
9
+ gem 'rubyzip', '< 1.0.0'
10
+ gem 'sqlite3'
11
+ gem 'nokogiri', '~> 1.5.0'
12
+ if RUBY_VERSION <= '1.8.7'
13
+ gem 'jbuilder', '< 2'
14
+ else
15
+ gem 'jbuilder'
16
+ end
@@ -0,0 +1,19 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'active_decorator', :path => '..'
4
+
5
+ gem 'rails', '~> 3.1.0'
6
+ gem 'rspec-rails', '~> 2.14.0'
7
+ if RUBY_VERSION <= '1.8.7'
8
+ gem 'i18n', '~> 0.6.11'
9
+ end
10
+ gem 'capybara', '~> 2.0.0'
11
+ # rubyzip >=1 doesn't support ruby 1.8
12
+ gem 'rubyzip', '< 1.0.0'
13
+ gem 'sqlite3'
14
+ gem 'nokogiri', '~> 1.5.0'
15
+ if RUBY_VERSION <= '1.8.7'
16
+ gem 'jbuilder', '< 2'
17
+ else
18
+ gem 'jbuilder'
19
+ end
@@ -0,0 +1,20 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'active_decorator', :path => '..'
4
+
5
+ gem 'rails', '~> 3.2.0'
6
+ gem 'rspec-rails', '~> 2.14.0'
7
+ if RUBY_VERSION <= '1.8.7'
8
+ gem 'i18n', '~> 0.6.11'
9
+ end
10
+ gem 'capybara', '~> 2.0.0'
11
+ # rubyzip >=1 doesn't support ruby 1.8
12
+ gem 'rubyzip', '< 1.0.0'
13
+ gem 'sqlite3'
14
+ gem 'nokogiri', '~> 1.5.0'
15
+ if RUBY_VERSION <= '1.8.7'
16
+ gem 'jbuilder', '< 2'
17
+ else
18
+ gem 'jbuilder'
19
+ end
20
+ gem 'test-unit'
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'active_decorator', :path => '..'
4
+
5
+ gem 'rails', '~> 4.0.0'
6
+ gem 'rspec-rails'
7
+ gem 'capybara'
8
+ gem 'sqlite3'
9
+ gem 'jbuilder'
10
+ gem 'test-unit'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'active_decorator', :path => '..'
4
+
5
+ gem 'rails', '~> 4.1.0'
6
+ gem 'rspec-rails'
7
+ gem 'capybara'
8
+ gem 'sqlite3'
9
+ gem 'jbuilder'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'active_decorator', :path => '..'
4
+
5
+ gem 'rails', '~> 4.2.0'
6
+ gem 'rspec-rails'
7
+ gem 'capybara'
8
+ gem 'sqlite3'
9
+ gem 'jbuilder'
@@ -0,0 +1,20 @@
1
+ module ActiveDecorator
2
+ def self.configure(&block)
3
+ yield @config ||= ActiveDecorator::Configuration.new
4
+ end
5
+
6
+ def self.config
7
+ @config
8
+ end
9
+
10
+ # need a Class for 3.0
11
+ class Configuration #:nodoc:
12
+ include ActiveSupport::Configurable
13
+
14
+ config_accessor :decorator_suffix
15
+ end
16
+
17
+ configure do |config|
18
+ config.decorator_suffix = 'Decorator'
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module ActiveDecorator
2
+ module Helpers
3
+ def method_missing(method, *args, &block)
4
+ super
5
+ #TODO need to make sure who raised the error?
6
+ rescue NoMethodError, NameError => original_error
7
+ begin
8
+ ActiveDecorator::ViewContext.current.send method, *args, &block
9
+ rescue NoMethodError, NameError
10
+ raise original_error
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module ActionController
2
+ class Base
3
+ def rescue_with_handler_with_decorator_view_context(exception)
4
+ ActiveDecorator::ViewContext.push(view_context)
5
+ rescue_with_handler_without_decorator_view_context(exception)
6
+ ensure
7
+ ActiveDecorator::ViewContext.pop
8
+ end
9
+ alias_method_chain :rescue_with_handler, :decorator_view_context
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ module ActiveDecorator
2
+ module ViewContext
3
+ class << self
4
+ def current
5
+ Thread.current[:active_decorator_view_contexts].last
6
+ end
7
+
8
+ def push(view_context)
9
+ Thread.current[:active_decorator_view_contexts] ||= []
10
+ Thread.current[:active_decorator_view_contexts] << view_context
11
+ end
12
+
13
+ def pop
14
+ Thread.current[:active_decorator_view_contexts].pop if Thread.current[:active_decorator_view_contexts]
15
+ end
16
+ end
17
+
18
+ module Filter
19
+ extend ActiveSupport::Concern
20
+
21
+ included do
22
+ if Rails::VERSION::MAJOR >= 4
23
+ around_action do |controller, blk|
24
+ begin
25
+ ActiveDecorator::ViewContext.push controller.view_context
26
+ blk.call
27
+ ensure
28
+ ActiveDecorator::ViewContext.pop
29
+ end
30
+ end
31
+ else
32
+ around_filter do |controller, blk|
33
+ begin
34
+ ActiveDecorator::ViewContext.push controller.view_context
35
+ blk.call
36
+ ensure
37
+ ActiveDecorator::ViewContext.pop
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ module Rails
2
+ module Generators
3
+ class DecoratorGenerator < Rails::Generators::NamedBase
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ desc <<DESC
7
+ Description:
8
+ Stubs out a decorator module in app/decorators directory.
9
+
10
+ Examples:
11
+ `rails g decorator book`
12
+
13
+ This creates:
14
+ app/decorators/book_decorator.rb
15
+ DESC
16
+
17
+ def create_decorator_file
18
+ template 'decorator.rb', File.join('app/decorators', class_path, "#{file_name}_decorator.rb")
19
+ end
20
+
21
+ hook_for :test_framework
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,2 @@
1
+ module <%= class_name %>Decorator
2
+ end
@@ -0,0 +1,9 @@
1
+ module Rspec
2
+ class DecoratorGenerator < ::Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def create_spec_file
6
+ template 'decorator_spec.rb', File.join('spec/decorators', class_path, "#{file_name}_decorator_spec.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require '<%= File.exists?('spec/rails_helper.rb') ? 'rails_helper' : 'spec_helper' %>'
2
+
3
+ describe <%= singular_name.camelize %>Decorator do
4
+ let(:<%= singular_name %>) { <%= class_name %>.new.extend <%= singular_name.camelize %>Decorator }
5
+ subject { <%= singular_name %> }
6
+ it { should be_a <%= class_name %> }
7
+ end
@@ -0,0 +1,9 @@
1
+ module TestUnit
2
+ class DecoratorGenerator < ::Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def create_test_file
6
+ template 'decorator_test.rb', File.join('test/decorators', class_path, "#{file_name}_decorator_test.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ class <%= singular_name.camelize %>DecoratorTest < ActiveSupport::TestCase
4
+ def setup
5
+ @<%= singular_name %> = <%= class_name %>.new.extend <%= singular_name.camelize %>Decorator
6
+ end
7
+
8
+ # test "the truth" do
9
+ # assert true
10
+ # end
11
+ end
@@ -0,0 +1,4 @@
1
+ require 'lulalala_presenter/version'
2
+ require 'lulalala_presenter/base'
3
+ require 'lulalala_presenter/railtie'
4
+ require 'active_decorator/config'
@@ -0,0 +1,10 @@
1
+ module LulalalaPresenter
2
+ module ActiveModelBridge
3
+ def presenter
4
+ return @_presenter if @_presenter
5
+
6
+ klass = "#{self.class.name}Presenter".constantize
7
+ @_presenter = klass.new(self)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module LulalalaPresenter
2
+ class Base
3
+ attr_accessor :model
4
+
5
+ def initialize(model)
6
+ @model = model
7
+ end
8
+
9
+ def view_context
10
+ @view_context ||= ActiveDecorator::ViewContext.current
11
+ end
12
+ alias_method :h, :view_context
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ require 'active_decorator/view_context'
2
+ require 'lulalala_presenter/active_model_bridge'
3
+ require 'rails'
4
+
5
+ module LulalalaPresenter
6
+ class Railtie < ::Rails::Railtie
7
+ initializer 'active_decorator' do
8
+ ActiveSupport.on_load(:action_controller) do
9
+ require 'active_decorator/monkey/action_controller/base/rescue_from'
10
+ ActionController::Base.send :include, ActiveDecorator::ViewContext::Filter
11
+ end
12
+ ActiveSupport.on_load(:action_mailer) do
13
+ if ActionMailer::Base.respond_to? :before_action
14
+ ActionMailer::Base.send :include, ActiveDecorator::ViewContext::Filter
15
+ end
16
+ end
17
+ ActiveSupport.on_load(:active_record) do
18
+ ActiveRecord::Base.send :include, LulalalaPresenter::ActiveModelBridge
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module LulalalaPresenter
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "lulalala_presenter/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "lulalala_presenter"
7
+ s.version = LulalalaPresenter::VERSION
8
+ s.authors = ["lulalala", "Akira Matsuda"]
9
+ s.email = ["mark@goodlife.tw", "ronnie@dio.jp"]
10
+ s.homepage = 'https://github.com/lulalala/lulalala_presenter'
11
+ s.summary = %q{A simple and Rubyish view helper for Rails}
12
+ s.description = %q{A simple and Rubyish view helper for Rails}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+ end
@@ -0,0 +1,27 @@
1
+ Comic = Struct.new(:title, :price)
2
+
3
+ module ComicPresenter
4
+ def price
5
+ "$#{super}"
6
+ end
7
+ end
8
+
9
+ describe ActiveDecorator::Configuration do
10
+ let(:comic) { ActiveDecorator::Decorator.instance.decorate(Comic.new("amatsuda's (Poignant) Guide to ActiveDecorator", 3)) }
11
+
12
+ context 'with a custom decorator_suffix' do
13
+ before do
14
+ ActiveDecorator.configure do |config|
15
+ config.decorator_suffix = 'Presenter'
16
+ end
17
+ end
18
+
19
+ after do
20
+ ActiveDecorator.configure do |config|
21
+ config.decorator_suffix = 'Decorator'
22
+ end
23
+ end
24
+
25
+ specify { comic.price.should == '$3' }
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ describe MoviesController, :type => :controller do
2
+ let(:movie){ Movie.create }
3
+
4
+ it 'reveals fakes' do
5
+ expect{ get :show, :id => movie.id }.not_to raise_error
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ <% @authors.each do |author| %>
2
+ <%= author.name %>
3
+ <%= author.reverse_name %>
4
+
5
+ <% if params[:partial] == 'collection' %>
6
+ <%= render author.books %>
7
+ <% elsif params[:partial] == 'locals' %>
8
+ <% author.books.each do |book| %>
9
+ <%= render :partial => 'books/book_locals', :locals => {:b => book} %>
10
+ <% end %>
11
+ <% else %>
12
+ <% author.books.each do |book| %>
13
+ <%= render book %>
14
+ <% end %>
15
+ <% end %>
16
+ <% end %>
@@ -0,0 +1,2 @@
1
+ <%= @author.name %>
2
+ <%= @author.capitalized_name %>
@@ -0,0 +1,2 @@
1
+ json.name @author.name
2
+ json.books @author.books, :partial => 'books/book', :as => :book
@@ -0,0 +1 @@
1
+ Thank you for purchasing <%= @book.upcased_title %>.
@@ -0,0 +1,2 @@
1
+ <%= book.title %>
2
+ <%= book.reverse_title %>
@@ -0,0 +1,2 @@
1
+ json.title book.title
2
+ json.reverse_title book.reverse_title
@@ -0,0 +1,2 @@
1
+ <%= b.title %>
2
+ <%= b.upcased_title %>
@@ -0,0 +1 @@
1
+ <%= @book.error %>
@@ -0,0 +1,4 @@
1
+ <% @books.each do |book| %>
2
+ <%= book.title %>
3
+ <%= book.reverse_title %>
4
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <%= @book.link %>
2
+ <%= @book.cover_image %>
3
+
4
+ <%= link_to 'purchase', [:purchase, @book.author, @book], :method => :post %>
@@ -0,0 +1 @@
1
+ <%= @movie.name %>
@@ -0,0 +1,194 @@
1
+ require 'active_record'
2
+ require 'action_controller/railtie'
3
+ require 'action_mailer/railtie'
4
+ require 'action_view/railtie'
5
+ require 'ostruct'
6
+ require 'jbuilder'
7
+
8
+ # config
9
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
10
+
11
+ module ActiveDecoratorTestApp
12
+ class Application < Rails::Application
13
+ config.secret_token = '"confusion" will be my epitaph.'
14
+ config.session_store :cookie_store, :key => '_myapp_session'
15
+ config.active_support.deprecation = :log
16
+ config.eager_load = false
17
+ config.action_dispatch.show_exceptions = false
18
+ config.root = File.dirname(__FILE__)
19
+
20
+ config.action_mailer.delivery_method = :test
21
+ end
22
+ end
23
+ ActiveDecoratorTestApp::Application.initialize!
24
+
25
+ # routes
26
+ ActiveDecoratorTestApp::Application.routes.draw do
27
+ resources :authors, :only => [:index, :show] do
28
+ resources :books, :only => [:index, :show] do
29
+ member do
30
+ get :error
31
+ post :purchase
32
+ end
33
+ end
34
+ end
35
+ resources :movies, :only => :show
36
+ end
37
+
38
+ # models
39
+ class Author < ActiveRecord::Base
40
+ has_many :books
41
+ end
42
+ class Book < ActiveRecord::Base
43
+ belongs_to :author
44
+ end
45
+ class Movie < ActiveRecord::Base
46
+ end
47
+
48
+ # helpers
49
+ module ApplicationHelper; end
50
+
51
+ # decorators
52
+ module AuthorDecorator
53
+ def reverse_name
54
+ name.reverse
55
+ end
56
+
57
+ def capitalized_name
58
+ name.capitalize
59
+ end
60
+ end
61
+ module BookDecorator
62
+ def reverse_title
63
+ title.reverse
64
+ end
65
+
66
+ def upcased_title
67
+ title.upcase
68
+ end
69
+
70
+ def link
71
+ link_to title, "#{request.protocol}#{request.host_with_port}/assets/sample.png", :class => 'title'
72
+ end
73
+
74
+ def cover_image
75
+ image_tag 'cover.png'
76
+ end
77
+
78
+ def error
79
+ "ERROR"
80
+ end
81
+ end
82
+
83
+ # decorator fake
84
+ class MovieDecorator; end
85
+
86
+ # controllers
87
+ class ApplicationController < ActionController::Base
88
+ self.append_view_path File.dirname(__FILE__)
89
+ end
90
+ class AuthorsController < ApplicationController
91
+ def index
92
+ if Author.respond_to?(:scoped)
93
+ # ActiveRecord 3.x
94
+ if params[:variable_type] == 'array'
95
+ @authors = Author.all
96
+ elsif params[:variable_type] == 'proxy'
97
+ @authors = RelationProxy.new(Author.scoped)
98
+ else
99
+ @authors = Author.scoped
100
+ end
101
+ else
102
+ # ActiveRecord 4.x
103
+ if params[:variable_type] == 'array'
104
+ @authors = Author.all.to_a
105
+ elsif params[:variable_type] == 'proxy'
106
+ @authors = RelationProxy.new(Author.all)
107
+ else
108
+ @authors = Author.all
109
+ end
110
+ end
111
+ end
112
+
113
+ def show
114
+ @author = Author.find params[:id]
115
+ end
116
+ end
117
+ class BooksController < ApplicationController
118
+ class CustomError < StandardError; end
119
+
120
+ rescue_from CustomError do
121
+ render "error"
122
+ end
123
+
124
+ def index
125
+ @author = Author.find params[:author_id]
126
+ @books = @author.books
127
+ end
128
+
129
+ def show
130
+ @book = Author.find(params[:author_id]).books.find(params[:id])
131
+ end
132
+
133
+ def error
134
+ @book = Author.find(params[:author_id]).books.find(params[:id])
135
+ raise CustomError, "error"
136
+ end
137
+
138
+ def purchase
139
+ @book = Author.find(params[:author_id]).books.find(params[:id])
140
+
141
+ @view_context_before_sending_mail = ActiveDecorator::ViewContext.current
142
+ BookMailer.thanks(@book).deliver
143
+ raise 'Wrong ViewContext!' if ActiveDecorator::ViewContext.current != @view_context_before_sending_mail
144
+ end
145
+ end
146
+ class MoviesController < ApplicationController
147
+ def show
148
+ @movie = Movie.find params[:id]
149
+ end
150
+ end
151
+
152
+ # mailers
153
+ class BookMailer < ActionMailer::Base
154
+ def thanks(book)
155
+ @book = book
156
+ mail :from => 'nobody@example.com', :to => 'test@example.com', :subject => 'Thanks'
157
+ end
158
+ end
159
+
160
+ # migrations
161
+ class CreateAllTables < ActiveRecord::Migration
162
+ def self.up
163
+ create_table(:authors) {|t| t.string :name}
164
+ create_table(:books) {|t| t.string :title; t.references :author}
165
+ create_table(:movies) {|t| t.string :name}
166
+ end
167
+ end
168
+
169
+ # Proxy for ActiveRecord::Relation
170
+ if RUBY_VERSION >= '1.9.0'
171
+ class RelationProxy < BasicObject
172
+ attr_accessor :ar_relation
173
+
174
+ def initialize(ar_relation)
175
+ @ar_relation = ar_relation
176
+ end
177
+
178
+ def method_missing(method, *args, &block)
179
+ @ar_relation.public_send(method, *args, &block)
180
+ end
181
+ end
182
+ else
183
+ class RelationProxy < Object
184
+ attr_accessor :ar_relation
185
+
186
+ def initialize(ar_relation)
187
+ @ar_relation = ar_relation
188
+ end
189
+
190
+ def method_missing(method, *args, &block)
191
+ @ar_relation.send(method, *args, &block)
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,25 @@
1
+ feature 'fallback to helpers' do
2
+ background do
3
+ aamine = Author.create! :name => 'aamine'
4
+ @rhg = aamine.books.create! :title => 'RHG'
5
+ end
6
+
7
+ scenario 'invoking action_view helper methods' do
8
+ visit "/authors/#{@rhg.author.id}/books/#{@rhg.id}"
9
+ within 'a.title' do
10
+ page.should have_content 'RHG'
11
+ end
12
+ page.should have_css('img')
13
+ end
14
+
15
+ scenario 'invoking action_view helper methods in rescue_from view' do
16
+ visit "/authors/#{@rhg.author.id}/books/#{@rhg.id}/error"
17
+ page.should have_content('ERROR')
18
+ end
19
+
20
+ scenario 'make sure that action_view + action_mailer works' do
21
+ visit "/authors/#{@rhg.author.id}/books/#{@rhg.id}"
22
+ click_link 'purchase'
23
+ page.should have_content 'done'
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ feature 'decorating controller ivar' do
2
+ background do
3
+ @matz = Author.create! :name => 'matz'
4
+ @matz.books.create! :title => 'the world of code'
5
+ Author.create! :name => 'takahashim'
6
+ end
7
+
8
+ scenario 'decorating a model object in ivar' do
9
+ visit "/authors/#{@matz.id}"
10
+ page.should have_content 'matz'
11
+ page.should have_content 'matz'.capitalize
12
+ end
13
+
14
+ scenario 'decorating model scope in ivar' do
15
+ visit '/authors'
16
+ page.should have_content 'takahashim'
17
+ page.should have_content 'takahashim'.reverse
18
+ end
19
+
20
+ scenario "decorating models' array in ivar" do
21
+ visit '/authors?variable_type=array'
22
+ page.should have_content 'takahashim'
23
+ page.should have_content 'takahashim'.reverse
24
+ end
25
+
26
+ scenario "decorating models' proxy object in ivar" do
27
+ visit '/authors?variable_type=proxy'
28
+ page.should have_content 'takahashim'
29
+ page.should have_content 'takahashim'.reverse
30
+ end
31
+
32
+ scenario 'decorating model association proxy in ivar' do
33
+ visit "/authors/#{@matz.id}/books"
34
+ page.should have_content 'the world of code'
35
+ page.should have_content 'the world of code'.reverse
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ feature 'decorating partial object in Jbuilder' do
2
+ background do
3
+ Author.create! :name => 'aamine'
4
+ nari = Author.create! :name => 'nari'
5
+ nari.books.create! :title => 'the gc book'
6
+ end
7
+
8
+ scenario 'decorating objects in Jbuilder partials' do
9
+ visit "/authors/#{Author.last.id}.json"
10
+ page.source.should eq '{"name":"nari","books":[{"title":"the gc book","reverse_title":"koob cg eht"}]}'
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ feature 'decorating partial object' do
2
+ background do
3
+ Author.create! :name => 'aamine'
4
+ nari = Author.create! :name => 'nari'
5
+ nari.books.create! :title => 'the gc book'
6
+ end
7
+
8
+ scenario 'decorating implicit @object' do
9
+ visit '/authors'
10
+ page.should have_content 'the gc book'
11
+ page.should have_content 'the gc book'.reverse
12
+ end
13
+
14
+ scenario 'decorating implicit @collection' do
15
+ visit '/authors?partial=collection'
16
+ page.should have_content 'the gc book'
17
+ page.should have_content 'the gc book'.reverse
18
+ end
19
+
20
+ scenario 'decorating objects in @locals' do
21
+ visit '/authors?partial=locals'
22
+ page.should have_content 'the gc book'
23
+ page.should have_content 'the gc book'.upcase
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ # load Rails first
4
+ require 'rails'
5
+ require 'active_decorator'
6
+ # needs to load the app before loading rspec/rails => capybara
7
+ require 'fake_app/fake_app'
8
+ require 'rspec/rails'
9
+ # Requires supporting files with custom matchers and macros, etc,
10
+ # in ./support/ and its subdirectories.
11
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
12
+
13
+ RSpec.configure do |config|
14
+ config.expect_with :rspec do |c|
15
+ c.syntax = [:should, :expect]
16
+ end
17
+
18
+ config.before :all do
19
+ CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'authors'
20
+ end
21
+
22
+ config.before :each do
23
+ Book.delete_all
24
+ Author.delete_all
25
+ Movie.delete_all
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lulalala_presenter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - lulalala
8
+ - Akira Matsuda
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-11-14 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A simple and Rubyish view helper for Rails
15
+ email:
16
+ - mark@goodlife.tw
17
+ - ronnie@dio.jp
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ".gitignore"
23
+ - ".rspec"
24
+ - ".travis.yml"
25
+ - Gemfile
26
+ - MIT-LICENSE
27
+ - README.md
28
+ - Rakefile
29
+ - gemfiles/Gemfile-rails.3.0.x
30
+ - gemfiles/Gemfile-rails.3.1.x
31
+ - gemfiles/Gemfile-rails.3.2.x
32
+ - gemfiles/Gemfile-rails.4.0.x
33
+ - gemfiles/Gemfile-rails.4.1.x
34
+ - gemfiles/Gemfile-rails.4.2.x
35
+ - lib/active_decorator/config.rb
36
+ - lib/active_decorator/helpers.rb
37
+ - lib/active_decorator/monkey/action_controller/base/rescue_from.rb
38
+ - lib/active_decorator/view_context.rb
39
+ - lib/generators/rails/decorator_generator.rb
40
+ - lib/generators/rails/templates/decorator.rb
41
+ - lib/generators/rspec/decorator_generator.rb
42
+ - lib/generators/rspec/templates/decorator_spec.rb
43
+ - lib/generators/test_unit/decorator_generator.rb
44
+ - lib/generators/test_unit/templates/decorator_test.rb
45
+ - lib/lulalala_presenter.rb
46
+ - lib/lulalala_presenter/active_model_bridge.rb
47
+ - lib/lulalala_presenter/base.rb
48
+ - lib/lulalala_presenter/railtie.rb
49
+ - lib/lulalala_presenter/version.rb
50
+ - lulalala_presenter.gemspec
51
+ - spec/configuration_spec.rb
52
+ - spec/controllers/fake_detection_spec.rb
53
+ - spec/fake_app/app/views/authors/index.html.erb
54
+ - spec/fake_app/app/views/authors/show.html.erb
55
+ - spec/fake_app/app/views/authors/show.json.jbuilder
56
+ - spec/fake_app/app/views/book_mailer/thanks.text.erb
57
+ - spec/fake_app/app/views/books/_book.html.erb
58
+ - spec/fake_app/app/views/books/_book.json.jbuilder
59
+ - spec/fake_app/app/views/books/_book_locals.html.erb
60
+ - spec/fake_app/app/views/books/error.html.erb
61
+ - spec/fake_app/app/views/books/index.html.erb
62
+ - spec/fake_app/app/views/books/purchase.html.erb
63
+ - spec/fake_app/app/views/books/show.html.erb
64
+ - spec/fake_app/app/views/movies/show.html.erb
65
+ - spec/fake_app/fake_app.rb
66
+ - spec/features/action_view_helpers_spec.rb
67
+ - spec/features/controller_ivar_spec.rb
68
+ - spec/features/jbuilder_spec.rb
69
+ - spec/features/partial_spec.rb
70
+ - spec/spec_helper.rb
71
+ homepage: https://github.com/lulalala/lulalala_presenter
72
+ licenses: []
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.4.5
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: A simple and Rubyish view helper for Rails
94
+ test_files:
95
+ - spec/configuration_spec.rb
96
+ - spec/controllers/fake_detection_spec.rb
97
+ - spec/fake_app/app/views/authors/index.html.erb
98
+ - spec/fake_app/app/views/authors/show.html.erb
99
+ - spec/fake_app/app/views/authors/show.json.jbuilder
100
+ - spec/fake_app/app/views/book_mailer/thanks.text.erb
101
+ - spec/fake_app/app/views/books/_book.html.erb
102
+ - spec/fake_app/app/views/books/_book.json.jbuilder
103
+ - spec/fake_app/app/views/books/_book_locals.html.erb
104
+ - spec/fake_app/app/views/books/error.html.erb
105
+ - spec/fake_app/app/views/books/index.html.erb
106
+ - spec/fake_app/app/views/books/purchase.html.erb
107
+ - spec/fake_app/app/views/books/show.html.erb
108
+ - spec/fake_app/app/views/movies/show.html.erb
109
+ - spec/fake_app/fake_app.rb
110
+ - spec/features/action_view_helpers_spec.rb
111
+ - spec/features/controller_ivar_spec.rb
112
+ - spec/features/jbuilder_spec.rb
113
+ - spec/features/partial_spec.rb
114
+ - spec/spec_helper.rb