ree_lib 1.0.85 → 1.0.87

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile.lock +31 -26
  4. data/lib/ree_lib/packages/ree_actions/package/ree_actions/dsl.rb +11 -3
  5. data/lib/ree_lib/packages/ree_actions/package/ree_actions/errors.rb +3 -0
  6. data/lib/ree_lib/packages/ree_actions/package/ree_actions.rb +1 -0
  7. data/lib/ree_lib/packages/ree_actions/spec/ree_actions/dsl_spec.rb +5 -1
  8. data/lib/ree_lib/packages/ree_dao/package/ree_dao/wrappers/pg_array.rb +12 -8
  9. data/lib/ree_lib/packages/ree_dao/package/ree_dao/wrappers/pg_jsonb.rb +12 -8
  10. data/lib/ree_lib/packages/ree_dao/spec/ree_dao/wrappers/pg_array_spec.rb +3 -3
  11. data/lib/ree_lib/packages/ree_dao/spec/ree_dao/wrappers/pg_jsonb_spec.rb +8 -6
  12. data/lib/ree_lib/packages/ree_enum/package/ree_enum/base_enum_mapper.rb +5 -10
  13. data/lib/ree_lib/packages/ree_enum/package/ree_enum/integer_value_enum_mapper.rb +5 -5
  14. data/lib/ree_lib/packages/ree_enum/package/ree_enum/string_value_enum_mapper.rb +5 -5
  15. data/lib/ree_lib/packages/ree_enum/spec/ree_enum/dsl_spec.rb +10 -2
  16. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/errors/coercion_error.rb +1 -1
  17. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/errors/error_with_location.rb +25 -0
  18. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/errors/type_error.rb +1 -1
  19. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/field.rb +12 -4
  20. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb +12 -6
  21. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb +17 -4
  22. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/abstract_type.rb +6 -0
  23. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/any.rb +8 -8
  24. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/bool.rb +12 -12
  25. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/date.rb +13 -13
  26. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/date_time.rb +13 -13
  27. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/float.rb +13 -13
  28. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/integer.rb +16 -16
  29. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/rational.rb +13 -13
  30. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/string.rb +12 -12
  31. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/time.rb +13 -13
  32. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/wrappers/abstract_wrapper.rb +7 -0
  33. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/wrappers/array.rb +73 -21
  34. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper.rb +2 -0
  35. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_factory_spec.rb +10 -6
  36. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_spec.rb +7 -0
  37. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/bool_spec.rb +10 -8
  38. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/date_spec.rb +12 -10
  39. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/date_time_spec.rb +20 -16
  40. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/float_spec.rb +17 -13
  41. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/hash_spec.rb +1 -1
  42. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/integer_spec.rb +14 -14
  43. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/rational_spec.rb +16 -12
  44. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/string_spec.rb +24 -12
  45. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/time_spec.rb +21 -16
  46. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/type_options_spec.rb +4 -4
  47. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/wrappers/array_spec.rb +6 -6
  48. data/lib/ree_lib/packages/ree_roda/package/ree_roda/app.rb +3 -2
  49. data/lib/ree_lib/packages/ree_roda/spec/ree_roda/app_spec.rb +28 -0
  50. data/lib/ree_lib/spec.init.rb +3 -1
  51. data/lib/ree_lib/version.rb +1 -1
  52. metadata +19 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79577e4a77cb22f4a504b2d6944064c878585a683b89c166418aa003c8fd7eb0
4
- data.tar.gz: 8ac9c51bea3e5c2611049a8002d23f191ee621801d5e0582e665f5fca51dbb97
3
+ metadata.gz: b5c70eda05d58f496b0eca7cbc95f853dd51c8b9e33b23c1fa1b51a74eb58104
4
+ data.tar.gz: bf15e2be0aa79c7696ec9bfb074c3748c7061a5aec1079c5fa208aa1cbc16f1c
5
5
  SHA512:
