lulalala_presenter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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