draper 0.18.0 → 1.1.0

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 (155) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +11 -0
  3. data/.yardopts +1 -1
  4. data/CHANGELOG.md +164 -0
  5. data/CONTRIBUTING.md +15 -0
  6. data/Gemfile +34 -0
  7. data/LICENSE +7 -0
  8. data/README.md +416 -0
  9. data/Rakefile +53 -31
  10. data/draper.gemspec +11 -9
  11. data/lib/draper/automatic_delegation.rb +50 -0
  12. data/lib/draper/collection_decorator.rb +107 -0
  13. data/lib/draper/decoratable/equality.rb +14 -0
  14. data/lib/draper/decoratable.rb +79 -0
  15. data/lib/draper/decorated_association.rb +74 -0
  16. data/lib/draper/decorator.rb +235 -0
  17. data/lib/draper/delegation.rb +13 -0
  18. data/lib/draper/finders.rb +37 -0
  19. data/lib/draper/helper_proxy.rb +36 -0
  20. data/lib/draper/lazy_helpers.rb +10 -6
  21. data/lib/draper/railtie.rb +27 -21
  22. data/lib/draper/tasks/test.rake +22 -0
  23. data/lib/draper/test/devise_helper.rb +30 -0
  24. data/lib/draper/test/minitest_integration.rb +2 -3
  25. data/lib/draper/test/rspec_integration.rb +7 -13
  26. data/lib/draper/test_case.rb +53 -0
  27. data/lib/draper/version.rb +1 -1
  28. data/lib/draper/view_context/build_strategy.rb +48 -0
  29. data/lib/draper/view_context.rb +81 -24
  30. data/lib/draper/view_helpers.rb +37 -0
  31. data/lib/draper.rb +50 -8
  32. data/lib/generators/decorator/decorator_generator.rb +10 -2
  33. data/lib/generators/decorator/templates/decorator.rb +12 -27
  34. data/lib/generators/mini_test/decorator_generator.rb +20 -0
  35. data/lib/generators/mini_test/templates/decorator_spec.rb +4 -0
  36. data/lib/generators/mini_test/templates/decorator_test.rb +4 -0
  37. data/lib/generators/test_unit/templates/decorator_test.rb +1 -1
  38. data/spec/draper/collection_decorator_spec.rb +259 -0
  39. data/spec/draper/decoratable/equality_spec.rb +10 -0
  40. data/spec/draper/decoratable_spec.rb +167 -0
  41. data/spec/draper/decorated_association_spec.rb +145 -0
  42. data/spec/draper/decorator_spec.rb +598 -0
  43. data/spec/draper/finders_spec.rb +166 -0
  44. data/spec/draper/helper_proxy_spec.rb +42 -0
  45. data/spec/draper/view_context/build_strategy_spec.rb +116 -0
  46. data/spec/draper/view_context_spec.rb +154 -0
  47. data/spec/draper/view_helpers_spec.rb +8 -0
  48. data/spec/dummy/.rspec +2 -0
  49. data/spec/dummy/Rakefile +7 -0
  50. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  51. data/spec/dummy/app/controllers/localized_urls.rb +5 -0
  52. data/spec/dummy/app/controllers/posts_controller.rb +18 -0
  53. data/spec/dummy/app/decorators/post_decorator.rb +56 -0
  54. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  55. data/spec/dummy/app/mailers/application_mailer.rb +3 -0
  56. data/spec/dummy/app/mailers/post_mailer.rb +19 -0
  57. data/spec/dummy/app/models/admin.rb +5 -0
  58. data/spec/dummy/app/models/mongoid_post.rb +5 -0
  59. data/spec/dummy/app/models/post.rb +3 -0
  60. data/spec/dummy/app/models/user.rb +5 -0
  61. data/spec/dummy/app/views/layouts/application.html.erb +11 -0
  62. data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
  63. data/spec/dummy/app/views/posts/_post.html.erb +34 -0
  64. data/spec/dummy/app/views/posts/show.html.erb +1 -0
  65. data/spec/dummy/bin/rails +4 -0
  66. data/spec/dummy/config/application.rb +70 -0
  67. data/spec/dummy/config/boot.rb +5 -0
  68. data/spec/dummy/config/database.yml +25 -0
  69. data/spec/dummy/config/environment.rb +5 -0
  70. data/spec/dummy/config/environments/development.rb +33 -0
  71. data/spec/dummy/config/environments/production.rb +57 -0
  72. data/spec/dummy/config/environments/test.rb +31 -0
  73. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  74. data/spec/dummy/config/initializers/inflections.rb +15 -0
  75. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  76. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  77. data/spec/dummy/config/initializers/session_store.rb +8 -0
  78. data/spec/dummy/config/locales/en.yml +5 -0
  79. data/spec/dummy/config/mongoid.yml +80 -0
  80. data/spec/dummy/config/routes.rb +9 -0
  81. data/spec/dummy/config.ru +4 -0
  82. data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
  83. data/spec/dummy/db/schema.rb +21 -0
  84. data/spec/dummy/db/seeds.rb +2 -0
  85. data/spec/dummy/fast_spec/post_decorator_spec.rb +38 -0
  86. data/spec/dummy/lib/tasks/test.rake +16 -0
  87. data/spec/dummy/log/.gitkeep +0 -0
  88. data/spec/dummy/public/404.html +26 -0
  89. data/spec/dummy/public/422.html +26 -0
  90. data/spec/dummy/public/500.html +25 -0
  91. data/spec/dummy/public/favicon.ico +0 -0
  92. data/spec/dummy/script/rails +6 -0
  93. data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
  94. data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
  95. data/spec/dummy/spec/decorators/post_decorator_spec.rb +46 -0
  96. data/spec/dummy/spec/decorators/spec_type_spec.rb +7 -0
  97. data/spec/dummy/spec/decorators/view_context_spec.rb +22 -0
  98. data/spec/dummy/spec/mailers/post_mailer_spec.rb +33 -0
  99. data/spec/dummy/spec/models/mongoid_post_spec.rb +10 -0
  100. data/spec/dummy/spec/models/post_spec.rb +14 -0
  101. data/spec/dummy/spec/spec_helper.rb +9 -0
  102. data/spec/dummy/test/decorators/minitest/devise_test.rb +64 -0
  103. data/spec/dummy/test/decorators/minitest/helpers_test.rb +21 -0
  104. data/spec/dummy/test/decorators/minitest/spec_type_test.rb +52 -0
  105. data/spec/dummy/test/decorators/minitest/view_context_test.rb +24 -0
  106. data/spec/dummy/test/decorators/test_unit/devise_test.rb +64 -0
  107. data/spec/dummy/test/decorators/test_unit/helpers_test.rb +21 -0
  108. data/spec/dummy/test/decorators/test_unit/view_context_test.rb +24 -0
  109. data/spec/dummy/test/minitest_helper.rb +4 -0
  110. data/spec/dummy/test/test_helper.rb +3 -0
  111. data/spec/generators/decorator/decorator_generator_spec.rb +48 -7
  112. data/spec/integration/integration_spec.rb +58 -0
  113. data/{performance → spec/performance}/decorators.rb +2 -4
  114. data/spec/spec_helper.rb +25 -43
  115. data/spec/support/dummy_app.rb +85 -0
  116. data/spec/support/matchers/have_text.rb +50 -0
  117. data/spec/support/shared_examples/decoratable_equality.rb +40 -0
  118. data/spec/support/shared_examples/view_helpers.rb +39 -0
  119. metadata +253 -87
  120. data/CHANGELOG.markdown +0 -57
  121. data/Readme.markdown +0 -387
  122. data/lib/draper/active_model_support.rb +0 -27
  123. data/lib/draper/base.rb +0 -312
  124. data/lib/draper/decorated_enumerable_proxy.rb +0 -90
  125. data/lib/draper/model_support.rb +0 -25
  126. data/lib/draper/rspec_integration.rb +0 -2
  127. data/lib/draper/system.rb +0 -18
  128. data/spec/draper/base_spec.rb +0 -873
  129. data/spec/draper/decorated_enumerable_proxy_spec.rb +0 -45
  130. data/spec/draper/model_support_spec.rb +0 -48
  131. data/spec/minitest-rails/spec_type_spec.rb +0 -63
  132. data/spec/support/samples/active_record.rb +0 -17
  133. data/spec/support/samples/decorator.rb +0 -5
  134. data/spec/support/samples/decorator_with_allows.rb +0 -3
  135. data/spec/support/samples/decorator_with_application_helper.rb +0 -25
  136. data/spec/support/samples/decorator_with_denies.rb +0 -3
  137. data/spec/support/samples/decorator_with_denies_all.rb +0 -3
  138. data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
  139. data/spec/support/samples/decorator_with_special_methods.rb +0 -13
  140. data/spec/support/samples/enumerable_proxy.rb +0 -3
  141. data/spec/support/samples/namespaced_product.rb +0 -51
  142. data/spec/support/samples/namespaced_product_decorator.rb +0 -7
  143. data/spec/support/samples/non_active_model_product.rb +0 -2
  144. data/spec/support/samples/product.rb +0 -80
  145. data/spec/support/samples/product_decorator.rb +0 -7
  146. data/spec/support/samples/products_decorator.rb +0 -10
  147. data/spec/support/samples/sequel_product.rb +0 -13
  148. data/spec/support/samples/some_thing.rb +0 -2
  149. data/spec/support/samples/some_thing_decorator.rb +0 -3
  150. data/spec/support/samples/specific_product_decorator.rb +0 -4
  151. data/spec/support/samples/widget.rb +0 -2
  152. data/spec/support/samples/widget_decorator.rb +0 -2
  153. /data/{performance → spec/performance}/active_record.rb +0 -0
  154. /data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
  155. /data/{performance → spec/performance}/models.rb +0 -0
