ree_lib 1.0.86 → 1.0.88

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile.lock +28 -23
  4. data/lib/ree_lib/packages/ree_dao/package/ree_dao/wrappers/pg_array.rb +12 -8
  5. data/lib/ree_lib/packages/ree_dao/package/ree_dao/wrappers/pg_jsonb.rb +12 -8
  6. data/lib/ree_lib/packages/ree_dao/spec/ree_dao/wrappers/pg_array_spec.rb +3 -3
  7. data/lib/ree_lib/packages/ree_dao/spec/ree_dao/wrappers/pg_jsonb_spec.rb +4 -4
  8. data/lib/ree_lib/packages/ree_enum/package/ree_enum/base_enum_mapper.rb +5 -5
  9. data/lib/ree_lib/packages/ree_enum/package/ree_enum/integer_value_enum_mapper.rb +5 -5
  10. data/lib/ree_lib/packages/ree_enum/package/ree_enum/string_value_enum_mapper.rb +5 -5
  11. data/lib/ree_lib/packages/ree_enum/spec/ree_enum/dsl_spec.rb +3 -3
  12. data/lib/ree_lib/packages/ree_http/package/ree_http/functions/execute_request.rb +27 -20
  13. data/lib/ree_lib/packages/ree_http/schemas/ree_http/functions/execute_request.schema.json +8 -0
  14. data/lib/ree_lib/packages/ree_http/spec/ree_http/functions/http_delete_spec.rb +10 -8
  15. data/lib/ree_lib/packages/ree_http/spec/ree_http/functions/http_get_spec.rb +79 -18
  16. data/lib/ree_lib/packages/ree_http/spec/ree_http/functions/http_options_spec.rb +6 -5
  17. data/lib/ree_lib/packages/ree_http/spec/ree_http/functions/http_patch_spec.rb +8 -4
  18. data/lib/ree_lib/packages/ree_http/spec/ree_http/functions/http_post_spec.rb +5 -10
  19. data/lib/ree_lib/packages/ree_http/spec/ree_http/functions/http_put_spec.rb +5 -3
  20. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/errors/coercion_error.rb +1 -1
  21. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/errors/error_with_location.rb +25 -0
  22. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/errors/type_error.rb +1 -1
  23. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/field.rb +12 -4
  24. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb +32 -10
  25. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb +17 -4
  26. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/any.rb +8 -8
  27. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/bool.rb +12 -12
  28. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/date.rb +13 -13
  29. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/date_time.rb +13 -13
  30. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/float.rb +13 -13
  31. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/integer.rb +13 -13
  32. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/rational.rb +13 -13
  33. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/string.rb +12 -12
  34. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/time.rb +13 -13
  35. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/wrappers/array.rb +73 -21
  36. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper.rb +1 -0
  37. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/benchmarks/mapper_benchmark_spec.rb +31 -0
  38. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_factory_spec.rb +10 -6
  39. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_spec.rb +7 -0
  40. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/bool_spec.rb +8 -8
  41. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/date_spec.rb +10 -10
  42. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/date_time_spec.rb +16 -16
  43. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/float_spec.rb +13 -13
  44. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/hash_spec.rb +2 -2
  45. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/integer_spec.rb +14 -14
  46. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/rational_spec.rb +12 -12
  47. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/string_spec.rb +12 -12
  48. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/time_spec.rb +17 -16
  49. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/type_options_spec.rb +4 -4
  50. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/wrappers/array_spec.rb +6 -6
  51. data/lib/ree_lib/spec.init.rb +3 -1
  52. data/lib/ree_lib/version.rb +1 -1
  53. metadata +19 -3
@@ -38,7 +38,7 @@ RSpec.describe :http_get do
38
38
 
39
39
  http_get(
40
40
  host,
41
- basic_auth: {username: 'user', password: 'pass'}
41
+ basic_auth: { username: 'user', password: 'pass' }
42
42
  )
43
43
  expect(WebMock).to have_requested(:get, host).with(basic_auth: ['user', 'pass'])
44
44
 
@@ -50,20 +50,20 @@ RSpec.describe :http_get do
50
50
 
51
51
  http_get(
52
52
  host,
53
- query_params: { q: 100, "s"=> 'simple'}
53
+ query_params: { q: 100, "s"=> 'simple' }
54
54
  )
