ree_lib 1.0.35 → 1.0.36

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: 190a7da138d373c34c6e7636265ccce86c37e6ad5fd0c02b4e3c81c7e376393a
4
- data.tar.gz: ad6b89d186eec9a9006cc6d217ee82d6f20a34428bd052953aac7e2624a6b41c
3
+ metadata.gz: 61b5c4cb5d7eef9fc932ebe3a674c5c752cb82d035248910a8a3da7a1ffe45b5
4
+ data.tar.gz: d604e93726df4c19ebfe4c244a9d91da836e2a587d8599969bd9e5980a4e07d9
5
5
  SHA512:
6
- metadata.gz: 45199483809ad7917a207699df3acd7689db5dd246dfdce7910a7427a4d100750196a903b51aba2e24d0594141a01b8086e0767f9427b555fa2bdece22e83491
7
- data.tar.gz: d20668755d3da265a0ec0351220dfe9604cfaf21ebbb78833b093445afd01280e7b6e7d83ebba428b3808c346754fb1debcbed29197098f136c3b1a30bb24369
6
+ metadata.gz: e05879958d07507dce29039623c4c88a5eb4b49ea7c9eee56b86346f004cbea2f455a42464142cc91d04aeefb07e65d3f2436073a3e58bcfd9434b6512cc8d31
7
+ data.tar.gz: c5888ac8151e1016bde7705fdbdc13bc4f814007401ff23d9da9bac160810ca6e1b92008015b507e90a110035848189d6d291093b7fea42ca1df7d6c5f962c24
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ree_lib (1.0.35)
4
+ ree_lib (1.0.36)
5
5
  binding_of_caller (~> 1.0.0)
6
6
  i18n (~> 1.12.0)
7
7
  loofah (~> 2.18.0)
@@ -36,6 +36,8 @@ GEM
36
36
  crass (~> 1.0.2)
37
37
  nokogiri (>= 1.5.9)
38
38
  msgpack (1.6.0)
39
+ nokogiri (1.14.2-x86_64-darwin)
40
+ racc (~> 1.4)
39
41
  nokogiri (1.14.2-x86_64-linux)
40
42
  racc (~> 1.4)
41
43
  oj (3.13.23)
@@ -44,7 +46,7 @@ GEM
44
46
  racc (1.6.2)
45
47
  rainbow (3.1.1)
46
48
  rake (13.0.6)
47
- ree (1.0.23)
49
+ ree (1.0.26)
48
50
  commander (~> 4.6.0)
49
51
  rexml (3.2.5)
50
52
  rollbar (3.3.3)
@@ -18,13 +18,13 @@ class ReeMapper::BuildMapperFactory
18
18
  @strategies = strategies
19
19
  }
20
20
 
21
- klass.register(:bool, Mapper.build(strategies, ReeMapper::Bool.new))
22
- klass.register(:date_time, Mapper.build(strategies, ReeMapper::DateTime.new))
23
- klass.register(:time, Mapper.build(strategies, ReeMapper::Time.new))
24
- klass.register(:date, Mapper.build(strategies, ReeMapper::Date.new))
25
- klass.register(:float, Mapper.build(strategies, ReeMapper::Float.new))
26
- klass.register(:integer, Mapper.build(strategies, ReeMapper::Integer.new))
27
- klass.register(:string, Mapper.build(strategies, ReeMapper::String.new))
21
+ klass.register_type(:bool, ReeMapper::Bool.new)
22
+ klass.register_type(:date_time, ReeMapper::DateTime.new)
23
+ klass.register_type(:time, ReeMapper::Time.new)
24
+ klass.register_type(:date, ReeMapper::Date.new)
25
+ klass.register_type(:float, ReeMapper::Float.new)
26
+ klass.register_type(:integer, ReeMapper::Integer.new)
27
+ klass.register_type(:string, ReeMapper::String.new)
28
28
 
29
29
  klass
