draper 1.0.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 (90) hide show
  1. data/CHANGELOG.md +3 -0
  2. data/CONTRIBUTING.md +5 -1
  3. data/Gemfile +23 -9
  4. data/README.md +144 -52
  5. data/Rakefile +1 -0
  6. data/draper.gemspec +1 -1
  7. data/lib/draper.rb +9 -6
  8. data/lib/draper/decoratable.rb +3 -7
  9. data/lib/draper/decoratable/equality.rb +14 -0
  10. data/lib/draper/decorator.rb +4 -7
  11. data/lib/draper/helper_proxy.rb +22 -3
  12. data/lib/draper/test/devise_helper.rb +18 -22
  13. data/lib/draper/test/rspec_integration.rb +4 -0
  14. data/lib/draper/test_case.rb +20 -0
  15. data/lib/draper/version.rb +1 -1
  16. data/lib/draper/view_context.rb +75 -13
  17. data/lib/draper/view_context/build_strategy.rb +48 -0
  18. data/lib/draper/view_helpers.rb +2 -2
  19. data/spec/draper/collection_decorator_spec.rb +169 -196
  20. data/spec/draper/decoratable/equality_spec.rb +10 -0
  21. data/spec/draper/decoratable_spec.rb +107 -132
  22. data/spec/draper/decorated_association_spec.rb +99 -96
  23. data/spec/draper/decorator_spec.rb +408 -434
  24. data/spec/draper/finders_spec.rb +160 -126
  25. data/spec/draper/helper_proxy_spec.rb +38 -8
  26. data/spec/draper/view_context/build_strategy_spec.rb +116 -0
  27. data/spec/draper/view_context_spec.rb +154 -0
  28. data/spec/draper/view_helpers_spec.rb +4 -37
  29. data/spec/dummy/app/controllers/posts_controller.rb +7 -0
  30. data/spec/dummy/app/decorators/post_decorator.rb +26 -2
  31. data/spec/dummy/app/helpers/application_helper.rb +3 -0
  32. data/spec/dummy/app/mailers/post_mailer.rb +10 -0
  33. data/spec/dummy/app/models/admin.rb +5 -0
  34. data/spec/dummy/app/models/mongoid_post.rb +5 -0
  35. data/spec/dummy/app/models/user.rb +5 -0
  36. data/spec/dummy/app/views/posts/_post.html.erb +15 -0
  37. data/spec/dummy/bin/rails +4 -0
  38. data/spec/dummy/config/application.rb +9 -3
  39. data/spec/dummy/config/boot.rb +2 -7
  40. data/spec/dummy/config/environments/development.rb +2 -3
  41. data/spec/dummy/config/environments/production.rb +2 -0
  42. data/spec/dummy/config/environments/test.rb +3 -4
  43. data/spec/dummy/config/initializers/secret_token.rb +1 -0
  44. data/spec/dummy/config/mongoid.yml +80 -0
  45. data/spec/dummy/config/routes.rb +2 -0
  46. data/spec/dummy/fast_spec/post_decorator_spec.rb +38 -0
  47. data/spec/dummy/lib/tasks/test.rake +11 -5
  48. data/spec/dummy/spec/decorators/devise_spec.rb +64 -0
  49. data/spec/dummy/spec/decorators/helpers_spec.rb +21 -0
  50. data/spec/dummy/spec/decorators/post_decorator_spec.rb +26 -6
  51. data/spec/dummy/spec/decorators/spec_type_spec.rb +7 -0
  52. data/spec/dummy/spec/decorators/view_context_spec.rb +22 -0
  53. data/spec/dummy/spec/mailers/post_mailer_spec.rb +10 -6
  54. data/spec/dummy/spec/models/mongoid_post_spec.rb +10 -0
  55. data/spec/dummy/spec/models/post_spec.rb +5 -5
  56. data/spec/dummy/spec/spec_helper.rb +1 -0
  57. data/spec/dummy/test/decorators/minitest/devise_test.rb +64 -0
  58. data/spec/dummy/test/decorators/minitest/helpers_test.rb +21 -0
  59. data/spec/dummy/{mini_test/mini_test_integration_test.rb → test/decorators/minitest/spec_type_test.rb} +9 -3
  60. data/spec/dummy/test/decorators/minitest/view_context_test.rb +24 -0
  61. data/spec/dummy/test/decorators/test_unit/devise_test.rb +64 -0
  62. data/spec/dummy/test/decorators/test_unit/helpers_test.rb +21 -0
  63. data/spec/dummy/test/decorators/test_unit/view_context_test.rb +24 -0
  64. data/spec/dummy/test/minitest_helper.rb +4 -0
  65. data/spec/dummy/test/test_helper.rb +3 -0
  66. data/spec/generators/decorator/decorator_generator_spec.rb +1 -0
  67. data/spec/integration/integration_spec.rb +31 -6
  68. data/spec/spec_helper.rb +32 -25
  69. data/spec/support/shared_examples/decoratable_equality.rb +40 -0
  70. data/spec/support/shared_examples/view_helpers.rb +39 -0
  71. metadata +56 -44
  72. data/spec/dummy/README.rdoc +0 -261
  73. data/spec/dummy/spec/decorators/rspec_integration_spec.rb +0 -19
  74. data/spec/support/action_controller.rb +0 -12
  75. data/spec/support/active_model.rb +0 -7
  76. data/spec/support/active_record.rb +0 -9
  77. data/spec/support/decorators/decorator_with_application_helper.rb +0 -25
  78. data/spec/support/decorators/namespaced_product_decorator.rb +0 -5
  79. data/spec/support/decorators/non_active_model_product_decorator.rb +0 -2
  80. data/spec/support/decorators/product_decorator.rb +0 -23
  81. data/spec/support/decorators/products_decorator.rb +0 -10
  82. data/spec/support/decorators/some_thing_decorator.rb +0 -2
  83. data/spec/support/decorators/specific_product_decorator.rb +0 -2
  84. data/spec/support/decorators/widget_decorator.rb +0 -2
  85. data/spec/support/models/namespaced_product.rb +0 -49
  86. data/spec/support/models/non_active_model_product.rb +0 -3
  87. data/spec/support/models/product.rb +0 -95
  88. data/spec/support/models/some_thing.rb +0 -5
  89. data/spec/support/models/uninferrable_decorator_model.rb +0 -3
  90. data/spec/support/models/widget.rb +0 -2