55
- expect(WebMock).to have_requested(:get, host).with(query: { "q"=> 100, "s"=> "simple"})
55
+ expect(WebMock).to have_requested(:get, host).with(query: { "q"=> 100, "s"=> "simple" })
56
56
 
57
57
  http_get(
58
58
  host_with_path + '?a=200',
59
- query_params: { q: 100, "s"=> 'simple'}
59
+ query_params: { q: 100, "s"=> 'simple' }
60
60
  )
61
- expect(WebMock).to have_requested(:get, host_with_path).with(query: {"a"=>200, "q"=> 100, "s"=> "simple"})
61
+
62
+ expect(WebMock).to have_requested(:get, host_with_path).with(query: { "a"=>200, "q"=> 100, "s"=> "simple" })
62
63
  end
63
64
  end
64
65
 
65
66
  context "force ssl" do
66
-
67
67
  before :all do
68
68
  WebMock.reset!
69
69
  WebMock
@@ -84,6 +84,7 @@ RSpec.describe :http_get do
84
84
  host,
85
85
  force_ssl: true, headers: { token: '321'}
86
86
  )
87
+
87
88
  expect(WebMock).to have_requested(:get, host_with_ssl).with(headers: { 'Token'=>'321' })
88
89
  end
89
90
  end
@@ -100,7 +101,7 @@ RSpec.describe :http_get do
100
101
  'User-Agent'=>'Ruby',
101
102
  }
102
103
  )
103
- .to_return(status: 307, headers: {'Location': 'https://www.example.com/'})
104
+ .to_return(status: 307, headers: { 'Location': 'https://www.example.com/' })
104
105
 
105
106
  WebMock
106
107
  .stub_request(:get, 'https://www.example.com/redirect_303')
@@ -111,7 +112,51 @@ RSpec.describe :http_get do
111
112
  'User-Agent'=>'Ruby',
112
113
  }
113
114
  )
114
- .to_return(status: 303, headers: {'Location': 'https://www.example.com/'})
115
+ .to_return(status: 303, headers: { 'Location': 'https://www.example.com/' })
116
+
117
+ WebMock
118
+ .stub_request(:any, 'https://domain.com')
119
+ .with(
120
+ headers: {
121
+ 'Accept'=>'*/*',
122
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
123
+ 'User-Agent'=>'Ruby',
124
+ }
125
+ )
126
+ .to_return(status: 302, headers: { 'Location': 'https://www.domain.com' })
127
+
128
+ WebMock
129
+ .stub_request(:any, 'https://www.domain.com')
130
+ .with(
131
+ headers: {
132
+ 'Accept'=>'*/*',
133
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
134
+ 'User-Agent'=>'Ruby',
135
+ }
136
+ )
137
+ .to_return(status: 200, headers: {})
138
+
139
+ WebMock
140
+ .stub_request(:any, 'https://www.anotherdomain.com')
141
+ .with(
142
+ headers: {
143
+ 'Accept'=>'*/*',
144
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
145
+ 'User-Agent'=>'Ruby',
146
+ }
147
+ )
148
+ .to_return(status: 302, headers: { 'Location': 'https://sub.anotherdomain.com' })
149
+
150
+ WebMock
151
+ .stub_request(:any, 'https://sub.anotherdomain.com')
152
+ .with(
153
+ headers: {
154
+ 'Accept'=>'*/*',
155
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
156
+ 'User-Agent'=>'Ruby',
157
+ }
158
+ )
159
+ .to_return(status: 200, headers: {})
115
160
 
116
161
  WebMock
117
162
  .stub_request(:any, 'https://www.example.com/redirect_303_infinity')
@@ -122,7 +167,7 @@ RSpec.describe :http_get do
122
167
  'User-Agent'=>'Ruby',
123
168
  }
124
169
  )
125
- .to_return(status: 303, headers: {'Location': 'https://www.example.com/redirect_303_infinity'})
170
+ .to_return(status: 303, headers: { 'Location': 'https://www.example.com/redirect_303_infinity' })
126
171
 
127
172
  WebMock
128
173
  .stub_request(:any, 'https://www.example.com/')