@@ -1,6 +1,5 @@
1
1
  require "./performance/models"
2
- class ProductDecorator < Draper::Base
3
- decorates :product
2
+ class ProductDecorator < Draper::Decorator
4
3
 
5
4
  def awesome_title
6
5
  "Awesome Title"
@@ -21,8 +20,7 @@ class ProductDecorator < Draper::Base
21
20
 
22
21
  end
23
22
 
24
- class FastProductDecorator < Draper::Base
25
- decorates :product
23
+ class FastProductDecorator < Draper::Decorator
26
24
 
27
25
  def awesome_title
28
26
  "Awesome Title"
data/spec/spec_helper.rb CHANGED
@@ -1,54 +1,36 @@
1
1
  require 'bundler/setup'
2
- require 'ammeter/init'
3
- require 'rails'
4
-
5
- require 'action_view'
6
- Bundler.require
7
-
8
- require './spec/support/samples/active_record'
9
- require './spec/support/samples/decorator'
10
- require './spec/support/samples/decorator_with_allows'
11
- require './spec/support/samples/decorator_with_multiple_allows'
12
- require './spec/support/samples/decorator_with_application_helper'
13
- require './spec/support/samples/decorator_with_denies'
14
- require './spec/support/samples/decorator_with_denies_all'
15
- require './spec/support/samples/decorator_with_special_methods'
16
- require './spec/support/samples/enumerable_proxy'
17
- require './spec/support/samples/namespaced_product'
18
- require './spec/support/samples/namespaced_product_decorator'
19
- require './spec/support/samples/non_active_model_product'
20
- require './spec/support/samples/product'
21
- require './spec/support/samples/product_decorator'
22
- require './spec/support/samples/products_decorator'
23
- require './spec/support/samples/sequel_product'
24
- require './spec/support/samples/specific_product_decorator'
25
- require './spec/support/samples/some_thing'
26
- require './spec/support/samples/some_thing_decorator'
27
- require './spec/support/samples/widget'
28
- require './spec/support/samples/widget_decorator'
29
-
2
+ require 'draper'
30
3
  require 'action_controller'