@@ -4,4 +4,6 @@ Dummy::Application.routes.draw do
4
4
  get "mail", on: :member
5
5
  end
6
6
  end
7
+
8
+ devise_for :users, :admins if defined?(Devise)
7
9
  end
@@ -0,0 +1,38 @@
1
+ require 'draper'
2
+ require 'rspec'
3
+
4
+ require 'active_model/naming'
5
+ require_relative '../app/decorators/post_decorator'
6
+
7
+ Draper::ViewContext.test_strategy :fast
8
+
9
+ Post = Struct.new(:id) { extend ActiveModel::Naming }
10
+
11
+ describe PostDecorator do
12
+ let(:decorator) { PostDecorator.new(source) }
13
+ let(:source) { Post.new(42) }
14
+
15
+ it "can use built-in helpers" do
16
+ expect(decorator.truncated).to eq "Once upon a..."
17
+ end
18
+
19
+ it "can use built-in private helpers" do
20
+ expect(decorator.html_escaped).to eq "<script>danger</script>"
21
+ end
22
+
23
+ it "can't use user-defined helpers from app/helpers" do
24
+ expect{decorator.hello_world}.to raise_error NoMethodError, /hello_world/
25
+ end
26
+
27
+ it "can't use path helpers" do
28
+ expect{decorator.path_with_model}.to raise_error NoMethodError, /post_path/
29
+ end
30
+
31
+ it "can't use url helpers" do
32
+ expect{decorator.url_with_model}.to raise_error NoMethodError, /post_url/
33
+ end
34
+
35
+ it "can't be passed implicitly to url_for" do
36
+ expect{decorator.link}.to raise_error
37
+ end
38
+ end
@@ -1,10 +1,16 @@
1
- require 'rspec/core/rake_task'
2
1
  require 'rake/testtask'
2
+ require 'rspec/core/rake_task'
3
+
4
+ Rake::Task[:test].clear
5
+ Rake::TestTask.new :test do |t|
6
+ t.libs << "test"
7
+ t.pattern = "test/**/*_test.rb"
8
+ end
3
9
 
4
- RSpec::Core::RakeTask.new :rspec
10
+ RSpec::Core::RakeTask.new :spec
5
11
 