6
- metadata.gz: 889a59aeae260e884cd25948b349866ec840bcdb0b85d02bd44c87cef6cdb5e72511669f86cb8f567f3a9e53fba81a85243af9469563fd0fcfbef6fb387356a9
7
- data.tar.gz: 1880826420b58191ca75292f7dea4a973d3250b93c99e9530a2cafa49d79cb4a1c68be4ee96fb6c6aba19a84fc927a7d22603c4f97f63e9c8141f97aa899e6b9
6
+ metadata.gz: c068ce8ba9567eab38bd06c0bdc01731f223f1f4126ac70f5d49c9fc40a9e5034cb7e3cfb2fd84ef578018a31dd5934b6c9283b9a72b3d58e69bdf265af481ca
7
+ data.tar.gz: e2f1b8a4428e46d27e40f98d9134d47139c5de080eef52eeee63cf5cf9eb86fb76fdc54b6d437c810f8a8d5b71889e180903ee8dce4463e82ec2f2769c3bffdf
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.0
1
+ 3.3.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ree_lib (1.0.85)
4
+ ree_lib (1.0.87)
5
+ bigdecimal (~> 3.1.6)
5
6
  binding_of_caller (~> 1.0.0)
6
7
  i18n (~> 1.12.0)
7
8
  loofah (~> 2.18.0)
@@ -14,46 +15,49 @@ PATH
14
15
  GEM
15
16
  remote: https://rubygems.org/
16
17
  specs:
17
- addressable (2.8.1)
18
+ abbrev (0.1.2)
19
+ addressable (2.8.6)
18
20
  public_suffix (>= 2.0.2, < 6.0)
21
+ bigdecimal (3.1.6)
19
22
  binding_of_caller (1.0.0)
20
23
  debug_inspector (>= 0.0.1)
21
- bootsnap (1.16.0)
24
+ bootsnap (1.17.0)
22
25
  msgpack (~> 1.2)
23
- commander (4.6.0)
24
- highline (~> 2.0.0)
26
+ commander (5.0.0)
27
+ highline (~> 3.0.0)
25
28
  concurrent-ruby (1.2.2)
26
29
  crack (0.4.5)
27
30
  rexml
28
31
  crass (1.0.6)
29
- debug_inspector (1.1.0)
32
+ debug_inspector (1.2.0)
30
33
  diff-lcs (1.5.0)
31
- faker (3.2.0)
34
+ faker (3.2.2)
32
35
  i18n (>= 1.8.11, < 2)
33
- hashdiff (1.0.1)
34
- highline (2.0.3)
36
+ hashdiff (1.1.0)
37
+ highline (3.0.0)
38
+ abbrev
35
39
  i18n (1.12.0)
36
40
  concurrent-ruby (~> 1.0)
37
41
  loofah (2.18.0)
38
42
  crass (~> 1.0.2)
39
43
  nokogiri (>= 1.5.9)
40
- msgpack (1.6.0)
41
- nokogiri (1.15.5-x86_64-darwin)
44
+ msgpack (1.7.2)
45
+ nokogiri (1.16.0-x86_64-darwin)
42
46
  racc (~> 1.4)
43
- nokogiri (1.15.5-x86_64-linux)
47
+ nokogiri (1.16.0-x86_64-linux)
44
48
  racc (~> 1.4)
45
49
  oj (3.13.23)
46
50
  pg (1.4.6)
47
- public_suffix (5.0.1)
51
+ public_suffix (5.0.4)
48
52
  racc (1.7.3)
49
- rack (3.0.5)
50
- rack-test (2.0.2)
53
+ rack (3.0.8)
54
+ rack-test (2.1.0)
51
55
  rack (>= 1.3)
52
56
  rainbow (3.1.1)
53
- rake (13.0.6)
54
- ree (1.0.32)
55
- commander (~> 4.6.0)
56
- rexml (3.2.5)
57
+ rake (13.1.0)
58
+ ree (1.0.34)
59
+ commander (~> 5.0.0)
60
+ rexml (3.2.6)
57
61
  roda (3.58.0)
58
62
  rack
59
63
  rollbar (3.3.3)
@@ -61,23 +65,23 @@ GEM
61
65
  rspec-core (~> 3.12.0)
62
66
  rspec-expectations (~> 3.12.0)
63
67
  rspec-mocks (~> 3.12.0)
