draper 2.1.0 → 3.0.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +16 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +24 -0
  4. data/.gitignore +3 -1
  5. data/.rubocop.yml +11 -0
  6. data/.travis.yml +3 -7
  7. data/CHANGELOG.md +26 -0
  8. data/Gemfile +4 -5
  9. data/Guardfile +5 -5
  10. data/README.md +61 -11
  11. data/Rakefile +1 -1
  12. data/draper.gemspec +12 -10
  13. data/lib/draper.rb +8 -3
  14. data/lib/draper/automatic_delegation.rb +5 -3
  15. data/lib/draper/collection_decorator.rb +1 -11
  16. data/lib/draper/compatibility/api_only.rb +23 -0
  17. data/lib/draper/configuration.rb +15 -0
  18. data/lib/draper/decoratable.rb +3 -4
  19. data/lib/draper/decorator.rb +4 -24
  20. data/lib/draper/finders.rb +0 -0
  21. data/lib/draper/helper_proxy.rb +1 -8
  22. data/lib/draper/railtie.rb +12 -21
  23. data/lib/draper/tasks/test.rake +2 -15
  24. data/lib/draper/test/devise_helper.rb +1 -8
  25. data/lib/draper/test/minitest_integration.rb +0 -0
  26. data/lib/draper/test/rspec_integration.rb +1 -5
  27. data/lib/draper/test_case.rb +4 -8
  28. data/lib/draper/undecorate.rb +8 -0
  29. data/lib/draper/version.rb +1 -1
  30. data/lib/draper/view_context.rb +3 -19
  31. data/lib/draper/view_context/build_strategy.rb +11 -2
  32. data/lib/generators/controller_override.rb +2 -2
  33. data/lib/generators/draper/install_generator.rb +14 -0
  34. data/lib/generators/draper/templates/application_decorator.rb +8 -0
  35. data/lib/generators/mini_test/decorator_generator.rb +1 -1
  36. data/lib/generators/rails/decorator_generator.rb +1 -8
  37. data/lib/generators/rspec/templates/decorator_spec.rb +2 -2
  38. data/spec/draper/collection_decorator_spec.rb +11 -26
  39. data/spec/draper/configuration_spec.rb +25 -0
  40. data/spec/draper/decoratable_spec.rb +29 -16
  41. data/spec/draper/decorated_association_spec.rb +9 -9
  42. data/spec/draper/decorates_assigned_spec.rb +6 -6
  43. data/spec/draper/decorator_spec.rb +112 -89
  44. data/spec/draper/draper_spec.rb +24 -0
  45. data/spec/draper/factory_spec.rb +26 -26
  46. data/spec/draper/finders_spec.rb +21 -21
  47. data/spec/draper/helper_proxy_spec.rb +3 -3
  48. data/spec/draper/lazy_helpers_spec.rb +2 -2
  49. data/spec/draper/undecorate_chain_spec.rb +20 -0
  50. data/spec/draper/view_context/build_strategy_spec.rb +26 -10
  51. data/spec/draper/view_context_spec.rb +49 -21
  52. data/spec/dummy/app/controllers/base_controller.rb +4 -0
  53. data/spec/dummy/app/controllers/posts_controller.rb +2 -2
  54. data/spec/dummy/app/decorators/post_decorator.rb +0 -0
  55. data/spec/dummy/app/views/posts/_post.html.erb +8 -6
  56. data/spec/dummy/config/boot.rb +1 -1
  57. data/spec/dummy/config/initializers/draper.rb +3 -0
  58. data/spec/dummy/config/mongoid.yml +104 -41
  59. data/spec/dummy/db/schema.rb +4 -4
  60. data/spec/dummy/fast_spec/post_decorator_spec.rb +1 -1
  61. data/spec/dummy/lib/tasks/test.rake +1 -1
  62. data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +4 -8
  63. data/spec/dummy/spec/decorators/devise_spec.rb +0 -9
  64. data/spec/dummy/spec/decorators/post_decorator_spec.rb +2 -4
  65. data/spec/dummy/spec/mailers/post_mailer_spec.rb +0 -8
  66. data/spec/dummy/spec/shared_examples/decoratable.rb +0 -2
  67. data/spec/dummy/test/decorators/minitest/devise_test.rb +0 -9
  68. data/spec/dummy/test/decorators/minitest/view_context_test.rb +3 -3
  69. data/spec/dummy/test/decorators/test_unit/devise_test.rb +0 -9
  70. data/spec/dummy/test/decorators/test_unit/view_context_test.rb +1 -1
  71. data/spec/generators/controller/controller_generator_spec.rb +3 -3
  72. data/spec/generators/decorator/decorator_generator_spec.rb +14 -12
  73. data/spec/generators/install/install_generator_spec.rb +19 -0
  74. data/spec/integration/integration_spec.rb +11 -8
  75. data/spec/performance/benchmark.rb +1 -1
  76. data/spec/spec_helper.rb +4 -4
  77. data/spec/support/matchers/have_text.rb +2 -2
  78. data/spec/support/shared_examples/view_helpers.rb +8 -8
  79. metadata +71 -29
  80. data/gemfiles/4.0.gemfile +0 -3
  81. data/gemfiles/4.1.gemfile +0 -3
  82. data/gemfiles/4.2.gemfile +0 -3
  83. data/spec/dummy/app/controllers/application_controller.rb +0 -4
