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 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