has_scope 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c24a5ed875375fb5da93be3f90ac863b0c72d676ecc1fe0959933924452b043d
4
- data.tar.gz: 2f8aacdef384ce75c7fc2e4b4b697ba62e68293deeac5754597d10dffc044052
3
+ metadata.gz: abf0ad461389302c6eef573bc313b2f0753a7dfaa02c23fdf685acce47be111c
4
+ data.tar.gz: 79209897cf738ba373be55f2b9fe4543d15880ae466c9a577e23cc1abb06ee3d
5
5
  SHA512:
6
- metadata.gz: 9541480b36218fb3c1b9b7c48a3297411c8875ec47bb1735b6b394127c02ad90010d79787931c0d0154d662b40f4c236627710ca7b2fa01edb7513f27e043fb9
7
- data.tar.gz: 5927fbd54e4a019b2d9f9fd7f7a60cf929fd46eac8f15c4c0e8cdb0cab2cac80a2b432e4398a70013d6bf88a519df60d2b6f571fb4f7f5db2d141292762b9eba
6
+ metadata.gz: 04a17d0ea9ee72e18ad98fa79c9d4e3a856219673fe066d1326df8b12af29a22f80282f0ec4cb8de9e25653d5f1179137fa4a8475d5fd8bf247ff12f3ab8c20e
7
+ data.tar.gz: 87978f08fed8aec6fe006b0d9faee4704b831a11b8b61b1c1211537965d4cd59a85784229d0e3260c49bd7f1313591ba48ac2feb0580417cb69ca1c60d435ad4
data/README.md CHANGED
@@ -1,10 +1,28 @@
1
1
  ## HasScope
2
2
 
