hash_cast 0.5.2 → 0.5.4

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: 899228916d29fc1b30a38151b850f6734ea57cb7390561b6a3aaecd0e3e1a7e6
4
- data.tar.gz: b055bcb17b4863fea30a1f5b3a6e739514aaff9ca853fcefb3ee702bed3ece5d
3
+ metadata.gz: b1ff1d676f80eaba8132c7027e6b70f59047a31df70a19f55183ecaff1d915cf
4
+ data.tar.gz: c1d44f71ee442b52abd55703e96dd4eca331e2ef63329e7fc17188d9bc053200
5
5
  SHA512:
6
- metadata.gz: 1ebd62549257464c42f8d9550b5a3a592e9b84fc430619821818497d74bc1c95946effc1c21188a619834f6420b3c78fef2aac6f9859289da0ec7719188e9726
7
- data.tar.gz: 0134f1c7695a0c205e0b9f57fa6ed995fc568e55e1e999b37d80973ac102c0450d2bde94eaf20c7c72f74f534d9da6d9432a017224d1bac4eb4b05e8b04e9f2c
6
+ metadata.gz: 9e7a988fa4dffefccb42d33249c923fb475b3f1e4605aa959d20ab1e92e44dc6ada092df1afd720eb4f5d5d0484b6182fb3b90822f00d50363f36a38e55b622e
7
+ data.tar.gz: df5c9a15f7c1ba2c25a7830d1426fb218202f16ce02cecab6e1234e0b8839e8ae31bd8150c15c6a58733b99e7b5d79bc61787d7133f7b12ab9360d7b36fb3a5e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ **Version 0.5.4**
2
+ - Integer caster should only allow integer range by default (-2^31, 2^31)
3
+
4
+ **Version 0.5.3**
5
+ - Added optional support for array and string size validation
6
+
1
7
  **Version 0.5.2**
2
8
  - Rename AttributesCaster to HashCast::RecursiveCasterApplicator, to highlight that it's not a regular Caster
