filterameter 0.4.2 → 0.5.0

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: fab4750d809945619906678860278bb1266e20f3167a7e1cf15ca2cfcdb2404d
4
- data.tar.gz: da0d8f1d87b5aa8393f0283ce92442b968a4f388f6aa86eaf65c0740f3da8a7f
3
+ metadata.gz: f44f6d30fd92e15bc7652df41d75e2d620740fb19f146cbb253274460c3686f2
4
+ data.tar.gz: 84109580ba0079787e3bcc0e20054a71c2eb2ae7efc512d511124172f19c69fc
5
5
  SHA512:
6
- metadata.gz: 6c4c735e792c7da17e8753e760e2e75143e1e959f0000fb2367246dc280a57fc3709d47ac063a8261a3429727ac178d41c18fc4a0fc2abcec8417e2ec0c28240
7
- data.tar.gz: 2a92f39bcd0af14ff33f3efc35f65def9d882a3caf01b18a04ec0c31ece6977966962ce88d893d0efb62c2b4492babe2d90b02fde8f730a76121c869d2ca3c3c
6
+ metadata.gz: 4b8606c20e87f96b25876da9b670f555b1c95b40bc5fa13368174d1e4264ea1a535a93ea714111171710de12e301876aa59081f327a9cbd8e4f5a6735f2c0406
7
+ data.tar.gz: 1f848be8b42e68845cebaabadd04b0e9019dab54d9cfdfa2628048215cb6ed5c5e37360fa99a473208cf4539a5963a065f0790a75ecc5d795e45037ae35f7347
data/README.md CHANGED
@@ -4,10 +4,10 @@
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/d9d87f9ce8020eb6e656/maintainability)](https://codeclimate.com/github/RockSolt/filterameter/maintainability)
5
5
 
6
6
  # Filterameter
7
- Declarative filter parameters provide clean and clear filters for queries.
7
+ Declarative filter parameters provide clean and clear filters for Rails controllers.
8
8
 
9
9
  ## Usage
10
- Declare filters in query classes or controllers to increase readability and reduce boilerplate code. Filters can be declared for attributes, scopes, or attributes from singular associations (`belongs_to` or `has_one`). Validations can also be assigned.
10
+ Declare filters in controllers to increase readability and reduce boilerplate code. Filters can be declared for attributes, scopes, or attributes from singular associations (`belongs_to` or `has_one`). Validations can also be assigned.
11
11
 
12
12
  ```ruby
13
13
  filter :color
@@ -85,39 +85,9 @@ filter :sale_price, range: :max_only
85
85
 
86
86
  In the first example, query parameters could include <tt>price</tt>, <tt>price_min</tt>, and <tt>price_max</tt>.
87
87
 
88
- ### Query Classes
89
-
90
- Include module `Filterameter::DeclarativeFilters` in the query class. The model must be declared using `model`, and a default query can optionally be declared using `default_query`. If no default query is provided, then the default is `.all`.
91
-
92
- #### Example
93
-
94
- Here's what a query class for the Widgets model with filters on size and color might look like:
95
-
96
- ```ruby
97
- class WidgetQuery
98
- include Filterameter::DeclarativeFilters
99
-
100
- model Widget
101
- filter :size
102
- filter :color
103
- end
104
- ```
105
-
106
- Build the query using class method `build_query`. The method takes two parameters:
107
-
108
- - filter: the hash of filter parameters
109
- - starting_query: any scope to build on (if not provided, the default query is the starting point)
110
-
111
- Here's how the query might be invoked:
112
-
113
- ```ruby
114
- filters = { size: 'large', color: 'blue' }
115
- widgets = WidgetQuery.build_query(filters, Widget.limit(10))
116
- ```
117
-
118
88
  ### Controllers
119
89
 
120
- Include module `Filterameter::DeclarativeControllerFilters` in the controller. Add before action callback `build_filtered_query` for controller actions that should build the query.
90
+ Include module `Filterameter::DeclarativeFilters` in the controller. Add before action callback `build_filtered_query` for controller actions that should build the query.
121
91
 
122
92
  Rails conventions are used to determine the controller's model as well as the name of the instance variable to apply the filters to. For example, the PhotosController will use the variable `@photos` to store a query against the Photo model. **If the conventions do not provide the correct info**, they can be overridden with the following two methods:
123
93
 
@@ -141,7 +111,7 @@ In the happy path, the WidgetsController serves Widgets and can filter on size a
141
111
 
142
112
  ```ruby
143
113
  class WidgetController < ApplicationController
144
- include Filterameter::DeclarativeControllerFilters
114
+ include Filterameter::DeclarativeFilters
145
115
  before_action :build_filtered_query, only: :index
146
116
 
147
117
  filter :size
@@ -1,27 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Filterameter
4
- # = Declarative Filters
4
+ # = Declarative Controller Filters
5
5
  #
6
- # Mixin DeclarativeFilters is included to build query classes using the filter DSL.
6
+ # Mixin DeclarativeFilters can included in controllers to enable the filter DSL.
7
7
  module DeclarativeFilters
8
8
  extend ActiveSupport::Concern
9
9
  include Filterameter::Filterable
10
10
 
11
11
  class_methods do
12
- delegate :build_query, to: :filter_coordinator
13
-
14
- def model(model_class)
12
+ def filter_model(model_class, query_var_name = nil)
15
13
  filter_coordinator.model_class = model_class
14
+ filter_query_var_name(query_var_name) if query_var_name.present?
16
15
  end
17
16
 
18
- def default_query(query)
19
- filter_coordinator.default_query = query
17
+ def filter_query_var_name(query_variable_name)
18
+ filter_coordinator.query_variable_name = query_variable_name
20
19
  end
21
20
 
22
21
  def filter_coordinator
23
- @filter_coordinator ||= Filterameter::Coordinators::QueryCoordinator.new
22
+ @filter_coordinator ||= Filterameter::FilterCoordinator.new(controller_name, controller_path)
24
23
  end
25
24
  end
25
+
26
+ private
27
+
28
+ def build_filtered_query
29
+ var_name = "@#{self.class.filter_coordinator.query_variable_name}"
30
+ instance_variable_set(
31
+ var_name,
32
+ self.class.filter_coordinator.build_query(params.to_unsafe_h.fetch(:filter, {}),
33
+ instance_variable_get(var_name))
34
+ )
35
+ end
26
36
  end
27
37
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/inflector'
4
+
5
+ require 'active_support/rails'
6
+ require 'action_dispatch'
7
+ require 'action_controller/metal/live'
8
+ require 'action_controller/metal/strong_parameters'
9
+
10
+ module Filterameter
11
+ # = Filter Coordinator
12
+ #
13
+ # Class FilterCoordinator stores the configuration declared via class-level method calls such as the list of
14
+ # filters and the optionally declared model class. Each controller will have one instance of the coordinator
15
+ # stored as a class variable.
16
+ #
17
+ # The coordinators encapsulate references to the Query Builder and Filter Registry to keep the namespace clean for
18
+ # controllers that implement filter parameters.
19
+ class FilterCoordinator
20
+ attr_writer :query_variable_name
21
+
22
+ delegate :add_filter, to: :registry
23
+ delegate :build_query, to: :query_builder
24
+
25
+ def initialize(controller_name, controller_path)
26
+ @controller_name = controller_name
27
+ @controller_path = controller_path
28
+ end
29
+
30
+ def model_class=(model_class)
31
+ @model_class = model_class.is_a?(String) ? model_class.constantize : model_class
32
+ end
33
+
34
+ def query_builder
35
+ @query_builder ||= Filterameter::QueryBuilder.new(default_query, registry)
36
+ end
37
+
38
+ def query_variable_name
39
+ @query_variable_name ||= model_class.model_name.plural
40
+ end
41
+
42
+ private
43
+
44
+ def model_class
45
+ @model_class ||= @controller_name.classify.safe_constantize ||
46
+ @controller_path.classify.safe_constantize ||
47
+ raise(Filterameter::Exceptions::CannotDetermineModelError.new(@controller_name,
48
+ @controller_path))
49
+ end
50
+
51
+ def default_query
52
+ model_class.all
53
+ end
54
+
55
+ # lazy so that model_class can be optionally set
56
+ def registry
57
+ @registry ||= Filterameter::FilterRegistry.new(Filterameter::FilterFactory.new(model_class))
58
+ end
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Filterameter
4
- VERSION = '0.4.2'
4
+ VERSION = '0.5.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: filterameter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Kummer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-13 00:00:00.000000000 Z
11
+ date: 2024-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -175,15 +175,12 @@ files:
175
175
  - Rakefile
176
176
  - lib/filterameter.rb
177
177
  - lib/filterameter/configuration.rb
178
- - lib/filterameter/coordinators/base.rb
179
- - lib/filterameter/coordinators/controller_coordinator.rb
180
- - lib/filterameter/coordinators/query_coordinator.rb
181
- - lib/filterameter/declarative_controller_filters.rb
182
178
  - lib/filterameter/declarative_filters.rb
183
179
  - lib/filterameter/exceptions.rb
184
180
  - lib/filterameter/exceptions/cannot_determine_model_error.rb
185
181
  - lib/filterameter/exceptions/undeclared_parameter_error.rb
186
182
  - lib/filterameter/exceptions/validation_error.rb
183
+ - lib/filterameter/filter_coordinator.rb
187
184
  - lib/filterameter/filter_declaration.rb
188
185
  - lib/filterameter/filter_factory.rb
189
186
  - lib/filterameter/filter_registry.rb
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Filterameter
4
- module Coordinators
5
- # = Coordinators Base
6
- #
7
- # The main responsibility of the Coordinators classes is to keep the namespace clean for controllers and query
8
- # objects that implement filter parameters. The coordinators encapsulate references to the Query Builder and
9
- # Filter Registry.
10
- class Base
11
- attr_reader :model_class
12
-
13
- delegate :add_filter, to: :registry
14
- delegate :build_query, to: :query_builder
15
-
16
- def model_class=(model_class)
17
- @model_class = model_class.is_a?(String) ? model_class.constantize : model_class
18
- end
19
-
20
- def query_builder
21
- @query_builder ||= Filterameter::QueryBuilder.new(default_query, registry)
22
- end
23
-
24
- private
25
-
26
- def default_query
27
- model_class.all
28
- end
29
-
30
- # lazy so that model_class can be optionally set
31
- def registry
32
- @registry ||= Filterameter::FilterRegistry.new(Filterameter::FilterFactory.new(model_class))
33
- end
34
- end
35
- end
36
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/inflector'
4
-
5
- require 'active_support/rails'
6
- require 'action_dispatch'
7
- require 'action_controller/metal/live'
8
- require 'action_controller/metal/strong_parameters'
9
-
10
- module Filterameter
11
- module Coordinators
12
- # = Controller Filters
13
- #
14
- # Class ControllerFilters stores the configuration declared via class-level method calls such as the list of
15
- # filters and the optionally declared model class. Each controller will have one instance of the controller
16
- # declarations stored as a class variable.
17
- class ControllerCoordinator < Filterameter::Coordinators::Base
18
- attr_writer :query_variable_name
19
-
20
- def initialize(controller_name, controller_path)
21
- @controller_name = controller_name
22
- @controller_path = controller_path
23
- super()
24
- end
25
-
26
- def query_variable_name
27
- @query_variable_name ||= model_class.model_name.plural
28
- end
29
-
30
- private
31
-
32
- def model_class
33
- @model_class ||= @controller_name.classify.safe_constantize ||
34
- @controller_path.classify.safe_constantize ||
35
- raise(Filterameter::Exceptions::CannotDetermineModelError.new(@controller_name,
36
- @controller_path))
37
- end
38
- end
39
- end
40
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Filterameter
4
- module Coordinators
5
- # = Query Coordinator
6
- #
7
- # Class QueryCoordinator coordinates the filter logic for query classes.
8
- class QueryCoordinator < Filterameter::Coordinators::Base
9
- attr_writer :default_query
10
-
11
- private
12
-
13
- def default_query
14
- @default_query || super
15
- end
16
- end
17
- end
18
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Filterameter
4
- # = Declarative Controller Filters
5
- #
6
- # Mixin DeclarativeControllerFilters can included in controllers to enable the filter DSL.
7
- module DeclarativeControllerFilters
8
- extend ActiveSupport::Concern
9
- include Filterameter::Filterable
10
-
11
- class_methods do
12
- def filter_model(model_class, query_var_name = nil)
13
- filter_coordinator.model_class = model_class
14
- filter_query_var_name(query_var_name) if query_var_name.present?
15
- end
16
-
17
- def filter_query_var_name(query_variable_name)
18
- filter_coordinator.query_variable_name = query_variable_name
19
- end
20
-
21
- def filter_coordinator
22
- @filter_coordinator ||= Filterameter::Coordinators::ControllerCoordinator.new(controller_name, controller_path)
23
- end
24
- end
25
-
26
- private
27
-
28
- def build_filtered_query
29
- var_name = "@#{self.class.filter_coordinator.query_variable_name}"
30
- instance_variable_set(
31
- var_name,
32
- self.class.filter_coordinator.build_query(params.to_unsafe_h.fetch(:filter, {}),
33
- instance_variable_get(var_name))
34
- )
35
- end
36
- end
37
- end