3
3
  [![Gem Version](https://fury-badge.herokuapp.com/rb/has_scope.svg)](http://badge.fury.io/rb/has_scope)
4
- [![Code Climate](https://codeclimate.com/github/heartcombo/has_scope.svg)](https://codeclimate.com/github/heartcombo/has_scope)
5
4
 
6
- Has scope allows you to map incoming controller parameters to named scopes in your resources.
7
- Imagine the following model called graduations:
5
+ _HasScope_ allows you to dynamically apply named scopes to your resources based on an incoming set of parameters.
6
+
7
+ The most common usage is to map incoming controller parameters to named scopes for filtering resources, but it can be used anywhere.
8
+
9
+ ## Installation
10
+
11
+ Add `has_scope` to your bundle
12
+
13
+ ```ruby
14
+ bundle add has_scope
15
+ ```
16
+
17
+ or add it manually to your Gemfile if you prefer.
18
+
19
+ ```ruby
20
+ gem 'has_scope'
21
+ ```
22
+
23
+ ## Examples
24
+
25
+ For the following examples we'll use a model called graduations:
8
26
 
9
27
  ```ruby
10
28
  class Graduation < ActiveRecord::Base
@@ -14,16 +32,19 @@ class Graduation < ActiveRecord::Base
14
32
  end
15
33
  ```
16
34
 
17
- You can use those named scopes as filters by declaring them on your controller:
35
+ ### Usage 1: Rails Controllers
36
+
37
+ _HasScope_ exposes the `has_scope` method automatically in all your controllers. This is used to declare the scopes a controller action can use to filter a resource:
18
38
 
19
39
  ```ruby
20
40
  class GraduationsController < ApplicationController
21
41
  has_scope :featured, type: :boolean
22
42
  has_scope :by_degree
43
+ has_scope :by_period, using: %i[started_at ended_at], type: :hash
23
44
  end
24
45
  ```
25
46
 
26
- Now, if you want to apply them to an specific resource, you just need to call `apply_scopes`:
47
+ To apply the scopes to a specific resource, you just need to call `apply_scopes`:
27
48
 
28
49
  ```ruby
29
50
  class GraduationsController < ApplicationController
@@ -37,36 +58,128 @@ class GraduationsController < ApplicationController
37
58
  end
38
59
  ```
39
60
 
40
- Then for each request:
61
+ Then for each request to the `index` action, _HasScope_ will automatically apply the scopes as follows:
41
62
 
42
- ```
43
- /graduations
44
- #=> acts like a normal request
63
+ ``` ruby
64
+ # GET /graduations
65
+ # No scopes applied
66
+ #=> brings all graduations
67
+ apply_scopes(Graduation).all == Graduation.all
45
68
 
46
- /graduations?featured=true
47
- #=> calls the named scope and bring featured graduations
69
+ # GET /graduations?featured=true
70
+ # The "featured' scope is applied
71
+ #=> brings featured graduations
72
+ apply_scopes(Graduation).all == Graduation.featured
48
73
 
49
- /graduations?by_period[started_at]=20100701&by_period[ended_at]=20101013
74
+ # GET /graduations?by_period[started_at]=20100701&by_period[ended_at]=20101013
50
75
  #=> brings graduations in the given period
76
+ apply_scopes(Graduation).all == Graduation.by_period('20100701', '20101013')
51
77
 
52
- /graduations?featured=true&by_degree=phd
78
+ # GET /graduations?featured=true&by_degree=phd
53
79
  #=> brings featured graduations with phd degree
80
+ apply_scopes(Graduation).all == Graduation.featured.by_degree('phd')
81
+
82
+ # GET /graduations?finished=true&by_degree=phd
83
+ #=> brings only graduations with phd degree because we didn't declare finished in our controller as a permitted scope
84
+ apply_scopes(Graduation).all == Graduation.by_degree('phd')
54
85
  ```
55
86
 
56
- You can retrieve all the scopes applied in one action with `current_scopes` method.
57
- In the last case, it would return: `{ featured: true, by_degree: 'phd' }`.
87
+ #### Check for currently applied scopes
58
88
 
59
- ## Installation
89
+ _HasScope_ creates a helper method called `current_scopes` to retrieve all the scopes applied. As it's a helper method, you'll be able to access it in the controller action or the view rendered in that action.
60
90
 
61
- Add `has_scope` to your Gemfile or install it from Rubygems.
91
+ Coming back to one of the examples above:
62
92
 
63
93
  ```ruby
64
- gem 'has_scope'
94
+ # GET /graduations?featured=true&by_degree=phd
95
+ #=> brings featured graduations with phd degree
96
+ apply_scopes(Graduation).all == Graduation.featured.by_degree('phd')
97
+ ```
98
+
99
+ Calling `current_scopes` after `apply_scopes` in the controller action or view would return the following:
100
+
101
+ ```
102
+ current_scopes
103
+ #=> { featured: true, by_degree: 'phd' }
104
+ ```
105
+
106
+ ### Usage 2: Standalone Mode
107
+
108
+ _HasScope_ can also be used in plain old Ruby objects (PORO). To implement the previous example using this approach, create a bare object and include `HasScope` to get access to its features:
109
+
110
+ > Note: We'll create a simple version of a query object for this example as this type of object can have multiple different implementations.
111
+
112
+
113
+ ```ruby
114
+ class GraduationsSearchQuery
115
+ include HasScope
116
+ # ...
117
+ end
118
+ ```
119
+
120
+ Next, declare the scopes to be used the same way:
121
+
122
+ ```ruby
123
+ class GraduationsSearchQuery
124
+ include HasScope
125
+
126
+ has_scope :featured, type: :boolean
127
+ has_scope :by_degree
128
+ has_scope :by_period, using: %i[started_at ended_at], type: :hash
129
+ # ...
130
+ end
131
+ ```
132
+
133
+ Now, allow your object to perform the query by exposing a method that will use `apply_scopes`:
134
+
135
+ ```ruby
136
+ class GraduationsSearchQuery
137
+ include HasScope
138
+
139
+ has_scope :featured, type: :boolean
140
+ has_scope :by_degree
141
+ has_scope :by_period, using: %i[started_at ended_at], type: :hash
142
+
143
+ def perform(collection: Graduation, params: {})
144
+ apply_scopes(collection, params)
145
+ end
146
+ end
147
+ ```
148
+
149
+ Note that `apply_scopes` receives a `Hash` as a second argument, which represents the incoming params that determine which scopes should be applied to the model/collection. It defaults to `params` for compatibility with controllers, which is why it's not necessary to pass that second argument in the controller context.
150
+
151
+ Now in your controller you can call the `GraduationsSearchQuery` with the incoming parameters from the controller:
152
+
153
+ ```ruby
154
+ class GraduationsController < ApplicationController
155
+ def index
156
+ graduations_query = GraduationsSearchQuery.new
157
+ @graduations = graduations_query.perform(collection: Graduation, params: params)
158
+ end
159
+ end
160
+ ```
161
+
162
+ #### Accessing `current_scopes`
163
+
164
+ In the controller context, `current_scopes` is made available as a helper method to the controller and view, but it's a `protected` method of _HasScope_'s implementation, to prevent it from becoming publicly accessible outside of _HasScope_ itself. This means that the object implementation showed above has access to `current_scopes` internally, but it's not exposed to other objects that interact with it.
165
+
166
+ If you need to access `current_scopes` elsewhere, you can change the method visibility like so:
167
+
168
+ ```ruby
169
+ class GraduationsSearchQuery
170
+ include HasScope
171
+
172
+ # ...
173
+
174
+ public :current_scopes
175
+
176
+ # ...
177
+ end
65
178
  ```
66
179
 
67
180
  ## Options
68
181
 
69
- HasScope supports several options:
182
+ `has_scope` supports several options:
70
183
 
71
184
  * `:type` - Checks the type of the parameter sent.
72
185
  By default, it does not allow hashes or arrays to be given,
@@ -116,9 +229,12 @@ the param value must be set to one of the "true" values above, e.g. `?active=tru
116
229
 
117
230
  ## Block usage
118
231
 
119
- `has_scope` also accepts a block. The controller, current scope and value are yielded
120
- to the block so the user can apply the scope on its own. This is useful in case we
121
- need to manipulate the given value:
232
+ `has_scope` also accepts a block in case we need to manipulate the given value and/or call the scope in some custom way. Usually three arguments are passed to the block:
233
+ - The instance of the controller or object where it's included
234
+ - The current scope chain
235
+ - The value of the scope to apply
236
+
237
+ > 💡 We suggest you name the first argument depending on how you're using _HasScope_. If it's the controller, use the word "controller". If it's a query object for example, use "query", or something meaningful for that context (or simply use "context"). In the following examples, we'll use controller for simplicity.
122
238
 
123
239
  ```ruby
124
240
  has_scope :category do |controller, scope, value|
@@ -1,3 +1,3 @@
1
1
  module HasScope
2
- VERSION = "0.8.0"
2
+ VERSION = "0.8.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has_scope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - José Valim
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-15 00:00:00.000000000 Z
11
+ date: 2023-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -77,12 +77,14 @@ files:
77
77
  - README.md
78
78
  - lib/has_scope.rb
79
79
  - lib/has_scope/version.rb
80
- - test/has_scope_test.rb
81
- - test/test_helper.rb
82
80
  homepage: http://github.com/plataformatec/has_scope
83
81
  licenses:
84
82
  - MIT
85
- metadata: {}
83
+ metadata:
84
+ homepage_uri: https://github.com/heartcombo/has_scope
85
+ changelog_uri: https://github.com/heartcombo/has_scope/blob/main/CHANGELOG.md
86
+ source_code_uri: https://github.com/heartcombo/has_scope
87
+ bug_tracker_uri: https://github.com/heartcombo/has_scope/issues
86
88
  post_install_message:
87
89
  rdoc_options:
88
90
  - "--charset=UTF-8"
@@ -99,10 +101,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
101
  - !ruby/object:Gem::Version
100
102
  version: '0'
101
103
  requirements: []
102
- rubygems_version: 3.2.6
104
+ rubygems_version: 3.4.5
103
105
  signing_key:
104
106
  specification_version: 4
105
107
  summary: Maps controller filters to your resource scopes.
106
- test_files:
107
- - test/test_helper.rb
108
- - test/has_scope_test.rb
108
+ test_files: []
@@ -1,507 +0,0 @@
1
- require 'test_helper'
2
-
3
- HasScope::ALLOWED_TYPES[:date] = [[String], -> v { Date.parse(v) rescue nil }]
4
-
5
- class Tree; end
6
-
7
- class TreesController < ApplicationController
8
- has_scope :color, unless: :show_all_colors?
9
- has_scope :only_tall, type: :boolean, only: :index, if: :restrict_to_only_tall_trees?
10
- has_scope :shadown_range, default: 10, except: [ :index, :show, :new ]
11
- has_scope :root_type, as: :root, allow_blank: true
12
- has_scope :planted_before, default: proc { Date.today }
13
- has_scope :planted_after, type: :date
14
- has_scope :calculate_height, default: proc { |c| c.session[:height] || 20 }, only: :new
15
- has_scope :paginate, type: :hash
16
- has_scope :paginate_blank, type: :hash, allow_blank: true
17
- has_scope :paginate_default, type: :hash, default: { page: 1, per_page: 10 }, only: :edit
18
- has_scope :args_paginate, type: :hash, using: [:page, :per_page]
19
- has_scope :args_paginate_blank, using: [:page, :per_page], allow_blank: true
20
- has_scope :args_paginate_default, using: [:page, :per_page], default: { page: 1, per_page: 10 }, only: :edit
21
- has_scope :categories, type: :array
22
- has_scope :title, in: :q
23
- has_scope :content, in: :q
24
- has_scope :metadata, in: :q
25
- has_scope :metadata_blank, in: :q, allow_blank: true
26
- has_scope :metadata_default, in: :q, default: "default", only: :edit
27
- has_scope :conifer, type: :boolean, allow_blank: true
28
- has_scope :eval_plant, if: "params[:eval_plant].present?", unless: "params[:skip_eval_plant].present?"
29
- has_scope :proc_plant, if: -> c { c.params[:proc_plant].present? }, unless: -> c { c.params[:skip_proc_plant].present? }
30
-
31
- has_scope :only_short, type: :boolean do |controller, scope|
32
- scope.only_really_short!(controller.object_id)
33
- end
34
-
35
- has_scope :by_category do |controller, scope, value|
36
- scope.by_given_category(controller.object_id, value + "_id")
37
- end
38
-
39
- def index
40
- @trees = apply_scopes(Tree).all
41
- end
42
-
43
- def new
44
- @tree = apply_scopes(Tree).new
45
- end
46
-
47
- def show
48
- @tree = apply_scopes(Tree).find(params[:id])
49
- end
50
-
51
- alias :edit :show
52
-
53
- protected
54
- # Silence deprecations in the test suite, except for the actual deprecated String if/unless options.
55
- # TODO: remove with the deprecation.
56
- def apply_scopes(*)
57
- if params[:eval_plant]
58
- super
59
- else
60
- ActiveSupport::Deprecation.silence { super }
61
- end
62
- end
63
-
64
- def restrict_to_only_tall_trees?
65
- true
66
- end
67
-
68
- def show_all_colors?
69
- false
70
- end
71
-
72
- def default_render
73
- render body: action_name
74
- end
75
- end
76
-
77
- class BonsaisController < TreesController
78
- has_scope :categories, if: :categories?
79
-
80
- protected
81
- def categories?
82
- false
83
- end
84
- end
85
-
86
- class HasScopeTest < ActionController::TestCase
87
- tests TreesController
88
-
89
- def test_boolean_scope_is_called_when_boolean_param_is_true
90
- Tree.expects(:only_tall).with().returns(Tree).in_sequence
91
- Tree.expects(:all).returns([mock_tree]).in_sequence
92
-
93
- get :index, params: { only_tall: 'true' }
94
-
95
- assert_equal([mock_tree], assigns(:@trees))
96
- assert_equal({ only_tall: true }, current_scopes)
97
- end
98
-
99
- def test_boolean_scope_is_not_called_when_boolean_param_is_false
100
- Tree.expects(:only_tall).never
101
- Tree.expects(:all).returns([mock_tree])
102
-
103
- get :index, params: { only_tall: 'false' }
104
-
105
- assert_equal([mock_tree], assigns(:@trees))
106
- assert_equal({ }, current_scopes)
107
- end
108
-
109
- def test_boolean_scope_with_allow_blank_is_called_when_boolean_param_is_true
110
- Tree.expects(:conifer).with(true).returns(Tree).in_sequence
111
- Tree.expects(:all).returns([mock_tree]).in_sequence
112
-
113
- get :index, params: { conifer: 'true' }
114
-
115
- assert_equal([mock_tree], assigns(:@trees))
116
- assert_equal({ conifer: true }, current_scopes)
117
- end
118
-
119
- def test_boolean_scope_with_allow_blank_is_called_when_boolean_param_is_false
120
- Tree.expects(:conifer).with(false).returns(Tree).in_sequence
121
- Tree.expects(:all).returns([mock_tree]).in_sequence
122
-
123
- get :index, params: { conifer: 'not_true' }
124
-
125
- assert_equal([mock_tree], assigns(:@trees))
126
- assert_equal({ conifer: false }, current_scopes)
127
- end
128
-
129
- def test_boolean_scope_with_allow_blank_is_not_called_when_boolean_param_is_not_present
130
- Tree.expects(:conifer).never
131
- Tree.expects(:all).returns([mock_tree])
132
-
133
- get :index
134
-
135
- assert_equal([mock_tree], assigns(:@trees))
136
- assert_equal({ }, current_scopes)
137
- end
138
-
139
- def test_scope_is_called_only_on_index
140
- Tree.expects(:only_tall).never
141
- Tree.expects(:find).with('42').returns(mock_tree)
142
-
143
- get :show, params: { only_tall: 'true', id: '42' }
144
-
145
- assert_equal(mock_tree, assigns(:@tree))
146
- assert_equal({ }, current_scopes)
147
- end
148
-
149
- def test_scope_is_skipped_when_if_option_is_false
150
- @controller.stubs(:restrict_to_only_tall_trees?).returns(false)
151
- Tree.expects(:only_tall).never
152
- Tree.expects(:all).returns([mock_tree])
153
-
154
- get :index, params: { only_tall: 'true' }
155
-
156
- assert_equal([mock_tree], assigns(:@trees))
157
- assert_equal({ }, current_scopes)
158
- end
159
-
160
- def test_scope_is_skipped_when_unless_option_is_true
161
- @controller.stubs(:show_all_colors?).returns(true)
162
- Tree.expects(:color).never
163
- Tree.expects(:all).returns([mock_tree])
164
-
165
- get :index, params: { color: 'blue' }
166
-
167
- assert_equal([mock_tree], assigns(:@trees))
168
- assert_equal({ }, current_scopes)
169
- end
170
-
171
- def test_scope_with_eval_string_if_and_unless_options_is_deprecated
172
- Tree.expects(:eval_plant).with('value').returns(Tree)
173
- Tree.expects(:all).returns([mock_tree])
174
-
175
- assert_deprecated(/Passing a string to determine if the scope should be applied is deprecated/) do
176
- get :index, params: { eval_plant: 'value', skip_eval_plant: nil }
177
- end
178
-
179
- assert_equal([mock_tree], assigns(:@trees))
180
- assert_equal({ eval_plant: 'value' }, current_scopes)
181
- end
182
-
183
- def test_scope_with_proc_if_and_unless_options
184
- Tree.expects(:proc_plant).with('value').returns(Tree)
185
- Tree.expects(:all).returns([mock_tree])
186
-
187
- get :index, params: { proc_plant: 'value', skip_proc_plant: nil }
188
-
189
- assert_equal([mock_tree], assigns(:@trees))
190
- assert_equal({ proc_plant: 'value' }, current_scopes)
191
- end
192
-
193
- def test_scope_is_called_except_on_index
194
- Tree.expects(:shadown_range).never
195
- Tree.expects(:all).returns([mock_tree])
196
-
197
- get :index, params: { shadown_range: 20 }
198
-
199
- assert_equal([mock_tree], assigns(:@trees))
200
- assert_equal({ }, current_scopes)
201
- end
202
-
203
- def test_scope_is_called_with_arguments
204
- Tree.expects(:color).with('blue').returns(Tree).in_sequence
205
- Tree.expects(:all).returns([mock_tree]).in_sequence
206
-
207
- get :index, params: { color: 'blue' }
208
-
209
- assert_equal([mock_tree], assigns(:@trees))
210
- assert_equal({ color: 'blue' }, current_scopes)
211
- end
212
-
213
- def test_scope_is_not_called_if_blank
214
- Tree.expects(:color).never
215
- Tree.expects(:all).returns([mock_tree]).in_sequence
216
-
217
- get :index, params: { color: '' }
218
-
219
- assert_equal([mock_tree], assigns(:@trees))
220
- assert_equal({ }, current_scopes)
221
- end
222
-
223
- def test_scope_is_called_when_blank_if_allow_blank_is_given
224
- Tree.expects(:root_type).with('').returns(Tree)
225
- Tree.expects(:all).returns([mock_tree]).in_sequence
226
-
227
- get :index, params: { root: '' }
228
-
229
- assert_equal([mock_tree], assigns(:@trees))
230
- assert_equal({ root: '' }, current_scopes)
231
- end
232
-
233
- def test_multiple_scopes_are_called
234
- Tree.expects(:only_tall).with().returns(Tree)
235
- Tree.expects(:color).with('blue').returns(Tree)
236
- Tree.expects(:all).returns([mock_tree])
237
-
238
- get :index, params: { color: 'blue', only_tall: 'true' }
239
-
240
- assert_equal([mock_tree], assigns(:@trees))
241
- assert_equal({ color: 'blue', only_tall: true }, current_scopes)
242
- end
243
-
244
- def test_scope_of_type_hash
245
- hash = { "page" => "1", "per_page" => "10" }
246
- Tree.expects(:paginate).with(hash).returns(Tree)
247
- Tree.expects(:all).returns([mock_tree])
248
-
249
- get :index, params: { paginate: hash }
250
-
251
- assert_equal([mock_tree], assigns(:@trees))
252
- assert_equal({ paginate: hash }, current_scopes)
253
- end
254
-
255
- def test_scope_of_type_hash_with_using
256
- hash = { "page" => "1", "per_page" => "10" }
257
- Tree.expects(:args_paginate).with("1", "10").returns(Tree)
258
- Tree.expects(:all).returns([mock_tree])
259
-
260
- get :index, params: { args_paginate: hash }
261
-
262
- assert_equal([mock_tree], assigns(:@trees))
263
- assert_equal({ args_paginate: hash }, current_scopes)
264
- end
265
-
266
- def test_hash_with_blank_values_is_ignored
267
- hash = { "page" => "", "per_page" => "" }
268
- Tree.expects(:paginate).never
269
- Tree.expects(:all).returns([mock_tree])
270
-
271
- get :index, params: { paginate: hash }
272
-
273
- assert_equal([mock_tree], assigns(:@trees))
274
- assert_equal({ }, current_scopes)
275
- end
276
-
277
- def test_hash_with_blank_values_and_allow_blank_is_called
278
- hash = { "page" => "", "per_page" => "" }
279
- Tree.expects(:paginate_blank).with({}).returns(Tree)
280
- Tree.expects(:all).returns([mock_tree])
281
-
282
- get :index, params: { paginate_blank: hash }
283
-
284
- assert_equal([mock_tree], assigns(:@trees))
285
- assert_equal({ paginate_blank: {} }, current_scopes)
286
- end
287
-
288
- def test_hash_with_using_and_blank_values_and_allow_blank_is_called
289
- hash = { "page" => "", "per_page" => "" }
290
- Tree.expects(:args_paginate_blank).with(nil, nil).returns(Tree)
291
- Tree.expects(:all).returns([mock_tree])
292
-
293
- get :index, params: { args_paginate_blank: hash }
294
-
295
- assert_equal([mock_tree], assigns(:@trees))
296
- assert_equal({ args_paginate_blank: {} }, current_scopes)
297
- end
298
-
299
- def test_nested_hash_with_blank_values_is_ignored
300
- hash = { "parent" => { "children" => "" } }
301
- Tree.expects(:paginate).never
302
- Tree.expects(:all).returns([mock_tree])
303
-
304
- get :index, params: { paginate: hash }
305
-
306
- assert_equal([mock_tree], assigns(:@trees))
307
- assert_equal({ }, current_scopes)
308
- end
309
-
310
- def test_nested_blank_array_param_is_ignored
311
- hash = { "parent" => [""] }
312
- Tree.expects(:paginate).never
313
- Tree.expects(:all).returns([mock_tree])
314
-
315
- get :index, params: { paginate: hash }
316
-
317
- assert_equal([mock_tree], assigns(:@trees))
318
- assert_equal({ }, current_scopes)
319
- end
320
-
321
- def test_scope_of_type_array
322
- array = %w(book kitchen sport)
323
- Tree.expects(:categories).with(array).returns(Tree)
324
- Tree.expects(:all).returns([mock_tree])
325
-
326
- get :index, params: { categories: array }
327
-
328
- assert_equal([mock_tree], assigns(:@trees))
329
- assert_equal({ categories: array }, current_scopes)
330
- end
331
-
332
- def test_array_of_blank_values_is_ignored
333
- Tree.expects(:categories).never
334
- Tree.expects(:all).returns([mock_tree])
335
-
336
- get :index, params: { categories: [""] }
337
-
338
- assert_equal([mock_tree], assigns(:@trees))
339
- assert_equal({ }, current_scopes)
340
- end
341
-
342
- def test_scope_of_invalid_type_silently_fails
343
- Tree.expects(:all).returns([mock_tree])
344
-
345
- get :index, params: { paginate: "1" }
346
-
347
- assert_equal([mock_tree], assigns(:@trees))
348
- assert_equal({ }, current_scopes)
349
- end
350
-
351
- def test_scope_is_called_with_default_value
352
- Tree.expects(:shadown_range).with(10).returns(Tree).in_sequence
353
- Tree.expects(:paginate_default).with('page' => 1, 'per_page' => 10).returns(Tree).in_sequence
354
- Tree.expects(:args_paginate_default).with(1, 10).returns(Tree).in_sequence
355
- Tree.expects(:metadata_default).with('default').returns(Tree).in_sequence
356
- Tree.expects(:find).with('42').returns(mock_tree).in_sequence
357
-
358
- get :edit, params: { id: '42' }
359
-
360
- assert_equal(mock_tree, assigns(:@tree))
361
- assert_equal({
362
- shadown_range: 10,
363
- paginate_default: { 'page' => 1, 'per_page' => 10 },
364
- args_paginate_default: { 'page' => 1, 'per_page' => 10 },
365
- q: { 'metadata_default' => 'default' }
366
- }, current_scopes)
367
- end
368
-
369
- def test_default_scope_value_can_be_overwritten
370
- Tree.expects(:shadown_range).with('20').returns(Tree).in_sequence
371
- Tree.expects(:paginate_default).with('page' => '2', 'per_page' => '20').returns(Tree).in_sequence
372
- Tree.expects(:args_paginate_default).with('3', '15').returns(Tree).in_sequence
373
- Tree.expects(:metadata_blank).with(nil).returns(Tree).in_sequence
374
- Tree.expects(:metadata_default).with('other').returns(Tree).in_sequence
375
- Tree.expects(:find).with('42').returns(mock_tree).in_sequence
376
-
377
- get :edit, params: {
378
- id: '42',
379
- shadown_range: '20',
380
- paginate_default: { page: 2, per_page: 20 },
381
- args_paginate_default: { page: 3, per_page: 15},
382
- q: { metadata_default: 'other' }
383
- }
384
-
385
- assert_equal(mock_tree, assigns(:@tree))
386
- assert_equal({
387
- shadown_range: '20',
388
- paginate_default: { 'page' => '2', 'per_page' => '20' },
389
- args_paginate_default: { 'page' => '3', 'per_page' => '15' },
390
- q: { 'metadata_default' => 'other' }
391
- }, current_scopes)
392
- end
393
-
394
- def test_scope_with_different_key
395
- Tree.expects(:root_type).with('outside').returns(Tree).in_sequence
396
- Tree.expects(:find).with('42').returns(mock_tree).in_sequence
397
-
398
- get :show, params: { id: '42', root: 'outside' }
399
-
400
- assert_equal(mock_tree, assigns(:@tree))
401
- assert_equal({ root: 'outside' }, current_scopes)
402
- end
403
-
404
- def test_scope_with_default_value_as_a_proc_without_argument
405
- Date.expects(:today).returns("today")
406
- Tree.expects(:planted_before).with("today").returns(Tree)
407
- Tree.expects(:all).returns([mock_tree])
408
-
409
- get :index
410
-
411
- assert_equal([mock_tree], assigns(:@trees))
412
- assert_equal({ planted_before: "today" }, current_scopes)
413
- end
414
-
415
- def test_scope_with_default_value_as_proc_with_argument
416
- session[:height] = 100
417
- Tree.expects(:calculate_height).with(100).returns(Tree).in_sequence
418
- Tree.expects(:new).returns(mock_tree).in_sequence
419
-
420
- get :new
421
-
422
- assert_equal(mock_tree, assigns(:@tree))
423
- assert_equal({ calculate_height: 100 }, current_scopes)
424
- end
425
-
426
- def test_scope_with_custom_type
427
- parsed = Date.civil(2014,11,11)
428
- Tree.expects(:planted_after).with(parsed).returns(Tree)
429
- Tree.expects(:all).returns([mock_tree])
430
-
431
- get :index, params: { planted_after: "2014-11-11" }
432
-
433
- assert_equal([mock_tree], assigns(:@trees))
434
- assert_equal({ planted_after: parsed }, current_scopes)
435
- end
436
-
437
- def test_scope_with_boolean_block
438
- Tree.expects(:only_really_short!).with(@controller.object_id).returns(Tree)
439
- Tree.expects(:all).returns([mock_tree])
440
-
441
- get :index, params: { only_short: 'true' }
442
-
443
- assert_equal([mock_tree], assigns(:@trees))
444
- assert_equal({ only_short: true }, current_scopes)
445
- end
446
-
447
- def test_scope_with_other_block_types
448
- Tree.expects(:by_given_category).with(@controller.object_id, 'for_id').returns(Tree)
449
- Tree.expects(:all).returns([mock_tree])
450
-
451
- get :index, params: { by_category: 'for' }
452
-
453
- assert_equal([mock_tree], assigns(:@trees))
454
- assert_equal({ by_category: 'for' }, current_scopes)
455
- end
456
-
457
- def test_scope_with_nested_hash_and_in_option
458
- hash = { 'title' => 'the-title', 'content' => 'the-content' }
459
- Tree.expects(:title).with('the-title').returns(Tree)
460
- Tree.expects(:content).with('the-content').returns(Tree)
461
- Tree.expects(:metadata).never
462
- Tree.expects(:metadata_blank).with(nil).returns(Tree)
463
- Tree.expects(:all).returns([mock_tree])
464
-
465
- get :index, params: { q: hash }
466
-
467
- assert_equal([mock_tree], assigns(:@trees))
468
- assert_equal({ q: hash }, current_scopes)
469
- end
470
-
471
- def test_overwritten_scope
472
- assert_nil(TreesController.scopes_configuration[:categories][:if])
473
- assert_equal(:categories?, BonsaisController.scopes_configuration[:categories][:if])
474
- end
475
-
476
- protected
477
-
478
- def mock_tree(stubs = {})
479
- @mock_tree ||= mock(stubs)
480
- end
481
-
482
- def current_scopes
483
- @controller.send :current_scopes
484
- end
485
-
486
- def assigns(ivar)
487
- @controller.instance_variable_get(ivar)
488
- end
489
- end
490
-
491
- class TreeHugger
492
- include HasScope
493
-
494
- has_scope :color
495
-
496
- def by_color
497
- apply_scopes(Tree, color: 'blue')
498
- end
499
- end
500
-
501
- class HasScopeOutsideControllerTest < ActiveSupport::TestCase
502
- def test_has_scope_usable_outside_controller
503
- Tree.expects(:color).with('blue')
504
-
505
- TreeHugger.new.by_color
506
- end
507
- end
data/test/test_helper.rb DELETED
@@ -1,28 +0,0 @@
1
- require 'bundler/setup'
2
-
3
- require 'minitest/autorun'
4
- require 'mocha'
5
- require 'mocha/mini_test'
6
-
7
- # Configure Rails
8
- ENV['RAILS_ENV'] = 'test'
9
-
10
- $:.unshift File.expand_path('../../lib', __FILE__)
11
- require 'has_scope'
12
-
13
- HasScope::Routes = ActionDispatch::Routing::RouteSet.new
14
- HasScope::Routes.draw do
15
- resources :trees, only: %i[index new edit show]
16
- end
17
-
18
- class ApplicationController < ActionController::Base
19
- include HasScope::Routes.url_helpers
20
- end
21
-
22
- class ActiveSupport::TestCase
23
- self.test_order = :random if respond_to?(:test_order=)
24
-
25
- setup do
26
- @routes = HasScope::Routes
27
- end
28
- end