30
30
  end
@@ -7,7 +7,7 @@ class ReeMapper::Mapper
7
7
  strategies.each do |strategy|
8
8
  method = strategy.method
9
9
  next if type.respond_to?(method)
10
- raise ReeMapper::UnsupportedTypeError, "type #{type.name} should implement method `#{method}`"
10
+ raise ReeMapper::UnsupportedTypeError, "type #{type.inspect} should implement method `#{method}`"
11
11
  end
12
12
  end
13
13
 
@@ -113,7 +113,7 @@ class ReeMapper::Mapper
113
113
 
114
114
  contract(Symbol => Class).throws(ArgumentError)
115
115
  def dto(strategy_method)
116
- strategy = strategies.detect { _1.method == strategy_method }
116
+ strategy = find_strategy(strategy_method)
117
117
  raise ArgumentError, "there is no :#{strategy_method} strategy" unless strategy
118
118
  strategy.dto
119
119
  end
@@ -124,4 +124,9 @@ class ReeMapper::Mapper
124
124
  strategies.each { _1.prepare_dto(fields.keys) }
125
125
  nil
126
126
  end
127
+
128
+ contract(Symbol => Nilor[ReeMapper::MapperStrategy])
129
+ def find_strategy(strategy_method)
130
+ strategies.detect { _1.method == strategy_method }
131
+ end
127
132
  end
@@ -5,35 +5,42 @@ class ReeMapper::MapperFactory
5
5
  attr_reader :types, :strategies
6
6
  end
7
7
 