64
- rspec-core (3.12.1)
68
+ rspec-core (3.12.2)
65
69
  rspec-support (~> 3.12.0)
66
- rspec-expectations (3.12.2)
70
+ rspec-expectations (3.12.3)
67
71
  diff-lcs (>= 1.2.0, < 2.0)
68
72
  rspec-support (~> 3.12.0)
69
- rspec-mocks (3.12.3)
73
+ rspec-mocks (3.12.6)
70
74
  diff-lcs (>= 1.2.0, < 2.0)
71
75
  rspec-support (~> 3.12.0)
72
- rspec-support (3.12.0)
76
+ rspec-support (3.12.1)
73
77
  sequel (5.58.0)
74
78
  sqlite3 (1.4.4)
75
- timecop (0.9.6)
79
+ timecop (0.9.8)
76
80
  tzinfo (2.0.6)
77
81
  concurrent-ruby (~> 1.0)
78
82
  warden (1.2.9)
79
83
  rack (>= 2.0.9)
80
- webmock (3.18.1)
84
+ webmock (3.19.1)
81
85
  addressable (>= 2.8.0)
82
86
  crack (>= 0.3.2)
83
87
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -85,6 +89,7 @@ GEM
85
89
  PLATFORMS
86
90
  x86_64-darwin-19
87
91
  x86_64-darwin-21
92
+ x86_64-darwin-22
88
93
  x86_64-linux
89
94
 
90
95
  DEPENDENCIES
@@ -103,4 +108,4 @@ DEPENDENCIES
103
108
  webmock
104
109
 
105
110
  BUNDLED WITH
106
- 2.3.7
111
+ 2.5.4
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+ package_require("ree_mapper/errors/type_error")
3
+ package_require("ree_mapper/errors/coercion_error")
4
+
1
5
  module ReeActions
2
6
  module DSL
3
7
  def self.included(base)
@@ -57,10 +61,14 @@ module ReeActions
57
61
  raise ArgumentError.new("ActionCaster does not respond to `cast` method")
58
62
  end
59
63
 
60
- __original_call(user_access, caster.cast(attrs))
61
- else
62
- __original_call(user_access, attrs)
64
+ attrs = begin
65
+ caster.cast(attrs)
66
+ rescue ReeMapper::TypeError, ReeMapper::CoercionError => e
67
+ raise ReeActions::ParamError, e.message
68
+ end
63
69
  end
70
+
71
+ __original_call(user_access, attrs)
64
72
  ensure
65
73
  __ree_dao_drop_cache
66
74
  end
@@ -0,0 +1,3 @@
1
+ module ReeActions
2
+ ParamError = Class.new(StandardError)
3
+ end
@@ -9,4 +9,5 @@ module ReeActions
9
9
  end
10
10
  end
11
11
 
12
+ require_relative "ree_actions/errors"
12
13
  require_relative "ree_actions/dsl"
@@ -59,6 +59,10 @@ RSpec.describe ReeActions::DSL, type: [:autoclean] do
59
59
 
60
60
  result = ReeActionsTest::TestAction.new.call('user_access', {user_id: 1})
61
61
  expect(result).to eq(1)
62
+
63
+ expect {
64
+ ReeActionsTest::TestAction.new.call('user_access', {user_id: 'not integer'})
65
+ }.to raise_error(ReeActions::ParamError)
62
66
  }
63
67
 
64
68
  it {
@@ -161,7 +165,7 @@ RSpec.describe ReeActions::DSL, type: [:autoclean] do
161
165
  users_dao.put(ReeActionsTest::User.new(name: 'Sam', age: 19))
162
166
  end.join
163
167
  end.join
164
-
168
+
165
169
  $thread_cache = ReeDao::DaoCache.new.get(:users, $user.id)
166
170
 
167
171
  attrs[:user_id]
@@ -8,12 +8,13 @@ class ReeDao::PgArray < ReeMapper::AbstractWrapper
8
8
  Kwargs[
9
9
  name: String,
10
10
  role: Nilor[Symbol, ArrayOf[Symbol]],
11
- fields_filters: ArrayOf[ReeMapper::FieldsFilter]
11
+ fields_filters: ArrayOf[ReeMapper::FieldsFilter],
12
+ location: Nilor[String],
12
13
  ] => Or[Sequel::Postgres::PGArray, String]
13
14
  )