@@ -7,7 +7,7 @@ module Draper
7
7
  let(:controller) { Class.new(base) { include ViewContext } }
8
8
 
9
9
  it "saves the superclass's view context" do
10
- ViewContext.should_receive(:current=).with(:controller_view_context)
10
+ expect(ViewContext).to receive(:current=).with(:controller_view_context)
11
11
  controller.new.view_context
12
12
  end
13
13
 
@@ -18,7 +18,7 @@ module Draper
18
18
 
19
19
  describe ".controller" do
20
20
  it "returns the stored controller from RequestStore" do
21
- RequestStore.stub store: {current_controller: :stored_controller}
21
+ allow(RequestStore).to receive_messages store: {current_controller: :stored_controller}
22
22
 
23
23
  expect(ViewContext.controller).to be :stored_controller
24
24
  end
@@ -27,34 +27,62 @@ module Draper
27
27
  describe ".controller=" do
28
28
  it "stores a controller in RequestStore" do
29
29
  store = {}
30
- RequestStore.stub store: store
30
+ allow(RequestStore).to receive_messages store: store
31
31
 
32
32
  ViewContext.controller = :stored_controller
33
33
  expect(store[:current_controller]).to be :stored_controller
34
34
  end
35
+
36
+ it "cleans context when controller changes" do
37
+ store = {
38
+ current_controller: :stored_controller,
39
+ current_view_context: :stored_view_context
40
+ }
41
+
42
+ allow(RequestStore).to receive_messages store: store
43
+
44
+ ViewContext.controller = :other_stored_controller
45
+
46
+ expect(store).to include(current_controller: :other_stored_controller)
47
+ expect(store).not_to include(:current_view_context)
48
+ end
49
+
50
+ it "doesn't clean context when controller is the same" do
51
+ store = {
52
+ current_controller: :stored_controller,
53
+ current_view_context: :stored_view_context
54
+ }
55
+
56
+ allow(RequestStore).to receive_messages store: store
57
+
58
+ ViewContext.controller = :stored_controller
59
+
60
+ expect(store).to include(current_controller: :stored_controller)
61
+ expect(store).to include(current_view_context: :stored_view_context)
62
+ end
35
63
  end
36
64
 
37
65
  describe ".current" do
38
66
  it "returns the stored view context from RequestStore" do
39
- RequestStore.stub store: {current_view_context: :stored_view_context}
67
+ allow(RequestStore).to receive_messages store: {current_view_context: :stored_view_context}
40
68
 
41
69
  expect(ViewContext.current).to be :stored_view_context
42
70
  end
43
71
 
44
72
  context "when no view context is stored" do
45
73
  it "builds a view context" do