8
- contract(Symbol, Any => Class).throws(ArgumentError)
9
- def self.register_type(name, object_type)
10
- register(
8
+ contract(Symbol => Nilor[ReeMapper::MapperStrategy])
9
+ def self.find_strategy(strategy_method)
10
+ strategies.detect { _1.method == strategy_method }
11
+ end
12
+
13
+ contract(Symbol, ReeMapper::AbstractType, Kwargs[strategies: ArrayOf[ReeMapper::MapperStrategy]] => Class)
14
+ def self.register_type(name, object_type, strategies: self.strategies)
15
+ register_mapper(
11
16
  name,
12
17
  ReeMapper::Mapper.build(strategies, object_type)
13
18
  )
14
19
  end
15
20
 
16
- contract(Symbol, Any => Class).throws(ArgumentError)
17
- def self.register(name, type)
18
- raise ArgumentError, "name of mapper type should not include `?`" if name.to_s.end_with?('?')
19
- raise ArgumentError, "type :#{name} already registered" if types.key?(name)
20
- raise ArgumentError, "method :#{name} already defined" if method_defined?(name)
21
+ contract(Symbol, ReeMapper::Mapper => Class).throws(ArgumentError)
22
+ def self.register_mapper(name, type)
23
+ raise ArgumentError, "name of mapper type should not end with `?`" if name.to_s.end_with?('?')
24
+
25
+ defined_strategy_method = types[name]&.flat_map(&:strategy_methods)&.detect { type.find_strategy(_1) }
26
+ raise ArgumentError, "type :#{name} with `#{defined_strategy_method}` strategy already registered" if defined_strategy_method
27
+ raise ArgumentError, "method :#{name} already defined" if !types.key?(name) && method_defined?(name)
21
28
 
22
29
  type = type.dup
23
30
  type.name = name
24
31
  type.freeze
25
- types[name] = type
32
+ types[name] ||= []
33
+ types[name] << type
26
34
 
27
35
  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
28
36
  def #{name}(field_name = nil, optional: false, **opts)
29
37
  raise ReeMapper::Error, "invalid DSL usage" unless @mapper
30
38
  raise ArgumentError, "array item can't be optional" if field_name.nil? && optional
31
39
 
32
- type = self.class.types.fetch(:#{name})
40
+ type = self.class.types.fetch(:#{name}).detect { (@mapper.strategy_methods - _1.strategy_methods).empty? }
33
41
 
34
- @mapper.strategy_methods.each do |method|
35
- next if type.respond_to?(method)
36
- raise ReeMapper::UnsupportedTypeError, "type :#{name} should implement method `\#{method}`"
42
+ unless type
43
+ raise ReeMapper::UnsupportedTypeError, "type :#{name} should implement `\#{@mapper.strategy_methods.join(', ')}`"
37
44
  end
38
45
 
39
46
  return ReeMapper::Field.new(type, optional: optional, **opts) unless field_name
@@ -22,7 +22,7 @@ class ReeMapper::MapperFactoryProxy
22
22
  if strategy_or_method.is_a?(ReeMapper::MapperStrategy)
23
23
  strategy = strategy_or_method
24
24
  else
25
- strategy = mapper_factory.strategies.detect { _1.method == strategy_or_method }
25
+ strategy = mapper_factory.find_strategy(strategy_or_method)
26
26
  raise ArgumentError, "MapperFactory strategy :#{strategy_or_method} not found" unless strategy
27
27
  strategy = strategy.dup
28
28
  strategy.dto = dto if dto
@@ -36,7 +36,7 @@ class ReeMapper::MapperFactoryProxy
36
36
  mapper_factory.new(mapper).instance_exec(&blk)
37
37
  mapper.prepare_dto
38
38
 
39
- mapper_factory.register(register_as, mapper) if register_as
39
+ mapper_factory.register_mapper(register_as, mapper) if register_as
40
40
 
41
41
  after_build&.call(mapper)
42
42
 
@@ -1,17 +1,2 @@
1
1
  class ReeMapper::AbstractType
2
- def serialize(value, name:, role: nil)
3
- raise NotImplementedError
4
- end
5
-
6
- def cast(value, name:, role: nil)
7
- raise NotImplementedError
8
- end
9
-
10
- def db_dump(value, name:, role: nil)
11
- raise NotImplementedError
12
- end
13
-
14
- def db_load(value, name:, role: nil)
15
- raise NotImplementedError
16
- end
17
2
  end
@@ -20,6 +20,8 @@ class ReeMapper::Float < ReeMapper::AbstractType
20
20
  rescue ArgumentError => e
21
21
  raise ReeMapper::CoercionError, "`#{name}` is invalid float"
22
22
  end
23
+ elsif defined?(BigDecimal) && value.is_a?(BigDecimal)
24
+ value.to_f
23
25
  else
24
26
  raise ReeMapper::TypeError, "`#{name}` should be a float"
25
27
  end
@@ -160,7 +160,7 @@ Create `mapper_factory.rb` file to declare `MapperFactory` class.
160
160
  build_mapper_strategy(method: :db_load, dto: Object)
161
161
  ])
162
162
 
163
- mapper_factory.register(:cart_user, user_caster)
163
+ mapper_factory.register_mapper(:cart_user, user_caster)
164
164
 
165
165
  mapper_factory
166
166
  end
@@ -5,35 +5,76 @@ RSpec.describe ReeMapper::MapperFactory do
5
5
  link :build_mapper_factory, from: :ree_mapper
6
6
  link :build_mapper_strategy, from: :ree_mapper
7
7
 
8
- let(:mapper_factory) {
9
- build_mapper_factory(strategies: [
10
- build_mapper_strategy(method: :cast, dto: Hash)
11
- ])
12
- }
8
+ let(:cast_strategy) { build_mapper_strategy(method: :cast, dto: Hash) }
9
+ let(:serialize_strategy) { build_mapper_strategy(method: :serialize, dto: Hash) }
10
+ let(:mapper_factory) { build_mapper_factory(strategies: [cast_strategy, serialize_strategy]) }
11
+
12
+ describe '.register_type' do
13
+ let(:mapper_type) {
14
+ Class.new(ReeMapper::AbstractType) do
15
+ def cast(*); :value end
16
+ def serialize(*); end
17
+ end
18
+ }
13
19
 
14
- describe '.register' do
15
20
  it {
16
- mapper_factory.register(:new_type, ReeMapper::Mapper.build([], ReeMapper::AbstractType.new))
17
- expect(mapper_factory.instance_methods).to include(:new_type)
21
+ mapper_factory.register_type(:new_type, mapper_type.new)
22
+ expect(
23
+ mapper_factory.call.use(:cast) { new_type :val }.cast({ val: :any })
24
+ ).to eq({ val: :value })
18
25
  }
19
26
 
20
- it 'raise an error if the type is already registered' do
21
- mapper_factory.register(:new_type, ReeMapper::Mapper.build([], ReeMapper::AbstractType.new))
27
+ it {
28
+ mapper_factory.register_type(:new_type, mapper_type.new, strategies: [cast_strategy])
29
+ expect(
30
+ mapper_factory.call.use(:cast) { new_type :val }.cast({ val: :any })
31
+ ).to eq({ val: :value })
32
+ }
33
+ end
34
+
35
+ describe '.register_mapper' do
36
+ let(:serializer) { mapper_factory.call.use(:serialize) { integer :id } }
37
+
38
+ it {
39
+ mapper_factory.register_mapper(:new_type, serializer)
40
+
41
+ expect(
42
+ mapper_factory.call.use(:serialize) { new_type :val }.serialize({ val: { id: 1 } })
43
+ ).to eq({ val: { id: 1 } })
44
+ }
45
+
46
+ it 'allow to register caster and serializer with same name' do
47
+ caster = mapper_factory.call.use(:cast) { string :name }
48
+
49
+ mapper_factory.register_mapper(:new_type, serializer)
50
+ mapper_factory.register_mapper(:new_type, caster)
51
+
52
+ expect(
53
+ mapper_factory.call.use(:serialize) { new_type :val }.serialize({ val: { id: 1 } })
54
+ ).to eq({ val: { id: 1 } })
55
+
56
+ expect(
57
+ mapper_factory.call.use(:cast) { new_type :val }.cast({ val: { name: '1' } })
58
+ ).to eq({ val: { name: '1' } })
59
+ end
60
+
61
+ it 'raise an error if the mapper is already registered' do
62
+ mapper_factory.register_mapper(:new_type, serializer)
22
63
 
23
64
  expect {
24
- mapper_factory.register(:new_type, ReeMapper::Mapper.build([], ReeMapper::AbstractType.new))
25
- }.to raise_error(ArgumentError, 'type :new_type already registered')
65
+ mapper_factory.register_mapper(:new_type, serializer)
66
+ }.to raise_error(ArgumentError, 'type :new_type with `serialize` strategy already registered')
26
67
  end
