ama-entity-mapper 0.1.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|