permittable 0.1.0 → 0.1.1

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: deed1778579c6d35f58ff18111114b00566ad0d6d2a92db5d4a9bfc3a730c6a6
4
- data.tar.gz: 57c83b026226096fcc96552d2df3a51577da12e704b5883fb4ba8c1110704433
3
+ metadata.gz: 7e937b7a8fd46ed18f2828e5ad79b3ba5b4bda3133a108f7113472c51a1a664e
4
+ data.tar.gz: e64f2c0b4b2b2a7196657e944fca56c3f8ac01a5bf1fead0a32713029b53d34b
5
5
  SHA512:
6
- metadata.gz: 1c89bc7b9ff00e4246f0ac9bcc2937b97fb5ba8cdcfda1cbb5308d7d9cff5b4a7410eb48c5a185acd2b8feb82f595f771319edc33badd64ad1155f3d5e691b51
7
- data.tar.gz: a0087bd69e30d6739a9fc7af090b35cdbc268fbdad7cb57666d3fc71fc140a7b9e5304827e7d1789ff43ccc3f99789b576fbc8340d23595db38712e27abdb0db
6
+ metadata.gz: e6158d39d4c9a3a84d5dff5f6bc6afb121197bc0a1759d16f0e628d5639639c6d6c3c3ecc7bacb29280dc395e511f197a0429209fb81375acac4142246604731
7
+ data.tar.gz: 7e9adee7f244edfba05b5b9f7b5e93f8bd15c5c2af323315fd2dbafbd2f66f12ffdf74abb748614c56cd44146e0137e4af25ffe145914d53a61b26a6044ea639
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  <!-- CHANGELOG.md -->
2
2
 
3
+ ## 0.1.1 (2026-08-16)
4
+
5
+ Maintenance release. The public API and every documented behaviour are identical to 0.1.0; upgrading is a no-op.
6
+
7
+ ### Changed
8
+ - Internal style pass to satisfy the RuboCop config added in this release (hash alignment, guard clauses, anonymous block forwarding).
9
+ - `cast_datetime` folds `DateTime` into the `Time` branch whose body it already shared. Dispatch order is unchanged, so `DateTime` still matches ahead of `Date`, which it subclasses.
10
+ - Dropped `require "set"` from the filter parameter registry: `Set` has been autoloaded since Ruby 3.1 and the gemspec already floors at 3.2.
11
+
12
+ ### Added
13
+ - CI on Ruby 3.2 (RuboCop + RSpec) and tag-driven publishing to RubyGems via trusted publishing. Repository tooling only — not part of the packaged gem.
14
+
3
15
  ## 0.1.0 (2026-08-16)
4
16
 
