Class: Mongory::Converters::AbstractConverter

Inherits:
Utils::SingletonBuilder show all
Includes:
Singleton
Defined in:
lib/mongory/converters/abstract_converter.rb

Overview

AbstractConverter provides a flexible DSL-style mechanism for dynamically converting objects based on their class.

It allows you to register conversion rules for specific classes, with optional fallback behavior.

Examples:

Basic usage

converter = AbstractConverter.instance
converter.register(String) { |v| v.upcase }
converter.convert("hello") #=> "HELLO"

Defined Under Namespace

Classes: Registry

Constant Summary collapse

NOTHING =

A sentinel value used to indicate absence of a secondary argument.

Utils::SingletonBuilder.new('NOTHING')

Instance Method Summary collapse

Methods inherited from Utils::SingletonBuilder

#inspect, #to_s

Constructor Details

#initializeAbstractConverter

Initializes the builder with a label and optional configuration block.



33
34
35
36
37
# File 'lib/mongory/converters/abstract_converter.rb', line 33

def initialize
  super(self.class.to_s)
  @registries = []
  @convert_strategy_map = {}.compare_by_identity
end

Instance Method Details

#configure { ... } ⇒ void

This method returns an undefined value.

Opens a configuration block to register more converters.

Yields:

  • DSL block to configure more rules



77
78
79
80
# File 'lib/mongory/converters/abstract_converter.rb', line 77

def configure
  yield self
  freeze
end

#convert(target, other = NOTHING) ⇒ Object

Applies the registered conversion to the given target object.

Parameters:

  • target (Object)

    the object to convert

  • other (Object) (defaults to: NOTHING)

    optional secondary value

Returns:

  • (Object)

    converted result



44
45
46
47
48
49
50
51
# File 'lib/mongory/converters/abstract_converter.rb', line 44

def convert(target, other = NOTHING)
  convert_strategy = @convert_strategy_map[target.class] ||= find_strategy(target)

  return fallback(target, other) if convert_strategy == NOTHING
  return target.instance_exec(&convert_strategy) if other == NOTHING

  target.instance_exec(other, &convert_strategy)
end

#fallback(target, _) ⇒ Object



53
54
55
# File 'lib/mongory/converters/abstract_converter.rb', line 53

def fallback(target, _)
  target
end

#find_strategy(target) ⇒ Proc

Finds the appropriate conversion strategy for the target object. Searches through registered rules and returns the first matching one, or the fallback strategy if no match is found.

Parameters:

  • target (Object)

    the object to find a strategy for

Returns:

  • (Proc)

    the conversion strategy to use



63
64
65
66
67
68
69
70
71
# File 'lib/mongory/converters/abstract_converter.rb', line 63

def find_strategy(target)
  @registries.each do |registry|
    next unless target.is_a?(registry.klass)

    return registry.exec
  end

  NOTHING
end

#freezevoid

This method returns an undefined value.

Freezes all internal registries.



85
86
87
# File 'lib/mongory/converters/abstract_converter.rb', line 85

def freeze
  @registries.freeze
end

#register(klass, converter = nil) {|*args| ... } ⇒ void

This method returns an undefined value.

Registers a conversion rule for a given class.

Parameters:

  • klass (Class, Module)

    the target class

  • converter (Symbol, nil) (defaults to: nil)

    method name to call as a conversion

Yields:

  • (*args)

    block that performs the conversion

Raises:

  • (RuntimeError)

    if input is invalid



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/mongory/converters/abstract_converter.rb', line 96

def register(klass, converter = nil, &block)
  raise 'converter or block is required.' if [converter, block].compact.empty?
  raise 'A class or module is reuqired.' unless klass.is_a?(Module)

  if converter.is_a?(Symbol)
    register(klass) { |*args, &bl| send(converter, *args, &bl) }
  elsif block.is_a?(Proc)
    @registries.unshift(Registry.new(klass, block))
    @convert_strategy_map[klass] = block
  else
    raise 'Support Symbol and block only.'
  end
end