paramore 1.0.2 → 3.0.0

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: 78a77466a7f6ac56ded5b60abc47444b7b922ac84f56641900800fbf6f4baeb7
4
- data.tar.gz: b70caca4654067991e12eead85b235209b0690908a80b6afbb8eb2001d45c51f
3
+ metadata.gz: 7f6231e51cfe1acb4969ec05739c8386d6c772d5df241dee728fa2428e6bfc2a
4
+ data.tar.gz: 7bc786c9b1a163b1bcc6774c8a709d68e80b36cca3c69c6d501f98084d6538e9
5
5
  SHA512:
6
- metadata.gz: 5e888539e7933c6b7d339e564e7d6ed6904b9c3aae715f7c533463b25c6ce93cc74753a031933ced70c50bf354f2830574b25ebbd56ba572915a6d1eeb0ab3e8
7
- data.tar.gz: a54ccd70ffdcf5b76dfba4db4f51883c776e52915b3971dcafbdbb821b2000a90997780187fdb3832c3e27d83ef0bafcf5ac0b7ff3e044d330b7e4c94a808af0
6
+ metadata.gz: 1665184eba554c3216a5d8185535695dcfbb9e5ce5a38559acac184130ee4f7787065ac72445c258873a7479ac1c2ecaab34f6a68b65f607da6b96542a317a0c
7
+ data.tar.gz: 834d1432f9958709891ccd285280d4dd7f21caab56c1aa7d88d5178a4ef7745d0c5340553d346fbd32d4f17a6d525fd3e872c399640820940ef8830fca34ec99
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,59 +3,49 @@ 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
+ 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 |param_name, value|
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
- { param_name => recursive_merge(value) }
13
+ { name => recursive_merge(value) }
18
14
  else
19
- { param_name => value }
15
+ { name => value }
20
16
  end
21
17
  end.reduce(:merge)
22
18
  end
23
19
 
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
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
- def cast(definition, value)
41
- case definition.type
29
+ case field.type
42
30
  when Hash
43
- recursive_typecast(definition.type, value || {})
31
+ typecast_hash(field.type, value || {})
44
32
  when Array
45
- typecast_array(definition, value)
33
+ typecast_array(field, value)
46
34
  else
47
- typecast_value(definition.type, value)
35
+ typecast_value(field.type, value)
48
36
  end
49
37
  end
50
38
 
51
- def typecast_array(definition, array)
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 == '' && 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
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)
@@ -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
@@ -4,33 +4,42 @@ require_relative 'permitted_parameter_argument'
4
4
 
5
5
  module Paramore
6
6
  module Extension
7
- def paramorize(accessor_name, parameter_configuration)
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: #{param_definition.keys}"
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?(Hash)
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
- permitted_parameter_argument =
22
- if types_definition.is_a?(Hash)
23
- Paramore::PermittedParameterArgument.parse(types_definition)
24
- else
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?(Hash)
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(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,8 +2,8 @@ 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 " +
@@ -12,13 +12,22 @@ module Paramore
12
12
  end
13
13
  end
14
14
 
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
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
- paratype.type.is_a?(Hash) ? types(paratype.type) : paratype.type
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 '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.0.2
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-07-01 00:00:00.000000000 Z
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 1.0.2 !
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