14
- def db_dump(value, name:, role: nil, fields_filters: [])
15
+ def db_dump(value, name:, role: nil, fields_filters: [], location: nil)
15
16
  if !value.is_a?(Array)
16
- raise ReeMapper::TypeError, "`#{name}` should be an array"
17
+ raise ReeMapper::TypeError.new("`#{name}` should be an array, got `#{truncate(value.inspect)}`", location)
17
18
  end
18
19
 
19
20
  value = value.map.with_index do |el, index|
@@ -21,7 +22,8 @@ class ReeDao::PgArray < ReeMapper::AbstractWrapper
21
22
  el,
22
23
  name: "#{name}[#{index}]",
23
24
  role: role,
24
- fields_filters: fields_filters + [subject.fields_filter]
25
+ fields_filters: fields_filters + [subject.fields_filter],
26
+ location: subject.location,
25
27
  )
26
28
  end
27
29
 
@@ -37,12 +39,13 @@ class ReeDao::PgArray < ReeMapper::AbstractWrapper
37
39
  Kwargs[
38
40
  name: String,
39
41
  role: Nilor[Symbol, ArrayOf[Symbol]],
40
- fields_filters: ArrayOf[ReeMapper::FieldsFilter]
42
+ fields_filters: ArrayOf[ReeMapper::FieldsFilter],
43
+ location: Nilor[String],
41
44
  ] => Array
42
45
  ).throws(ReeMapper::TypeError)
43
- def db_load(value, name:, role: nil, fields_filters: [])
46
+ def db_load(value, name:, role: nil, fields_filters: [], location: nil)
44
47
  if !value.is_a?(Sequel::Postgres::PGArray)
45
- raise ReeMapper::TypeError, "`#{name}` is not Sequel::Postgres::PGArray"
48
+ raise ReeMapper::TypeError.new("`#{name}` should be a Sequel::Postgres::PGArray, got `#{truncate(value.inspect)}`", location)
46
49
  end
47
50
 
48
51
  value.map.with_index do |val, index|
@@ -50,7 +53,8 @@ class ReeDao::PgArray < ReeMapper::AbstractWrapper
50
53
  val,
51
54
  name: "#{name}[#{index}]",
52
55
  role: role,
53
- fields_filters: fields_filters + [subject.fields_filter]
56
+ fields_filters: fields_filters + [subject.fields_filter],
57
+ location: subject.location,
54
58
  )
55
59
  end
56
60
  end
@@ -8,7 +8,8 @@ class ReeDao::PgJsonb < ReeMapper::AbstractWrapper
8
8
  Kwargs[
9
9
  name: String,
10
10
  role: Nilor[Symbol, ArrayOf[Symbol]],
11
- fields_filters: ArrayOf[ReeMapper::FieldsFilter]
11
+ fields_filters: ArrayOf[ReeMapper::FieldsFilter],
12
+ location: Nilor[String],
12
13
  ] => Or[
13
14
  Sequel::Postgres::JSONBHash,
14
15
  Sequel::Postgres::JSONBArray,
@@ -20,18 +21,19 @@ class ReeDao::PgJsonb < ReeMapper::AbstractWrapper
20
21
  Sequel::Postgres::JSONBNull
21
22
  ]
22
23
  ).throws(ReeMapper::TypeError)
23
- def db_dump(value, name:, role: nil, fields_filters: [])
24
+ def db_dump(value, name:, role: nil, fields_filters: [], location: nil)
24
25
  value = subject.type.db_dump(
25
26
  value,
26
27
  name: name,
27
28
  role: role,
28
- fields_filters: fields_filters + [subject.fields_filter]
29
+ fields_filters: fields_filters + [subject.fields_filter],
30
+ location: subject.location,
29
31
  )
30
32
 
31
33
  begin
32
34
  Sequel.pg_jsonb_wrap(value)
33
35
  rescue Sequel::Error