46
- RequestStore.stub store: {}
47
- ViewContext.stub build_strategy: ->{ :new_view_context }
48
- HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
74
+ allow(RequestStore).to receive_messages store: {}
75
+ allow(ViewContext).to receive_messages build_strategy: ->{ :new_view_context }
76
+ allow(HelperProxy).to receive(:new).with(:new_view_context).and_return(:new_helper_proxy)
49
77
 
50
78
  expect(ViewContext.current).to be :new_helper_proxy
51
79
  end
52
80
 
53
81
  it "stores the built view context" do
54
82
  store = {}
55
- RequestStore.stub store: store
56
- ViewContext.stub build_strategy: ->{ :new_view_context }
57
- HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
83
+ allow(RequestStore).to receive_messages store: store
84
+ allow(ViewContext).to receive_messages build_strategy: ->{ :new_view_context }
85
+ allow(HelperProxy).to receive(:new).with(:new_view_context).and_return(:new_helper_proxy)
58
86
 
59
87
  ViewContext.current
60
88
  expect(store[:current_view_context]).to be :new_helper_proxy
@@ -65,8 +93,8 @@ module Draper
65
93
  describe ".current=" do
66
94
  it "stores a helper proxy for the view context in RequestStore" do
67
95
  store = {}
68
- RequestStore.stub store: store
69
- HelperProxy.stub(:new).with(:stored_view_context).and_return(:stored_helper_proxy)
96
+ allow(RequestStore).to receive_messages store: store
97
+ allow(HelperProxy).to receive(:new).with(:stored_view_context).and_return(:stored_helper_proxy)
70
98
 
71
99
  ViewContext.current = :stored_view_context
72
100
  expect(store[:current_view_context]).to be :stored_helper_proxy
@@ -76,7 +104,7 @@ module Draper
76
104
  describe ".clear!" do
77
105
  it "clears the stored controller and view controller" do
78
106
  store = {current_controller: :stored_controller, current_view_context: :stored_view_context}
79
- RequestStore.stub store: store
107
+ allow(RequestStore).to receive_messages store: store
80
108
 
81
109
  ViewContext.clear!
82
110
  expect(store).not_to have_key :current_controller
@@ -86,7 +114,7 @@ module Draper
86
114
 
87
115
  describe ".build" do
88
116
  it "returns a new view context using the build strategy" do
89
- ViewContext.stub build_strategy: ->{ :new_view_context }
117
+ allow(ViewContext).to receive_messages build_strategy: ->{ :new_view_context }
90
118
 
91
119
  expect(ViewContext.build).to be :new_view_context
92
120
  end
@@ -94,17 +122,17 @@ module Draper
94
122
 
95
123
  describe ".build!" do
96
124
  it "returns a helper proxy for the new view context" do
97
- ViewContext.stub build_strategy: ->{ :new_view_context }
98
- HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
125
+ allow(ViewContext).to receive_messages build_strategy: ->{ :new_view_context }
126
+ allow(HelperProxy).to receive(:new).with(:new_view_context).and_return(:new_helper_proxy)
99
127
 
100
128
  expect(ViewContext.build!).to be :new_helper_proxy
101
129
  end
102
130
 
103
131
  it "stores the helper proxy" do
104
132
  store = {}
105
- RequestStore.stub store: store
106
- ViewContext.stub build_strategy: ->{ :new_view_context }
107
- HelperProxy.stub(:new).with(:new_view_context).and_return(:new_helper_proxy)
133
+ allow(RequestStore).to receive_messages store: store
134
+ allow(ViewContext).to receive_messages build_strategy: ->{ :new_view_context }
135
+ allow(HelperProxy).to receive(:new).with(:new_view_context).and_return(:new_helper_proxy)
108
136
 
109
137
  ViewContext.build!
110
138
  expect(store[:current_view_context]).to be :new_helper_proxy
@@ -131,7 +159,7 @@ module Draper
131
159
  end
132
160
 
133
161
  it "passes a block to the strategy" do
