paramore 0.2.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +44 -64
- data/lib/paramore/cast_parameters.rb +65 -0
- data/lib/paramore/cli.rb +2 -10
- data/lib/paramore/configuration.rb +3 -7
- data/lib/paramore/errors.rb +11 -0
- data/lib/paramore/extension.rb +41 -13
- data/lib/paramore/permitted_parameter_argument.rb +37 -0
- data/lib/paramore/railtie.rb +0 -2
- data/lib/paramore/types.rb +52 -0
- data/lib/paramore/validate.rb +13 -28
- data/lib/paramore.rb +2 -2
- data/lib/paratype.rb +32 -0
- metadata +34 -10
- data/lib/paramore/format.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a45a04ffeaabb270fd7b57a2e27e195205a26ad281c46d69561040d71fb6961
|
4
|
+
data.tar.gz: 0df60483be44946c6e1fedb711039d5a915787c54e46c5f841c73172393e35f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0f3ed2da9f139467f5d4f6db3d7cbc7f0b29c3c1385a4eb8835d0cbffced915d0c77700d69722d11807984624e611856b2acd36462fe6ea4cb577736f8c6255
|
7
|
+
data.tar.gz: decf8bc3cbaa99c75ce7070b59f58f4e84d5cd0b3d22681836ae56f61596a600f3777e58c929d9db31a698689ea07a7b00330d45f54a9706262b512734b07393
|
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
|
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
|
20
|
+
<h3>Without typing</h3>
|
22
21
|
|
23
22
|
```ruby
|
24
|
-
|
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
|
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
|
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
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
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/
|
92
|
+
# app/types/item_tag.rb
|
120
93
|
|
121
|
-
module
|
94
|
+
module Types::ItemTag
|
122
95
|
module_function
|
123
|
-
def
|
124
|
-
|
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,
|
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
|
154
|
-
|
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.
|
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
|
-
-
|
166
|
-
-
|
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
|
|
@@ -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
|
-
#
|
19
|
-
#
|
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
|
-
|
6
|
-
DEFAULT_FORMATTER_METHOD_NAME = 'run'
|
3
|
+
DEFAULT_TYPE_METHOD_NAME = :[]
|
7
4
|
|
8
|
-
attr_accessor :
|
5
|
+
attr_accessor :type_method_name
|
9
6
|
|
10
7
|
def initialize
|
11
|
-
@
|
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
|
data/lib/paramore/extension.rb
CHANGED
@@ -1,27 +1,55 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require_relative 'validate'
|
4
|
-
require_relative '
|
2
|
+
require_relative 'cast_parameters'
|
3
|
+
require_relative 'permitted_parameter_argument'
|
5
4
|
|
6
5
|
module Paramore
|
7
6
|
module Extension
|
8
|
-
|
9
|
-
|
7
|
+
OPTIONS = %i[
|
8
|
+
default
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
def paramorize(accessor_name, configuration)
|
12
|
+
parameter_configuration = configuration.except(*OPTIONS)
|
13
|
+
|
14
|
+
unless parameter_configuration.keys.size == 1
|
15
|
+
raise ArgumentError,
|
16
|
+
"Paramore: exactly one required attribute allowed! Given: #{parameter_configuration.keys}"
|
17
|
+
end
|
10
18
|
|
11
|
-
|
19
|
+
required_parameter_name = parameter_configuration.keys.first
|
20
|
+
types_definition = parameter_configuration.values.first
|
12
21
|
|
13
|
-
|
14
|
-
|
22
|
+
Paramore::Validate.run(types_definition) if types_definition.is_a?(Hash)
|
23
|
+
|
24
|
+
permitted_parameter_argument =
|
25
|
+
if types_definition.is_a?(Hash)
|
26
|
+
Paramore::PermittedParameterArgument.parse(types_definition)
|
27
|
+
else
|
28
|
+
types_definition
|
29
|
+
end
|
15
30
|
|
16
31
|
define_method(accessor_name) do |rails_parameters = params|
|
17
32
|
return instance_variable_get("@#{accessor_name}") if instance_variable_defined?("@#{accessor_name}")
|
18
33
|
|
19
|
-
|
34
|
+
if rails_parameters[required_parameter_name].nil? && configuration[:default]
|
35
|
+
instance_variable_set("@#{accessor_name}", configuration[:default])
|
36
|
+
return instance_variable_get("@#{accessor_name}")
|
37
|
+
end
|
38
|
+
|
39
|
+
permitted_params = rails_parameters
|
40
|
+
.require(required_parameter_name)
|
41
|
+
.permit(permitted_parameter_argument)
|
42
|
+
|
43
|
+
parameter_values =
|
44
|
+
if types_definition.is_a?(Hash)
|
45
|
+
permitted_params.merge(
|
46
|
+
Paramore::CastParameters.run(types_definition, permitted_params)
|
47
|
+
).permit!
|
48
|
+
else
|
49
|
+
permitted_params.permit!
|
50
|
+
end
|
20
51
|
|
21
|
-
instance_variable_set(
|
22
|
-
"@#{accessor_name}",
|
23
|
-
permitted_params.merge(Format.run(format_definition, permitted_params)).permit!
|
24
|
-
)
|
52
|
+
instance_variable_set("@#{accessor_name}", parameter_values)
|
25
53
|
end
|
26
54
|
end
|
27
55
|
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
|
data/lib/paramore/railtie.rb
CHANGED
@@ -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
|
data/lib/paramore/validate.rb
CHANGED
@@ -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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
31
|
-
|
32
|
-
|
33
|
-
|
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/paramore.rb
CHANGED
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:
|
4
|
+
version: 1.1.0
|
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:
|
11
|
+
date: 2021-08-27 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
|
- - "~>"
|
@@ -39,22 +39,42 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: combustion
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
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'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
46
60
|
- !ruby/object:Gem::Version
|
47
61
|
version: '5.0'
|
62
|
+
- - "<"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '7'
|
48
65
|
type: :runtime
|
49
66
|
prerelease: false
|
50
67
|
version_requirements: !ruby/object:Gem::Requirement
|
51
68
|
requirements:
|
52
|
-
- - "
|
69
|
+
- - ">="
|
53
70
|
- !ruby/object:Gem::Version
|
54
71
|
version: '5.0'
|
72
|
+
- - "<"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '7'
|
55
75
|
description: |
|
56
76
|
Paramore lets you declare which parameters are permitted and what object is responsible
|
57
|
-
for
|
77
|
+
for typing/sanitizing/type-casting them before they are passed along to your models/domain.
|
58
78
|
It is intended to reduce the amount of imperative code in controllers.
|
59
79
|
email: lukas.kairevicius9@gmail.com
|
60
80
|
executables:
|
@@ -66,18 +86,22 @@ files:
|
|
66
86
|
- README.md
|
67
87
|
- bin/paramore
|
68
88
|
- lib/paramore.rb
|
89
|
+
- lib/paramore/cast_parameters.rb
|
69
90
|
- lib/paramore/cli.rb
|
70
91
|
- lib/paramore/configuration.rb
|
92
|
+
- lib/paramore/errors.rb
|
71
93
|
- lib/paramore/extension.rb
|
72
|
-
- lib/paramore/
|
94
|
+
- lib/paramore/permitted_parameter_argument.rb
|
73
95
|
- lib/paramore/railtie.rb
|
96
|
+
- lib/paramore/types.rb
|
74
97
|
- lib/paramore/validate.rb
|
98
|
+
- lib/paratype.rb
|
75
99
|
homepage: https://github.com/lumzdas/paramore
|
76
100
|
licenses:
|
77
101
|
- MIT
|
78
102
|
metadata: {}
|
79
103
|
post_install_message: |
|
80
|
-
Thank you for installing Paramore
|
104
|
+
Thank you for installing Paramore 1.1.0 !
|
81
105
|
From the command line you can run `paramore` to generate a configuration file
|
82
106
|
|
83
107
|
More details here : https://github.com/lumzdas/paramore/blob/master/README.md
|
@@ -96,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
120
|
- !ruby/object:Gem::Version
|
97
121
|
version: '0'
|
98
122
|
requirements: []
|
99
|
-
rubygems_version: 3.0.
|
123
|
+
rubygems_version: 3.0.8
|
100
124
|
signing_key:
|
101
125
|
specification_version: 4
|
102
|
-
summary: A declarative approach to Rails' strong parameter
|
126
|
+
summary: A declarative approach to Rails' strong parameter typing and sanitizing
|
103
127
|
test_files: []
|
data/lib/paramore/format.rb
DELETED
@@ -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
|