filterameter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 97bc00d12d3a953cbedcfa92a1b8c469ef442936ebaac28157fd4a88cb8dc62c
4
+ data.tar.gz: f7233773047377d725a047e3b01b159f097ecbece898b83d824b197e6146db61
5
+ SHA512:
6
+ metadata.gz: e19b7c776809225651165bf7714ca7820cb5c3824138ff798842d4b99cf67c58d92eb077070d9959874aa6ebf2352c2b5cf34f6c223241c64b36d4dc7b2ee59e
7
+ data.tar.gz: d24c6b1abe68ef70cbb03c8abecda1147f1dc889b2b7cd90062c35245f1c442d07ff6562866cb4d097b0bc2e3572cc02c5c5a406a146f7af91fa85b3abc883c9
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2019 Todd Kummer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # Filterameter
2
+ Declarative Filter Parameters for Rails Controllers.
3
+
4
+ ## Usage
5
+ Declare filters at the top of 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.
6
+
7
+ ```ruby
8
+ filter :color
9
+ filter :size, validates: { inclusion: { in: %w[Small Medium Large] }, unless: -> { size.is_a? Array } }
10
+ filter :brand_name, association: :brand, name: :name
11
+ filter :on_sale, association: :price, validates: [{ numericality: { greater_than: 0 } },
12
+ { numericality: { less_than: 100 } }]
13
+ ```
14
+
15
+ ### Filtering Options
16
+
17
+ The following options can be specified for each filter.
18
+
19
+ #### name
20
+ If the name of the parameter is different than the name of the attribute or scope, then use the name parameter to specify the name of the attribute or scope. For example, if the attribute name is `current_status` but the filter is exposed simply as `status` use the following:
21
+
22
+ ```ruby
23
+ filter :status, name: :current_status
24
+ ```
25
+
26
+ #### association
27
+ If the attribute or scope is nested, it can be referenced by naming the association. Only singular associations are valid. For example, if the manager_id attribute lives on an employee's department record, use the following:
28
+
29
+ ```ruby
30
+ filter :manager_id, association: :department
31
+ ```
32
+
33
+ #### validates
34
+ If the filter value should be validated, use the `validates` option along with [ActiveModel validations](https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates). Here's an example of the inclusion validator being used to restrict sizes:
35
+
36
+ ```ruby
37
+ filter :size, validates: { inclusion: { in: %w[Small Medium Large] }, unless: -> { size.is_a? Array } }
38
+ ```
39
+
40
+ Note that the `inclusion` validator does not allow arrays to be specified. If the filter should allow multiple values to be specified, then the validation needs to be disabled when the value an array.
41
+
42
+ ### Configuring Controllers
43
+
44
+ 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:
45
+
46
+ #### filter_model
47
+ Provide the name of the model. This method also allows the variable name to be optionally provided as the second parameter.
48
+
49
+ ```ruby
50
+ filter_model 'Picture'
51
+ ```
52
+
53
+ #### filter_query_var_name
54
+ Provide the name of the instance variable. For example, if the query is stored as `@data`, use the following:
55
+
56
+ ```ruby
57
+ filter_query_var_name :data
58
+ ```
59
+
60
+ ## Installation
61
+ Add this line to your application's Gemfile:
62
+
63
+ ```ruby
64
+ gem 'filterameter'
65
+ ```
66
+
67
+ And then execute:
68
+ ```bash
69
+ $ bundle
70
+ ```
71
+
72
+ Or install it yourself as:
73
+ ```bash
74
+ $ gem install filterameter
75
+ ```
76
+
77
+
78
+ ## Running Tests
79
+
80
+ Tests are written in RSpec and the dummy app uses a docker database. First, start the database and prepare it from the dummy folder.
81
+
82
+ ```bash
83
+ cd spec/dummy
84
+ docker-compose up -d
85
+ bundle exec rails db:test:prepare
86
+ cd ../..
87
+ ```
88
+
89
+ Run the tests from the main directory
90
+
91
+ ```bash
92
+ bundle exec rspec
93
+ ```
94
+
95
+ ## License
96
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Filterameter'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ require 'bundler/gem_tasks'
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ # = Configuration
5
+ #
6
+ # Class Configuration stores the following settings:
7
+ # - action_on_undeclared_parameters
8
+ # - action_on_validation_failure
9
+ #
10
+ # == Action on Undeclared Parameters
11
+ # Occurs when the filter parameter contains any keys that are not defined. Valid actions are :log, :raise, and
12
+ # false (do not take action). By default, development will log, test will raise, and production will do nothing.
13
+ #
14
+ # == Action on Validation Failure
15
+ # Occurs when a filter parameter fails a validation. Valid actions are :log, :raise, and false (do not take action).
16
+ # By default, development will log, test will raise, and production will do nothing.
17
+ class Configuration
18
+ attr_accessor :action_on_undeclared_parameters, :action_on_validation_failure
19
+
20
+ def initialize
21
+ @action_on_undeclared_parameters =
22
+ @action_on_validation_failure =
23
+ if Rails.env.development?
24
+ :log
25
+ elsif Rails.env.test?
26
+ :raise
27
+ else
28
+ false
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,110 @@
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
+ require 'filterameter/filter_factory'
11
+ require 'filterameter/filter_declaration'
12
+ require 'filterameter/log_subscriber'
13
+ require 'filterameter/parameters_base'
14
+
15
+ module Filterameter
16
+ # = Controller Filters
17
+ #
18
+ # Class ControllerFilters stores the configuration declared via class-level method calls such as the list of
19
+ # filters and the optionally declared model class. Each controller will have one instance of the controller
20
+ # declarations stored as a class variable.
21
+ class ControllerFilters
22
+ attr_writer :query_variable_name
23
+
24
+ def initialize(controller_name, controller_path)
25
+ @controller_name = controller_name
26
+ @controller_path = controller_path
27
+ @declarations = {}
28
+ @filters = Hash.new { |hash, key| hash[key] = filter_factory.build(@declarations[key]) }
29
+ end
30
+
31
+ def model_class=(model_class)
32
+ @model_class = model_class.is_a?(String) ? model_class.constantize : model_class
33
+ end
34
+
35
+ def add_filter(parameter_name, options)
36
+ @declarations[parameter_name.to_s] = Filterameter::FilterDeclaration.new(parameter_name, options)
37
+ end
38
+
39
+ def query_variable_name
40
+ @query_variable_name ||= model_class.model_name.plural
41
+ end
42
+
43
+ def build_query(filter_params)
44
+ valid_filters(filter_params).reduce(model_class.all) do |query, (name, value)|
45
+ @filters[name].apply(query, value)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def model_class
52
+ @model_class ||= @controller_name.classify.safe_constantize ||
53
+ @controller_path.classify.safe_constantize ||
54
+ raise(Filterameter::Exceptions::CannotDetermineModelError.new(@controller_name,
55
+ @controller_path))
56
+ end
57
+
58
+ # lazy so that model_class can be optionally set
59
+ def filter_factory
60
+ @filter_factory ||= Filterameter::FilterFactory.new(model_class)
61
+ end
62
+
63
+ def valid_filters(filter_params)
64
+ remove_invalid_values(
65
+ remove_undeclared_filters(filter_params)
66
+ )
67
+ end
68
+
69
+ def remove_undeclared_filters(filter_params)
70
+ filter_params.slice(*declared_parameter_names).tap do |declared_parameters|
71
+ handle_undeclared_parameters(filter_params) if declared_parameters.size != filter_params.size
72
+ end
73
+ end
74
+
75
+ def handle_undeclared_parameters(filter_params)
76
+ action = Filterameter.configuration.action_on_undeclared_parameters
77
+ return unless action
78
+
79
+ undeclared_parameter_names = filter_params.keys - declared_parameter_names
80
+ case action
81
+ when :log
82
+ ActiveSupport::Notifications.instrument('undeclared_parameters.filterameter', keys: undeclared_parameter_names)
83
+ when :raise
84
+ raise Filterameter::Exceptions::UndeclaredParameterError, undeclared_parameter_names
85
+ end
86
+ end
87
+
88
+ def remove_invalid_values(filter_params)
89
+ validator = validator_class.new(filter_params)
90
+ return filter_params if validator.valid?
91
+
92
+ case Filterameter.configuration.action_on_validation_failure
93
+ when :log
94
+ ActiveSupport::Notifications.instrument('validation_failure.filterameter', errors: validator.errors)
95
+ when :raise
96
+ raise Filterameter::Exceptions::ValidationError, validator.errors
97
+ end
98
+
99
+ filter_params.except(*validator.errors.keys.map(&:to_s))
100
+ end
101
+
102
+ def declared_parameter_names
103
+ @declared_parameter_names ||= @declarations.keys
104
+ end
105
+
106
+ def validator_class
107
+ @validator_class ||= Filterameter::ParametersBase.build_sub_class(@declarations.values)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'filterameter/controller_filters'
4
+
5
+ module Filterameter
6
+ # = Declarative Filters
7
+ #
8
+ # module DeclarativeFilters provides a controller DSL to declare filters along with any validations.
9
+ module DeclarativeFilters
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ before_action :build_filtered_query, only: :index
14
+ end
15
+
16
+ class_methods do
17
+ def filter_model(model_class, query_var_name = nil)
18
+ controller_filters.model_class = model_class
19
+ filter_query_var_name(query_var_name) if query_var_name.present?
20
+ end
21
+
22
+ def filter_query_var_name(query_variable_name)
23
+ controller_filters.query_variable_name = query_variable_name
24
+ end
25
+
26
+ def filter(name, options = {})
27
+ controller_filters.add_filter(name, options)
28
+ end
29
+
30
+ def filters(*names)
31
+ names.each { |name| filter(name) }
32
+ end
33
+
34
+ def controller_filters
35
+ @controller_filters ||= Filterameter::ControllerFilters.new(controller_name, controller_path)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def build_filtered_query
42
+ instance_variable_set("@#{self.class.controller_filters.query_variable_name}",
43
+ self.class.controller_filters.build_query(params.to_unsafe_h.fetch(:filter, {})))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Exceptions
5
+ # = Cannot Determine Model Error
6
+ #
7
+ # Class CannotDetermineModelError is raised when the model class cannot be determined from either the controller
8
+ # name or controller path. This is a setup issue; the resolution is for the controller to specify the model class
9
+ # explicitly by adding a call to `filter_model`.
10
+ class CannotDetermineModelError < FilterameterError
11
+ def initialize(name, path)
12
+ super "Cannot determine model name from controller name #{value_and_classify(name)} " \
13
+ "or path #{value_and_classify(path)}. Declare the model explicitly with filter_model."
14
+ end
15
+
16
+ private
17
+
18
+ def value_and_classify(value)
19
+ "(#{value} => #{value.classify})"
20
+ rescue StandardError
21
+ value
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Exceptions
5
+ # = Undeclared Parameter Error
6
+ #
7
+ # Class UndeclaredParameterError is raised when a request contains filter parameters that have not been declared.
8
+ # Configuration setting `action_on_undeclared_parameters` determines whether or not the exception is raised.
9
+ class UndeclaredParameterError < FilterameterError
10
+ attr_reader :keys
11
+
12
+ def initialize(keys)
13
+ @keys = keys
14
+ end
15
+
16
+ def message
17
+ "The following filter parameter(s) have not been declared: #{keys}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Exceptions
5
+ # = Validation Error
6
+ #
7
+ # Class ValidationError is raised when a specified parameter fails a validation. Configuration setting
8
+ # `action_on_validation_failure` determines whether or not the exception is raised.
9
+ class ValidationError < FilterameterError
10
+ attr_reader :errors
11
+
12
+ def initialize(errors)
13
+ @errors = errors
14
+ end
15
+
16
+ def message
17
+ "The following parameter(s) failed validation: #{errors.full_messages}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Exceptions
5
+ class FilterameterError < StandardError
6
+ end
7
+ end
8
+ end
9
+
10
+ require 'filterameter/exceptions/cannot_determine_model_error'
11
+ require 'filterameter/exceptions/validation_error'
12
+ require 'filterameter/exceptions/undeclared_parameter_error'
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/array/wrap'
4
+
5
+ module Filterameter
6
+ # = Filter Declaration
7
+ #
8
+ # Class FilterDeclaration captures the filter declaration within the controller.
9
+ class FilterDeclaration
10
+ attr_reader :name, :parameter_name, :association, :validations
11
+
12
+ def initialize(parameter_name, options)
13
+ @parameter_name = parameter_name.to_s
14
+
15
+ validate_options(options)
16
+ @name = options.fetch(:name, parameter_name).to_s
17
+ @association = options[:association]
18
+ @filter_on_empty = options.fetch(:filter_on_empty, false)
19
+ @validations = Array.wrap(options[:validates])
20
+ end
21
+
22
+ def nested?
23
+ @association.present?
24
+ end
25
+
26
+ def validations?
27
+ !@validations.empty?
28
+ end
29
+
30
+ def filter_on_empty?
31
+ @filter_on_empty
32
+ end
33
+
34
+ private
35
+
36
+ def validate_options(options)
37
+ options.assert_valid_keys(:name, :association, :filter_on_empty, :validates)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'filterameter/filters/attribute_filter'
4
+ require 'filterameter/filters/conditional_scope_filter'
5
+ require 'filterameter/filters/nested_filter'
6
+ require 'filterameter/filters/scope_filter'
7
+
8
+ module Filterameter
9
+ # = Filter Factory
10
+ #
11
+ # Class FilterFactory builds a filter from a FilterDeclaration.
12
+ class FilterFactory
13
+ def initialize(model_class)
14
+ @model_class = model_class
15
+ end
16
+
17
+ def build(declaration)
18
+ model = declaration.nested? ? model_from_association(declaration.association) : @model_class
19
+ filter = build_filter(model, declaration.name)
20
+
21
+ declaration.nested? ? Filterameter::Filters::NestedFilter.new(declaration.association, model, filter) : filter
22
+ end
23
+
24
+ private
25
+
26
+ def build_filter(model, name)
27
+ # checking dangerous_class_method? excludes any names that cannot be scope names, such as "name"
28
+ if model.respond_to?(name) && !model.dangerous_class_method?(name)
29
+ Filterameter::Filters::ScopeFilter.new(name)
30
+ else
31
+ Filterameter::Filters::AttributeFilter.new(name)
32
+ end
33
+ end
34
+
35
+ # TODO: rescue then raise custom error with cause
36
+ def model_from_association(association)
37
+ [association].flatten.reduce(@model_class) { |memo, name| memo.reflect_on_association(name).klass }
38
+ # rescue StandardError => e
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Filters
5
+ # = Attribute Filter
6
+ #
7
+ # Class AttributeFilter leverages ActiveRecord's where query method to add criteria for an attribute.
8
+ class AttributeFilter
9
+ def initialize(attribute_name)
10
+ @attribute_name = attribute_name
11
+ end
12
+
13
+ def apply(query, value)
14
+ query.where(@attribute_name => value)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Filters
5
+ # = Conditional Scope Filter
6
+ #
7
+ # Class ConditionalScopeFilter applies the scope if the parameter is not false.
8
+ class ConditionalScopeFilter
9
+ def initialize(scope_name)
10
+ @scope_name = scope_name
11
+ end
12
+
13
+ def apply(query, value)
14
+ return query unless ActiveModel::Type::Boolean.new.cast(value)
15
+
16
+ query.send(@scope_name)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Filters
5
+ # = Nested Attribute Filter
6
+ #
7
+ # Class NestedFilter joins the nested table(s) then merges the filter to the association's model.
8
+ class NestedFilter
9
+ def initialize(joins_values, association_model, attribute_filter)
10
+ @joins_values = joins_values
11
+ @association_model = association_model
12
+ @attribute_filter = attribute_filter
13
+ end
14
+
15
+ def apply(query, value)
16
+ query.joins(@joins_values)
17
+ .merge(@attribute_filter.apply(@association_model, value))
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ module Filters
5
+ # = Scope Filter
6
+ #
7
+ # Class ScopeFilter applies the named scope passing in the parameter value.
8
+ class ScopeFilter
9
+ def initialize(scope_name)
10
+ @scope_name = scope_name
11
+ end
12
+
13
+ def apply(query, value)
14
+ query.send(@scope_name, value)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ # = Log Subscriber
5
+ #
6
+ # Class LogSubscriber provides instrumentation for events.
7
+ class LogSubscriber < ActiveSupport::LogSubscriber
8
+ def validation_failure(event)
9
+ debug do
10
+ errors = event.payload[:errors]
11
+ ([' The following filter validation errors occurred:'] + errors.full_messages).join("\n - ")
12
+ end
13
+ end
14
+
15
+ def undeclared_parameters(event)
16
+ debug do
17
+ keys = event.payload[:keys]
18
+ " Undeclared filter parameter#{'s' if keys.size > 1}: #{keys.map { |e| ":#{e}" }.join(', ')}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Filterameter::LogSubscriber.attach_to :filterameter
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/attribute_assignment'
4
+ require 'active_model/validations'
5
+
6
+ module Filterameter
7
+ # = Parameters
8
+ #
9
+ # Class Parameters is sub-classed to provide controller-specific validations.
10
+ class ParametersBase
11
+ include ActiveModel::Validations
12
+
13
+ def self.build_sub_class(declarations)
14
+ Class.new(self).tap do |sub_class|
15
+ declarations.select(&:validations?).each do |declaration|
16
+ sub_class.add_validation(declaration.parameter_name, declaration.validations)
17
+ end
18
+ end
19
+ end
20
+
21
+ def self.name
22
+ 'ControllerParameters'
23
+ end
24
+
25
+ def self.add_validation(parameter_name, validations)
26
+ attr_accessor parameter_name
27
+
28
+ default_options = { allow_nil: true }
29
+ validations.each do |validation|
30
+ validates parameter_name, default_options.merge(validation)
31
+ end
32
+ end
33
+
34
+ def initialize(attributes)
35
+ attributes.each { |k, v| assign_attribute(k, v) }
36
+ end
37
+
38
+ private
39
+
40
+ def assign_attribute(key, value)
41
+ setter = :"#{key}="
42
+ public_send(setter, value) if respond_to?(setter)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Filterameter
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'filterameter/configuration'
4
+ require 'filterameter/declarative_filters'
5
+ require 'filterameter/exceptions'
6
+
7
+ # = Filterameter
8
+ #
9
+ # Module Filterameter can be mixed into a controller to provide the DSL to describe each controller's filters.
10
+ #
11
+ # The model class must be declared if it cannot be derived. It can be derived if (A) the model is not namespaced and its
12
+ # name matches the controller name (for example BrandsController -> Brand) or (B) both the controller and model share
13
+ # the same namespace and name.
14
+ module Filterameter
15
+ class << self
16
+ attr_writer :configuration
17
+ end
18
+
19
+ def self.configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+
23
+ def self.reset
24
+ @configuration = Configuration.new
25
+ end
26
+
27
+ def self.configure
28
+ yield(configuration)
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # desc "Explaining what the task does"
3
+ # task :filterameter do
4
+ # # Task goes here
5
+ # end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: filterameter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Todd Kummer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: pg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.77'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.77'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Enable filter parameters to be declared in controllers.
84
+ email:
85
+ - todd@rockridgesolutions.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - MIT-LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - lib/filterameter.rb
94
+ - lib/filterameter/configuration.rb
95
+ - lib/filterameter/controller_filters.rb
96
+ - lib/filterameter/declarative_filters.rb
97
+ - lib/filterameter/exceptions.rb
98
+ - lib/filterameter/exceptions/cannot_determine_model_error.rb
99
+ - lib/filterameter/exceptions/undeclared_parameter_error.rb
100
+ - lib/filterameter/exceptions/validation_error.rb
101
+ - lib/filterameter/filter_declaration.rb
102
+ - lib/filterameter/filter_factory.rb
103
+ - lib/filterameter/filters/attribute_filter.rb
104
+ - lib/filterameter/filters/conditional_scope_filter.rb
105
+ - lib/filterameter/filters/nested_filter.rb
106
+ - lib/filterameter/filters/scope_filter.rb
107
+ - lib/filterameter/log_subscriber.rb
108
+ - lib/filterameter/parameters_base.rb
109
+ - lib/filterameter/version.rb
110
+ - lib/tasks/filterameter_tasks.rake
111
+ homepage: https://github.com/RockSolt/filterameter
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubygems_version: 3.0.8
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Declarative Filter Parameters for Rails Controllers
134
+ test_files: []