134
- ViewContext::BuildStrategy::Fast.stub(:new) { |&block| block.call }
162
+ allow(ViewContext::BuildStrategy::Fast).to receive(:new) { |&block| block.call }
135
163
 
136
164
  expect(ViewContext.test_strategy(:fast){:passed}).to be :passed
137
165
  end
@@ -144,7 +172,7 @@ module Draper
144
172
  end
145
173
 
146
174
  it "passes a block to the strategy" do
147
- ViewContext::BuildStrategy::Full.stub(:new) { |&block| block.call }
175
+ allow(ViewContext::BuildStrategy::Full).to receive(:new) { |&block| block.call }
148
176
 
149
177
  expect(ViewContext.test_strategy(:full){:passed}).to be :passed
150
178
  end
@@ -0,0 +1,4 @@
1
+ class BaseController < ActionController::Base
2
+ include LocalizedUrls
3
+ protect_from_forgery
4
+ end
@@ -1,4 +1,4 @@
1
- class PostsController < ApplicationController
1
+ class PostsController < BaseController
2
2
  decorates_assigned :post
3
3
 
4
4
  def show
@@ -8,7 +8,7 @@ class PostsController < ApplicationController
8
8
  def mail
9
9
  post = Post.find(params[:id])
10
10
  email = PostMailer.decorated_email(post).deliver
11
- render text: email.body
11
+ render html: email.body.to_s.html_safe
12
12
  end
13
13
 
14
14
  private
File without changes
@@ -20,14 +20,16 @@
20
20
  <dt>Helpers from the controller:</dt>
21
21
  <dd id="goodnight_moon"><%= post.goodnight_moon %></dd>
22
22
 
23
- <dt>Path with decorator:</dt>
24
- <dd id="path_with_decorator"><%= post_path(post) %></dd>
23
+ <% unless defined? mailer %>
24
+ <dt>Path with decorator:</dt>
25
+ <dd id="path_with_decorator"><%= post_url(post) %></dd>
25
26
 
26
- <dt>Path with model:</dt>
27
- <dd id="path_with_model"><%= post.path_with_model %></dd>
27
+ <dt>Path with model:</dt>
28
+ <dd id="path_with_model"><%= post.path_with_model %></dd>
28
29
 
29
- <dt>Path with id:</dt>
30
- <dd id="path_with_id"><%= post.path_with_id %></dd>
30
+ <dt>Path with id:</dt>
31
+ <dd id="path_with_id"><%= post.path_with_id %></dd>
32
+ <% end %>
31
33
 
32
34
  <dt>URL with decorator:</dt>
33
35
  <dd id="url_with_decorator"><%= post_url(post) %></dd>
@@ -2,4 +2,4 @@ require 'rubygems'
2
2
 
3
3
  ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
4
4
 
5
- require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
5
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
@@ -0,0 +1,3 @@
1
+ Draper.configure do |config|
2
+ config.default_controller = BaseController
3
+ end
@@ -1,54 +1,117 @@
1
1
  development:
2
- # Configure available database sessions. (required)
3
- sessions:
4
- # Defines the default session. (required)
2
+ # Configure available database clients. (required)
3
+ clients:
4
+ # Defines the default client. (required)
5
5
  default:
6
6
  # Defines the name of the default database that Mongoid can connect to.
7
7
  # (required).
8
8
  database: dummy_development
9
- # Provides the hosts the default session can connect to. Must be an array
9
+ # Provides the hosts the default client can connect to. Must be an array
10
10
  # of host:port pairs. (required)
11
11
  hosts:
12
12
  - localhost:27017
13
13
  options:
