smart_params 4.1.0 → 5.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: 51307d488e1178966b88bac2344fbbdf03f0d99468d810c8c3d1b5f4337563be
4
- data.tar.gz: 89a122fe01133ea7906a3edf35f3b8158ebe05d63377ae75783f06dfdc289482
3
+ metadata.gz: 72ea358328d6d2de0b7cb159c3f7a02eaeeba1114428d0dd1eef74033311a4b5
4
+ data.tar.gz: 3b864136adce02b4393645f42e56f46086b4a7b0b8a1e75a326ffcb0ab3a6b49
5
5
  SHA512:
6
- metadata.gz: be60295f1c9144554bad8cd96b99cf28c288ee6881a813af72c7c49ff6dbb84a73972ed0da21defccce6b7146b9454abeeadc5c0000aaea01c2f91be3448a5f2
7
- data.tar.gz: ce85f9a928fb36067586e1ece4cd2372c4e97be76363ef31c2793581d718fcac5f48c010482b539fcff1cb0872bc97968414732a7a3ea1f5d88635de71ebf0b3
6
+ metadata.gz: b6020bd0591d343040c21882a091e6bb9535132f116e6c538ea60edbe4f7da15581dafae6158d37fe81d0aa52f920827e416af88fdd25e4ea9e6da182a719096
7
+ data.tar.gz: 20c54169633985ed7febf49f4b5028c0b375017f793d6a3f0ee172ea9ce41e72869ec745cc5e6e854fdd4f6c3ae989e80cce6806f3b1e286e6e8be92c8f45c10
data/README.md CHANGED
@@ -11,19 +11,19 @@ So lets say you have a complex set of incoming data, say a JSON:API-specificatio
11
11
  class CreateAccountSchema
12
12
  include SmartParams
13
13
 
14
- schema type: Strict::Hash do
15
- field :data, type: Strict::Hash do
16
- field :id, type: Coercible::String.optional
14
+ schema do
15
+ field :data, subschema: true do
16
+ field :id, type: Coercible::String, nullable: true
17
17
  field :type, type: Strict::String
18
- field :attributes, type: Strict::Hash.optional do
19
- field :email, type: Strict::String.optional
20
- field :username, type: Strict::String.optional
21
- field :name, type: Strict::String.optional
22
- field :password, type: Strict::String.optional.default { SecureRandom.hex(32) }
18
+ field :attributes, subschema: true, nullable: true do
19
+ field :email, type: Strict::String, nullable: true
20
+ field :username, type: Strict::String, nullable: true
21
+ field :name, type: Strict::String, nullable: true
22
+ field :password, type: Strict::String.default { SecureRandom.hex(32) }, nullable: true
23
23
  end
24
24
  end
25
- field :meta, type: Strict::Hash.optional
26
- field :included, type: Strict::Array.optional
25
+ field :meta, Strict::Hash, nullable: true
26
+ field :included, type: Strict::Array, nullable: true
27
27
  end
28
28
  end
