paramore 1.1.0 → 3.1.1

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: 2a45a04ffeaabb270fd7b57a2e27e195205a26ad281c46d69561040d71fb6961
4
- data.tar.gz: 0df60483be44946c6e1fedb711039d5a915787c54e46c5f841c73172393e35f9
3
+ metadata.gz: fb73686fb48a297c559c211476f565f8aba18a2e93a10936b75cacd4eab2bcb2
4
+ data.tar.gz: df12fd5715e1c4e3851a1ed2f9748f24cccec9d9ccc817c7b6ba74960370f426
5
5
  SHA512:
6
- metadata.gz: f0f3ed2da9f139467f5d4f6db3d7cbc7f0b29c3c1385a4eb8835d0cbffced915d0c77700d69722d11807984624e611856b2acd36462fe6ea4cb577736f8c6255
7
- data.tar.gz: decf8bc3cbaa99c75ce7070b59f58f4e84d5cd0b3d22681836ae56f61596a600f3777e58c929d9db31a698689ea07a7b00330d45f54a9706262b512734b07393
6
+ metadata.gz: 5d7f2e6f52065f18ebb5b7d51577950ceb234db5f5a21fd3a20fdb987066c451da22beda1bc86a4101ad9bfaf4ccf195a38b1281b02c92c4d8cc2d1fa6602958
7
+ data.tar.gz: b5dd8ae054488a628c580924cfdfb0355ef063a43eb7e46fe249ae9ecad62a4a80d5603b4eed182d1b69c1d691926c97165c605b11d05eec4b5ed66efbc3cac3
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Paramore
2
2
 
3
- Paramore is a small gem intended to make strong parameter definitions declarative
4
- and provide a unified way to typecast and sanitize their values outside of controllers.
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
- paramorize :item_params,
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
- 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
- }
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 `Paratype[Paramore::Int, null: true]`.
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 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]`.
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,58 +3,38 @@ require_relative 'errors'
3
3
  module Paramore
4
4
  module CastParameters
5
5
  module_function
6
- def run(types_definition, permitted_params)
7
- recursive_merge(
8
- recursive_typecast(
9
- types_definition, permitted_params
10
- )
11
- )
6
+ def run(field, data)
7
+ cast(field, data, 'data')
12
8
  end
13
9
 
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) }
10
+ def cast(field, value, name = nil)
11
+ if value.nil?
12
+ if field.nullable? || field.default
13
+ return field.default
18
14
  else
19
- { param_name => value }
15
+ raise Paramore::NilParameter, name
20
16
  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
17
  end
38
- end
39
18
 
40
- def cast(definition, value)
41
- case definition.type
19
+ case field.type
42
20
  when Hash
43
- recursive_typecast(definition.type, value || {})
21
+ typecast_hash(field.type, value || {})
44
22
  when Array
45
- typecast_array(definition, value)
23
+ typecast_array(field, value)
46
24
  else
47
- typecast_value(definition.type, value)
25
+ typecast_value(field.type, value)
48
26
  end
49
27
  end
50
28
 
51
- def typecast_array(definition, array)
29
+ def typecast_hash(field, hash)
30
+ field.to_h { |name, field| [name, cast(field, hash[name], name)] }
31
+ end
32
+
33
+ def typecast_array(field, array)
52
34
  array
53
- .reject { |unit| unit.to_s == '' && definition.compact? }
35
+ .reject { |unit| unit.to_s == '' && field.compact? }
54
36
  .map do |unit|
55
- if unit.to_s != '' || definition.use_empty_strings?
56
- typecast_value(definition.type.first, unit)
57
- end
37
+ cast(Paramore.field(field.type.first, null: true), unit)
58
38
  end
59
39
  end
60
40
 
@@ -4,8 +4,8 @@ class Paramore::NilParameter < StandardError
4
4
  end
5
5
  end
6
6
 
7
- class Paramore::NonParatype < StandardError
7
+ class Paramore::NonField < StandardError
8
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[{}]?")
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
@@ -8,9 +8,7 @@ module Paramore
8
8
  default
9
9
  ].freeze
10
10
 
11
- def paramorize(accessor_name, configuration)
12
- parameter_configuration = configuration.except(*OPTIONS)
13
-
11
+ def param_schema(accessor_name, parameter_configuration)
14
12
  unless parameter_configuration.keys.size == 1
15
13
  raise ArgumentError,
16
14
  "Paramore: exactly one required attribute allowed! Given: #{parameter_configuration.keys}"
@@ -19,10 +17,10 @@ module Paramore
19
17
  required_parameter_name = parameter_configuration.keys.first
20
18
  types_definition = parameter_configuration.values.first
21
19
 
22
- Paramore::Validate.run(types_definition) if types_definition.is_a?(Hash)
20
+ Paramore::Validate.run(types_definition) if types_definition.is_a?(Paramore::Field)
23
21
 
24
22
  permitted_parameter_argument =
25
- if types_definition.is_a?(Hash)
23
+ if types_definition.is_a?(Paramore::Field)
26
24
  Paramore::PermittedParameterArgument.parse(types_definition)
27
25
  else
28
26
  types_definition
@@ -31,8 +29,8 @@ module Paramore
31
29
  define_method(accessor_name) do |rails_parameters = params|
32
30
  return instance_variable_get("@#{accessor_name}") if instance_variable_defined?("@#{accessor_name}")
33
31
 
34
- if rails_parameters[required_parameter_name].nil? && configuration[:default]
35
- instance_variable_set("@#{accessor_name}", configuration[:default])
32
+ if rails_parameters[required_parameter_name].nil? && types_definition.default
33
+ instance_variable_set("@#{accessor_name}", types_definition.default)
36
34
  return instance_variable_get("@#{accessor_name}")
37
35
  end
38
36
 
@@ -41,7 +39,7 @@ module Paramore
41
39
  .permit(permitted_parameter_argument)
42
40
 
43
41
  parameter_values =
44
- if types_definition.is_a?(Hash)
42
+ if types_definition.is_a?(Paramore::Field)
45
43
  permitted_params.merge(
46
44
  Paramore::CastParameters.run(types_definition, permitted_params)
47
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(types_definition)
5
+ def parse(field)
6
+ parse_type(field.type)
7
+ end
8
+
9
+ def parse_type(type)
6
10
  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)) }
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
- key
20
+ name
19
21
  end
20
22
  end
23
+ else
24
+ []
21
25
  end
22
26
  )
23
27
  end
@@ -2,23 +2,34 @@ module Paramore
2
2
  module Validate
3
3
  module_function
4
4
 
5
- def run(types_definition)
6
- types(types_definition).each do |type|
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 " +
10
10
  "`#{Paramore.configuration.type_method_name}`!"