14
- # Change whether the session persists in safe mode by default.
15
- # (default: false)
16
- # safe: false
17
-
18
- # Change the default consistency model to :eventual or :strong.
19
- # :eventual will send reads to secondaries, :strong sends everything
20
- # to master. (default: :eventual)
21
- # consistency: :eventual
22
-
23
- # How many times Moped should attempt to retry an operation after
24
- # failure. (default: 30)
25
- # max_retries: 30
26
-
27
- # The time in seconds that Moped should wait before retrying an
28
- # operation on failure. (default: 1)
29
- # retry_interval: 1
30
- # Configure Mongoid specific options. (optional)
31
- options:
32
- # Configuration for whether or not to allow access to fields that do
33
- # not have a field definition on the model. (default: true)
34
- # allow_dynamic_fields: true
14
+ # Change the default write concern. (default = { w: 1 })
15
+ # write:
16
+ # w: 1
17
+
18
+ # Change the default read preference. Valid options for mode are: :secondary,
19
+ # :secondary_preferred, :primary, :primary_preferred, :nearest
20
+ # (default: primary)
21
+ # read:
22
+ # mode: :secondary_preferred
23
+ # tag_sets:
24
+ # - use: web
25
+
26
+ # The name of the user for authentication.
27
+ # user: 'user'
28
+
29
+ # The password of the user for authentication.
30
+ # password: 'password'
31
+
32
+ # The user's database roles.
33
+ # roles:
34
+ # - 'dbOwner'
35
+
36
+ # Change the default authentication mechanism. Valid options are: :scram,
37
+ # :mongodb_cr, :mongodb_x509, and :plain. (default on 3.0 is :scram, default
38
+ # on 2.4 and 2.6 is :plain)
39
+ # auth_mech: :scram
40
+
41
+ # The database or source to authenticate the user against. (default: admin)
42
+ # auth_source: admin
43
+
44
+ # Force a the driver cluster to behave in a certain manner instead of auto-
45
+ # discovering. Can be one of: :direct, :replica_set, :sharded. Set to :direct
46
+ # when connecting to hidden members of a replica set.
47
+ # connect: :direct
48
+
49
+ # Changes the default time in seconds the server monitors refresh their status
50
+ # via ismaster commands. (default: 10)
51
+ # heartbeat_frequency: 10
52
+
53
+ # The time in seconds for selecting servers for a near read preference. (default: 5)
54
+ # local_threshold: 5
55
+
56
+ # The timeout in seconds for selecting a server for an operation. (default: 30)
57
+ # server_selection_timeout: 30
58
+
59
+ # The maximum number of connections in the connection pool. (default: 5)
60
+ # max_pool_size: 5
61
+
62
+ # The minimum number of connections in the connection pool. (default: 1)
63
+ # min_pool_size: 1
64
+
65
+ # The time to wait, in seconds, in the connection pool for a connection
66
+ # to be checked in before timing out. (default: 5)
67
+ # wait_queue_timeout: 5
35
68
 
36
- # Enable the identity map, needed for eager loading. (default: false)
37
- # identity_map_enabled: false
69
+ # The time to wait to establish a connection before timing out, in seconds.
70
+ # (default: 5)
71
+ # connect_timeout: 5
38
72
 
73
+ # The timeout to wait to execute operations on a socket before raising an error.
74
+ # (default: 5)
75
+ # socket_timeout: 5
76
+
77
+ # The name of the replica set to connect to. Servers provided as seeds that do
78
+ # not belong to this replica set will be ignored.
79
+ # replica_set: name
80
+
81
+ # Whether to connect to the servers via ssl. (default: false)
82
+ # ssl: true
83
+
84
+ # The certificate file used to identify the connection against MongoDB.
85
+ # ssl_cert: /path/to/my.cert
86
+
87
+ # The private keyfile used to identify the connection against MongoDB.
88
+ # Note that even if the key is stored in the same file as the certificate,
89
+ # both need to be explicitly specified.
90
+ # ssl_key: /path/to/my.key
91
+
92
+ # A passphrase for the private key.
93
+ # ssl_key_pass_phrase: password
94
+
95
+ # Whether or not to do peer certification validation. (default: true)
96
+ # ssl_verify: true
97
+
98
+ # The file containing a set of concatenated certification authority certifications
99
+ # used to validate certs passed from the other end of the connection.
100
+ # ssl_ca_cert: /path/to/ca.cert
101
+
102
+
103
+ # Configure Mongoid specific options. (optional)
104
+ options:
39
105
  # Includes the root model name in json serialization. (default: false)