29
29
  ```
@@ -6,16 +6,22 @@ module SmartParams
6
6
  attr_reader :keychain
7
7
  attr_reader :wanted
8
8
  attr_reader :raw
9
+ attr_reader :missing_key
9
10
 
10
- def initialize(keychain:, wanted:, raw:)
11
+ def initialize(keychain:, wanted:, raw:, missing_key: nil)
11
12
  super
12
13
  @keychain = keychain
13
14
  @wanted = wanted
14
15
  @raw = raw
16
+ @missing_key = missing_key
15
17
  end
16
18
 
17
19
  def message
18
- "expected #{keychain.inspect} to be #{wanted.name}, but was #{raw.inspect}"
20
+ if missing_key
21
+ "expected #{keychain.inspect} to be #{wanted.name} with key #{missing_key.inspect}, but is #{raw.inspect}"
22
+ else
23
+ "expected #{keychain.inspect} to be #{wanted.name}, but is #{raw.inspect}"
24
+ end
19
25
  end
20
26
 
21
27
  def as_json
@@ -3,13 +3,23 @@
3
3
  require "spec_helper"
4
4
 
5
5
  RSpec.describe SmartParams::Error::InvalidPropertyType do
6
- let(:error) { described_class.new(keychain: [:data], wanted: SmartParams::Strict::Hash, raw: "") }
7
-
8
6
  describe "#message" do
9
7
  subject { error.message }
10
8
 
11
- it "returns the message" do
12
- expect(subject).to eq("expected [:data] to be Hash, but was \"\"")
9
+ context "when the error is about the type mismatch" do
10
+ let(:error) { described_class.new(keychain: [:data], wanted: SmartParams::Strict::Hash, raw: "") }
11
+
12
+ it "returns the message" do
13
+ expect(subject).to eq("expected [:data] to be Hash, but is \"\"")
14
+ end
15
+ end
16
+
17
+ context "when the error is about a missing key" do
18
+ let(:error) { described_class.new(keychain: [:data], wanted: SmartParams::Strict::Hash.schema(data: SmartParams::Strict::String), raw: {}, missing_key: :data) }
19
+
20
+ it "returns the message" do
21
+ expect(subject).to eq("expected [:data] to be Hash with key :data, but is {}")
22
+ end
13
23
  end
14
24
  end
15
25
  end
@@ -5,18 +5,36 @@ module SmartParams
5
5
  attr_reader :keychain
6
6
  attr_reader :subfields
7
7
  attr_reader :type
8
+ attr_reader :nullable
9
+ attr_reader :key
8
10
 
9
- def initialize(keychain:, type:, nullable: false, &nesting)
11
+ def inspect
12
+ "#<#{self.class.name}:#{__id__} #{[
13
+ ('subschema' if @subschema),
14
+ ("#/#{@keychain.join('/')}" if @keychain),
15
+ ("-> #{type.name}" if @type),
16
+ ("= #{@value.inspect}" if @value)
17
+ ].compact.join(' ')}>"
18
+ end
19
+
20
+ def initialize(keychain:, type:, key: nil, subschema: false, nullable: false, &nesting)
21
+ @key = key
10
22
  @keychain = Array(keychain)
11
23
  @subfields = Set.new
12
24
  @type = type
13
25
  @nullable = nullable
26
+ @subschema = subschema
14
27
  @specified = false
15
28
  @dirty = false
16
29
 
17
- return unless nesting
30
+ instance_eval(&nesting) if nesting
18
31
 
19
- instance_eval(&nesting)
32
+ if subschema
33
+ @type = @type.schema(subfields.reduce({}) do |mapping, field|
34
+ mapping.merge("#{field.key}#{'?' if field.nullable}": field.type)
35
+ end).with_key_transform(&:to_sym)
36
+ end
37
+ @type = @type.optional if nullable
20
38
  end
21
39
 
22
40
  def deep?
@@ -72,8 +90,10 @@ module SmartParams
72
90
  return type[dug(raw)] if deep?
73
91
 
74
92
  @value = type[dug(raw)]
75
- rescue Dry::Types::ConstraintError
93
+ rescue Dry::Types::ConstraintError => _constraint_exception
76
94
  raise SmartParams::Error::InvalidPropertyType.new(keychain:, wanted: type, raw: keychain.empty? ? raw : raw.dig(*keychain))
95
+ rescue Dry::Types::MissingKeyError => missing_key_exception
96
+ raise SmartParams::Error::InvalidPropertyType.new(keychain:, wanted: type, raw: keychain.empty? ? raw : raw.dig(*keychain), missing_key: missing_key_exception.key)
77
97
  end
78
98
 
79
99
  def to_hash
@@ -95,9 +115,8 @@ module SmartParams
95
115
  keychain.map(&:to_s)
96
116
  end
97
117
 
98
- private def field(key, type:, nullable: false, &subfield)
99
- type |= SmartParams::Strict::Nil if nullable
100
- @subfields << self.class.new(keychain: [*keychain, key], type:, nullable:, &subfield)
118
+ private def field(key, subschema: false, type: SmartParams::Hash, nullable: false, &subfield)
119
+ @subfields << self.class.new(key:, keychain: [*keychain, key], type:, nullable:, subschema:, &subfield)
101
120
  end
102
121
 
103
122
  # Very busy method with recent changes. TODO: clean-up
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SmartParams
4
- VERSION = "4.1.0"
4
+ VERSION = "5.0.0"
5
5
  end
data/lib/smart_params.rb CHANGED
@@ -24,10 +24,14 @@ module SmartParams
24
24
  @schema = self.class.instance_variable_get(:@schema)[name]
25
25
 
26
26
  @fields = [@schema, *unfold(@schema.subfields)].sort_by(&:weight).each { |field| field.claim(raw) }
27
- rescue SmartParams::Error::InvalidPropertyType => e
28
- raise e if safe?
27
+ rescue SmartParams::Error::InvalidPropertyType => invalid_property_exception
28
+ raise invalid_property_exception if safe?
29
29
 
30
- @exception = e
30
+ @exception = invalid_property_exception
31
+ end
32
+
33
+ def inspect
34
+ "#<#{self.class.name}:#{__id__} @fields=#{@fields.inspect} @raw=#{@raw.inspect}>"
31
35
  end
32
36
 
33
37
  def payload
@@ -96,9 +100,9 @@ module SmartParams
96
100
  end
97
101
 
98
102
  class_methods do
99
- def schema(name: :default, type:, &definitions)
103
+ def schema(name: :default, type: Hash, subschema: false, &definitions)
100
104
  @schema ||= {}
101
- @schema[name] = Field.new(keychain: [], type:, &definitions)
105
+ @schema[name] = Field.new(keychain: [], type:, subschema:, &definitions)
102
106
  end
103
107
  end
104
108
  end
@@ -12,12 +12,12 @@ RSpec.describe SmartParams do
12
12
  let(:params) { {} }
13
13
 
14
14
  it "throws an error with a message detailing the invalid property type and given properties" do
15
- expect { schema }.to raise_exception(SmartParams::Error::InvalidPropertyType, "expected [:data] to be Hash, but was nil")
15
+ expect { schema }.to raise_exception(SmartParams::Error::InvalidPropertyType, "expected [:data] to be Hash, but is nil")
16
16
  end
17
17
 
18
18
  it "throws an error with the missing property and given properties" do
19
19
  expect { schema }.to raise_exception do |exception|
20
- expect(exception).to have_attributes(keychain: [:data], wanted: SmartParams::Strict::Hash, raw: nil)
20
+ expect(exception).to have_attributes(keychain: [:data], wanted: a_kind_of(Dry::Types::Constrained), raw: nil)
21
21
  end
22
22
  end
23
23
  end
@@ -26,12 +26,12 @@ RSpec.describe SmartParams do
26
26
  let(:params) { { data: "" } }
27
27
 
28
28
  it "throws an error with a message detailing the invalid property, expected type, given type, and given value" do
29
- expect { schema }.to raise_exception(SmartParams::Error::InvalidPropertyType, "expected [:data] to be Hash, but was \"\"")
29
+ expect { schema }.to raise_exception(SmartParams::Error::InvalidPropertyType, "expected [:data] to be Hash, but is \"\"")
30
30
  end
31
31
 
32
32
  it "throws an error with the invalid property, expected type, given type, and given value" do
33
33
  expect { schema }.to raise_exception do |exception|
34
- expect(exception).to have_attributes(keychain: [:data], wanted: SmartParams::Strict::Hash, raw: "")
34
+ expect(exception).to have_attributes(keychain: [:data], wanted: a_kind_of(Dry::Types::Constrained), raw: "")
35
35
  end
36
36
  end
37
37
  end
@@ -456,18 +456,20 @@ RSpec.describe SmartParams do
456
456
  let(:params) do
457
457
  {
458
458
  data: {
459
+ id: "x",
460
+ type: "y",
459
461
  is: "garbage"
460
462
  }
461
463
  }
462
464
  end
463
465
 
464
- it "does not provide data" do
466
+ it "does not return key that isn't specified" do
465
467
  expect(
466
468
  subject
467
469
  ).to match(
468
470
  hash_excluding(
469
471
  {
470
- "data" => nil
472
+ "is" => "garbage"
471
473
  }
472
474
  )
473
475
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_params
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kurtis Rainbolt-Greene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-08 00:00:00.000000000 Z
11
+ date: 2023-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport