ree_lib 1.0.35 → 1.0.37

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +11 -2
  3. data/lib/ree_lib/Packages.schema.json +8 -0
  4. data/lib/ree_lib/packages/ree_actions/.gitignore +0 -0
  5. data/lib/ree_lib/packages/ree_actions/.rspec +2 -0
  6. data/lib/ree_lib/packages/ree_actions/Package.schema.json +20 -0
  7. data/lib/ree_lib/packages/ree_actions/bin/console +5 -0
  8. data/lib/ree_lib/packages/ree_actions/package/ree_actions/action.rb +10 -0
  9. data/lib/ree_lib/packages/ree_actions/package/ree_actions/action_builder.rb +65 -0
  10. data/lib/ree_lib/packages/ree_actions/package/ree_actions/action_dsl.rb +60 -0
  11. data/lib/ree_lib/packages/ree_actions/package/ree_actions/dsl.rb +102 -0
  12. data/lib/ree_lib/packages/ree_actions/package/ree_actions.rb +12 -0
  13. data/lib/ree_lib/packages/ree_actions/spec/package_schema_spec.rb +14 -0
  14. data/lib/ree_lib/packages/ree_actions/spec/ree_actions/action_dsl_spec.rb +62 -0
  15. data/lib/ree_lib/packages/ree_actions/spec/ree_actions/dsl_spec.rb +93 -0
  16. data/lib/ree_lib/packages/ree_actions/spec/spec_helper.rb +3 -0
  17. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/functions/build_mapper_factory.rb +7 -7
  18. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper.rb +7 -2
  19. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb +20 -13
  20. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory_proxy.rb +2 -2
  21. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/abstract_type.rb +0 -15
  22. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper/types/float.rb +2 -0
  23. data/lib/ree_lib/packages/ree_mapper/package/ree_mapper.rb +1 -1
  24. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_factory_spec.rb +77 -20
  25. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/mapper_spec.rb +25 -1
  26. data/lib/ree_lib/packages/ree_mapper/spec/ree_mapper/types/float_spec.rb +9 -0
  27. data/lib/ree_lib/packages/ree_object/package/ree_object/functions/to_hash.rb +5 -3
  28. data/lib/ree_lib/packages/ree_object/spec/ree_object/functions/to_hash_spec.rb +5 -0
  29. data/lib/ree_lib/packages/ree_roda/.gitignore +0 -0
  30. data/lib/ree_lib/packages/ree_roda/.rspec +2 -0
  31. data/lib/ree_lib/packages/ree_roda/Package.schema.json +58 -0
  32. data/lib/ree_lib/packages/ree_roda/bin/console +5 -0
  33. data/lib/ree_lib/packages/ree_roda/package/ree_roda/app.rb +46 -0
  34. data/lib/ree_lib/packages/ree_roda/package/ree_roda/plugins/ree_actions.rb +150 -0
  35. data/lib/ree_lib/packages/ree_roda/package/ree_roda/plugins/ree_logger.rb +66 -0
  36. data/lib/ree_lib/packages/ree_roda/package/ree_roda/services/build_action_errors.rb +76 -0
  37. data/lib/ree_lib/packages/ree_roda/package/ree_roda/services/build_swagger_from_actions.rb +55 -0
  38. data/lib/ree_lib/packages/ree_roda/package/ree_roda/services/status_from_error.rb +25 -0
  39. data/lib/ree_lib/packages/ree_roda/package/ree_roda.rb +19 -0
  40. data/lib/ree_lib/packages/ree_roda/schemas/ree_roda/services/build_action_errors.schema.json +28 -0
  41. data/lib/ree_lib/packages/ree_roda/schemas/ree_roda/services/build_swagger_from_actions.schema.json +63 -0
  42. data/lib/ree_lib/packages/ree_roda/schemas/ree_roda/services/status_from_error.schema.json +28 -0
  43. data/lib/ree_lib/packages/ree_roda/spec/package_schema_spec.rb +14 -0
  44. data/lib/ree_lib/packages/ree_roda/spec/ree_roda/app_spec.rb +84 -0
  45. data/lib/ree_lib/packages/ree_roda/spec/spec_helper.rb +3 -0
  46. data/lib/ree_lib/packages/ree_swagger/spec/functions/build_serializer_schema_spec.rb +8 -11
  47. data/lib/ree_lib/packages/ree_swagger/spec/functions/register_type_spec.rb +2 -7
  48. data/lib/ree_lib/version.rb +1 -1
  49. metadata +60 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 190a7da138d373c34c6e7636265ccce86c37e6ad5fd0c02b4e3c81c7e376393a
4
- data.tar.gz: ad6b89d186eec9a9006cc6d217ee82d6f20a34428bd052953aac7e2624a6b41c
3
+ metadata.gz: bfa479493ff3b8d80a181db242e9f443324b5c7f46b3629dae816f06eb2fd758
4
+ data.tar.gz: 371e0a229e967c47f8ad61de6c86aba1bb0e0b17651bf6447e7727734629e294
5
5
  SHA512:
6
- metadata.gz: 45199483809ad7917a207699df3acd7689db5dd246dfdce7910a7427a4d100750196a903b51aba2e24d0594141a01b8086e0767f9427b555fa2bdece22e83491
7
- data.tar.gz: d20668755d3da265a0ec0351220dfe9604cfaf21ebbb78833b093445afd01280e7b6e7d83ebba428b3808c346754fb1debcbed29197098f136c3b1a30bb24369
6
+ metadata.gz: 71b4a7f35d1a0569af42794acf8bf8c1193cf390ca773fd6ebab395cb86192199496812c9ae356e29a299a453304d6c25217cd20d9bd7884ded1e10fa798d68f
7
+ data.tar.gz: c5b3cf9ea44d8012ea7be12cf8ef9f33ac735a28c8d9bb384bf69fec6f8bc7932b7a1cf6f43be4439d7fa220b3cc2e630d8e0816b75c732fcb9b13e3e1b6ef22
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.37)
5
5
  binding_of_caller (~> 1.0.0)
6
6
  i18n (~> 1.12.0)
7
7
  loofah (~> 2.18.0)
@@ -36,17 +36,24 @@ 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)
42
44
  pg (1.4.6)
43
45
  public_suffix (5.0.1)
44
46
  racc (1.6.2)
47
+ rack (3.0.5)
48
+ rack-test (2.0.2)
49
+ rack (>= 1.3)
45
50
  rainbow (3.1.1)
46
51
  rake (13.0.6)
47
- ree (1.0.23)
52
+ ree (1.0.27)
48
53
  commander (~> 4.6.0)
49
54
  rexml (3.2.5)
55
+ roda (3.58.0)
56
+ rack
50
57
  rollbar (3.3.3)
51
58
  rspec (3.12.0)
52
59
  rspec-core (~> 3.12.0)
@@ -79,8 +86,10 @@ PLATFORMS
79
86
  DEPENDENCIES
80
87
  bootsnap
81
88
  pg (~> 1.4.1)
89
+ rack-test
82
90
  rake (~> 13.0)
83
91
  ree_lib!
92
+ roda (~> 3.58.0)
84
93
  rollbar (~> 3.3.1)
85
94
  rspec
86
95
  sqlite3 (~> 1.4.4)
@@ -2,6 +2,10 @@
2
2
  "schema_version": "1.0",
3
3
  "schema_type": "packages",
4
4
  "packages": [
5
+ {
6
+ "name": "ree_actions",
7
+ "schema": "packages/ree_actions/Package.schema.json"
8
+ },
5
9
  {
6
10
  "name": "ree_array",
7
11
  "schema": "packages/ree_array/Package.schema.json"
@@ -66,6 +70,10 @@
66
70
  "name": "ree_object",
67
71
  "schema": "packages/ree_object/Package.schema.json"
68
72
  },
73
+ {
74
+ "name": "ree_roda",
75
+ "schema": "packages/ree_roda/Package.schema.json"
76
+ },
69
77
  {
70
78
  "name": "ree_string",
71
79
  "schema": "packages/ree_string/Package.schema.json"
File without changes
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,20 @@
1
+ {
2
+ "schema_type": "package",
3
+ "schema_version": "1.1",
4
+ "name": "ree_actions",
5
+ "entry_path": "packages/ree_actions/package/ree_actions.rb",
6
+ "tags": [
7
+ "ree_actions"
8
+ ],
9
+ "depends_on": [
10
+ {
11
+ "name": "ree_mapper"
12
+ }
13
+ ],
14
+ "env_vars": [
15
+
16
+ ],
17
+ "objects": [
18
+
19
+ ]
20
+ }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/setup"
3
+ require "ree"
4
+
5
+ Ree.init(__dir__, irb: true)
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReeActions::Action
4
+ attr_accessor :summary, :request_method, :serializer, :respond_to,
5
+ :sections, :action, :warden_scope, :path
6
+
7
+ def valid?
8
+ !@action.nil? && !summary.nil? && !warden_scope.nil?
9
+ end
10
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "action"
4
+
5
+ class ReeActions::ActionBuilder
6
+ Redirect = Struct.new(:path, :code)
7
+
8
+ def initialize
9
+ @action = ReeActions::Action.new
10
+ @action.respond_to = :json
11
+ end
12
+
13
+ contract Symbol => Symbol
14
+ def warden_scope(scope)
15
+ @action.warden_scope = scope
16
+ end
17
+
18
+ contract Symbol => Symbol
19
+ def respond_to(v)
20
+ @action.respond_to = v
21
+ end
22
+
23
+ contract None => ReeActions::Action
24
+ def get_action
25
+ @action
26
+ end
27
+
28
+ contract Block => nil
29
+ def before(&proc)
30
+ @action.before = proc
31
+ nil
32
+ end
33
+
34
+ contract String => String
35
+ def summary(str)
36
+ @action.summary = str
37
+ end
38
+
39
+ contract Symbol, Symbol => nil
40
+ def serializer(name, from:)
41
+ object = Ree.container.packages_facade.get_object(from, name)
42
+ @action.serializer = object
43
+ nil
44
+ end
45
+
46
+ contract SplatOf[String] => nil
47
+ def sections(*names)
48
+ @action.sections = names
49
+ nil
50
+ end
51
+
52
+ contract Symbol, Symbol => nil
53
+ def action(name, from:)
54
+ object = Ree.container.packages_facade.get_object(from, name)
55
+ @action.action = object
56
+ nil
57
+ end
58
+
59
+ contract String, Kwargs[code: Integer] => nil
60
+ def redirect(path, code: 301)
61
+ raise ArgumentError if ![301, 302, 303, 307, 308].include?(code)
62
+ @action.redirect = Redirect.new(path, code)
63
+ nil
64
+ end
65
+ end
@@ -0,0 +1,60 @@
1
+ module ReeActions
2
+ module ActionDSL
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ base.include(ReeMapper::DSL)
6
+ end
7
+
8
+ def self.extended(base)
9
+ base.extend(ClassMethods)
10
+ base.include(ReeMapper::DSL)
11
+ end
12
+
13
+ module ClassMethods
14
+ include Ree::Contracts::Core
15
+ include Ree::Contracts::ArgContracts
16
+
17
+ def action(name, &proc)
18
+ dsl = Ree::ObjectDsl.new(
19
+ Ree.container.packages_facade, name, self, :fn
20
+ )
21
+
22
+ dsl.instance_exec(&proc) if block_given?
23
+ dsl.tags(["action"])
24
+ dsl.freeze(false)
25
+ dsl.object.set_as_compiled(false)
26
+
27
+ Ree.container.compile(dsl.package, name)
28
+ end
29
+
30
+ def method_added(method_name)
31
+ return super if method_name != :call
32
+
33
+ if @__original_call_defined
34
+ remove_instance_variable(:@__original_call_defined)
35
+ return
36
+ end
37
+
38
+ @__original_call_defined = true
39
+
40
+ alias_method(:__original_call, :call)
41
+
42
+ define_method :call do |user_access, attrs|
43
+ if self.class.const_defined?(:ActionCaster)
44
+ caster = self.class.const_get(:ActionCaster)
45
+
46
+ if !caster.respond_to?(:cast)
47
+ raise ArgumentError.new("ActionCaster does not respond to `cast` method")
48
+ end
49
+
50
+ __original_call(user_access, caster.cast(attrs))
51
+ else
52
+ __original_call(user_access, attrs)
53
+ end
54
+ end
55
+
56
+ nil
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "action_builder"
4
+ require "uri"
5
+
6
+ module ReeActions
7
+ module DSL
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ def self.extended(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+
16
+ module FactoryMethod
17
+ def build
18
+ self.class.instance_variable_get(:@actions) || []
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+ include Ree::Contracts::Core
24
+ include Ree::Contracts::ArgContracts
25
+
26
+ def actions(name, &proc)
27
+ raise ArgumentError.new("block is required") if !block_given?
28
+
29
+ @dsl = Ree::ObjectDsl.new(
30
+ Ree.container.packages_facade, name, self, :object
31
+ )
32
+
33
+ @dsl.singleton
34
+ @dsl.factory(:build)
35
+ @dsl.tags(["actions"])
36
+
37
+ instance_exec(&proc)
38
+
39
+ klass = @dsl.object.klass
40
+ klass.send(:include, FactoryMethod)
41
+
42
+
43
+ Ree.container.compile(@dsl.package, name)
44
+ end
45
+
46
+ def default_warden_scope(method_name)
47
+ @default_warden_scope = method_name
48
+ end
49
+
50
+ [:get, :post, :put, :delete, :patch, :head, :options].each do |request_method|
51
+ define_method request_method do |path, &proc|
52
+ define_action(request_method, path, &proc)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ contract Symbol, String, Block => ReeActions::Action
59
+ def define_action(request_method, path, &proc)
60
+ raise ArgumentError.new("actions should be called") if !@dsl
61
+ raise ArgumentError.new("block is required") if !block_given?
62
+
63
+ @actions ||= []
64
+
65
+ builder = ReeActions::ActionBuilder.new
66
+ builder.instance_exec(&proc)
67
+
68
+ if @default_warden_scope && !builder.get_action.warden_scope
69
+ builder.warden_scope(@default_warden_scope)
70
+ end
71
+
72
+ uri = URI.parse(path) rescue nil
73
+
74
+ if uri.nil? || uri.path != path
75
+ raise ArgumentError.new("invalid path provided #{path}")
76
+ end
77
+
78
+ if uri.query && !uri.query.empty?
79
+ raise ArgumentError.new("action path should not include query params: #{path}")
80
+ end
81
+
82
+ builder.get_action.path = path
83
+ builder.get_action.request_method = request_method
84
+
85
+ if !builder.get_action.valid?
86
+ raise ArgumentError.new("action, summary and auth scope should be provider for #{builder.get_action.inspect}")
87
+ end
88
+
89
+ action = builder.get_action
90
+
91
+ @dsl.link(action.action.name, from: action.action.package_name)
92
+
93
+ if action.serializer
94
+ @dsl.link(action.serializer.name, from: action.serializer.package_name)
95
+ end
96
+
97
+ @actions << action
98
+ action
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReeActions
4
+ include Ree::PackageDSL
5
+
6
+ package do
7
+ depends_on :ree_mapper
8
+ end
9
+ end
10
+
11
+ require_relative "ree_actions/dsl"
12
+ require_relative "ree_actions/action_dsl"
@@ -0,0 +1,14 @@
1
+ RSpec.describe "ReeActions" do
2
+ it "generates package schema" do
3
+ require "fileutils"
4
+
5
+ packages_schema_path = Ree.locate_packages_schema(__dir__)
6
+ packages_schema_dir = Pathname.new(packages_schema_path).dirname.to_s
7
+
8
+ FileUtils.cd packages_schema_dir do
9
+ expect(
10
+ system("REE_SKIP_ENV_VARS_CHECK=true bundle exec ree gen.package_json ree_actions --silence")
11
+ ).to eq(true)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,62 @@
1
+ package_require("ree_actions/action_dsl")
2
+
3
+ RSpec.describe ReeActions::ActionDSL, type: [:autoclean] do
4
+ before do
5
+ Ree.enable_irb_mode
6
+ end
7
+
8
+ after do
9
+ Ree.disable_irb_mode
10
+ end
11
+
12
+ it {
13
+ module ReeActionsTest
14
+ include Ree::PackageDSL
15
+
16
+ package do
17
+ depends_on :ree_mapper
18
+ end
19
+
20
+ class TestAction
21
+ include ReeActions::ActionDSL
22
+
23
+ action :test_action
24
+
25
+ ActionCaster = build_mapper.use(:cast) do
26
+ integer :user_id
27
+ end
28
+
29
+ contract Any, ActionCaster.dto(:cast) => Integer
30
+ def call(user_access, attrs)
31
+ attrs[:user_id]
32
+ end
33
+ end
34
+ end
35
+
36
+ result = ReeActionsTest::TestAction.new.call('user_access', {user_id: 1})
37
+ expect(result).to eq(1)
38
+ }
39
+
40
+ it {
41
+ module ReeActionsTest
42
+ include Ree::PackageDSL
43
+
44
+ package do
45
+ end
46
+
47
+ class TestAction2
48
+ include ReeActions::ActionDSL
49
+
50
+ action :test_action2
51
+
52
+ contract Any, Hash => Integer
53
+ def call(user_access, attrs)
54
+ attrs[:user_id]
55
+ end
56
+ end
57
+ end
58
+
59
+ result = ReeActionsTest::TestAction2.new.call('user_access', {user_id: 1})
60
+ expect(result).to eq(1)
61
+ }
62
+ end
@@ -0,0 +1,93 @@
1
+ package_require("ree_actions/dsl")
2
+
3
+ RSpec.describe ReeActions::DSL, type: [:autoclean] do
4
+ before :all do
5
+ Ree.enable_irb_mode
6
+
7
+ module ReeActionsTest
8
+ include Ree::PackageDSL
9
+
10
+ package
11
+ end
12
+
13
+ class ReeActionsTest::EmptyActions
14
+ include ReeActions::DSL
15
+
16
+ actions :empty_actions do
17
+ end
18
+ end
19
+
20
+ class ReeActionsTest::Cmd
21
+ include Ree::FnDSL
22
+
23
+ fn :cmd
24
+
25
+ def call
26
+ end
27
+ end
28
+
29
+ class ReeActionsTest::Serializer
30
+ include ReeMapper::DSL
31
+
32
+ mapper :serializer
33
+
34
+ build_mapper.use(:serialize) do
35
+ integer :id
36
+ end
37
+ end
38
+
39
+ class ReeActionsTest::Caster
40
+ include ReeMapper::DSL
41
+
42
+ mapper :caster
43
+
44
+ build_mapper.use(:cast) do
45
+ integer :id
46
+ end
47
+ end
48
+
49
+ class ReeActionsTest::Actions
50
+ include ReeActions::DSL
51
+
52
+ actions :actions do
53
+ default_warden_scope :user
54
+
55
+ post "users" do
56
+ summary "Test action"
57
+ action :cmd, from: :ree_actions_test
58
+ serializer :serializer, from: :ree_actions_test
59
+ respond_to :json
60
+ end
61
+
62
+ get "files.csv" do
63
+ summary "Test action"
64
+ action :cmd, from: :ree_actions_test
65
+ respond_to :csv
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ after :all do
72
+ Ree.disable_irb_mode
73
+ end
74
+
75
+ it {
76
+ expect(ReeActionsTest::EmptyActions.new).to eq([])
77
+ }
78
+
79
+ it {
80
+ actions = ReeActionsTest::Actions.new
81
+
82
+ expect(actions.size).to eq(2)
83
+
84
+ post_action = actions.first
85
+ csv_action = actions.last
86
+
87
+ expect(post_action.serializer.name).to eq(:serializer)
88
+ expect(post_action.action.name).to eq(:cmd)
89
+ expect(post_action.respond_to).to eq(:json)
90
+
91
+ expect(csv_action.respond_to).to eq(:csv)
92
+ }
93
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.extend Ree::RSpecLinkDSL
3
+ end
@@ -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