34
- raise ReeMapper::TypeError, "`#{name}` should be an jsonb primitive"
36
+ raise ReeMapper::TypeError.new("`#{name}` should be an jsonb primitive, got `#{truncate(value.inspect)}`", location)
35
37
  end
36
38
  end
37
39
 
@@ -40,7 +42,8 @@ class ReeDao::PgJsonb < ReeMapper::AbstractWrapper
40
42
  Kwargs[
41
43
  name: String,
42
44
  role: Nilor[Symbol, ArrayOf[Symbol]],
43
- fields_filters: ArrayOf[ReeMapper::FieldsFilter]
45
+ fields_filters: ArrayOf[ReeMapper::FieldsFilter],
46
+ location: Nilor[String],
44
47
  ] => Or[
45
48
  Hash,
46
49
  Array,
@@ -52,7 +55,7 @@ class ReeDao::PgJsonb < ReeMapper::AbstractWrapper
52
55
  Rational,
53
56
  ]
54
57
  ).throws(ReeMapper::TypeError)
55
- def db_load(value, name:, role: nil, fields_filters: [])
58
+ def db_load(value, name:, role: nil, fields_filters: [], location: nil)
56
59
  value = case value
57
60
  when Sequel::Postgres::JSONBHash
58
61
  ReeObject::ToHash.new.call(value.to_h)
@@ -61,14 +64,15 @@ class ReeDao::PgJsonb < ReeMapper::AbstractWrapper
61
64
  when Numeric, String, TrueClass, FalseClass, NilClass
62
65
  value
63
66
  else
64
- raise ReeMapper::TypeError, "`#{name}` is not Sequel::Postgres::JSONB"
67
+ raise ReeMapper::TypeError.new("`#{name}` should be a Sequel::Postgres::JSONB, got `#{truncate(value.inspect)}`", location)
65
68
  end
66
69
 
67
70
  subject.type.db_load(
68
71
  value,
69
72
  name: name,
70
73
  role: role,
71
- fields_filters: fields_filters + [subject.fields_filter]
74
+ fields_filters: fields_filters + [subject.fields_filter],
75
+ location: subject.location,
72
76
  )
73
77
  end
74
78
  end
@@ -46,7 +46,7 @@ RSpec.describe 'ReeDao::PgArray' do
46
46
  it {
47
47
  expect {
48
48
  mapper.db_dump({ tags: 1 })
49
- }.to raise_error(ReeMapper::TypeError, "`tags` should be an array")
49
+ }.to raise_error(ReeMapper::TypeError, /`tags` should be an array, got `1`/)
50
50
  }
51
51
  end
52
52
 
@@ -66,7 +66,7 @@ RSpec.describe 'ReeDao::PgArray' do
66
66
  mapper.db_load({
67
67
  tags: 1
68
68
  })
69
- }.to raise_error(ReeMapper::TypeError, "`tags` is not Sequel::Postgres::PGArray")
69
+ }.to raise_error(ReeMapper::TypeError, /`tags` should be a Sequel::Postgres::PGArray, got `1`/)
70
70
  }
71
71
  end
72
- end
72
+ end
@@ -55,13 +55,14 @@ RSpec.describe 'ReeDao::PgJsonb' do
55
55
  it {
56
56
  expect {
57
57
  mapper.db_dump({ numbers: ['1'] })
58
- }.to raise_error(ReeMapper::TypeError, "`numbers[0]` should be an integer")
58
+ }.to raise_error(ReeMapper::TypeError, /`numbers\[0\]` should be an integer, got `\"1\"`/)
59
59
  }
60
60
 
61
61
  it {
62
+ object = Object.new
62
63
  expect {
63
- mapper.db_dump({ any: Object.new })
64
- }.to raise_error(ReeMapper::TypeError, "`any` should be an jsonb primitive")
64
+ mapper.db_dump({ any: object })
65
+ }.to raise_error(ReeMapper::TypeError, /`any` should be an jsonb primitive, got `#{object.inspect}`/)
65
66
  }
66
67
  end
67
68
 