6
- Rake::TestTask.new :mini_test do |t|
7
- t.test_files = ["mini_test/mini_test_integration_test.rb"]
12
+ RSpec::Core::RakeTask.new :fast_spec do |t|
13
+ t.pattern = "fast_spec/**/*_spec.rb"
8
14
  end
9
15
 
10
- task :default => [:rspec, :mini_test]
16
+ task :default => [:test, :spec, :fast_spec]
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ if defined?(Devise)
4
+ describe "A decorator spec" do
5
+ it "can sign in a real user" do
6
+ user = User.new
7
+ sign_in user
8
+
9
+ expect(helper.current_user).to be user
10
+ end
11
+
12
+ it "can sign in a mock user" do
13
+ user = double("User")
14
+ sign_in :user, user
15
+
16
+ expect(helper.current_user).to be user
17
+ end
18
+
19
+ it "can sign in a real admin" do
20
+ admin = Admin.new
21
+ sign_in admin
22
+
23
+ expect(helper.current_admin).to be admin
24
+ end
25
+
26
+ it "can sign in a mock admin" do
27
+ admin = double("Admin")
28
+ sign_in :admin, admin
29
+
30
+ expect(helper.current_admin).to be admin
31
+ end
32
+
33
+ it "can sign out a real user" do
34
+ user = User.new
35
+ sign_in user
36
+ sign_out user
37
+
38
+ expect(helper.current_user).to be_nil
39
+ end
40
+
41
+ it "can sign out a mock user" do
42
+ user = double("User")
43
+ sign_in :user, user
44
+ sign_out :user
45
+
46
+ expect(helper.current_user).to be_nil
47
+ end
48
+
49
+ it "can sign out without a user" do
50
+ sign_out :user
51
+
52
+ expect(helper.current_user).to be_nil
53
+ end
54
+
55
+ it "is backwards-compatible" do
56
+ user = double("User")
57
+ ActiveSupport::Deprecation.silence do
58
+ sign_in user
59
+ end
60
+
61
+ expect(helper.current_user).to be user
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe "A decorator spec" do
4
+ it "can access helpers through `helper`" do
5
+ expect(helper.content_tag(:p, "Help!")).to eq "<p>Help!</p>"
6
+ end
7
+
8
+ it "can access helpers through `helpers`" do
9
+ expect(helpers.content_tag(:p, "Help!")).to eq "<p>Help!</p>"
10
+ end
11
+
12
+ it "can access helpers through `h`" do
13
+ expect(h.content_tag(:p, "Help!")).to eq "<p>Help!</p>"
14
+ end
15
+
16
+ it "gets the same helper object as a decorator" do
17
+ decorator = Draper::Decorator.new(Object.new)
18
+
19
+ expect(helpers).to be decorator.helpers
20
+ end
21
+ end
@@ -1,26 +1,46 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe PostDecorator do
4
- subject { PostDecorator.new(source) }
4
+ let(:decorator) { PostDecorator.new(source) }
5
5
  let(:source) { Post.create }
6
6
 
7
+ it "can use built-in helpers" do
8
+ expect(decorator.truncated).to eq "Once upon a..."
9
+ end
10
+
11
+ it "can use built-in private helpers" do
12
+ expect(decorator.html_escaped).to eq "&lt;script&gt;danger&lt;/script&gt;"
13
+ end
14
+
15
+ it "can use user-defined helpers from app/helpers" do
16
+ expect(decorator.hello_world).to eq "Hello, world!"
17
+ end
18
+
7
19
  it "can use path helpers with its model" do
8
- subject.path_with_model.should == "/en/posts/#{source.id}"
20
+ expect(decorator.path_with_model).to eq "/en/posts/#{source.id}"
9
21
  end
10
22
 
11
23
  it "can use path helpers with its id" do
12
- subject.path_with_id.should == "/en/posts/#{source.id}"
24
+ expect(decorator.path_with_id).to eq "/en/posts/#{source.id}"
13
25
  end
14
26
 
15
27
  it "can use url helpers with its model" do
16
- subject.url_with_model.should == "http://www.example.com:12345/en/posts/#{source.id}"
28
+ expect(decorator.url_with_model).to eq "http://www.example.com:12345/en/posts/#{source.id}"
17
29
  end
18
30
 
19
31
  it "can use url helpers with its id" do