3
9
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hash_cast (0.5.2)
4
+ hash_cast (0.5.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,14 +1,20 @@
1
1
  class HashCast::Casters::ArrayCaster
2
2
 
3
3
  def self.cast(value, attr_name, options = {})
4
- if value.is_a?(Array)
5
- if options[:each]
6
- cast_array_items(value, attr_name, options)
7
- else
8
- value
4
+ unless value.is_a?(Array)
5
+ raise HashCast::Errors::CastingError, "should be an array"
6
+ end
7
+
8
+ if HashCast.config.array_size_validator_enabled
9
+ if value.size > HashCast.config.array_size_validator_limit
10
+ HashCast.config.array_size_validator_callback.call(value, attr_name, options)
9
11
  end
12
+ end
13
+
14
+ if options[:each]
15
+ cast_array_items(value, attr_name, options)
10
16
  else
11
- raise HashCast::Errors::CastingError, "should be an array"
17
+ value
12
18
  end
13
19
  end
14
20
 
@@ -1,17 +1,36 @@
1
1
  class HashCast::Casters::IntegerCaster
2
2
 
3
+ DEFAULT_MIN_VALUE = 2**31 * -1
4
+ DEFAULT_MAX_VALUE = 2**31
5
+
3
6
  def self.cast(value, attr_name, options = {})
4
- if value.is_a?(Integer)
5
- value
6
- elsif value.is_a?(String)
7
- begin
8
- Integer(value)
9
- rescue ArgumentError => e
10
- raise HashCast::Errors::CastingError, "is invalid integer"
11
- end
12
- else
13
- raise HashCast::Errors::CastingError, "should be a integer"
7
+ integer_value = get_integer_value(value)
8
+
9
+ if integer_value < options.fetch(:min_value, DEFAULT_MIN_VALUE)
10
+ raise HashCast::Errors::CastingError, "should be within allowed range"
14
11
  end
12
+
13
+ if integer_value > options.fetch(:max_value, DEFAULT_MAX_VALUE)
14
+ raise HashCast::Errors::CastingError, "should be within allowed range"
15
+ end
16
+
17
+ integer_value
15
18
  end
16
19
 
20
+ private
21
+ def self.get_integer_value(value)
22
+ if value.is_a?(Integer)
23
+ return value
24
+ end
25
+
26
+ if value.is_a?(String)
27
+ begin
28
+ return Integer(value)
29
+ rescue ArgumentError => e
30
+ raise HashCast::Errors::CastingError, "is invalid integer"
31
+ end
32
+ end
33
+
34
+ raise HashCast::Errors::CastingError, "should be a integer"
35
+ end
17
36
  end
@@ -8,6 +8,12 @@ class HashCast::Casters::StringCaster
8
8
  raise HashCast::Errors::CastingError, 'contains invalid characters'
9
9
  end
10
10
 
11
+ if HashCast.config.string_size_validator_enabled
12
+ if value.size > HashCast.config.string_size_validator_limit
13
+ HashCast.config.string_size_validator_callback.call(value, attr_name, options)
14
+ end
15
+ end
16
+
11
17
  casted_value
12
18
  end
13
19
 
@@ -1,5 +1,14 @@
1
1
  class HashCast::Config
2
- attr_accessor :input_keys, :output_keys, :validate_string_null_byte
2
+ attr_writer :input_keys, :output_keys, :validate_string_null_byte,
3
+ :array_size_validator_enabled,
4
+ :array_size_validator_limit,
5
+ :array_size_validator_callback,
6
+ :string_size_validator_enabled,
7
+ :string_size_validator_limit,
8
+ :string_size_validator_callback
9
+
10
+ DEFAULT_ARRAY_SIZE_VALIDATOR_LIMIT = 1000_000
11
+ DEFAULT_STRING_SIZE_VALIDATOR_LIMIT = 1000_000
3
12
 
4
13
  def input_keys
5
14
  @input_keys || :symbol
@@ -14,4 +23,48 @@ class HashCast::Config
14
23
 
15
24
  @validate_string_null_byte
16
25
  end
26
+
27
+ def array_size_validator_enabled
28
+ return false if @array_size_validator_enabled.nil?
29
+
30
+ @array_size_validator_enabled
31
+ end
32
+
33
+ def array_size_validator_limit
34
+ return DEFAULT_ARRAY_SIZE_VALIDATOR_LIMIT if @array_size_validator_limit.nil?
35
+
36
+ @array_size_validator_limit
37
+ end
38
+
39
+ def array_size_validator_callback
40
+ if @array_size_validator_callback.nil?
41
+ return lambda{ |value, name, options|
42
+ raise HashCast::Errors::CastingError, "array is too large"
43
+ }
44
+ end
45
+
46
+ @array_size_validator_callback
47
+ end
48
+
49
+ def string_size_validator_enabled
50
+ return false if @string_size_validator_enabled.nil?
51
+
52
+ @string_size_validator_enabled
53
+ end
54
+
55
+ def string_size_validator_limit
56
+ return DEFAULT_STRING_SIZE_VALIDATOR_LIMIT if @string_size_validator_limit.nil?
57
+
58
+ @string_size_validator_limit
59
+ end
60
+
61
+ def string_size_validator_callback
62
+ if @string_size_validator_callback.nil?
63
+ return lambda{ |value, name, options|
64
+ raise HashCast::Errors::CastingError, "string is too large"
65
+ }
66
+ end
67
+
68
+ @string_size_validator_callback
69
+ end
17
70
  end
@@ -1,3 +1,3 @@
1
1
  module HashCast
2
- VERSION = "0.5.2"
2
+ VERSION = "0.5.4"
3
3
  end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashCast::Casters::ArrayCaster do
4
+ subject { HashCast::Casters::ArrayCaster }
5
+
6
+ it "should cast an array" do
7
+ result = subject.cast([1,2,3], :ids)
8
+ expect(result).to eq([1,2,3])
9
+ end
10
+
11
+ it "should raise an error for non-array" do
12
+ expect {
13
+ subject.cast(1, :ids)
14
+ }.to raise_error(HashCast::Errors::CastingError, "should be an array")
15
+ end
16
+
17
+ context "array size validation" do
18
+ after{
19
+ HashCast.config.array_size_validator_enabled = nil
20
+ HashCast.config.array_size_validator_limit = nil
21
+ }
22
+
23
+ it "should not raise an error for large array by default" do
24
+ result = subject.cast([1] * 10_000, :ids)
25
+ expect(result).to eq([1] * 10_000)
26
+ end
27
+
28
+ it "should raise an error for large array when validation is enabled" do
29
+ HashCast.config.array_size_validator_enabled = true
30
+ HashCast.config.array_size_validator_limit = 1000
31
+
32
+ expect {
33
+ subject.cast([1] * 10_000, :ids)
34
+ }.to raise_error(HashCast::Errors::CastingError, "array is too large")
35
+ end
36
+
37
+ it "should allow overriding the callback" do
38
+ HashCast.config.array_size_validator_enabled = true
39
+ HashCast.config.array_size_validator_limit = 1000
40
+ HashCast.config.array_size_validator_callback = lambda { |value, name, options|
41
+ raise HashCast::Errors::UnexpectedAttributeError, 'test'
42
+ }
43
+
44
+ expect {
45
+ subject.cast([1] * 10_000, :ids)
46
+ }.to raise_error(HashCast::Errors::UnexpectedAttributeError, "test")
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashCast::Casters::IntegerCaster do
4
+ subject { HashCast::Casters::IntegerCaster }
5
+
6
+ it "should cast from a numeric string" do
7
+ result = subject.cast("123", :number)
8
+ expect(result).to eq(123)
9
+ end
10
+
11
+ it "should cast from an positive integer" do
12
+ result = subject.cast(10_000, :number)
13
+ expect(result).to eq(10_000)
14
+ end
15
+
16
+ it "should cast from a negative integer" do
17
+ result = subject.cast(-10_000, :number)
18
+ expect(result).to eq(-10_000)
19
+ end
20
+
21
+ it "should cast from a zero" do
22
+ result = subject.cast(0, :number)
23
+ expect(result).to eq(0)
24
+ end
25
+
26
+ it "should not cast from a random string" do
27
+ expect {
28
+ subject.cast("test", :number)
29
+ }.to raise_error(HashCast::Errors::CastingError, "is invalid integer")
30
+ end
31
+
32
+ it "should not cast from an array" do
33
+ expect {
34
+ subject.cast([1], :number)
35
+ }.to raise_error(HashCast::Errors::CastingError, "should be a integer")
36
+ end
37
+
38
+ it "only allow values larger than max integer range" do
39
+ expect {
40
+ subject.cast(2**40, :number)
41
+ }.to raise_error(HashCast::Errors::CastingError, "should be within allowed range")
42
+ end
43
+
44
+ it "only allow values smaller than min integer range" do
45
+ expect {
46
+ subject.cast(2**40 * -1, :number)
47
+ }.to raise_error(HashCast::Errors::CastingError, "should be within allowed range")
48
+ end
49
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe HashCast::Casters::StringCaster do
4
+ subject { HashCast::Casters::StringCaster }
5
+
6
+ it "should cast a string" do
7
+ result = subject.cast("foobar", :name)
8
+ expect(result).to eq("foobar")
9
+ end
10
+
11
+ context "string size validation" do
12
+ after{
13
+ HashCast.config.string_size_validator_enabled = nil
14
+ HashCast.config.string_size_validator_limit = nil
15
+ }
16
+
17
+ it "should not raise an error for large string by default" do
18
+ result = subject.cast("a" * 10_000, :name)
19
+ expect(result).to eq("a" * 10_000)
20
+ end
21
+
22
+ it "should raise an error for large string when validation is enabled" do
23
+ HashCast.config.string_size_validator_enabled = true
24
+ HashCast.config.string_size_validator_limit = 1000
25
+
26
+ expect {
27
+ subject.cast("a" * 10_000, :ids)
28
+ }.to raise_error(HashCast::Errors::CastingError, "string is too large")
29
+ end
30
+
31
+ it "should allow overriding the callback" do
32
+ HashCast.config.string_size_validator_enabled = true
33
+ HashCast.config.string_size_validator_limit = 1000
34
+ HashCast.config.string_size_validator_callback = lambda { |value, name, options|
35
+ raise HashCast::Errors::UnexpectedAttributeError, 'test'
36
+ }
37
+
38
+ expect {
39
+ subject.cast("a" * 10_000, :ids)
40
+ }.to raise_error(HashCast::Errors::UnexpectedAttributeError, "test")
41
+ end
42
+ end
43
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash_cast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Albert Gazizov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-13 00:00:00.000000000 Z
11
+ date: 2025-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -78,6 +78,9 @@ files:
78
78
  - lib/hash_cast/recursive_caster_applicator.rb
79
79
  - lib/hash_cast/version.rb
80
80
  - spec/hash_cast/caster_spec.rb
81
+ - spec/hash_cast/casters/array_caster_spec.rb
82
+ - spec/hash_cast/casters/integer_caster_spec.rb
83
+ - spec/hash_cast/casters/string_caster_spec.rb
81
84
  - spec/hash_cast/hash_cast_spec.rb
82
85
  - spec/spec_helper.rb
83
86
  homepage: http://github.com/droidlabs/hash_cast
@@ -105,5 +108,8 @@ specification_version: 4
105
108
  summary: Declarative Hash Caster
106
109
  test_files:
107
110
  - spec/hash_cast/caster_spec.rb
111
+ - spec/hash_cast/casters/array_caster_spec.rb
112
+ - spec/hash_cast/casters/integer_caster_spec.rb
113
+ - spec/hash_cast/casters/string_caster_spec.rb
108
114
  - spec/hash_cast/hash_cast_spec.rb
109
115
  - spec/spec_helper.rb