@@ -130,36 +175,52 @@ RSpec.describe :http_get do
130
175
  headers: {
131
176
  'Accept'=>'*/*',
132
177
  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
133
- 'User-Agent'=>'Ruby',
134
- 'Token'=>'123'
178
+ 'Host' => 'www.example.com',
179
+ 'User-Agent'=>'Ruby'
135
180
  }
136
181
  )
137
- .to_return(status: 200, headers: {'Token': '123'})
182
+ .to_return(status: 200, headers: { 'Token': '123' })
138
183
  end
184
+
139
185
  after :all do
140
186
  WebMock.reset!
141
187
  end
188
+
142
189
  include ReeHttp::HttpExceptions
190
+
143
191
  let(:err_result) {
144
192
  http_get(
145
- host_with_ssl + '/redirect_303_infinity',
193
+ 'https://www.example.com/redirect_303_infinity',
146
194
  force_ssl: true, headers: { token: '123'}
147
195
  )
148
196
  }
149
197
 
150
198
  it do
151
- expect{err_result}.to raise_error(ReeHttp::HttpExceptions::TooManyRedirectsError)
199
+ expect{ err_result }.to raise_error(ReeHttp::HttpExceptions::TooManyRedirectsError)
152
200
 
153
201
  http_get(
154
- host_with_ssl + '/redirect_307',
155
- force_ssl: true, headers: { token: '123'}
202
+ "https://domain.com",
203
+ force_ssl: true
156
204
  )
157
205
 
206
+ expect(WebMock).to have_requested(:get, "https://domain.com").once
207
+ expect(WebMock).to have_requested(:get, "https://www.domain.com").once
208
+
158
209
  http_get(
159
- host_with_ssl + '/redirect_303',
210
+ "https://www.anotherdomain.com",
211
+ force_ssl: true
212
+ )
213
+
214
+ expect(WebMock).to have_requested(:get, "https://www.anotherdomain.com").once
215
+ expect(WebMock).to have_requested(:get, "https://sub.anotherdomain.com").once
216
+
217
+ http_get(
218
+ host_with_ssl + '/redirect_307',
160
219
  force_ssl: true, headers: { token: '123'}
161
220
  )
162
- expect(WebMock).to have_requested(:get, host_with_ssl).with(headers: { 'Token'=>'123' }).twice
221
+
222
+ expect(WebMock).to have_requested(:get, 'https://www.example.com/redirect_307').with(headers: { token: '123'}).once
223
+ expect(WebMock).to have_requested(:get, 'https://www.example.com').once
163
224
  end
164
225
  end
165
226
  end
@@ -148,10 +148,10 @@ RSpec.describe :http_options do
148
148
  'Accept'=>'*/*',
149
149
  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
150
150
  'User-Agent'=>'Ruby',
151
- 'Token'=>'123'
151
+ 'Host' => 'www.example.com'
152
152
  }
153
153
  )
154
- .to_return(status: 200, headers: {'Token': '123'})
154
+ .to_return(status: 200)
155
155
  end
156
156
  after :all do
157
157
  WebMock.reset!
@@ -171,14 +171,15 @@ RSpec.describe :http_options do
171
171
  host_with_ssl + '/redirect_307',
172
172
  force_ssl: true, headers: { token: '123'}
173
173
  )
174
- expect(WebMock).to have_requested(:options, host_with_ssl).with(headers: { 'Token'=>'123' })
174
+ expect(WebMock).to have_requested(:options, host_with_ssl + '/redirect_307').with(headers: { 'Token'=>'123' }).once
175
+ expect(WebMock).to have_requested(:options, host_with_ssl).once
175
176
 
176
177
  http_options(
177
178
  host_with_ssl + '/redirect_303',
178
179
  force_ssl: true, headers: { token: '123'}
179
180
  )
180
- expect(WebMock).to have_requested(:get, host_with_ssl).with(headers: { 'Token'=>'123' })
181
+ expect(WebMock).to have_requested(:options, host_with_ssl + '/redirect_303').with(headers: { 'Token'=>'123' })
182
+ expect(WebMock).to have_requested(:get, host_with_ssl).once
181
183
  end
182
184
  end
183
185
  end
184
-
@@ -141,10 +141,10 @@ RSpec.describe :http_patch do
141
141
  'Accept'=>'*/*',
