Class: ReeMapper::MapperFactory

Inherits:
Object
  • Object
show all
Defined in:
lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mapper) ⇒ MapperFactory

Returns a new instance of MapperFactory.



147
148
149
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 147

def initialize(mapper)
  @mapper = mapper
end

Class Attribute Details

.strategiesObject (readonly)

Returns the value of attribute strategies.



5
6
7
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 5

def strategies
  @strategies
end

.typesObject (readonly)

Returns the value of attribute types.



5
6
7
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 5

def types
  @types
end

.wrappersObject (readonly)

Returns the value of attribute wrappers.



5
6
7
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 5

def wrappers
  @wrappers
end

Class Method Details

.call(register_as: nil, &blk) ⇒ Object



142
143
144
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 142

def self.call(register_as: nil, &blk)
  ReeMapper::MapperFactoryProxy.new(self, register_as: register_as, &blk)
end

.find_strategy(strategy_method) ⇒ Object



9
10
11
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 9

def self.find_strategy(strategy_method)
  strategies.detect { _1.method == strategy_method }
end

.register_mapper(name, type) ⇒ Object

Raises:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 22

def self.register_mapper(name, type)
  raise ArgumentError, "mapper registration name should not end with `?`" if name.to_s.end_with?('?')

  defined_strategy_method = types[name]&.flat_map(&:strategy_methods)&.detect { type.find_strategy(_1) }
  raise ArgumentError, "type :#{name} with `#{defined_strategy_method}` strategy already registered" if defined_strategy_method
  raise ArgumentError, "method :#{name} already defined" if !types.key?(name) && method_defined?(name)

  type = type.dup
  type.name = name
  type.freeze
  types[name] ||= []
  types[name] << type

  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
    def #{name}(field_name = nil, optional: false, **opts)
      raise ReeMapper::Error, "invalid DSL usage" unless @mapper
      raise ArgumentError, "wrapped item can't be optional" if field_name.nil? && optional

      type = self.class.types.fetch(:#{name}).detect { (@mapper.strategy_methods - _1.strategy_methods).empty? }

      unless type
        raise ReeMapper::UnsupportedTypeError, "type :#{name} should implement `\#{@mapper.strategy_methods.join(', ')}`"
      end

      field = ReeMapper::Field.new(
        type,
        field_name,
        optional: optional,
        **opts,
        location: caller_locations&.first&.to_s
      )

      return field unless field_name

      @mapper.add_field(field)
    end

    def #{name}?(field_name, **opts)
      #{name}(field_name, optional: true, **opts)
    end
  RUBY

  self
end

.register_type(name, object_type, strategies: self.strategies) ⇒ Object



14
15
16
17
18
19
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 14

def self.register_type(name, object_type, strategies: self.strategies)
  register_mapper(
    name,
    ReeMapper::Mapper.build(strategies, object_type)
  )
end

.register_wrapper(name, wrapper) ⇒ Object

Raises:



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 68

def self.register_wrapper(name, wrapper)
  raise ArgumentError, "wrapper registration name should not end with `?`" if name.to_s.end_with?('?')
  raise ArgumentError, "method :#{name} already defined" if !wrappers.key?(name) && method_defined?(name)

  wrappers[name] ||= []
  wrappers[name] << wrapper

  class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
    contract(
      Nilor[Symbol, ReeMapper::Field],
      Nilor[ReeMapper::Field],
      Kwargs[optional: Bool, dto: Nilor[Class]],
      Ksplat[RestKeys => Any],
      Optblock => Nilor[ReeMapper::Field]
    ).throws(ReeMapper::Error, ArgumentError, ReeMapper::UnsupportedTypeError)
    def #{name}(field_name = nil, subject = nil, optional: false, dto: nil, **opts, &blk)
      raise ReeMapper::Error, "invalid DSL usage" unless @mapper
      raise ArgumentError, 'wrapped type does not permit :dto without :block' if dto && !blk

      if field_name.is_a?(ReeMapper::Field)
        raise ArgumentError, "field_name should be a Symbol" if subject

        subject = field_name
        field_name = nil
      end

      raise ArgumentError, "wrapped item can't be optional" if field_name.nil? && optional
      raise ArgumentError, "wrapped type should use either :subject or :block" if subject && blk || !subject && !blk

      if blk
        subject = ReeMapper::Field.new(
          hash_from_blk(dto: dto, &blk),
          location: caller_locations&.first&.to_s,
        )
      end

      wrapper = self.class.wrappers.fetch(:#{name}).detect do |wrapper|
        @mapper.strategy_methods.all? { wrapper.method_defined?(_1) }
      end

      unless wrapper
        raise ReeMapper::UnsupportedTypeError, "wrapper :#{name} should implement `\#{@mapper.strategy_methods.join(', ')}`"
      end

      type = ReeMapper::Mapper.build(@mapper.strategies, wrapper.new(subject))
      type.name = :#{name}

      field = ReeMapper::Field.new(
        type,
        field_name,
        optional: optional,
        **opts,
        location: caller_locations&.first&.to_s,
      )

      return field unless field_name

      @mapper.add_field(field)
    end

    def #{name}?(*args, **opts, &blk)
      #{name}(*args, optional: true, **opts, &blk)
    end
  RUBY

  self
end

Instance Method Details

#hash(field_name, dto: nil, **opts, &blk) ⇒ Object

Raises:



152
153
154
155
156
157
158
159
160
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 152

def hash(field_name, dto: nil, **opts, &blk)
  raise ReeMapper::Error, "invalid DSL usage" unless @mapper

  type = hash_from_blk(dto: dto, &blk)

  field = ReeMapper::Field.new(type, field_name, **opts, location: caller_locations&.first&.to_s)

  @mapper.add_field(field)
end

#hash?(field_name, **opts, &blk) ⇒ Boolean

Returns:

  • (Boolean)


163
164
165
# File 'lib/ree_lib/packages/ree_mapper/package/ree_mapper/mapper_factory.rb', line 163

def hash?(field_name, **opts, &blk)
  hash(field_name, optional: true, **opts, &blk)
end