smart_params 4.0.1 → 5.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: b6ba2f5aec658ea03696c44adb78d7672dfbdff38e09bb180747df60c052806f
4
- data.tar.gz: 17b96fa105e034549bc1c27d6ed99cd4cc322a483a7c06a7248e01f980926c92
3
+ metadata.gz: 72ea358328d6d2de0b7cb159c3f7a02eaeeba1114428d0dd1eef74033311a4b5
4
+ data.tar.gz: 3b864136adce02b4393645f42e56f46086b4a7b0b8a1e75a326ffcb0ab3a6b49
5
5
  SHA512:
6
- metadata.gz: 2e0ec9ae013b8d240dfe0006d82d35cd954edad38813e2626e1a1eac2d414838f9afa415ff8b34c94a960afad83bb6e7d4b9bbf7e109c665e63d43453afb81d3
7
- data.tar.gz: a08bf1ce80d8fcb4078d86ca5b4b7dd8899ecfc045401dff5cc1a8dc659cae0cfc6a524c65a51a92fb1424641460cd021b940790f0650a9fbb1a931bdaf7e2f0
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.0.1"
4
+ VERSION = "5.0.0"
5
5
  end
data/lib/smart_params.rb CHANGED
@@ -18,16 +18,20 @@ module SmartParams
18
18
  attr_reader :schema
19
19
  attr_reader :fields
20
20
 
21
- def initialize(raw, safe: true)
21
+ def initialize(raw, safe: true, name: :default)
22
22
  @safe = safe
23
23
  @raw = raw
24
- @schema = self.class.instance_variable_get(:@schema)
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,8 +100,9 @@ module SmartParams
96
100
  end
97
101
 
98
102
  class_methods do
99
- def schema(type:, &subfield)
100
- @schema = Field.new(keychain: [], type:, &subfield)
103
+ def schema(name: :default, type: Hash, subschema: false, &definitions)
104
+ @schema ||= {}
105
+ @schema[name] = Field.new(keychain: [], type:, subschema:, &definitions)
101
106
  end
102
107
  end
103
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.0.1
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-08-31 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