paramore 0.2.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78c8a8c6985a0f9044fa608f0473cbd6ce872c5ff7f9626a2fb6e49f39c67f69
4
- data.tar.gz: c6c18de5f2dd039d06044ba58f7c4bfc38dda160fd6730213748c883529f8823
3
+ metadata.gz: d42894f0d3cefbd8979dc3048515ad8285a7f322f1ec1907b19d9941d6f95620
4
+ data.tar.gz: '0283777104760cb5d2d8774d95a61aa5841adaa38f35a488218cf89865a2571b'
5
5
  SHA512:
6
- metadata.gz: e406c95c757d7c583fb5d962f4b453c8dbda6dc141ad581169aab7ba767e2903723eb31c830ef8f55b98e5a12606feb578644141800e64a154217c0cd2f886e0
7
- data.tar.gz: 9061803ea9cdcccd492bb58f280d0037e01870c61d7dd30d8fad1d1ceabcb580f0e715531cf71ceff6fb8f875f60810ec95d7cfbedb14594f6fc65e85d491a1e
6
+ metadata.gz: 19def8fd4558111735cb93a28157e3fd7a7905be0b11b4d4515c85ccee3f26f64d6ab1c1d6c464d96230030960a89bac4ff31c96e391603a8786a08c98bdb8a1
7
+ data.tar.gz: da286395c83d3e13fc5ec1a0344a0232800fbf841bbc8bec14e32072059c32f678caef0d609cb17a6a4780e8ef3b4cd699fd52e2432ecca3dede925156ff0162
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # Paramore
2
2
 
3
3
  Paramore is a small gem intended to make strong parameter definitions declarative
4
- and provide a unified way to format and sanitize their values outside of controllers.
4
+ and provide a unified way to typecast and sanitize their values outside of controllers.
5
5
 
6
6
  # Installation
7
7
 
8
-
9
8
  In your Gemfile:
10
9
  ```ruby
11
10
  gem 'paramore'
@@ -18,14 +17,14 @@ $ bundle
18
17
 
19
18
  # Usage
20
19
 
21
- <h3>Without formatting/sanitizing</h3>
20
+ <h3>Without typing</h3>
22
21
 
23
22
  ```ruby
24
- declare_params :item_params
23
+ paramorize :item_params,
25
24
  item: [:name, :description, :for_sale, :price, metadata: [tags: []]]
26
25
  ```
27
26
 
28
- This is completely equivalent (including return type) to
27
+ This is completely equivalent (including the return type) to
29
28
 
30
29
  ```ruby
31
30
  def item_params
@@ -35,10 +34,10 @@ def item_params
35
34
  end
36
35
  ```
37
36
 
38
- <h3>With formatting/sanitizing</h3>
37
+ <h3>With typing</h3>
39
38
 
40
39
  A common problem in app development is untrustworthy input given by clients.
41
- That input needs to be sanitized and potentially formatted and type-cast for further processing.
40
+ That input needs to be sanitized and typecast for further processing.
42
41
  A naive approach could be:
43
42
 
44
43
  ```ruby
@@ -48,7 +47,7 @@ def item_params
48
47
  @item_params ||= begin
49
48
  _params = params
50
49
  .require(:item)
51
- .permit(:name, :description, :price, metadata: [tags: []])
50
+ .permit(:name, :description, :for_sale, :price, metadata: [tags: []])
52
51
 
53
52
  _params[:name] = _params[:name].strip.squeeze(' ') if _params[:name]
54
53
  _params[:description] = _params[:description].strip.squeeze(' ') if _params[:description]
@@ -70,69 +69,42 @@ The next logical step is extracting those procedures - this is where Paramore st
70
69
  ```ruby
71
70
  # app/controllers/items_controller.rb
72
71
 
73
- declare_params :item_params
74
- item: [:name, :description, :price, metadata: [tags: []]],
75
- format: {
76
- name: :Text,
77
- description: :Text,
78
- for_sale: :Boolean,
79
- price: :Decimal,
80
- metadata: {
81
- tags: :ItemTags
82
- }
83
- }
84
- ```
85
-
86
- ```ruby
87
- # app/formatter/text.rb
88
-
89
- module Formatter::Text
90
- module_function
91
- def run(input)
92
- input.strip.squeeze(' ')
72
+ class ItemsController < ApplicationController
73
+ def create
74
+ Item.create(item_params)
93
75
  end
94
- end
95
- ```
96
- ```ruby
97
- # app/formatter/boolean.rb
98
76
 
99
- module Formatter::Boolean
100
- TRUTHY_TEXT_VALUES = %w[t true 1]
101
-
102
- module_function
103
- def run(input)
104
- input.in?(TRUTHY_TEXT_VALUES)
105
- end
77
+ paramorize :item_params,
78
+ item: {
79
+ name: Paratype[Paramore::SanitizedString],
80
+ description: Paratype[Paramore::StrippedString, null: true],
81
+ for_sale: Paratype[Paramore::Boolean],
82
+ price: Paratype[Paramore::Decimal],
83
+ metadata: Paratype[{
84
+ tags: Paratype[[Types::ItemTag], compact: true]
85
+ }]
86
+ }
106
87
  end
107
88
  ```
108
- ```ruby
109
- # app/formatter/decimal.rb
110
89
 
111
- module Formatter::Decimal
112
- module_function
113
- def run(input)
114
- input.to_d
115
- end
116
- end
117
- ```
90
+ `Types::ItemTag` could be your own type:
118
91
  ```ruby
119
- # app/formatter/item_tags.rb
92
+ # app/types/item_tag.rb
120
93
 
121
- module Formatter::ItemTags
94
+ module Types::ItemTag
122
95
  module_function
123
- def run(input)
124
- input.map { |tag_id| Item.tags[tag_id.to_i] }
96
+ def [](input)
97
+ Item.tags[input.to_i]
125
98
  end
126
99
  end
127
100
  ```
128
101
 
129
-
130
102
  Now, given `params` are:
131
103
  ```ruby
132
104
  <ActionController::Parameters {
133
105
  "unpermitted"=>"parameter",
134
106
  "name"=>"Shoe \n",
135
- "description"=>"Black, with laces",
107
+ "description"=>" Black, with laces",
136
108
  "for_sale"=>"true",
137
109
  "price"=>"39.99",
138
110
  "metadata"=><ActionController::Parameters { "tags"=>["38", "112"] } permitted: false>
@@ -142,7 +114,7 @@ Calling `item_params` will return:
142
114
  ```ruby