@@ -87,13 +88,14 @@ RSpec.describe 'ReeDao::PgJsonb' do
87
88
  it {
88
89
  expect {
89
90
  mapper.db_load({ numbers: Sequel::Postgres::JSONBArray.new([1.1]) })
90
- }.to raise_error(ReeMapper::TypeError, "`numbers[0]` should be an integer")
91
+ }.to raise_error(ReeMapper::TypeError, /`numbers\[0\]` should be an integer, got `1.1`/)
91
92
  }
92
93
 
93
94
  it {
95
+ object = Object.new
94
96
  expect {
95
- mapper.db_load({ numbers: Object.new })
96
- }.to raise_error(ReeMapper::TypeError, "`numbers` is not Sequel::Postgres::JSONB")
97
+ mapper.db_load({ numbers: object })
98
+ }.to raise_error(ReeMapper::TypeError, /`numbers` should be a Sequel::Postgres::JSONB, got `#{object.inspect}`/)
97
99
  }
98
100
  end
99
101
  end
@@ -12,10 +12,10 @@ class ReeEnum::BaseEnumMapper < ReeMapper::AbstractType
12
12
  ReeEnum::Value,
13
13
  Kwargs[
14
14
  name: String,
15
- role: Nilor[Symbol, ArrayOf[Symbol]]
15
+ location: Nilor[String],
16
16
  ] => Or[Integer, String]
17
17
  )
18
- def db_dump(value, name:, role: nil)
18
+ def db_dump(value, name:, location: nil)
19
19
  value.mapped_value
20
20
  end
21
21
 
@@ -23,14 +23,14 @@ class ReeEnum::BaseEnumMapper < ReeMapper::AbstractType
23
23
  Or[Integer, String],
24
24
  Kwargs[
25
25
  name: String,
26
- role: Nilor[Symbol, ArrayOf[Symbol]]
26
+ location: Nilor[String],
27
27
  ] => ReeEnum::Value
28
28
  ).throws(ReeMapper::CoercionError)
29
- def db_load(value, name:, role: nil)
29
+ def db_load(value, name:, location: nil)
30
30
  enum_val = @enum.get_values.by_mapped_value(value)
31
31
 
32
32
  if !enum_val
33
- raise ReeMapper::CoercionError, "`#{name}` should be one of #{enum_inspection}"
33
+ raise ReeMapper::CoercionError.new("`#{name}` should be one of #{enum_inspection}, got `#{truncate(value.inspect)}`", location)
34
34
  end
35
35
 
36
36
  enum_val
@@ -41,9 +41,4 @@ class ReeEnum::BaseEnumMapper < ReeMapper::AbstractType
41
41
  def enum_inspection
42
42
  @enum_inspection ||= truncate(@enum.get_values.each.map(&:to_s).inspect)
43
43
  end
44
-
45
- def truncate(str, limit = 180)
46
- return str if str.length <= limit
47
- "#{str[0..limit]}..."
48
- end
49
44
  end
@@ -6,10 +6,10 @@ class ReeEnum::IntegerValueEnumMapper < ReeEnum::BaseEnumMapper
6
6
  ReeEnum::Value,
7
7
  Kwargs[
8
8
  name: String,
9
- role: Nilor[Symbol, ArrayOf[Symbol]]
9
+ location: Nilor[String],
10
10
  ] => Integer
11
11
  )
12
- def serialize(value, name:, role: nil)
12
+ def serialize(value, name:, location: nil)
13
13
  value.value
14
14
  end
15
15
 
@@ -17,10 +17,10 @@ class ReeEnum::IntegerValueEnumMapper < ReeEnum::BaseEnumMapper
17
17
  Any,
18
18
  Kwargs[
19
19
  name: String,
20
- role: Nilor[Symbol, ArrayOf[Symbol]]
20
+ location: Nilor[String],
21
21
  ] => ReeEnum::Value
22
22
  ).throws(ReeMapper::CoercionError)
23
- def cast(value, name:, role: nil)
23
+ def cast(value, name:, location: nil)
24
24
  enum_value = case value
25
25
  when Integer
26
26
  @enum.get_values.by_value(value)
@@ -34,7 +34,7 @@ class ReeEnum::IntegerValueEnumMapper < ReeEnum::BaseEnumMapper
34
34
  end
