paramore 1.0.2 → 3.0.0
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 +4 -4
- data/README.md +16 -17
- data/lib/paramore/cast_parameters.rb +24 -34
- data/lib/paramore/errors.rb +2 -2
- data/lib/paramore/extension.rb +19 -10
- data/lib/paramore/field.rb +32 -0
- data/lib/paramore/permitted_parameter_argument.rb +16 -12
- data/lib/paramore/validate.rb +17 -8
- data/lib/paramore.rb +8 -1
- metadata +12 -6
- data/lib/paratype.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f6231e51cfe1acb4969ec05739c8386d6c772d5df241dee728fa2428e6bfc2a
|
4
|
+
data.tar.gz: 7bc786c9b1a163b1bcc6774c8a709d68e80b36cca3c69c6d501f98084d6538e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1665184eba554c3216a5d8185535695dcfbb9e5ce5a38559acac184130ee4f7787065ac72445c258873a7479ac1c2ecaab34f6a68b65f607da6b96542a317a0c
|
7
|
+
data.tar.gz: 834d1432f9958709891ccd285280d4dd7f21caab56c1aa7d88d5178a4ef7745d0c5340553d346fbd32d4f17a6d525fd3e872c399640820940ef8830fca34ec99
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Paramore
|
2
2
|
|
3
|
-
Paramore
|
4
|
-
|
3
|
+
Paramore allows you to declare a typed schema for your params,
|
4
|
+
so that any downstream code can work with the data it expects.
|
5
5
|
|
6
6
|
# Installation
|
7
7
|
|
@@ -20,7 +20,7 @@ $ bundle
|
|
20
20
|
<h3>Without typing</h3>
|
21
21
|
|
22
22
|
```ruby
|
23
|
-
|
23
|
+
param_schema :item_params,
|
24
24
|
item: [:name, :description, :for_sale, :price, metadata: [tags: []]]
|
25
25
|
```
|
26
26
|
|
@@ -74,16 +74,16 @@ class ItemsController < ApplicationController
|
|
74
74
|
Item.create(item_params)
|
75
75
|
end
|
76
76
|
|
77
|
-
|
78
|
-
item: {
|
79
|
-
name:
|
80
|
-
description:
|
81
|
-
for_sale:
|
82
|
-
price:
|
83
|
-
metadata:
|
84
|
-
tags:
|
85
|
-
}
|
86
|
-
}
|
77
|
+
param_schema :item_params,
|
78
|
+
item: Paramore.field({
|
79
|
+
name: Paramore.field(Paramore::SanitizedString),
|
80
|
+
description: Paramore.field(Paramore::StrippedString, null: true),
|
81
|
+
for_sale: Paramore.field(Paramore::Boolean, default: false),
|
82
|
+
price: Paramore.field(Paramore::Decimal),
|
83
|
+
metadata: Paramore.field({
|
84
|
+
tags: Paramore.field([Types::ItemTag], compact: true)
|
85
|
+
})
|
86
|
+
})
|
87
87
|
end
|
88
88
|
```
|
89
89
|
|
@@ -129,13 +129,12 @@ Notice that the `Paramore::StrippedString` does not perform `.squeeze(' ')`, onl
|
|
129
129
|
<h3>nil</h3>
|
130
130
|
|
131
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 `
|
132
|
+
This can be disabled for any type by declaring `Paramore.field(Paramore::Int, null: true)`.
|
133
133
|
|
134
134
|
nils will usually not reach any of the type classes - if some parameter is nullable, the class will not be called.
|
135
135
|
If a parameter is non-nullable, then a `Paramore::NilParameter` error will be raised before calling the class.
|
136
|
-
If
|
137
|
-
|
138
|
-
If you wish to get rid of empty array elements, declare `Paratype[Paramore::Int, compact: true]`.
|
136
|
+
If an incoming array contains nils, they will get passed to type classes.
|
137
|
+
If you wish to get rid of empty array elements, declare `Paramore.field(Paramore::Int, compact: true)`.
|
139
138
|
|
140
139
|
<h3>Configuration</h3>
|
141
140
|
|
@@ -3,59 +3,49 @@ require_relative 'errors'
|
|
3
3
|
module Paramore
|
4
4
|
module CastParameters
|
5
5
|
module_function
|
6
|
-
def run(
|
7
|
-
recursive_merge(
|
8
|
-
recursive_typecast(
|
9
|
-
types_definition, permitted_params
|
10
|
-
)
|
11
|
-
)
|
6
|
+
def run(field, data)
|
7
|
+
recursive_merge(cast(field, data, 'data'))
|
12
8
|
end
|
13
9
|
|
14
10
|
def recursive_merge(nested_hash_array)
|
15
|
-
nested_hash_array.reduce(:merge).map do |
|
11
|
+
nested_hash_array.reduce(:merge).map do |name, value|
|
16
12
|
if value.is_a?(Array) && value.all? { |_value| _value.is_a?(Hash) }
|
17
|
-
{
|
13
|
+
{ name => recursive_merge(value) }
|
18
14
|
else
|
19
|
-
{
|
15
|
+
{ name => value }
|
20
16
|
end
|
21
17
|
end.reduce(:merge)
|
22
18
|
end
|
23
19
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
next { param_name => nil }
|
31
|
-
else
|
32
|
-
raise Paramore::NilParameter, param_name
|
33
|
-
end
|
20
|
+
def cast(field, value, name = nil)
|
21
|
+
if value.nil?
|
22
|
+
if field.nullable? || field.default
|
23
|
+
return field.default
|
24
|
+
else
|
25
|
+
raise Paramore::NilParameter, name
|
34
26
|
end
|
35
|
-
|
36
|
-
{ param_name => cast(definition, value) }
|
37
27
|
end
|
38
|
-
end
|
39
28
|
|
40
|
-
|
41
|
-
case definition.type
|
29
|
+
case field.type
|
42
30
|
when Hash
|
43
|
-
|
31
|
+
typecast_hash(field.type, value || {})
|
44
32
|
when Array
|
45
|
-
typecast_array(
|
33
|
+
typecast_array(field, value)
|
46
34
|
else
|
47
|
-
typecast_value(
|
35
|
+
typecast_value(field.type, value)
|
48
36
|
end
|
49
37
|
end
|
50
38
|
|
51
|
-
def
|
39
|
+
def typecast_hash(field, hash)
|
40
|
+
field.map do |name, field|
|
41
|
+
{ name => cast(field, hash[name], name) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def typecast_array(field, array)
|
52
46
|
array
|
53
|
-
.reject { |unit| unit.to_s == '' &&
|
54
|
-
.map
|
55
|
-
if unit.to_s != '' || definition.use_empty_strings?
|
56
|
-
typecast_value(definition.type.first, unit)
|
57
|
-
end
|
58
|
-
end
|
47
|
+
.reject { |unit| unit.to_s == '' && field.compact? }
|
48
|
+
.map { |unit| typecast_value(field.type.first, unit) }
|
59
49
|
end
|
60
50
|
|
61
51
|
def typecast_value(type, value)
|
data/lib/paramore/errors.rb
CHANGED
@@ -4,8 +4,8 @@ class Paramore::NilParameter < StandardError
|
|
4
4
|
end
|
5
5
|
end
|
6
6
|
|
7
|
-
class Paramore::
|
7
|
+
class Paramore::NonField < StandardError
|
8
8
|
def initialize(param_name, type)
|
9
|
-
super("`#{param_name}` defined as a `#{type.class}`, expected `
|
9
|
+
super("`#{param_name}` defined as a `#{type.class}`, expected a call of `Paramore.field()`! Perhaps you declared a plain hash instead of Paramore.field({})?")
|
10
10
|
end
|
11
11
|
end
|
data/lib/paramore/extension.rb
CHANGED
@@ -4,33 +4,42 @@ require_relative 'permitted_parameter_argument'
|
|
4
4
|
|
5
5
|
module Paramore
|
6
6
|
module Extension
|
7
|
-
|
7
|
+
OPTIONS = %i[
|
8
|
+
default
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
def param_schema(accessor_name, parameter_configuration)
|
8
12
|
unless parameter_configuration.keys.size == 1
|
9
13
|
raise ArgumentError,
|
10
|
-
"Paramore: exactly one required attribute allowed! Given: #{
|
14
|
+
"Paramore: exactly one required attribute allowed! Given: #{parameter_configuration.keys}"
|
11
15
|
end
|
12
16
|
|
13
17
|
required_parameter_name = parameter_configuration.keys.first
|
14
18
|
types_definition = parameter_configuration.values.first
|
15
19
|
|
16
|
-
Paramore::Validate.run(types_definition) if types_definition.is_a?(
|
20
|
+
Paramore::Validate.run(types_definition) if types_definition.is_a?(Paramore::Field)
|
21
|
+
|
22
|
+
permitted_parameter_argument =
|
23
|
+
if types_definition.is_a?(Paramore::Field)
|
24
|
+
Paramore::PermittedParameterArgument.parse(types_definition)
|
25
|
+
else
|
26
|
+
types_definition
|
27
|
+
end
|
17
28
|
|
18
29
|
define_method(accessor_name) do |rails_parameters = params|
|
19
30
|
return instance_variable_get("@#{accessor_name}") if instance_variable_defined?("@#{accessor_name}")
|
20
31
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
types_definition
|
26
|
-
end
|
32
|
+
if rails_parameters[required_parameter_name].nil? && types_definition.default
|
33
|
+
instance_variable_set("@#{accessor_name}", types_definition.default)
|
34
|
+
return instance_variable_get("@#{accessor_name}")
|
35
|
+
end
|
27
36
|
|
28
37
|
permitted_params = rails_parameters
|
29
38
|
.require(required_parameter_name)
|
30
39
|
.permit(permitted_parameter_argument)
|
31
40
|
|
32
41
|
parameter_values =
|
33
|
-
if types_definition.is_a?(
|
42
|
+
if types_definition.is_a?(Paramore::Field)
|
34
43
|
permitted_params.merge(
|
35
44
|
Paramore::CastParameters.run(types_definition, permitted_params)
|
36
45
|
).permit!
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Paramore
|
2
|
+
class Field
|
3
|
+
DEFAULT_OPTIONS = {
|
4
|
+
null: false,
|
5
|
+
compact: false,
|
6
|
+
default: nil,
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
def initialize(given_type, null:, compact:, default:)
|
10
|
+
@given_type = given_type
|
11
|
+
@nullable = null
|
12
|
+
@compact = compact
|
13
|
+
@default = default
|
14
|
+
end
|
15
|
+
|
16
|
+
def default
|
17
|
+
@default
|
18
|
+
end
|
19
|
+
|
20
|
+
def compact?
|
21
|
+
@compact
|
22
|
+
end
|
23
|
+
|
24
|
+
def nullable?
|
25
|
+
@nullable
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
@given_type
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -2,22 +2,26 @@ module Paramore
|
|
2
2
|
module PermittedParameterArgument
|
3
3
|
module_function
|
4
4
|
|
5
|
-
def parse(
|
5
|
+
def parse(field)
|
6
|
+
parse_type(field.type)
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_type(type)
|
6
10
|
merge_hashes(
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
case
|
13
|
-
when Array
|
14
|
-
{
|
15
|
-
when Hash
|
16
|
-
{ key => merge_hashes(parse(definition.type)) }
|
11
|
+
case type
|
12
|
+
when Array
|
13
|
+
parse_type(type.first)
|
14
|
+
when Hash
|
15
|
+
type.map do |name, field|
|
16
|
+
case field.type
|
17
|
+
when Array, Hash
|
18
|
+
{ name => parse_type(field.type) }
|
17
19
|
else
|
18
|
-
|
20
|
+
name
|
19
21
|
end
|
20
22
|
end
|
23
|
+
else
|
24
|
+
[]
|
21
25
|
end
|
22
26
|
)
|
23
27
|
end
|
data/lib/paramore/validate.rb
CHANGED
@@ -2,8 +2,8 @@ module Paramore
|
|
2
2
|
module Validate
|
3
3
|
module_function
|
4
4
|
|
5
|
-
def run(
|
6
|
-
types(
|
5
|
+
def run(root_field)
|
6
|
+
types(root_field.type).uniq.each do |type|
|
7
7
|
unless type.respond_to?(Paramore.configuration.type_method_name)
|
8
8
|
raise NoMethodError,
|
9
9
|
"Paramore: type `#{type}` does not respond to " +
|
@@ -12,13 +12,22 @@ module Paramore
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
def types(
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
def types(type)
|
16
|
+
case type
|
17
|
+
when Hash
|
18
|
+
hash_types(type)
|
19
|
+
when Array
|
20
|
+
type.flat_map { |subtype| types(subtype) }
|
21
|
+
else
|
22
|
+
[type]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def hash_types(hash)
|
27
|
+
hash.flat_map do |param_name, field|
|
28
|
+
raise Paramore::NonField.new(param_name, field) unless field.is_a?(Paramore::Field)
|
20
29
|
|
21
|
-
|
30
|
+
field.type.is_a?(Hash) ? types(field.type) : field.type
|
22
31
|
end.uniq
|
23
32
|
end
|
24
33
|
end
|
data/lib/paramore.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative 'paramore/configuration'
|
2
2
|
require_relative 'paramore/railtie'
|
3
3
|
require_relative 'paramore/types'
|
4
|
-
require_relative '
|
4
|
+
require_relative 'paramore/field'
|
5
5
|
|
6
6
|
module Paramore
|
7
7
|
class << self
|
@@ -15,4 +15,11 @@ module Paramore
|
|
15
15
|
def self.configure
|
16
16
|
yield(configuration)
|
17
17
|
end
|
18
|
+
|
19
|
+
def self.field(given_type, options = {})
|
20
|
+
Paramore::Field.new(
|
21
|
+
given_type,
|
22
|
+
**Paramore::Field::DEFAULT_OPTIONS.merge(options)
|
23
|
+
)
|
24
|
+
end
|
18
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paramore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.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: 2021-
|
11
|
+
date: 2021-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec-rails
|
@@ -56,16 +56,22 @@ dependencies:
|
|
56
56
|
name: rails
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '5.0'
|
62
|
+
- - "<"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '7'
|
62
65
|
type: :runtime
|
63
66
|
prerelease: false
|
64
67
|
version_requirements: !ruby/object:Gem::Requirement
|
65
68
|
requirements:
|
66
|
-
- - "
|
69
|
+
- - ">="
|
67
70
|
- !ruby/object:Gem::Version
|
68
71
|
version: '5.0'
|
72
|
+
- - "<"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '7'
|
69
75
|
description: |
|
70
76
|
Paramore lets you declare which parameters are permitted and what object is responsible
|
71
77
|
for typing/sanitizing/type-casting them before they are passed along to your models/domain.
|
@@ -85,17 +91,17 @@ files:
|
|
85
91
|
- lib/paramore/configuration.rb
|
86
92
|
- lib/paramore/errors.rb
|
87
93
|
- lib/paramore/extension.rb
|
94
|
+
- lib/paramore/field.rb
|
88
95
|
- lib/paramore/permitted_parameter_argument.rb
|
89
96
|
- lib/paramore/railtie.rb
|
90
97
|
- lib/paramore/types.rb
|
91
98
|
- lib/paramore/validate.rb
|
92
|
-
- lib/paratype.rb
|
93
99
|
homepage: https://github.com/lumzdas/paramore
|
94
100
|
licenses:
|
95
101
|
- MIT
|
96
102
|
metadata: {}
|
97
103
|
post_install_message: |
|
98
|
-
Thank you for installing Paramore
|
104
|
+
Thank you for installing Paramore 3.0.0 !
|
99
105
|
From the command line you can run `paramore` to generate a configuration file
|
100
106
|
|
101
107
|
More details here : https://github.com/lumzdas/paramore/blob/master/README.md
|
data/lib/paratype.rb
DELETED
@@ -1,32 +0,0 @@
|
|
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
|