31
4
  require 'action_controller/test_case'
32
5
 
33
- module ActionController
34
- class Base
35
- Draper::System.setup_action_controller(self)
36
- end
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.expect_with(:rspec) {|c| c.syntax = :expect}
9
+ config.order = :random
37
10
  end
38
11
 
39
- module ActiveRecord
40
- class Relation
41
- end
42
- end
12
+ class Model; include Draper::Decoratable; end
13
+
14
+ class Product < Model; end
15
+ class ProductDecorator < Draper::Decorator; end
16
+ class ProductsDecorator < Draper::CollectionDecorator; end
17
+
18
+ class ProductPresenter < Draper::Decorator; end
43
19
 
44
- class ApplicationController < ActionController::Base
45
- def hello_world
46
- "Hello, World!"
47
- end
48
- helper_method :hello_world
20
+ class OtherDecorator < Draper::Decorator; end
21
+
22
+ module Namespaced
23
+ class Product < Model; end
24
+ class ProductDecorator < Draper::Decorator; end
25
+
26
+ class OtherDecorator < Draper::Decorator; end
49
27
  end
50
28
 
29
+ # After each example, revert changes made to the class
30
+ def protect_class(klass)
31
+ before { stub_const klass.name, Class.new(klass) }
32
+ end
51
33
 
