ama-entity-mapper 0.1.0.beta.2
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.
- checksums.yaml +7 -0
- data/docs/algorithm.md +61 -0
- data/docs/basic-usage.md +179 -0
- data/docs/dsl.md +90 -0
- data/docs/generics.md +55 -0
- data/docs/handlers.md +196 -0
- data/docs/index.md +23 -0
- data/docs/installation.md +27 -0
- data/docs/logging.md +18 -0
- data/docs/wildcards.md +16 -0
- data/lib/ama-entity-mapper.rb +42 -0
- data/lib/ama-entity-mapper/aux/null_stream.rb +30 -0
- data/lib/ama-entity-mapper/context.rb +61 -0
- data/lib/ama-entity-mapper/dsl.rb +21 -0
- data/lib/ama-entity-mapper/dsl/class_methods.rb +100 -0
- data/lib/ama-entity-mapper/engine.rb +88 -0
- data/lib/ama-entity-mapper/engine/recursive_mapper.rb +164 -0
- data/lib/ama-entity-mapper/engine/recursive_normalizer.rb +74 -0
- data/lib/ama-entity-mapper/error.rb +11 -0
- data/lib/ama-entity-mapper/error/compliance_error.rb +15 -0
- data/lib/ama-entity-mapper/error/mapping_error.rb +14 -0
- data/lib/ama-entity-mapper/error/validation_error.rb +14 -0
- data/lib/ama-entity-mapper/handler/attribute/validator.rb +107 -0
- data/lib/ama-entity-mapper/handler/entity/denormalizer.rb +97 -0
- data/lib/ama-entity-mapper/handler/entity/enumerator.rb +76 -0
- data/lib/ama-entity-mapper/handler/entity/factory.rb +86 -0
- data/lib/ama-entity-mapper/handler/entity/injector.rb +69 -0
- data/lib/ama-entity-mapper/handler/entity/normalizer.rb +68 -0
- data/lib/ama-entity-mapper/handler/entity/validator.rb +66 -0
- data/lib/ama-entity-mapper/mixin/errors.rb +55 -0
- data/lib/ama-entity-mapper/mixin/handler_support.rb +69 -0
- data/lib/ama-entity-mapper/mixin/reflection.rb +67 -0
- data/lib/ama-entity-mapper/mixin/suppression_support.rb +37 -0
- data/lib/ama-entity-mapper/path.rb +91 -0
- data/lib/ama-entity-mapper/path/segment.rb +51 -0
- data/lib/ama-entity-mapper/type.rb +243 -0
- data/lib/ama-entity-mapper/type/analyzer.rb +27 -0
- data/lib/ama-entity-mapper/type/any.rb +66 -0
- data/lib/ama-entity-mapper/type/attribute.rb +197 -0
- data/lib/ama-entity-mapper/type/aux/hash_tuple.rb +35 -0
- data/lib/ama-entity-mapper/type/builtin/array_type.rb +28 -0
- data/lib/ama-entity-mapper/type/builtin/datetime_type.rb +65 -0
- data/lib/ama-entity-mapper/type/builtin/enumerable_type.rb +74 -0
- data/lib/ama-entity-mapper/type/builtin/hash_tuple_type.rb +33 -0
- data/lib/ama-entity-mapper/type/builtin/hash_type.rb +82 -0
- data/lib/ama-entity-mapper/type/builtin/primitive_type.rb +61 -0
- data/lib/ama-entity-mapper/type/builtin/primitive_type/denormalizer.rb +62 -0
- data/lib/ama-entity-mapper/type/builtin/rational_type.rb +59 -0
- data/lib/ama-entity-mapper/type/builtin/set_type.rb +74 -0
- data/lib/ama-entity-mapper/type/parameter.rb +70 -0
- data/lib/ama-entity-mapper/type/registry.rb +117 -0
- data/lib/ama-entity-mapper/type/resolver.rb +105 -0
- data/lib/ama-entity-mapper/version.rb +17 -0
- metadata +194 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../mixin/reflection'
|
4
|
+
require_relative '../../mixin/errors'
|
5
|
+
|
6
|
+
module AMA
|
7
|
+
module Entity
|
8
|
+
class Mapper
|
9
|
+
module Handler
|
10
|
+
module Entity
|
11
|
+
# Default attribute injector
|
12
|
+
class Injector
|
13
|
+
include Mixin::Reflection
|
14
|
+
|
15
|
+
INSTANCE = new
|
16
|
+
|
17
|
+
# @param [Object] entity
|
18
|
+
# @param [AMA::Entity::Mapper::Type] _type
|
19
|
+
# @param [AMA::Entity::Mapper::Type::Attribute] attribute
|
20
|
+
# @param [Object] value
|
21
|
+
# @param [AMA::Entity::Mapper::Context] _context
|
22
|
+
def inject(entity, _type, attribute, value, _context = nil)
|
23
|
+
return entity if attribute.virtual
|
24
|
+
set_object_attribute(entity, attribute.name, value)
|
25
|
+
entity
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
include Mixin::Reflection
|
30
|
+
|
31
|
+
# @param [Injector] implementation
|
32
|
+
# @return [Injector]
|
33
|
+
def wrap(implementation)
|
34
|
+
handler = handler_factory(implementation, INSTANCE)
|
35
|
+
description = "Safety wrapper for #{implementation}"
|
36
|
+
wrapper = method_object(:inject, to_s: description, &handler)
|
37
|
+
wrapper.singleton_class.instance_eval do
|
38
|
+
include Mixin::Errors
|
39
|
+
end
|
40
|
+
wrapper
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# @param [Injector] impl
|
46
|
+
# @param [Injector] fallback
|
47
|
+
# @return [Injector]
|
48
|
+
def handler_factory(impl, fallback)
|
49
|
+
lambda do |entity, type, attr, val, ctx|
|
50
|
+
begin
|
51
|
+
impl.inject(entity, type, attr, val, ctx) do |e, t, a, v, c|
|
52
|
+
fallback.inject(e, t, a, v, c)
|
53
|
+
end
|
54
|
+
rescue StandardError => e
|
55
|
+
raise_if_internal(e)
|
56
|
+
message = "Unexpected error from injector #{impl}"
|
57
|
+
signature = '(entity, type, attr, val, ctx)'
|
58
|
+
options = { parent: e, context: ctx, signature: signature }
|
59
|
+
compliance_error(message, options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../mixin/reflection'
|
4
|
+
require_relative '../../mixin/errors'
|
5
|
+
|
6
|
+
module AMA
|
7
|
+
module Entity
|
8
|
+
class Mapper
|
9
|
+
module Handler
|
10
|
+
module Entity
|
11
|
+
# Default normalization handler
|
12
|
+
class Normalizer
|
13
|
+
include Mixin::Reflection
|
14
|
+
|
15
|
+
INSTANCE = new
|
16
|
+
|
17
|
+
# @param [Object] entity
|
18
|
+
# @param [AMA::Entity::Mapper::Type] type
|
19
|
+
# @param [AMA::Entity::Mapper::Context] _context
|
20
|
+
def normalize(entity, type, _context = nil)
|
21
|
+
type.attributes.values.each_with_object({}) do |attribute, data|
|
22
|
+
next if attribute.virtual || attribute.sensitive
|
23
|
+
data[attribute.name] = object_variable(entity, attribute.name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
include Mixin::Reflection
|
29
|
+
|
30
|
+
# @param [Normalizer] implementation
|
31
|
+
# @return [Normalizer]
|
32
|
+
def wrap(implementation)
|
33
|
+
handler = handler_factory(implementation, INSTANCE)
|
34
|
+
description = "Safety wrapper for #{implementation}"
|
35
|
+
wrapper = method_object(:normalize, to_s: description, &handler)
|
36
|
+
wrapper.singleton_class.instance_eval do
|
37
|
+
include Mixin::Errors
|
38
|
+
end
|
39
|
+
wrapper
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# @param [Normalizer] impl
|
45
|
+
# @param [Normalizer] fallback
|
46
|
+
# @return [Proc]
|
47
|
+
def handler_factory(impl, fallback)
|
48
|
+
lambda do |entity, type, ctx|
|
49
|
+
begin
|
50
|
+
impl.normalize(entity, type, ctx) do |e, t, c|
|
51
|
+
fallback.normalize(e, t, c)
|
52
|
+
end
|
53
|
+
rescue StandardError => e
|
54
|
+
raise_if_internal(e)
|
55
|
+
message = "Unexpected error from normalizer #{impl}"
|
56
|
+
signature = '(entity, type, context)'
|
57
|
+
options = { parent: e, context: ctx, signature: signature }
|
58
|
+
compliance_error(message, **options)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../mixin/reflection'
|
4
|
+
require_relative '../../mixin/errors'
|
5
|
+
|
6
|
+
module AMA
|
7
|
+
module Entity
|
8
|
+
class Mapper
|
9
|
+
module Handler
|
10
|
+
module Entity
|
11
|
+
# Default entity validator
|
12
|
+
class Validator
|
13
|
+
INSTANCE = new
|
14
|
+
|
15
|
+
# @param [Object] entity
|
16
|
+
# @param [Mapper::Type] type
|
17
|
+
# @param [Mapper::Context] _context
|
18
|
+
# @return [Array<Array<Attribute, String, Segment>] List of
|
19
|
+
# violations, combined with attribute and segment
|
20
|
+
def validate(entity, type, _context)
|
21
|
+
return [] if type.instance?(entity)
|
22
|
+
["Provided object is not an instance of #{type.type}"]
|
23
|
+
end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
include Mixin::Reflection
|
27
|
+
|
28
|
+
# @param [Validator] validator
|
29
|
+
# @return [Validator]
|
30
|
+
def wrap(validator)
|
31
|
+
handler = handler_factory(validator, INSTANCE)
|
32
|
+
description = "Safety wrapper for #{validator}"
|
33
|
+
wrapper = method_object(:validate, to_s: description, &handler)
|
34
|
+
wrapper.singleton_class.instance_eval do
|
35
|
+
include Mixin::Errors
|
36
|
+
end
|
37
|
+
wrapper
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @param [Validator] validator
|
43
|
+
# @param [Validator] fallback
|
44
|
+
# @return [Proc]
|
45
|
+
def handler_factory(validator, fallback)
|
46
|
+
lambda do |entity, type, ctx|
|
47
|
+
begin
|
48
|
+
validator.validate(entity, type, ctx) do |e, t, c|
|
49
|
+
fallback.validate(e, t, c)
|
50
|
+
end
|
51
|
+
rescue StandardError => e
|
52
|
+
raise_if_internal(e)
|
53
|
+
message = "Unexpected error from validator #{validator}"
|
54
|
+
signature = '(entity, type, context)'
|
55
|
+
options = { parent: e, context: ctx, signature: signature }
|
56
|
+
compliance_error(message, **options)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../error'
|
4
|
+
require_relative '../error/mapping_error'
|
5
|
+
require_relative '../error/compliance_error'
|
6
|
+
require_relative '../error/validation_error'
|
7
|
+
|
8
|
+
module AMA
|
9
|
+
module Entity
|
10
|
+
class Mapper
|
11
|
+
module Mixin
|
12
|
+
# Simple mixin that provides shortcuts for raising common errors
|
13
|
+
module Errors
|
14
|
+
error_types = %i[Mapping Compliance Validation]
|
15
|
+
error_namespace = ::AMA::Entity::Mapper::Error
|
16
|
+
|
17
|
+
# @!method mapping_error(message, **options)
|
18
|
+
# @param [String] message
|
19
|
+
|
20
|
+
# @!method compliance_error(message, **options)
|
21
|
+
# @param [String] message
|
22
|
+
|
23
|
+
# @!method validation_error(message, **options)
|
24
|
+
# @param [String] message
|
25
|
+
error_types.each do |type|
|
26
|
+
method = "#{type.to_s.downcase}_error"
|
27
|
+
error_class = error_namespace.const_get("#{type}Error")
|
28
|
+
define_method method do |message, **options|
|
29
|
+
parent_error = options[:parent]
|
30
|
+
unless parent_error.nil?
|
31
|
+
if options[:signature] && parent_error.is_a?(ArgumentError)
|
32
|
+
message += '.' if /\w$/ =~ message
|
33
|
+
message += ' Does called method have signature ' \
|
34
|
+
"#{options[:signature]}?"
|
35
|
+
end
|
36
|
+
message += '.' if /\w$/ =~ message
|
37
|
+
message += " Parent error: #{parent_error.message}"
|
38
|
+
end
|
39
|
+
if options[:context]
|
40
|
+
message += " (path: #{options[:context].path})"
|
41
|
+
end
|
42
|
+
raise error_class, message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Raises error again if this is an internal error
|
47
|
+
# @param [Exception] e
|
48
|
+
def raise_if_internal(e)
|
49
|
+
raise e if e.is_a?(Mapper::Error)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'reflection'
|
4
|
+
|
5
|
+
module AMA
|
6
|
+
module Entity
|
7
|
+
class Mapper
|
8
|
+
module Mixin
|
9
|
+
# This module provides Type and Attribute classes with shortcut
|
10
|
+
# handler :name, :method method to register handlers
|
11
|
+
module HandlerSupport
|
12
|
+
class << self
|
13
|
+
def included(klass)
|
14
|
+
declare_namespace_method(klass)
|
15
|
+
declare_handler_method(klass)
|
16
|
+
end
|
17
|
+
|
18
|
+
def declare_namespace_method(klass)
|
19
|
+
klass.define_singleton_method(:handler_namespace) do |namespace|
|
20
|
+
@handler_namespace = namespace
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def declare_handler_method(klass)
|
25
|
+
processor = self
|
26
|
+
klass.define_singleton_method(:handler) do |key, method|
|
27
|
+
handler_name = key.capitalize
|
28
|
+
handler_class = @handler_namespace.const_get(handler_name)
|
29
|
+
processor.declare_handler_getter(klass, key, handler_class)
|
30
|
+
processor.declare_handler_setter(klass, key, handler_class)
|
31
|
+
processor.declare_handler_block_setter(klass, key, method)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def declare_handler_getter(klass, handler_key, handler_class)
|
36
|
+
instance = handler_class::INSTANCE
|
37
|
+
klass.instance_eval do
|
38
|
+
define_method(handler_key) do
|
39
|
+
instance_variable_get("@#{handler_key}") || instance
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def declare_handler_setter(klass, handler_key, handler_class)
|
45
|
+
klass.instance_eval do
|
46
|
+
define_method("#{handler_key}=") do |handler|
|
47
|
+
unless handler.class == handler_class
|
48
|
+
handler = handler_class.wrap(handler)
|
49
|
+
end
|
50
|
+
instance_variable_set("@#{handler_key}", handler)
|
51
|
+
self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def declare_handler_block_setter(klass, handler_key, method)
|
57
|
+
klass.instance_eval do
|
58
|
+
include Mixin::Reflection
|
59
|
+
define_method("#{handler_key}_block") do |&block|
|
60
|
+
send("#{handler_key}=", method_object(method, &block))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'errors'
|
4
|
+
|
5
|
+
module AMA
|
6
|
+
module Entity
|
7
|
+
class Mapper
|
8
|
+
module Mixin
|
9
|
+
# Collection of common methods twiddling with object internals
|
10
|
+
module Reflection
|
11
|
+
include Errors
|
12
|
+
|
13
|
+
# @param [Object] object
|
14
|
+
# @param [String, Symbol] name
|
15
|
+
# @param [Object] value
|
16
|
+
def set_object_attribute(object, name, value)
|
17
|
+
method = "#{name}="
|
18
|
+
return object.send(method, value) if object.respond_to?(method)
|
19
|
+
object.instance_variable_set("@#{name}", value)
|
20
|
+
rescue StandardError => e
|
21
|
+
message = "Failed to set attribute #{name} on #{object.class}, " \
|
22
|
+
"this is most likely due to `#{method}` method not following " \
|
23
|
+
'accessor conventions'
|
24
|
+
mapping_error(message, parent: e)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [Object] object
|
28
|
+
def object_variables(object)
|
29
|
+
intermediate = object.instance_variables.map do |variable|
|
30
|
+
[variable[1..-1].to_sym, object.instance_variable_get(variable)]
|
31
|
+
end
|
32
|
+
Hash[intermediate]
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Object] object
|
36
|
+
# @param [String, Symbol] name
|
37
|
+
def object_variable(object, name)
|
38
|
+
name = "@#{name}" unless name[0] == '@'
|
39
|
+
object.instance_variable_get(name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def object_variable_exists(object, name)
|
43
|
+
object.instance_variables.include?("@#{name}".to_sym)
|
44
|
+
end
|
45
|
+
|
46
|
+
def install_object_method(object, name, handler)
|
47
|
+
compliance_error('Handler not provided') unless handler
|
48
|
+
object.define_singleton_method(name, &handler)
|
49
|
+
object
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_object(method, to_s: nil, &handler)
|
53
|
+
object = install_object_method(Object.new, method, handler)
|
54
|
+
unless to_s
|
55
|
+
to_s = "Wrapper object for proc #{handler} " \
|
56
|
+
"(installed as method :#{method})"
|
57
|
+
end
|
58
|
+
object.define_singleton_method(:to_s) do
|
59
|
+
to_s
|
60
|
+
end
|
61
|
+
object
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'errors'
|
4
|
+
|
5
|
+
module AMA
|
6
|
+
module Entity
|
7
|
+
class Mapper
|
8
|
+
module Mixin
|
9
|
+
# Special module with method for playing with error suppression
|
10
|
+
module SuppressionSupport
|
11
|
+
include Errors
|
12
|
+
|
13
|
+
# Enumerates elements in enumerator, applying block to each one,
|
14
|
+
# returning result or suppressing specified error. If no element
|
15
|
+
# has succeeded, raises last error.
|
16
|
+
#
|
17
|
+
# @param [Enumerator] enumerator
|
18
|
+
# @param [Class<? extends StandardError>] error
|
19
|
+
# @param [AMA::Entity::Mapper::Context] ctx
|
20
|
+
def successful(enumerator, error = StandardError, ctx = nil)
|
21
|
+
suppressed = []
|
22
|
+
enumerator.each do |*args|
|
23
|
+
begin
|
24
|
+
return yield(*args)
|
25
|
+
rescue error => e
|
26
|
+
ctx.logger.debug("#{e.class} raised: #{e.message}") if ctx
|
27
|
+
suppressed.push(e)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
compliance_error('Empty enumerator passed') if suppressed.empty?
|
31
|
+
raise suppressed.last
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'path/segment'
|
4
|
+
|
5
|
+
module AMA
|
6
|
+
module Entity
|
7
|
+
class Mapper
|
8
|
+
# Wrapper for simple array. Helps to understand where exactly processing
|
9
|
+
# is taking place.
|
10
|
+
class Path
|
11
|
+
attr_reader :segments
|
12
|
+
|
13
|
+
def initialize(stack = [])
|
14
|
+
@segments = stack
|
15
|
+
end
|
16
|
+
|
17
|
+
def empty?
|
18
|
+
@segments.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [String, Symbol, Integer] name
|
22
|
+
# @return [AMA::Entity::Mapper::Path]
|
23
|
+
def index(name)
|
24
|
+
push(Segment.index(name))
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [String, Symbol] name
|
28
|
+
# @return [AMA::Entity::Mapper::Path]
|
29
|
+
def attribute(name)
|
30
|
+
push(Segment.attribute(name))
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [Array<AMA::Entity::Mapper::Path::Segment>] segments
|
34
|
+
# @return [AMA::Entity::Mapper::Path]
|
35
|
+
def push(*segments)
|
36
|
+
segments = segments.map do |segment|
|
37
|
+
next segment if segment.is_a?(Segment)
|
38
|
+
Segment.attribute(segment)
|
39
|
+
end
|
40
|
+
self.class.new(@segments + segments)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [AMA::Entity::Mapper::Path]
|
44
|
+
def pop
|
45
|
+
self.class.new(@segments[0..-2])
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [AMA::Entity::Mapper::Path::Segment]
|
49
|
+
def current
|
50
|
+
@segments.last
|
51
|
+
end
|
52
|
+
|
53
|
+
def each
|
54
|
+
@segments.each do |item|
|
55
|
+
yield(item)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def reduce(carrier)
|
60
|
+
@segments.reduce(carrier) do |inner_carrier, item|
|
61
|
+
yield(inner_carrier, item)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param [AMA::Entity::Mapper::Path] path
|
66
|
+
# @return [AMA::Entity::Mapper::Path]
|
67
|
+
def merge(path)
|
68
|
+
push(*path.segments)
|
69
|
+
end
|
70
|
+
|
71
|
+
def size
|
72
|
+
@segments.size
|
73
|
+
end
|
74
|
+
|
75
|
+
def segments
|
76
|
+
@segments.clone
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Array<AMA::Entity::Mapper::Path::Segment>]
|
80
|
+
def to_a
|
81
|
+
@segments.clone
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [String]
|
85
|
+
def to_s
|
86
|
+
"$#{@segments.join}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|