142
142
  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
143
143
  'User-Agent'=>'Ruby',
144
- 'Token'=>'123'
144
+ 'Host' => 'www.example.com'
145
145
  }
146
146
  )
147
- .to_return(status: 200, headers: {'Token': '123'})
147
+ .to_return(status: 200)
148
148
  end
149
149
  after :all do
150
150
  WebMock.reset!
@@ -164,13 +164,17 @@ RSpec.describe :http_patch do
164
164
  host_with_ssl + '/redirect_307',
165
165
  force_ssl: true, headers: { token: '123'}
166
166
  )
167
- expect(WebMock).to have_requested(:patch, host_with_ssl).with(headers: { 'Token'=>'123' })
167
+
168
+ expect(WebMock).to have_requested(:patch, host_with_ssl + '/redirect_307').with(headers: { 'Token'=>'123' }).once
169
+ expect(WebMock).to have_requested(:patch, host_with_ssl).once
168
170
 
169
171
  http_patch(
170
172
  host_with_ssl + '/redirect_303',
171
173
  force_ssl: true, headers: { token: '123'}
172
174
  )
173
- expect(WebMock).to have_requested(:get, host_with_ssl).with(headers: { 'Token'=>'123' })
175
+
176
+ expect(WebMock).to have_requested(:patch, host_with_ssl + '/redirect_303').with(headers: { 'Token'=>'123' }).once
177
+ expect(WebMock).to have_requested(:get, host_with_ssl).once
174
178
  end
175
179
  end
176
180
  end
@@ -90,13 +90,6 @@ RSpec.describe :http_post do
90
90
  ensure
91
91
  tempfile&.close!
92
92
  end
93
-
94
- # works !
95
- # response = http_post(
96
- # 'http://127.0.0.1:8085/end',
97
- # query_params: { q: 100, "s"=> 'simple'},
98
- # form_data: {arg: "abc"}
99
- # )
100
93
  end
101
94
  end
102
95
 
@@ -169,7 +162,7 @@ RSpec.describe :http_post do
169
162
  'Accept'=>'*/*',
170
163
  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
171
164
  'User-Agent'=>'Ruby',
172
- 'Token'=>'123'
165
+ 'Host'=>'www.example.com'
173
166
  }
174
167
  )
175
168
  .to_return(status: 200, headers: {'Token': '123'})
@@ -192,13 +185,15 @@ RSpec.describe :http_post do
192
185
  host_with_ssl + '/redirect_307',
193
186
  force_ssl: true, headers: { token: '123'}
194
187
  )
195
- expect(WebMock).to have_requested(:post, host_with_ssl).with(headers: { 'Token'=>'123' })
188
+ expect(WebMock).to have_requested(:post, host_with_ssl + "/redirect_307").with(headers: { 'Token'=>'123' }).once
189
+ expect(WebMock).to have_requested(:post, host_with_ssl).once
196
190
 
197
191
  http_post(
198
192
  host_with_ssl + '/redirect_303',
199
193
  force_ssl: true, headers: { token: '123'}
200
194
  )
201
- expect(WebMock).to have_requested(:get, host_with_ssl).with(headers: { 'Token'=>'123' })
195
+ expect(WebMock).to have_requested(:post, host_with_ssl + "/redirect_303").with(headers: { 'Token'=>'123' }).once
196
+ expect(WebMock).to have_requested(:get, host_with_ssl).once
202
197
  end
203
198
  end
204
199
  end
@@ -141,7 +141,7 @@ RSpec.describe :http_put do
141
141
  'Accept'=>'*/*',
142
142
  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
143
143
  'User-Agent'=>'Ruby',
144
- 'Token'=>'123'
144
+ 'Host' => 'www.example.com'
145
145
  }
146
146
  )
147
147
  .to_return(status: 200, headers: {'Token': '123'})
@@ -164,13 +164,15 @@ RSpec.describe :http_put do
164
164
  host_with_ssl + '/redirect_307',
165
165
  force_ssl: true, headers: { token: '123'}
166
166
  )