40
106
  # include_root_in_json: false
41
107
 
42
- # Include the _type field in serializaion. (default: false)
108
+ # Include the _type field in serialization. (default: false)
43
109
  # include_type_for_serialization: false
44
110
 
45
111
  # Preload all models in development, needed when models use
46
112
  # inheritance. (default: false)
47
113
  # preload_models: false
48
114
 
49
- # Protect id and type from mass assignment. (default: true)
50
- # protect_sensitive_fields: true
51
-
52
115
  # Raise an error when performing a #find and the document is not found.
53
116
  # (default: true)
54
117
  # raise_not_found_error: true
@@ -57,23 +120,23 @@ development:
57
120
  # existing method. (default: false)
58
121
  # scope_overwrite_exception: false
59
122
 
60
- # Skip the database version check, used when connecting to a db without
61
- # admin access. (default: false)
62
- # skip_version_check: false
63
-
64
- # User Active Support's time zone in conversions. (default: true)
123
+ # Use Active Support's time zone in conversions. (default: true)
65
124
  # use_activesupport_time_zone: true
66
125
 
67
126
  # Ensure all times are UTC in the app side. (default: false)
68
127
  # use_utc: false
128
+
129
+ # Set the Mongoid and Ruby driver log levels when not in a Rails
130
+ # environment. The Mongoid logger will be set to the Rails logger
131
+ # otherwise.(default: :info)
132
+ # log_level: :info
69
133
  test:
70
- sessions:
134
+ clients:
71
135
  default:
72
136
  database: dummy_test
73
137
  hosts:
74
138
  - localhost:27017
75
139
  options:
76
- # In the test environment we lower the retries and retry interval to
77
- # low amounts for fast failures.
78
- max_retries: 1
79
- retry_interval: 0
140
+ read:
141
+ mode: :primary
142
+ max_pool_size: 1
@@ -11,11 +11,11 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20121019115657) do
14
+ ActiveRecord::Schema.define(version: 20121019115657) do
15
15
 
16
- create_table "posts", :force => true do |t|
17
- t.datetime "created_at", :null => false
18
- t.datetime "updated_at", :null => false
16
+ create_table "posts", force: true do |t|
17
+ t.datetime "created_at", null: false
18
+ t.datetime "updated_at", null: false
19
19
  end
20
20
 
21
21
  end
@@ -32,6 +32,6 @@ describe PostDecorator do
32
32
  end
33
33
 
34
34
  it "can't be passed implicitly to url_for" do
35
- expect{decorator.link}.to raise_error
35
+ expect{decorator.link}.to raise_error ArgumentError
36
36
  end
37
37
  end
@@ -13,4 +13,4 @@ RSpec::Core::RakeTask.new :fast_spec do |t|
13
13
  t.pattern = "fast_spec/**/*_spec.rb"
14
14
  end
15
15
 
16
- task :default => [:test, :spec, :fast_spec]
16
+ task default: [:test, :spec, :fast_spec]
@@ -2,15 +2,11 @@ require 'spec_helper'
2
2
 
3
3
  describe Draper::CollectionDecorator do
4
4
  describe "#active_model_serializer" do
5
- it "returns ActiveModel::ArraySerializer" do
6
- collection_decorator = Draper::CollectionDecorator.new([])
7
- if defined?(ActiveModel::ArraySerializerSupport)
8
- collection_serializer = collection_decorator.active_model_serializer
9
- else
10
- collection_serializer = ActiveModel::Serializer.serializer_for(collection_decorator)
11
- end
5
+ it "returns ActiveModel::Serializer::CollectionSerializer" do
6
+ collection_decorator = Draper::CollectionDecorator.new([])
7
+ collection_serializer = ActiveModel::Serializer.serializer_for(collection_decorator)
12
8
 
13
- expect(collection_serializer).to be ActiveModel::ArraySerializer
9
+ expect(collection_serializer).to be ActiveModel::Serializer::CollectionSerializer
14
10
  end
15
11
  end
16
12
  end