20
- subject.url_with_id.should == "http://www.example.com:12345/en/posts/#{source.id}"
32
+ expect(decorator.url_with_id).to eq "http://www.example.com:12345/en/posts/#{source.id}"
21
33
  end
22
34
 
23
35
  it "can be passed implicitly to url_for" do
24
- subject.link.should == "<a href=\"/en/posts/#{source.id}\">#{source.id}</a>"
36
+ expect(decorator.link).to eq "<a href=\"/en/posts/#{source.id}\">#{source.id}</a>"
37
+ end
38
+
39
+ it "serializes overriden attributes" do
40
+ expect(decorator.serializable_hash["updated_at"]).to be :overridden
41
+ end
42
+
43
+ it "uses a test view context from ApplicationController" do
44
+ expect(Draper::ViewContext.current.controller).to be_an ApplicationController
25
45
  end
26
46
  end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe "A spec in this folder" do
4
+ it "is a decorator spec" do
5
+ expect(example.metadata[:type]).to be :decorator
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ def it_does_not_leak_view_context
4
+ 2.times do
5
+ it "has an independent view context" do
6
+ expect(Draper::ViewContext.current).not_to be :leaked
7
+ Draper::ViewContext.current = :leaked
8
+ end
9
+ end
10
+ end
11
+
12
+ describe "A decorator spec", type: :decorator do
13
+ it_does_not_leak_view_context
14
+ end
15
+
16
+ describe "A controller spec", type: :controller do
17
+ it_does_not_leak_view_context
18
+ end
19
+
20
+ describe "A mailer spec", type: :mailer do
21
+ it_does_not_leak_view_context
22
+ end
@@ -2,28 +2,32 @@ require 'spec_helper'
2
2
 
3
3
  describe PostMailer do
4
4
  describe "#decorated_email" do
5
- subject { Capybara.string(email.body.to_s) }
5
+ let(:email_body) { Capybara.string(email.body.to_s) }
6
6
  let(:email) { PostMailer.decorated_email(post).deliver }
7
7
  let(:post) { Post.create }
8
8
 
9
9
  it "decorates" do
10
- subject.should have_content "Today"
10
+ expect(email_body).to have_content "Today"
11
11
  end
12
12
 
13
13
  it "can use path helpers with a model" do
14
- subject.should have_css "#path_with_model", text: "/en/posts/#{post.id}"
14
+ expect(email_body).to have_css "#path_with_model", text: "/en/posts/#{post.id}"
15
15
  end
16
16
 
17
17
  it "can use path helpers with an id" do
18
- subject.should have_css "#path_with_id", text: "/en/posts/#{post.id}"
18
+ expect(email_body).to have_css "#path_with_id", text: "/en/posts/#{post.id}"
19
19
  end
20
20
 
21
21
  it "can use url helpers with a model" do
22
- subject.should have_css "#url_with_model", text: "http://www.example.com:12345/en/posts/#{post.id}"
22
+ expect(email_body).to have_css "#url_with_model", text: "http://www.example.com:12345/en/posts/#{post.id}"
23
23
  end
24
24
 
25
25
  it "can use url helpers with an id" do
26
- subject.should have_css "#url_with_id", text: "http://www.example.com:12345/en/posts/#{post.id}"
26
+ expect(email_body).to have_css "#url_with_id", text: "http://www.example.com:12345/en/posts/#{post.id}"
27
+ end
28
+
29
+ it "uses the correct view context controller" do
30
+ expect(email_body).to have_css "#controller", text: "PostMailer"
27
31
  end
28
32
  end
29
33
  end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ if defined?(Mongoid)
4
+ describe MongoidPost do
5
+ it "is decoratable" do
6
+ expect(MongoidPost).to respond_to :decorator_class
7
+ expect(MongoidPost.new).to respond_to :decorate
8
+ end
9
+ end
10
+ end
@@ -2,13 +2,13 @@ require 'spec_helper'
2
2
 
3
3
  describe Post do
4
4
  describe "#==" do
5
- before { Post.create }
6
- subject { Post.first }
7
-
8
5
  it "is true for other instances' decorators" do
6
+ Post.create
7
+ one = Post.first
9
8
  other = Post.first
10
- subject.should_not be other
11
- (subject == other.decorate).should be_true
9
+
10
+ expect(one).not_to be other
11
+ expect(one == other.decorate).to be_true
12
12
  end
13
13
  end