35
35
 
36
36
  if enum_value.nil?
37
- raise ReeMapper::CoercionError, "`#{name}` should be one of #{enum_inspection}"
37
+ raise ReeMapper::CoercionError.new("`#{name}` should be one of #{enum_inspection}, got `#{truncate(value.inspect)}`", location)
38
38
  end
39
39
 
40
40
  enum_value
@@ -6,10 +6,10 @@ class ReeEnum::StringValueEnumMapper < ReeEnum::BaseEnumMapper
6
6
  ReeEnum::Value,
7
7
  Kwargs[
8
8
  name: String,
9
- role: Nilor[Symbol, ArrayOf[Symbol]]
9
+ location: Nilor[String],
10
10
  ] => String
11
11
  )
12
- def serialize(value, name:, role: nil)
12
+ def serialize(value, name:, location: nil)
13
13
  value.value
14
14
  end
15
15
 
@@ -17,10 +17,10 @@ class ReeEnum::StringValueEnumMapper < ReeEnum::BaseEnumMapper
17
17
  Any,
18
18
  Kwargs[
19
19
  name: String,
20
- role: Nilor[Symbol, ArrayOf[Symbol]]
20
+ location: Nilor[String],
21
21
  ] => ReeEnum::Value
22
22
  ).throws(ReeMapper::CoercionError)
23
- def cast(value, name:, role: nil)
23
+ def cast(value, name:, location: nil)
24
24
  enum_value = case value
25
25
  when String
26
26
  @enum.get_values.by_value(value)
@@ -29,7 +29,7 @@ class ReeEnum::StringValueEnumMapper < ReeEnum::BaseEnumMapper
29
29
  end
30
30
 
31
31
  if enum_value.nil?
32
- raise ReeMapper::CoercionError, "`#{name}` should be one of #{enum_inspection}"
32
+ raise ReeMapper::CoercionError.new("`#{name}` should be one of #{enum_inspection}, got `#{truncate(value.inspect)}`", location)
33
33
  end
34
34
 
35
35
  enum_value
@@ -152,7 +152,15 @@ RSpec.describe ReeEnum::DSL do
152
152
  type: 'invalid',
153
153
  number: 0,
154
154
  })
155
- }.to raise_error(ReeMapper::CoercionError, '`type` should be one of ["account"]')
155
+ }.to raise_error(ReeMapper::CoercionError, /`type` should be one of \["account"\], got `"invalid"`/)
156
+
157
+ expect {
158
+ mapper.db_load({
159
+ state: 'first',
160
+ type: 'invalid',
161
+ number: 0,
162
+ })
163
+ }.to raise_error(ReeMapper::CoercionError, /`type` should be one of \["account"\], got `"invalid"`/)
156
164
 
157
165
  expect(
158
166
  mapper.cast({
@@ -234,4 +242,4 @@ RSpec.describe ReeEnum::DSL do
234
242
  swagger_definition_fetcher.call(TestReeEnum::ContentTypes.type_for_mapper, -> {})
235
243
  )
236
244
  }
237
- end
245
+ end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class ReeMapper::CoercionError < ReeMapper::Error
3
+ class ReeMapper::CoercionError < ReeMapper::ErrorWithLocation
4
4
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReeMapper::ErrorWithLocation < ReeMapper::Error
4
+ attr_reader :location
5
+
6
+ def initialize(message, location = nil)
7
+ if message.is_a?(String) && location && ENV["RUBY_ENV"] == "test"
8
+ message = "#{message}, located at #{location}"
9
+ end
10
+
11
+ super(message)
12
+ @location = location
13
+ end
14
+
15
+ def full_message(...)
16
+ msg = super
17
+ return msg if location.nil?
18
+
19
+ idx = msg.index(/\).*\n/)
20
+ return msg if idx.nil?
21
+ return msg if ENV["RUBY_ENV"] == "test"
22
+
23
+ msg.insert(idx + 1, ", located at #{location}")
24
+ end
25
+ end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class ReeMapper::TypeError < ReeMapper::Error
3
+ class ReeMapper::TypeError < ReeMapper::ErrorWithLocation
4
4
  end