143
115
  <ActionController::Parameters {
144
116
  "name"=>"Shoe",
145
- "description"=>"Black, with laces",
117
+ "description"=>"Black, with laces",
146
118
  "for_sale"=>true,
147
119
  "price"=>39.99,
148
120
  "metadata"=><ActionController::Parameters { "tags"=>[:shoe, :new] } permitted: true>
@@ -150,22 +122,30 @@ Calling `item_params` will return:
150
122
  ```
151
123
 
152
124
  This is useful when the values are not used with Rails models, but are passed to simple functions for processing.
153
- The formatters can also be easily reused anywhere in the app,
154
- since they are completely decoupled from Rails.
125
+ The types can also be easily reused anywhere in the app, since they are completely decoupled from Rails.
126
+
127
+ Notice that the `Paramore::StrippedString` does not perform `.squeeze(' ')`, only `Paramore::SanitizedString` does.
128
+
129
+ <h3>nil</h3>
130
+
131
+ Types are non-nullable by default and raise exceptions if the param hash misses any.
132
+ This can be disabled for any type by declaring `Paratype[Paramore::Int, null: true]`.
133
+
134
+ nils will usually not reach any of the type classes - if some parameter is nullable, the class will not be called.
135
+ If a parameter is non-nullable, then a `Paramore::NilParameter` error will be raised before calling the class.
136
+ If a, say, `item_ids` array is non-nullable, but the received parameter is `['1', '', '3']`, only the `'1'` and `'2'` will get passed to type classes, and the resulting array will contain a nil, eg.: `['1', nil, '3']`.
137
+ nils inside arrays can still be passed to type classes by declaring `Paratype[[Paramore::Int], empty: true]`.
138
+ If you wish to get rid of empty array elements, declare `Paratype[Paramore::Int, compact: true]`.
155
139
 
156
140
  <h3>Configuration</h3>
157
141
 
158
142
  Running `$ paramore` will generate a configuration file located in `config/initializers/paramore.rb`.
159
- - `config.formatter_namespace` - default is `Formatter`. Set to `nil` to have top level named formatters
160
- (this also allows specifying the formatter object itself, eg.: `name: Formatter::Text`).
161
- - `config.formatter_method_name` - default is `run`. Don't set to `nil` :D
143
+ - `config.type_method_name` - default is `[]`, to allow using, for example, `SuperString["foo"]` syntax. Note that changing this value will preclude you from using built in types.
162
144
 
163
145
  <h3>Safety</h3>
164
146
 
165
- - Formatters will not be called if their parameter is missing (no key in the param hash)
166
- - Formatters are validated - all given formatter names must match actual modules/classes defined in the app
167
- and must respond to the configured `formatter_method_name`.
168
- This means that all used formatters are loaded when the controller is loaded.
147
+ - Types will not be called if their parameter is missing (no key in the param hash)
148
+ - All given types must respond to the configured `type_method_name` and an error will be raised when controllers are loaded if they don't.
169
149
 
170
150
  # License
171
151
 
data/lib/paramore.rb CHANGED
@@ -1,7 +1,7 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative 'paramore/configuration'
4
2
  require_relative 'paramore/railtie'
3
+ require_relative 'paramore/types'
4
+ require_relative 'paratype'
5
5
 
6
6
  module Paramore
7
7
  class << self
@@ -0,0 +1,65 @@
1
+ require_relative 'errors'
2
+
3
+ module Paramore
4
+ module CastParameters
5
+ module_function
6
+ def run(types_definition, permitted_params)
7
+ recursive_merge(
8
+ recursive_typecast(
9
+ types_definition, permitted_params
10
+ )
11
+ )
12
+ end
13
+
14
+ def recursive_merge(nested_hash_array)
15
+ nested_hash_array.reduce(:merge).map do |param_name, value|
16
+ if value.is_a?(Array) && value.all? { |_value| _value.is_a?(Hash) }
17
+ { param_name => recursive_merge(value) }
18
+ else
19
+ { param_name => value }
20
+ end
21
+ end.reduce(:merge)
22
+ end
23
+
24
+ def recursive_typecast(types_definition, permitted_params)
25
+ types_definition.map do |param_name, definition|
26
+ value = permitted_params[param_name]
27
+
28
+ if value.nil?
29
+ if definition.nullable?
30
+ next { param_name => nil }
31
+ else
32
+ raise Paramore::NilParameter, param_name
33
+ end
34
+ end
35
+
36
+ { param_name => cast(definition, value) }
37
+ end
38
+ end
39
+
40
+ def cast(definition, value)
41
+ case definition.type
42
+ when Hash
43
+ recursive_typecast(definition.type, value || {})
44
+ when Array
45
+ typecast_array(definition, value)
46
+ else
47
+ typecast_value(definition.type, value)
48
+ end
49
+ end
50
+
51
+ def typecast_array(definition, array)
52
+ array
53
+ .reject { |unit| unit.to_s == '' && definition.compact? }
54
+ .map do |unit|
55
+ if unit.to_s != '' || definition.use_empty_strings?
56
+ typecast_value(definition.type.first, unit)
57
+ end
58
+ end
59
+ end
60
+
61
+ def typecast_value(type, value)
62
+ type.send(Paramore.configuration.type_method_name, value)
63
+ end
64
+ end
65
+ end
data/lib/paramore/cli.rb CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Paramore
4
2
  module Cli
5
3
  module_function
@@ -12,15 +10,9 @@ module Paramore
12
10
  end
13
11
 
14
12
  File.write(config_file_path, <<~CONF)
15
- # frozen_string_literal: true
16
-
17
13
  Paramore.configure do |config|
18
- # change this to any level you need, eg.: `'A::B'` for doubly nested formatters
19
- # or `nil` for top level formatters
20
- # config.formatter_namespace = 'Formatter'
21
-
22
- # what method name to call formatters with
23
- # config.formatter_method_name = 'run'
14
+ # what method name to call types with
15
+ # config.type_method_name = :[]
24
16
  end
25
17
  CONF
26
18
 
@@ -1,15 +1,11 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Paramore
4
2
  class Configuration
5
- DEFAULT_FORMATTER_NAMESPACE = 'Formatter'
6
- DEFAULT_FORMATTER_METHOD_NAME = 'run'
3
+ DEFAULT_TYPE_METHOD_NAME = :[]
7
4
 
8
- attr_accessor :formatter_namespace, :formatter_method_name
5
+ attr_accessor :type_method_name
9
6
 
10
7
  def initialize
11
- @formatter_namespace = DEFAULT_FORMATTER_NAMESPACE
12
- @formatter_method_name = DEFAULT_FORMATTER_METHOD_NAME
8
+ @type_method_name = DEFAULT_TYPE_METHOD_NAME
13
9
  end
14
10
  end
15
11
  end
@@ -0,0 +1,11 @@
1
+ class Paramore::NilParameter < StandardError
2
+ def initialize(param_name)
3
+ super("Received a nil `#{param_name}`, but it's type is non nullable!")
4
+ end
5
+ end
6
+
7
+ class Paramore::NonParatype < StandardError
8
+ def initialize(param_name, type)
9
+ super("`#{param_name}` defined as a `#{type.class}`, expected `Paratype`! Perhaps you declared a plain hash instead of Paratype[{}]?")
10
+ end
11
+ end
@@ -1,27 +1,44 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative 'validate'
4
- require_relative 'format'
2
+ require_relative 'cast_parameters'
3
+ require_relative 'permitted_parameter_argument'
5
4
 
6
5
  module Paramore
7
6
  module Extension
8
- def declare_params(accessor_name, param_definition)
9
- format_definition = param_definition.delete(:format)
7
+ def paramorize(accessor_name, parameter_configuration)
8
+ unless parameter_configuration.keys.size == 1
9
+ raise ArgumentError,
10
+ "Paramore: exactly one required attribute allowed! Given: #{param_definition.keys}"
11
+ end
10
12
 
11
- Validate.run(param_definition, format_definition)
13
+ required_parameter_name = parameter_configuration.keys.first
14
+ types_definition = parameter_configuration.values.first
12
15
 
13
- required = param_definition.keys.first
14
- permitted = param_definition.values.first
16
+ Paramore::Validate.run(types_definition) if types_definition.is_a?(Hash)
15
17
 
16
18
  define_method(accessor_name) do |rails_parameters = params|
17
19
  return instance_variable_get("@#{accessor_name}") if instance_variable_defined?("@#{accessor_name}")
18
20
 
19
- permitted_params = rails_parameters.require(required).permit(permitted)
21
+ permitted_parameter_argument =
22
+ if types_definition.is_a?(Hash)
23
+ Paramore::PermittedParameterArgument.parse(types_definition)
24
+ else
25
+ types_definition
26
+ end
27
+
28
+ permitted_params = rails_parameters
29
+ .require(required_parameter_name)
30
+ .permit(permitted_parameter_argument)
31
+
32
+ parameter_values =
33
+ if types_definition.is_a?(Hash)
34
+ permitted_params.merge(
35
+ Paramore::CastParameters.run(types_definition, permitted_params)
36
+ ).permit!
37
+ else
38
+ permitted_params.permit!
39
+ end
20
40
 
21
- instance_variable_set(
22
- "@#{accessor_name}",
23
- permitted_params.merge(Format.run(format_definition, permitted_params)).permit!
24
- )
41
+ instance_variable_set("@#{accessor_name}", parameter_values)
25
42
  end
26
43
  end
27
44
  end
@@ -0,0 +1,37 @@
1
+ module Paramore
2
+ module PermittedParameterArgument
3
+ module_function
4
+
5
+ def parse(types_definition)
6
+ merge_hashes(
7
+ types_definition.map do |key, definition|
8
+ case definition
9
+ when Hash
10
+ { key => merge_hashes(parse(definition)) }
11
+ when Paratype
12
+ case definition.type
13
+ when Array
14
+ { key => [] }
15
+ when Hash
16
+ { key => merge_hashes(parse(definition.type)) }
17
+ else
18
+ key
19
+ end
20
+ end
21
+ end
22
+ )
23
+ end
24
+
25
+ def merge_hashes(parsed)
26
+ (flat_parameters(parsed) + nested_parameters(parsed)).compact
27
+ end
28
+
29
+ def flat_parameters(parsed)
30
+ parsed.select { |arg| arg.is_a?(Symbol) }
31
+ end
32
+
33
+ def nested_parameters(parsed)
34
+ [parsed.reject { |arg| arg.is_a?(Symbol) }.reduce(:merge)]
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative 'extension'
4
2
 
5
3
  return unless defined?(Rails)
@@ -0,0 +1,52 @@
1
+ module Paramore
2
+ module BigDecimal
3
+ module_function
4
+ def [](input)
5
+ BigDecimal(input)
6
+ end
7
+ end
8
+
9
+ module Boolean
10
+ TRUTHY_TEXT_VALUES = %w[t true 1]
11
+
12
+ module_function
13
+ def [](input)
14
+ input.in?(TRUTHY_TEXT_VALUES)
15
+ end
16
+ end
17
+
18
+ module Float
19
+ module_function
20
+ def [](input)
21
+ input.to_f
22
+ end
23
+ end
24
+
25
+ module Int
26
+ module_function
27
+ def [](input)
28
+ input.to_i
29
+ end
30
+ end
31
+
32
+ module String
33
+ module_function
34
+ def [](input)
35
+ input.to_s
36
+ end
37
+ end
38
+
39
+ module StrippedString
40
+ module_function
41
+ def [](input)
42
+ input.to_s.strip
43
+ end
44
+ end
45
+
46
+ module SanitizedString
47
+ module_function
48
+ def [](input)
49
+ Paramore::StrippedString[input].squeeze(' ')
50
+ end
51
+ end
52
+ end
@@ -1,39 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Paramore
4
2
  module Validate
5
3
  module_function
6
- def run(param_definition, format_definition)
7
- unless param_definition.keys.size == 1
8
- raise ArgumentError,
9
- "Paramore: exactly one required attribute allowed! Given: #{param_definition.keys}"
10
- end
11
-
12
- return unless format_definition
13
4
 
14
- formatter_names(format_definition).each do |formatter_name|
15
- formatter =
16
- begin
17
- Paramore::Format.formatter_for(formatter_name)
18
- rescue NameError => e
19
- raise NameError, "Paramore: formatter `#{formatter_name}` is undefined! #{e}"
20
- end
21
-
22
- unless formatter.respond_to?(Paramore.configuration.formatter_method_name)
23
- raise NoMethodError,
24
- "Paramore: formatter `#{formatter_name}` does not respond to " +
25
- "`#{Paramore.configuration.formatter_method_name}`!"
26
- end
5
+ def run(types_definition)
6
+ types(types_definition).each do |type|
7
+ unless type.respond_to?(Paramore.configuration.type_method_name)
8
+ raise NoMethodError,
9
+ "Paramore: type `#{type}` does not respond to " +
10
+ "`#{Paramore.configuration.type_method_name}`!"
11
+ end
27
12
  end
28
13
  end
29
14
 
30
- def formatter_names(format_definition)
31
- format_definition.flat_map do |_, value|
32
- if value.kind_of?(Hash)
33
- formatter_names(value)
34
- else
35
- value
15
+ def types(types_definition)
16
+ types_definition.flat_map do |param_name, paratype|
17
+ unless paratype.is_a?(Paratype)
18
+ raise Paramore::NonParatype.new(param_name, paratype)
36
19
  end
20
+
21
+ paratype.type.is_a?(Hash) ? types(paratype.type) : paratype.type
37
22
  end.uniq
38
23
  end
39
24
  end
data/lib/paratype.rb ADDED
@@ -0,0 +1,32 @@
1
+ class Paratype
2
+ def self.[](given_type, null: false, empty: false, compact: false)
3
+ self.new(given_type, null: null, empty: empty, compact: compact)
4
+ end
5
+
6
+ def initialize(given_type, null:, empty:, compact:)
7
+ @given_type = given_type
8
+ @nullable = null
9
+ @empty = empty
10
+ @compact = compact
11
+ end
12
+
13
+ def compact?
14
+ compact
15
+ end
16
+
17
+ def nullable?
18
+ nullable
19
+ end
20
+
21
+ def use_empty_strings?
22
+ empty
23
+ end
24
+
25
+ def type
26
+ given_type
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :given_type, :nullable, :empty, :compact
32
+ end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paramore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lukas Kairevičius
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-09 00:00:00.000000000 Z
11
+ date: 2021-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rspec
14
+ name: rspec-rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: combustion
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rails
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -54,7 +68,7 @@ dependencies:
54
68
  version: '5.0'
55
69
  description: |
56
70
  Paramore lets you declare which parameters are permitted and what object is responsible
57
- for formatting/sanitizing/type-casting them before they passed along to your models/processors.
71
+ for typing/sanitizing/type-casting them before they are passed along to your models/domain.
58
72
  It is intended to reduce the amount of imperative code in controllers.
59
73
  email: lukas.kairevicius9@gmail.com
60
74
  executables:
@@ -66,18 +80,22 @@ files:
66
80
  - README.md
67
81
  - bin/paramore
68
82
  - lib/paramore.rb
83
+ - lib/paramore/cast_parameters.rb
69
84
  - lib/paramore/cli.rb
70
85
  - lib/paramore/configuration.rb
86
+ - lib/paramore/errors.rb
71
87
  - lib/paramore/extension.rb
72
- - lib/paramore/format.rb
88
+ - lib/paramore/permitted_parameter_argument.rb
73
89
  - lib/paramore/railtie.rb
90
+ - lib/paramore/types.rb
74
91
  - lib/paramore/validate.rb
92
+ - lib/paratype.rb
75
93
  homepage: https://github.com/lumzdas/paramore
76
94
  licenses:
77
95
  - MIT
78
96
  metadata: {}
79
97
  post_install_message: |
80
- Thank you for installing Paramore 0.2.0 !
98
+ Thank you for installing Paramore 1.0.1 !
81
99
  From the command line you can run `paramore` to generate a configuration file
82
100
 
83
101
  More details here : https://github.com/lumzdas/paramore/blob/master/README.md
@@ -96,8 +114,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
114
  - !ruby/object:Gem::Version
97
115
  version: '0'
98
116
  requirements: []
99
- rubygems_version: 3.0.3
117
+ rubygems_version: 3.0.8
100
118
  signing_key:
101
119
  specification_version: 4
102
- summary: A declarative approach to Rails' strong parameter formatting and sanitizing
120
+ summary: A declarative approach to Rails' strong parameter typing and sanitizing
103
121
  test_files: []
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Paramore
4
- module Format
5
- module_function
6
- def run(format_definition, permitted_params)
7
- return {} unless format_definition
8
-
9
- recursive_merge(
10
- recursive_format(
11
- format_definition, permitted_params
12
- )
13
- )
14
- end
15
-
16
- def recursive_merge(nested_hash_array)
17
- nested_hash_array.reduce(:merge).map do |param_name, value|
18
- if value.kind_of?(Array) && value.all? { |_value| _value.kind_of?(Hash) }
19
- { param_name => recursive_merge(value) }
20
- else
21
- { param_name => value }
22
- end
23
- end.reduce(:merge)
24
- end
25
-
26
- def recursive_format(format_definition, permitted_params)
27
- format_definition.map do |param_name, value|
28
- next {} unless permitted_params[param_name]
29
-
30
- if value.kind_of?(Hash)
31
- { param_name => recursive_format(value, permitted_params[param_name]) }
32
- else
33
- { param_name => formatted_value(permitted_params[param_name], formatter_for(value)) }
34
- end
35
- end
36
- end
37
-
38
- def formatted_value(value, formatter)
39
- formatter.send(Paramore.configuration.formatter_method_name, value)
40
- end
41
-
42
- def formatter_for(formatter_name)
43
- Object.const_get(
44
- [Paramore.configuration.formatter_namespace, formatter_name].compact.join('::'),
45
- false # inherit=false - only get exact match
46
- )
47
- end
48
- end
49
- end