27
68
 
28
- it 'raise an error if the type is ended by ?' do
69
+ it 'raise an error if the mapper name is ended by ?' do
29
70
  expect {
30
- mapper_factory.register(:new_type?, ReeMapper::Mapper.build([], ReeMapper::AbstractType.new))
31
- }.to raise_error(ArgumentError)
71
+ mapper_factory.register_mapper(:new_type?, serializer)
72
+ }.to raise_error(ArgumentError, 'name of mapper type should not end with `?`')
32
73
  end
33
74
 
34
- it 'raise an error if the type method is already registered' do
75
+ it 'raise an error if the mapper name is reserved' do
35
76
  expect {
36
- mapper_factory.register(:array, ReeMapper::Mapper.build([], ReeMapper::AbstractType.new))
77
+ mapper_factory.register_mapper(:array, serializer)
37
78
  }.to raise_error(ArgumentError, 'method :array already defined')
38
79
  end
39
80
  end
@@ -48,13 +89,17 @@ RSpec.describe ReeMapper::MapperFactory do
48
89
  }
49
90
 
50
91
  it {
51
- mapper_factory.register(:new_type, ReeMapper::Mapper.build([], ReeMapper::AbstractType.new))
92
+ serializer = mapper_factory.call.use(:serialize) do
93
+ integer :my_field
94
+ end
95
+
96
+ mapper_factory.register_mapper(:new_type, serializer)
52
97
 
53
98
  expect {
54
99
  mapper_factory.call.use(:cast) do
55
100
  new_type :settings
56
101
  end
57
- }.to raise_error(ReeMapper::UnsupportedTypeError)
102
+ }.to raise_error(ReeMapper::UnsupportedTypeError, 'type :new_type should implement `cast`')
58
103
  }