167
- expect(WebMock).to have_requested(:put, host_with_ssl).with(headers: { 'Token'=>'123' })
167
+ expect(WebMock).to have_requested(:put, host_with_ssl + '/redirect_307').with(headers: { 'Token'=>'123' }).once
168
+ expect(WebMock).to have_requested(:put, host_with_ssl).once
168
169
 
169
170
  http_put(
170
171
  host_with_ssl + '/redirect_303',
171
172
  force_ssl: true, headers: { token: '123'}
172
173
  )
173
- expect(WebMock).to have_requested(:get, host_with_ssl).with(headers: { 'Token'=>'123' })
174
+ expect(WebMock).to have_requested(:put, host_with_ssl + '/redirect_303').with(headers: { 'Token'=>'123' }).once
175
+ expect(WebMock).to have_requested(:get, host_with_ssl).once
174
176
  end
175
177
  end
176
178
  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
 
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ReeMapper::Mapper
4
+ EMPTY_ARY = [].freeze
5
+
4
6
  contract(
5
7
  ArrayOf[ReeMapper::MapperStrategy],
6
8
  Nilor[ReeMapper::AbstractType, ReeMapper::AbstractWrapper] => self
@@ -23,19 +25,19 @@ class ReeMapper::Mapper
23
25
 
24
26
  if type
25
27
  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
26
- def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [])
28
+ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: EMPTY_ARY, location: nil)
27
29
  #{
28
30
  if type.is_a?(ReeMapper::AbstractWrapper)
29
- "@type.#{method}(obj, name: name, role: role, fields_filters: fields_filters)"
31
+ "@type.#{method}(obj, name: name, role: role, fields_filters: fields_filters, location: location)"
30
32
  else
31
- "@type.#{method}(obj, name: name, role: role)"
33
+ "@type.#{method}(obj, name: name, location: location)"
32
34
  end
33
35
  }
34
36
  end
35
37
  RUBY
36
38
  else
37
39
  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
38
- def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: [])
40
+ def #{method}(obj, name: nil, role: nil, only: nil, except: nil, fields_filters: EMPTY_ARY, location: nil)
39
41
  if only && !ReeMapper::FilterFieldsContract.valid?(only)
40
42
  raise ReeMapper::ArgumentError, "Invalid `only` format"
41
43
  end
@@ -47,7 +49,11 @@ class ReeMapper::Mapper
47
49
  user_fields_filter = ReeMapper::FieldsFilter.build(only: only, except: except)
48
50
 
49
51
  @fields.each_with_object(@#{method}_strategy.build_object) do |(_, field), acc|
50
- field_fields_filters = fields_filters + [user_fields_filter]
52
+ field_fields_filters = if user_fields_filter == ReeMapper::FieldsFilter::NoneStrategy
53
+ fields_filters
54
+ else
55
+ fields_filters + [user_fields_filter]
56
+ end
51
57
 
52
58
  next unless field_fields_filters.all? { _1.allow? field.name }
53
59
  next unless field.has_role?(role)
@@ -56,7 +62,10 @@ class ReeMapper::Mapper
56
62
  is_optional = field.optional || @#{method}_strategy.always_optional
57
63
 
58
64
  if !is_with_value && !is_optional
59
- raise ReeMapper::TypeError, "Missing required field `\#{field.from_as_str}` for `\#{name || 'root'}`"
65
+ raise ReeMapper::TypeError.new(
66
+ "Missing required field `\#{field.from_as_str}` for `\#{name || 'root'}`",
67
+ field.location
68
+ )
60
69
  end
61
70
 
62
71
  next if !is_with_value && !field.has_default?
@@ -70,10 +79,23 @@ class ReeMapper::Mapper
70
79
  unless value.nil? && field.null
71
80
  nested_name = name ? "\#{name}[\#{field.name_as_str}]" : field.name_as_str
72
81
 
73
- nested_fields_filters = field_fields_filters.map { _1.filter_for(field.name) }
74
- nested_fields_filters += [field.fields_filter]
75
-
76
- value = field.type.#{method}(value, name: nested_name, role: role, fields_filters: nested_fields_filters)
82
+ nested_fields_filters = if field_fields_filters.empty?
83
+ field_fields_filters
84
+ else
85
+ field_fields_filters.map { _1.filter_for(field.name) }
86
+ end
87
+
88
+ if field.fields_filter != ReeMapper::FieldsFilter::NoneStrategy
89
+ nested_fields_filters += [field.fields_filter]
90
+ end
91
+
92
+ value = field.type.#{method}(
93
+ value,
94
+ name: nested_name,
95
+ role: role,
96
+ fields_filters: nested_fields_filters,
97
+ location: field.location,
98
+ )
77
99
  end