11
11
  end
12
12
  end
13
+
14
+ root_field
13
15
  end
14
16
 
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)
19
- end
17
+ def types(type)
18
+ case type
19
+ when Hash
20
+ hash_types(type)
21
+ when Array
22
+ type.flat_map { |subtype| types(subtype) }
23
+ else
24
+ [type]
25
+ end
26
+ end
27
+
28
+ def hash_types(hash)
29
+ hash.flat_map do |param_name, field|
30
+ raise Paramore::NonField.new(param_name, field) unless field.is_a?(Paramore::Field)
20
31
 
21
- paratype.type.is_a?(Hash) ? types(paratype.type) : paratype.type
32
+ field.type.is_a?(Hash) ? types(field.type) : field.type
22
33
  end.uniq
23
34
  end
24
35
  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 'paratype'
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: 1.1.0
4
+ version: 3.1.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: 2021-08-27 00:00:00.000000000 Z
11
+ date: 2021-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-rails
@@ -91,17 +91,17 @@ files:
91
91
  - lib/paramore/configuration.rb
92
92
  - lib/paramore/errors.rb
93
93
  - lib/paramore/extension.rb
94
+ - lib/paramore/field.rb
94
95
  - lib/paramore/permitted_parameter_argument.rb
95
96
  - lib/paramore/railtie.rb
96
97
  - lib/paramore/types.rb
97
98
  - lib/paramore/validate.rb
98
- - lib/paratype.rb
99
99
  homepage: https://github.com/lumzdas/paramore
100
100
  licenses:
101
101
  - MIT
102
102
  metadata: {}
103
103
  post_install_message: |
104
- Thank you for installing Paramore 1.1.0 !
104
+ Thank you for installing Paramore 3.1.1 !
105
105
  From the command line you can run `paramore` to generate a configuration file
106
106
 
107
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