59
104
 
60
105
  it {
@@ -62,7 +107,9 @@ RSpec.describe ReeMapper::MapperFactory do
62
107
  integer :id
63
108
  end
64
109
 
65
- expect(mapper_factory.instance_methods).to include(:user)
110
+ expect(
111
+ mapper_factory.call.use(:cast) { user :user }.cast({ user: { id: 1 } })
112
+ ).to eq({ user: { id: 1 } })
66
113
  }
67
114
 
68
115
  it {
@@ -80,4 +127,14 @@ RSpec.describe ReeMapper::MapperFactory do
80
127
  }.to raise_error(ReeMapper::ArgumentError, "mapper should contain at least one field")
81
128
  }
82
129
  end
130
+
131
+ describe '.find_strategy' do
132
+ it {
133
+ expect(mapper_factory.find_strategy(:cast)).to eq(cast_strategy)
134
+ }
135
+
136
+ it {
137
+ expect(mapper_factory.find_strategy(:unknown)).to be_nil
138
+ }
139
+ end
83
140
  end
@@ -92,7 +92,7 @@ RSpec.describe ReeMapper::Mapper do
92
92
  )
93
93
  }
94
94
 
95
- it {
95
+ it {
96
96
  expect(mapper.cast({ my_field: 1, hsh: { nested_field: 1 } })).to be_a(Struct)
97
97
  }
98
98
  end
@@ -166,4 +166,28 @@ RSpec.describe ReeMapper::Mapper do
166
166
  expect { mapper.dto(:db_dump) }.to raise_error(ArgumentError, "there is no :db_dump strategy")
167
167
  }
168
168
  end
169
+
170
+ describe '#find_strategy' do
171
+ let(:mapper_factory) {
172
+ build_mapper_factory(
173
+ strategies: [
174
+ build_mapper_strategy(method: :cast),
175
+ build_mapper_strategy(method: :serialize),
176
+ ]
177
+ )
178
+ }
179
+ let(:mapper) {
180
+ mapper_factory.call.use(:cast) do
181
+ integer :my_field
182
+ end
183
+ }
184
+
185
+ it {
186
+ expect(mapper.find_strategy(:cast)).to be_a(ReeMapper::MapperStrategy)
187
+ }
188
+
189
+ it {
190
+ expect(mapper.find_strategy(:serialize)).to be_nil
191
+ }
192
+ end
169
193
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'bigdecimal'
2
3
 
3
4
  RSpec.describe 'ReeMapper::Float' do
4
5
  link :build_mapper_factory, from: :ree_mapper
@@ -30,6 +31,10 @@ RSpec.describe 'ReeMapper::Float' do
30
31
  expect(mapper.cast({ float: '1.1' })).to eq({ float: 1.1 })
31
32
  }
32
33
 
34
+ it {
35
+ expect(mapper.db_load({ float: BigDecimal("1.1") })).to eq({ float: 1.1 })
36
+ }
37
+
33
38
  it {
34
39
  expect { mapper.cast({ float: 'a1.1' }) }.to raise_error(ReeMapper::CoercionError, '`float` is invalid float')
35
40
  }
@@ -88,6 +93,10 @@ RSpec.describe 'ReeMapper::Float' do
88
93
  expect(mapper.db_load({ float: '1.1' })).to eq({ float: 1.1 })