78
100
 
79
101
  @#{method}_strategy.assign_value(acc, field, value)
@@ -43,7 +43,13 @@ class ReeMapper::MapperFactory
43
43
  raise ReeMapper::UnsupportedTypeError, "type :#{name} should implement `\#{@mapper.strategy_methods.join(', ')}`"
44
44
  end
45
45
 
46
- field = ReeMapper::Field.new(type, field_name, optional: optional, **opts)
46
+ field = ReeMapper::Field.new(
47
+ type,
48
+ field_name,
49
+ optional: optional,
50
+ **opts,
51
+ location: caller_locations&.first&.to_s
52
+ )
47
53
 
48
54
  return field unless field_name
49
55
 
@@ -90,7 +96,8 @@ class ReeMapper::MapperFactory
90
96
 
91
97
  if blk
92
98
  subject = ReeMapper::Field.new(
93
- hash_from_blk(dto: dto, &blk)
99
+ hash_from_blk(dto: dto, &blk),
100
+ location: caller_locations&.first&.to_s,
94
101
  )
95
102
  end
96
103
 
@@ -105,7 +112,13 @@ class ReeMapper::MapperFactory
105
112
  type = ReeMapper::Mapper.build(@mapper.strategies, wrapper.new(subject))
106
113
  type.name = :#{name}
107
114
 
108
- field = ReeMapper::Field.new(type, field_name, optional: optional, **opts)
115
+ field = ReeMapper::Field.new(
116
+ type,
117
+ field_name,
118
+ optional: optional,
119
+ **opts,
120
+ location: caller_locations&.first&.to_s,
121
+ )
109
122
 
110
123
  return field unless field_name
111
124
 
@@ -141,7 +154,7 @@ class ReeMapper::MapperFactory
141
154
 
142
155
  type = hash_from_blk(dto: dto, &blk)
143
156
 
144
- field = ReeMapper::Field.new(type, field_name, **opts)
157
+ field = ReeMapper::Field.new(type, field_name, **opts, location: caller_locations&.first&.to_s)
145
158
 
146
159
  @mapper.add_field(field)
147
160
  end
@@ -1,23 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ReeMapper::Any < ReeMapper::AbstractType
4
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
5
- def serialize(value, name:, role: nil)
4
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Any)
5
+ def serialize(value, name:, location: nil)
6
6
  value
7
7
  end
8
8
 
9
- contract(Any , Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
10
- def cast(value, name:, role: nil)
9
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Any)
10
+ def cast(value, name:, location: nil)
11
11
  value
12
12
  end
13
13
 
14
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
15
- def db_dump(value, name:, role: nil)
14
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Any)
15
+ def db_dump(value, name:, location: nil)
16
16
  value
17
17
  end
18
18
 
19
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Any)
20
- def db_load(value, name:, role: nil)
19
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Any)
20
+ def db_load(value, name:, location: nil)
21
21
  value
22
22
  end
23
23
  end
@@ -4,33 +4,33 @@ class ReeMapper::Bool < ReeMapper::AbstractType
4
4
  TRUE_CAST_VALUES = ['1', 'true', 'on', 1, true].freeze
5
5
  FALSE_CAST_VALUES = ['0', 'false', 'off', 0, false].freeze
6
6
 
7
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Bool).throws(ReeMapper::TypeError)
8
- def serialize(value, name:, role: nil)
7
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Bool).throws(ReeMapper::TypeError)
8
+ def serialize(value, name:, location: nil)
9
9
  if value.is_a?(TrueClass) || value.is_a?(FalseClass)
10
10
  value
11
11
  else
12
- raise ReeMapper::TypeError, "`#{name}` should be a boolean, got `#{truncate(value.inspect)}`"
12
+ raise ReeMapper::TypeError.new("`#{name}` should be a boolean, got `#{truncate(value.inspect)}`", location)
13
13
  end
14
14
  end
15
15
 