@@ -3,7 +3,7 @@
3
3
  class ReeMapper::Field
4
4
  attr_reader :type, :name, :from, :doc, :optional, :null, :roles, :default,
5
5
  :name_as_str, :name_as_instance_var_name, :from_as_str,
6
- :fields_filter
6
+ :fields_filter, :location
7
7
 
8
8
  NO_DEFAULT = Object.new.freeze
9
9
 
@@ -18,11 +18,12 @@ class ReeMapper::Field
18
18
  role: Nilor[ArrayOf[Symbol], Symbol],
19
19
  default: Any,
20
20
  only: Nilor[ReeMapper::FilterFieldsContract],
21
- except: Nilor[ReeMapper::FilterFieldsContract]
21
+ except: Nilor[ReeMapper::FilterFieldsContract],
22
+ location: Nilor[String],
22
23
  ] => Any
23
24
  ).throws(ArgumentError)
24
- def initialize(type, name = nil, from: nil, doc: nil, optional: false, null: false, role: nil, default: NO_DEFAULT,
25
- only: nil, except: nil)
25
+ def initialize(type, name = nil, from: nil, doc: nil, optional: false, null: false, role: nil, default: NO_DEFAULT,
26
+ only: nil, except: nil, location: nil)
26
27
  @type = type
27
28
  @name = name
28
29
  @from = from || name
@@ -38,6 +39,13 @@ class ReeMapper::Field
38
39
  @name_as_instance_var_name = :"@#{@name}"
39
40
  @from_as_str = @from.to_s
40
41
 
42
+ @location = location
43
+ if @location
44
+ @location = @location
45
+ .sub(Ree.root_dir, ".")
46
+ .sub(/:in.+/, "")
47
+ end
48
+
41
49
  raise ArgumentError, 'required fields do not support defaults' if has_default? && !optional
42
50
  end
43
51
 
@@ -23,19 +23,19 @@ class ReeMapper::Mapper
23
23
 
24
24
  if type
25
25
  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
26
- def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [])
26
+ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [], location: nil)
27
27
  #{
28
28
  if type.is_a?(ReeMapper::AbstractWrapper)
29
- "@type.#{method}(obj, name: name, role: role, fields_filters: fields_filters)"
29
+ "@type.#{method}(obj, name: name, role: role, fields_filters: fields_filters, location: location)"
30
30
  else
31
- "@type.#{method}(obj, name: name, role: role)"
31
+ "@type.#{method}(obj, name: name, location: location)"
32
32
  end
33
33
  }
34
34
  end
35
35
  RUBY
36
36
  else
37
37
  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
38
- def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [])
38
+ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [], location: nil)
39
39
  if only && !ReeMapper::FilterFieldsContract.valid?(only)
40
40
  raise ReeMapper::ArgumentError, "Invalid `only` format"
41
41
  end
@@ -56,7 +56,7 @@ class ReeMapper::Mapper
56
56
  is_optional = field.optional || @#{method}_strategy.always_optional
57
57
 
58
58
  if !is_with_value && !is_optional
59
- raise ReeMapper::TypeError, "Missing required field `\#{field.from_as_str}` for `\#{name || 'root'}`"
59
+ raise ReeMapper::TypeError.new("Missing required field `\#{field.from_as_str}` for `\#{name || 'root'}`", field.location)
60
60
  end
61
61
 
62
62
  next if !is_with_value && !field.has_default?
@@ -73,7 +73,13 @@ class ReeMapper::Mapper
73
73
  nested_fields_filters = field_fields_filters.map { _1.filter_for(field.name) }
74
74
  nested_fields_filters += [field.fields_filter]
75
75
 
76
- value = field.type.#{method}(value, name: nested_name, role: role, fields_filters: nested_fields_filters)
76
+ value = field.type.#{method}(
77
+ value,
78
+ name: nested_name,
79
+ role: role,
80
+ fields_filters: nested_fields_filters,
81
+ location: field.location,
82
+ )
77
83
  end
78
84
 
79
85
  @#{method}_strategy.assign_value(acc, field, value)