89
94
  }
90
95
 
96
+ it {
97
+ expect(mapper.db_load({ float: BigDecimal("1.1") })).to eq({ float: 1.1 })
98
+ }
99
+
91
100
  it {
92
101
  expect { mapper.db_load({ float: 'a1.1' }) }.to raise_error(ReeMapper::CoercionError, '`float` is invalid float')
93
102
  }
@@ -6,7 +6,7 @@ class ReeObject::ToHash
6
6
  fn :to_hash do
7
7
  def_error { RecursiveObjectErr }
8
8
  end
9
-
9
+
10
10
  BASIC_TYPES = [
11
11
  Date, Time, Numeric, String, FalseClass, TrueClass, NilClass, Symbol,
12
12
  Module, Class
@@ -57,8 +57,8 @@ class ReeObject::ToHash
57
57
  raise RecursiveObjectErr, "Recursive object found: #{obj}"
58
58
  end
59
59
 
60
- cache[obj.object_id] = acc
61
-
60
+ cache[obj.object_id] = true
61
+
62
62
  obj.instance_variables.each do |var|
63
63
  key_name = var.to_s.delete("@")
64
64
  key_sym = key_name.to_sym
@@ -69,6 +69,8 @@ class ReeObject::ToHash
69
69
  acc[key] = recursively_convert(value, {}, cache)
70
70
  end
71
71
 
72
+ cache.delete(obj.object_id)
73
+
72
74
  acc
73
75
  end
74
76
  end
@@ -167,6 +167,11 @@ RSpec.describe :to_hash do
167
167
  to_hash(obj)
168
168
  }.to raise_error(ReeObject::ToHash::RecursiveObjectErr, /Recursive object found: /)
169
169
  }
170
+
171
+ it {
172
+ obj = obj_klass.new
173
+ expect(to_hash([obj, obj])).to eq([{}, {}])
174
+ }
170
175
  end
171
176
  end
172
177
  end
@@ -11,16 +11,13 @@ RSpec.describe :build_serializer_schema do
11
11
 
12
12
  build_mapper_factory(
13
13
  strategies: strategies
14
- ).register(
14
+ ).register_type(
15
15
  :unregistered_type,
16
- ReeMapper::Mapper.build(
17
- strategies,
18
- Class.new(ReeMapper::AbstractType) do
19
- def serialize(val, role: nil)
20
- val
21
- end
22
- end.new
23
- )
16
+ Class.new(ReeMapper::AbstractType) do
17
+ def serialize(val, role: nil)
18
+ val
19
+ end
20
+ end.new
24
21
  )
25
22
  }
26
23
 
@@ -118,10 +115,10 @@ RSpec.describe :build_serializer_schema do
118
115
  test_unregistered_type: {},
119
116
  partial_value: {
120
117
  type: 'object',
121
- properties: {
118
+ properties: {
122
119
  nested_partial_value: {
123
120
  type: 'object',
124
- properties: {
121
+ properties: {
125
122
  included: { type: 'string' }
126
123
  }
127
124
  }
@@ -15,13 +15,8 @@ RSpec.describe :register_type do
15
15
  build_mapper_strategy(method: :serialize, dto: Hash),
16
16
  ]
17
17
 
18
- build_mapper_factory(strategies: strategies).register(
19
- :my_type,
20
- ReeMapper::Mapper.build(
21
- strategies,
22
- ReeSwagger::MyType.new
23
- )
24
- )
18
+ build_mapper_factory(strategies: strategies)
19
+ .register_type(:my_type, ReeSwagger::MyType.new)
25
20
  }
26
21
 
27
22
  let(:mapper) {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReeLib
4
- VERSION = "1.0.35"
4
+ VERSION = "1.0.36"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ree_lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.35
4
+ version: 1.0.36
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-03-06 00:00:00.000000000 Z
11
+ date: 2023-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ree