14
14
  end
@@ -4,5 +4,6 @@ require 'rspec/rails'
4
4
 
5
5
  RSpec.configure do |config|
6
6
  config.treat_symbols_as_metadata_keys_with_true_values = true
7
+ config.expect_with(:rspec) {|c| c.syntax = :expect}
7
8
  config.order = :random
8
9
  end
@@ -0,0 +1,64 @@
1
+ require 'minitest_helper'
2
+
3
+ if defined?(Devise)
4
+ describe "A decorator test" do
5
+ it "can sign in a real user" do
6
+ user = User.new
7
+ sign_in user
8
+
9
+ assert_same user, helper.current_user
10
+ end
11
+
12
+ it "can sign in a mock user" do
13
+ user = Object.new
14
+ sign_in :user, user
15
+
16
+ assert_same user, helper.current_user
17
+ end
18
+
19
+ it "can sign in a real admin" do
20
+ admin = Admin.new
21
+ sign_in admin
22
+
23
+ assert_same admin, helper.current_admin
24
+ end
25
+
26
+ it "can sign in a mock admin" do
27
+ admin = Object.new
28
+ sign_in :admin, admin
29
+
30
+ assert_same admin, helper.current_admin
31
+ end
32
+
33
+ it "can sign out a real user" do
34
+ user = User.new
35
+ sign_in user
36
+ sign_out user
37
+
38
+ assert helper.current_user.nil?
39
+ end
40
+
41
+ it "can sign out a mock user" do
42
+ user = Object.new
43
+ sign_in :user, user
44
+ sign_out :user
45
+
46
+ assert helper.current_user.nil?
47
+ end
48
+
49
+ it "can sign out without a user" do
50
+ sign_out :user
51
+
52
+ assert helper.current_user.nil?
53
+ end
54
+
55
+ it "is backwards-compatible" do
56
+ user = Object.new
57
+ ActiveSupport::Deprecation.silence do
58
+ sign_in user
59
+ end
60
+
61
+ assert_same user, helper.current_user
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,21 @@
1
+ require 'minitest_helper'
2
+
3
+ describe "A decorator test" do
4
+ it "can access helpers through `helper`" do
5
+ assert_equal "<p>Help!</p>", helper.content_tag(:p, "Help!")
6
+ end
7
+
8
+ it "can access helpers through `helpers`" do
9
+ assert_equal "<p>Help!</p>", helpers.content_tag(:p, "Help!")
10
+ end
11
+
12
+ it "can access helpers through `h`" do
13
+ assert_equal "<p>Help!</p>", h.content_tag(:p, "Help!")
14
+ end
15
+
16
+ it "gets the same helper object as a decorator" do
17
+ decorator = Draper::Decorator.new(Object.new)
18
+
19
+ assert_same decorator.helpers, helpers
20
+ end
21
+ end
@@ -1,6 +1,4 @@
1
- require File.expand_path('../../config/environment', __FILE__)
2
- require 'minitest/autorun'
3
- require 'minitest/rails'
1
+ require 'minitest_helper'
4
2
 
5
3
  def it_is_a_decorator_test
6
4
  it "is a decorator test" do
@@ -33,6 +31,14 @@ describe "AnyDecorator" do
33
31
  it_is_a_decorator_test
34
32
  end
35
33
 
34
+ describe "Any decorator" do
35
+ it_is_a_decorator_test
36
+ end
37
+
38
+ describe "AnyDecoratorTest" do
39
+ it_is_a_decorator_test
40
+ end
41
+
36
42
  describe "Any decorator test" do
37
43
  it_is_a_decorator_test
38
44
  end
@@ -0,0 +1,24 @@
1
+ require 'minitest_helper'
2
+
3
+ def it_does_not_leak_view_context
4
+ 2.times do
5
+ it "has an independent view context" do
6
+ refute_equal :leaked, Draper::ViewContext.current
7
+ Draper::ViewContext.current = :leaked
8
+ end
9
+ end
10
+ end
11
+
12
+ describe "A decorator test" do
13
+ it_does_not_leak_view_context
14
+ end
15
+
16
+ describe "A controller test" do
17
+ tests Class.new(ActionController::Base)
18
+
19
+ it_does_not_leak_view_context
20
+ end
21
+
22
+ describe "A mailer test" do
23
+ it_does_not_leak_view_context
24
+ end