5
17
  Initial extraction from [concerns_on_rails](https://github.com/VSN2015/concerns_on_rails) (developed there on `feature/permittable` as `ConcernsOnRails::Controllers::Permittable`; concerns_on_rails now depends on this gem and aliases that constant to `::Permittable`).
@@ -1,5 +1,3 @@
1
- require "set"
2
-
3
1
  module Permittable
4
2
  # Registry of sensitive parameter names (populated by `sensitive: true`
5
3
  # contract fields) surfaced to Rails' log filtering. Appending plain symbols
@@ -1,3 +1,3 @@
1
1
  module Permittable
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.1.1".freeze
3
3
  end
data/lib/permittable.rb CHANGED
@@ -115,11 +115,11 @@ module Permittable
115
115
  ROUTING_KEYS = %w[controller action format].freeze
116
116
 
117
117
  NORMALIZERS = {
118
- squish: ->(v) { v.squish },
119
- strip: ->(v) { v.strip },
118
+ squish: ->(v) { v.squish },
119
+ strip: ->(v) { v.strip },
120
120
  downcase: ->(v) { v.downcase },
121
- upcase: ->(v) { v.upcase },
122
- email: ->(v) { v.strip.downcase },
121
+ upcase: ->(v) { v.upcase },
122
+ email: ->(v) { v.strip.downcase }
123
123
  }.freeze
124
124
 
125
125
  @registry_mutex = Mutex.new
@@ -271,8 +271,8 @@ module Permittable
271
271
  # (deterministic); explicit offsets are honoured and normalised to UTC.
272
272
  def cast_datetime(value)
273
273
  case value
274
- when ActiveSupport::TimeWithZone, Time then [:ok, value.to_time.utc]
275
- when DateTime then [:ok, value.to_time.utc]
274
+ # DateTime is listed here, ahead of Date, because it subclasses Date.
275
+ when ActiveSupport::TimeWithZone, Time, DateTime then [:ok, value.to_time.utc]
276
276
  when Date then [:ok, Time.utc(value.year, value.month, value.day)]
277
277
  when String then [:ok, DateTime.parse(value).to_time.utc]
278
278
  else [:error, "invalid_type"]
@@ -315,8 +315,8 @@ module Permittable
315
315
  @finalizer = nil
316
316
  end
317
317
 
318
- def build(&block)
319
- instance_eval(&block)
318
+ def build(&)
319
+ instance_eval(&)
320
320
  @fields.map(&:freeze).freeze
321
321
  end
322
322
 
@@ -331,12 +331,12 @@ module Permittable
331
331
 
332
332
  # `required :name` defaults the type to :string. A block instead of a
333
333
  # type declares a nested hash of sub-fields.
334
- def required(name, type = nil, **opts, &block)
335
- add_field(name, type, required: true, opts: opts, &block)
334
+ def required(name, type = nil, **opts, &)
335
+ add_field(name, type, required: true, opts: opts, &)
336
336
  end
337
337
 
338
- def optional(name, type = nil, **opts, &block)
339
- add_field(name, type, required: false, opts: opts, &block)
338
+ def optional(name, type = nil, **opts, &)
339
+ add_field(name, type, required: false, opts: opts, &)
340
340
  end
341
341
 
342
342
  # Array of scalars (`of:`, default :string) or, with a block, an array
@@ -384,9 +384,7 @@ module Permittable
384
384
 
385
385
  def field_name!(name)
386
386
  name = name.to_sym
387
- if @fields.any? { |f| f[:name] == name }
388
- raise ArgumentError, "#{LABEL}: field :#{name} is declared twice in the same contract"
389
- end
387
+ raise ArgumentError, "#{LABEL}: field :#{name} is declared twice in the same contract" if @fields.any? { |f| f[:name] == name }
390
388
 
391
389
  name
392
390
  end
@@ -408,9 +406,9 @@ module Permittable
408
406
  "(supported: #{SCALAR_TYPES.join(', ')})"
409
407
  end
410
408
 
411
- def nested_fields!(name, &block)
409
+ def nested_fields!(name, &)
412
410
  builder = ContractBuilder.new
413
- fields = builder.build(&block)
411
+ fields = builder.build(&)
414
412
  raise ArgumentError, "#{LABEL}: nested field :#{name} declares no sub-fields" if fields.empty?
415
413
  if builder.finalizer
416
414
  raise ArgumentError, "#{LABEL}: finalize is only available at the top level of a contract (found inside :#{name})"
@@ -638,7 +636,7 @@ module Permittable
638
636
  def render_invalid_parameters(error)
639
637
  ErrorEnvelope.render(
640
638
  self, message: error.message, status: error.status,
641
- code: "invalid_parameters", details: error.details
639
+ code: "invalid_parameters", details: error.details
642
640
  )
643
641
  end
644
642
 
@@ -650,12 +648,10 @@ module Permittable
650
648
  result = ActiveSupport::HashWithIndifferentAccess.new
651
649
  if source
652
650
  result = permittable_check_hash(rule[:fields], source, path: rule[:root] ? rule[:root].to_s : nil,
653
- unknown: rule[:unknown], top_level: !rule[:root], violations: violations)
651
+ unknown: rule[:unknown], top_level: !rule[:root], violations: violations)
654
652
  end
655
653
  # finalize only sees a hash every field vouched for — never garbage.
656
- if violations.empty? && rule[:finalize]
657
- result = permittable_run_finalize(rule[:finalize], result, violations)
658
- end
654
+ result = permittable_run_finalize(rule[:finalize], result, violations) if violations.empty? && rule[:finalize]
659
655
  return result if violations.empty?
660
656
 
661
657
  raise_invalid_parameters!(violations, status: source ? :unprocessable_entity : :bad_request)
@@ -757,9 +753,7 @@ module Permittable
757
753
 
758
754
  def permittable_check_array(field, value, path:, unknown:, violations:)
759
755
  before = violations.length
760
- if field[:length] && !Coercion.length_ok?(field[:length], value.length)
761
- violations << { param: path, code: "length" }
762
- end
756
+ violations << { param: path, code: "length" } if field[:length] && !Coercion.length_ok?(field[:length], value.length)
763
757
  out = value.each_with_index.map do |element, index|
764
758
  permittable_check_element(field, element, "#{path}[#{index}]", unknown: unknown, violations: violations)
765
759
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: permittable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan Nguyen
@@ -72,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
72
  - !ruby/object:Gem::Version
73
73
  version: '0'
74
74
  requirements: []
75
- rubygems_version: 3.4.10
75
+ rubygems_version: 3.4.19
76
76
  signing_key:
77
77
  specification_version: 4
78
78
  summary: Typed, validated params contracts for Rails controllers + schema-drift guard