52
- class << Rails
53
- undef application # Avoid silly Rails bug: https://github.com/rails/rails/pull/6429
34
+ def protect_module(mod)
35
+ before { stub_const mod.name, mod.dup }
54
36
  end
@@ -0,0 +1,85 @@
1
+ require 'socket'
2
+ require 'net/http'
3
+
4
+ # Adapted from code by Jon Leighton
5
+ # https://github.com/jonleighton/focused_controller/blob/ec7ccf1/test/acceptance/app_test.rb
6
+
7
+ class DummyApp
8
+
9
+ def initialize(environment)
10
+ raise ArgumentError, "Environment must be development or production" unless ["development", "production"].include?(environment.to_s)
11
+ @environment = environment
12
+ end
13
+
14
+ attr_reader :environment
15
+
16
+ def url
17
+ "http://#{localhost}:#{port}"
18
+ end
19
+
20
+ def get(path)
21
+ Net::HTTP.get(URI(url + path))
22
+ end
23
+
24
+ def within_app(&block)
25
+ Dir.chdir(root, &block)
26
+ end
27
+
28
+ def start_server
29
+ within_app do
30
+ IO.popen("bundle exec rails s -e #{@environment} -p #{port} 2>&1") do |out|
31
+ start = Time.now
32
+ started = false
33
+ output = ""
34
+ timeout = 60.0
35
+
36
+ while !started && !out.eof? && Time.now - start <= timeout
37
+ output << read_output(out)
38
+ sleep 0.1
39
+
40
+ begin
41
+ TCPSocket.new(localhost, port)
42
+ rescue Errno::ECONNREFUSED
43
+ else
44
+ started = true
45
+ end
46
+ end
47
+
48
+ raise "Server failed to start:\n#{output}" unless started
49
+
50
+ yield
51
+
52
+ Process.kill("KILL", out.pid)
53
+ File.delete("tmp/pids/server.pid")
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def root
61
+ File.expand_path("../../dummy", __FILE__)
62
+ end
63
+
64
+ def localhost
65
+ "127.0.0.1"
66
+ end
67
+
68
+ def port
69
+ @port ||= begin
70
+ server = TCPServer.new(localhost, 0)
71
+ server.addr[1]
72
+ ensure
73
+ server.close if server
74
+ end
75
+ end
76
+
77
+ def read_output(stream)
78
+ read = IO.select([stream], [], [stream], 0.1)
79
+ output = ""
80
+ loop { output << stream.read_nonblock(1024) } if read
81
+ output
82
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, EOFError
83
+ output
84
+ end
85
+ end
@@ -0,0 +1,50 @@
1
+ require 'capybara'
2
+
3
+ module HaveTextMatcher
4
+ def have_text(text)
5
+ HaveText.new(text)
6
+ end
7
+
8
+ class HaveText
9
+ def initialize(text)
10
+ @text = text
11
+ end
12
+
13
+ def in(css)
14
+ @css = css
15
+ self
16
+ end
17
+
18
+ def matches?(subject)
19
+ @subject = Capybara.string(subject)
20
+
21
+ @subject.has_css?(@css || "*", text: @text)
22
+ end
23
+
24
+ def failure_message_for_should
25
+ "expected to find #{@text.inspect} #{within}"
26
+ end
27
+
28
+ def failure_message_for_should_not
29
+ "expected not to find #{@text.inspect} #{within}"
30
+ end
31
+
32
+ private
33
+
34
+ def within
35
+ if @css && @subject.has_css?(@css)
36
+ "within\n#{@subject.find(@css).native}"
37
+ else
38
+ "#{inside} within\n#{@subject.native}"
39
+ end
40
+ end
41
+
42
+ def inside
43
+ @css ? "inside #{@css.inspect}" : "anywhere"
44
+ end
45
+ end
46
+ end
47
+
48
+ RSpec.configure do |config|
49
+ config.include HaveTextMatcher
50
+ end
@@ -0,0 +1,40 @@
1
+ shared_examples_for "decoration-aware #==" do |subject|
2
+ it "is true for itself" do
3
+ expect(subject == subject).to be_true
4
+ end
5
+
6
+ it "is false for another object" do
7
+ expect(subject == Object.new).to be_false
8
+ end
9
+
10
+ it "is true for a decorated version of itself" do
11
+ decorated = double(source: subject, decorated?: true)
12
+
13
+ expect(subject == decorated).to be_true
14
+ end
15
+
16
+ it "is false for a decorated other object" do
17
+ decorated = double(source: Object.new, decorated?: true)
18
+
19
+ expect(subject == decorated).to be_false
20
+ end
21
+
22
+ it "is false for a decoratable object with a `source` association" do
23
+ decoratable = double(source: subject, decorated?: false)
24
+
25
+ expect(subject == decoratable).to be_false
26
+ end
27
+
28
+ it "is false for an undecoratable object with a `source` association" do
29
+ undecoratable = double(source: subject)
30
+
31
+ expect(subject == undecoratable).to be_false
32
+ end
33
+
34
+ it "is true for a multiply-decorated version of itself" do
35
+ decorated = double(source: subject, decorated?: true)
36
+ redecorated = double(source: decorated, decorated?: true)
37
+
38
+ expect(subject == redecorated).to be_true
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ shared_examples_for "view helpers" do |subject|
2
+ describe "#helpers" do
3
+ it "returns the current view context" do
4
+ Draper::ViewContext.stub current: :current_view_context
5
+ expect(subject.helpers).to be :current_view_context
6
+ end
7
+
8
+ it "is aliased to #h" do
9
+ Draper::ViewContext.stub current: :current_view_context
10
+ expect(subject.h).to be :current_view_context
11
+ end
12
+ end
13
+
14
+ describe "#localize" do
15
+ it "delegates to #helpers" do
16
+ subject.stub helpers: double
17
+ subject.helpers.should_receive(:localize).with(:an_object, some: "parameter")
18
+ subject.localize(:an_object, some: "parameter")
19
+ end
20
+
21
+ it "is aliased to #l" do
22
+ subject.stub helpers: double
23
+ subject.helpers.should_receive(:localize).with(:an_object, some: "parameter")
24
+ subject.l(:an_object, some: "parameter")
25
+ end
26
+ end
27
+
28
+ describe ".helpers" do
29
+ it "returns the current view context" do
30
+ Draper::ViewContext.stub current: :current_view_context
31
+ expect(subject.class.helpers).to be :current_view_context
32
+ end
33
+
34
+ it "is aliased to .h" do
35
+ Draper::ViewContext.stub current: :current_view_context
36
+ expect(subject.class.h).to be :current_view_context
37
+ end
38
+ end
39
+ end