16
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Bool).throws(ReeMapper::CoercionError)
17
- def cast(value, name:, role: nil)
16
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Bool).throws(ReeMapper::CoercionError)
17
+ def cast(value, name:, location: nil)
18
18
  if TRUE_CAST_VALUES.include?(value)
19
19
  true
20
20
  elsif FALSE_CAST_VALUES.include?(value)
21
21
  false
22
22
  else
23
- raise ReeMapper::CoercionError, "`#{name}` is invalid boolean, got `#{truncate(value.inspect)}`"
23
+ raise ReeMapper::CoercionError.new("`#{name}` is invalid boolean, got `#{truncate(value.inspect)}`", location)
24
24
  end
25
25
  end
26
26
 
27
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Bool).throws(ReeMapper::TypeError)
28
- def db_dump(value, name:, role: nil)
29
- serialize(value, name: name, role: role)
27
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Bool).throws(ReeMapper::TypeError)
28
+ def db_dump(value, name:, location: nil)
29
+ serialize(value, name: name, location: location)
30
30
  end
31
31
 
32
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Bool).throws(ReeMapper::CoercionError)
33
- def db_load(value, name:, role: nil)
34
- cast(value, name: name, role: role)
32
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Bool).throws(ReeMapper::CoercionError)
33
+ def db_load(value, name:, location: nil)
34
+ cast(value, name: name, location: location)
35
35
  end
36
36
  end
@@ -3,17 +3,17 @@
3
3
  require 'date'
4
4
 
5
5
  class ReeMapper::Date < ReeMapper::AbstractType
6
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Date).throws(ReeMapper::TypeError)
7
- def serialize(value, name:, role: nil)
6
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Date).throws(ReeMapper::TypeError)
7
+ def serialize(value, name:, location: nil)
8
8
  if value.class == Date
9
9
  value
10
10
  else
11
- raise ReeMapper::TypeError, "`#{name}` should be a date, got `#{truncate(value.inspect)}`"
11
+ raise ReeMapper::TypeError.new("`#{name}` should be a date, got `#{truncate(value.inspect)}`", location)
12
12
  end
13
13
  end
14
14
 
15
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Date).throws(ReeMapper::TypeError, ReeMapper::CoercionError)
16
- def cast(value, name:, role: nil)
15
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Date).throws(ReeMapper::TypeError, ReeMapper::CoercionError)
16
+ def cast(value, name:, location: nil)
17
17
  if value.class == Date
18
18
  value
19
19
  elsif value.class == DateTime || value.class == Time
@@ -22,20 +22,20 @@ class ReeMapper::Date < ReeMapper::AbstractType
22
22
  begin
23
23
  Date.parse(value)
24
24
  rescue ArgumentError => e
25
- raise ReeMapper::CoercionError, "`#{name}` is invalid date, got `#{truncate(value.inspect)}`"
25
+ raise ReeMapper::CoercionError.new("`#{name}` is invalid date, got `#{truncate(value.inspect)}`", location)
26
26
  end
27
27
  else
28
- raise ReeMapper::TypeError, "`#{name}` should be a date, got `#{truncate(value.inspect)}`"
28
+ raise ReeMapper::TypeError.new("`#{name}` should be a date, got `#{truncate(value.inspect)}`", location)
29
29
  end
30
30
  end
31
31
 
32
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Date).throws(ReeMapper::TypeError)
33
- def db_dump(value, name:, role: nil)
34
- serialize(value, name: name, role: role)
32
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Date).throws(ReeMapper::TypeError)
33
+ def db_dump(value, name:, location: nil)
34
+ serialize(value, name: name, location: location)
35
35
  end
36
36
 
37
- contract(Any, Kwargs[name: String, role: Nilor[Symbol, ArrayOf[Symbol]]] => Date).throws(ReeMapper::TypeError, ReeMapper::CoercionError)
38
- def db_load(value, name:, role: nil)
39
- cast(value, name: name, role: role)
37
+ contract(Any, Kwargs[name: String, location: Nilor[String]] => Date).throws(ReeMapper::TypeError, ReeMapper::CoercionError)
38
+ def db_load(value, name:, location: nil)
39
+ cast(value, name: name, location: location)
40
40
  end
41
41
  end