lutaml-model 0.3.30 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +34 -18
  3. data/README.adoc +172 -8
  4. data/lib/lutaml/model/attribute.rb +6 -2
  5. data/lib/lutaml/model/key_value_mapping.rb +0 -1
  6. data/lib/lutaml/model/key_value_mapping_rule.rb +3 -1
  7. data/lib/lutaml/model/mapping_rule.rb +14 -2
  8. data/lib/lutaml/model/serialize.rb +174 -61
  9. data/lib/lutaml/model/type/decimal.rb +5 -0
  10. data/lib/lutaml/model/type/time.rb +4 -4
  11. data/lib/lutaml/model/utils.rb +1 -1
  12. data/lib/lutaml/model/validation.rb +6 -2
  13. data/lib/lutaml/model/version.rb +1 -1
  14. data/lib/lutaml/model/xml_adapter/builder/nokogiri.rb +1 -0
  15. data/lib/lutaml/model/xml_adapter/builder/oga.rb +180 -0
  16. data/lib/lutaml/model/xml_adapter/builder/ox.rb +1 -0
  17. data/lib/lutaml/model/xml_adapter/oga/document.rb +20 -0
  18. data/lib/lutaml/model/xml_adapter/oga/element.rb +117 -0
  19. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +77 -44
  20. data/lib/lutaml/model/xml_adapter/xml_document.rb +11 -9
  21. data/lib/lutaml/model/xml_mapping.rb +0 -1
  22. data/lib/lutaml/model/xml_mapping_rule.rb +16 -4
  23. data/spec/address_spec.rb +1 -0
  24. data/spec/fixtures/sample_model.rb +7 -0
  25. data/spec/lutaml/model/custom_model_spec.rb +47 -1
  26. data/spec/lutaml/model/custom_serialization_spec.rb +16 -0
  27. data/spec/lutaml/model/enum_spec.rb +131 -0
  28. data/spec/lutaml/model/included_spec.rb +192 -0
  29. data/spec/lutaml/model/mixed_content_spec.rb +48 -32
  30. data/spec/lutaml/model/multiple_mapping_spec.rb +329 -0
  31. data/spec/lutaml/model/ordered_content_spec.rb +1 -1
  32. data/spec/lutaml/model/render_nil_spec.rb +3 -2
  33. data/spec/lutaml/model/serializable_spec.rb +3 -3
  34. data/spec/lutaml/model/type/boolean_spec.rb +62 -0
  35. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +11 -11
  36. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +1 -1
  37. data/spec/lutaml/model/xml_adapter_spec.rb +2 -2
  38. data/spec/lutaml/model/xml_mapping_spec.rb +24 -9
  39. data/spec/sample_model_spec.rb +114 -0
  40. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cca2f0b92a3e71807ed2201909e02ea5877dc1468c34c62d887d523962e63968
4
- data.tar.gz: 56fe25dc8f9229d2bcabe1315c88f0f7d8fb3a3ca5f01b78b0e6494fb65ebc75
3
+ metadata.gz: b1472bd6c2746013aba5d315d47dc5e484cfa54f6f537ab5d613b81f4f63109e
4
+ data.tar.gz: 45c48daa9b4a0f7b98d04bb8174f6cfe298c59564b714b866f838b7d2bf6464b
5
5
  SHA512:
6
- metadata.gz: a6d19950a00e397146f8a8cfc8eeeb0e3c965f9fb7f5cb3bb5518cf636505f31ec72750552385b533d410eec51c6e325d0d57070fca52189ff00a48c8380c156
7
- data.tar.gz: b7d55249da057ffe7f222c997ae4f628c7dd5acdeee9d7a1a5919f7f6d034ac5342b961696797029233dcd931a7db82be67f00f89a5b78463c3a7c101fbc3e4f
6
+ metadata.gz: 94f772a0efbc35332c95fb55729c8d781d4168ff61784af79d2f09388c93263144b378d8485e578f43aeb0386b2c02d4769285c782dffaa2c5d4dd6f0f34fa70
7
+ data.tar.gz: 4dd7279a62a8835e1f7c908590cc653d693f9a0225a388eda89bfa02cdcc7fb9a934bbf8d273f57d93d9764c86b867ae42a7aab2a87a4322c89698fa207343d0
data/.rubocop_todo.yml CHANGED
@@ -1,14 +1,14 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2024-12-03 11:13:42 UTC using RuboCop version 1.66.1.
3
+ # on 2025-01-07 08:52:47 UTC using RuboCop version 1.69.2.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 224
9
+ # Offense count: 292
10
10
  # This cop supports safe autocorrection (--autocorrect).
11
- # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
11
+ # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
12
12
  # URISchemes: http, https
13
13
  Layout/LineLength:
14
14
  Enabled: false
@@ -31,7 +31,7 @@ Lint/DuplicateMethods:
31
31
  Exclude:
32
32
  - 'lib/lutaml/model/type/float.rb'
33
33
 
34
- # Offense count: 37
34
+ # Offense count: 40
35
35
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
36
36
  Metrics/AbcSize:
37
37
  Exclude:
@@ -42,18 +42,20 @@ Metrics/AbcSize:
42
42
  - 'lib/lutaml/model/schema/xsd_schema.rb'
43
43
  - 'lib/lutaml/model/serialize.rb'
44
44
  - 'lib/lutaml/model/xml_adapter/nokogiri_adapter.rb'
45
+ - 'lib/lutaml/model/xml_adapter/oga/element.rb'
46
+ - 'lib/lutaml/model/xml_adapter/oga_adapter.rb'
45
47
  - 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
46
48
  - 'lib/lutaml/model/xml_adapter/xml_document.rb'
47
49
  - 'lib/lutaml/model/xml_mapping.rb'
48
50
  - 'lib/lutaml/model/xml_mapping_rule.rb'
49
51
 
50
- # Offense count: 6
52
+ # Offense count: 9
51
53
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
52
54
  # AllowedMethods: refine
53
55
  Metrics/BlockLength:
54
56
  Max: 46
55
57
 
56
- # Offense count: 28
58
+ # Offense count: 32
57
59
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
58
60
  Metrics/CyclomaticComplexity:
59
61
  Exclude:
@@ -61,21 +63,23 @@ Metrics/CyclomaticComplexity:
61
63
  - 'lib/lutaml/model/comparable_model.rb'
62
64
  - 'lib/lutaml/model/serialize.rb'
63
65
  - 'lib/lutaml/model/type/integer.rb'
66
+ - 'lib/lutaml/model/xml_adapter/builder/oga.rb'
64
67
  - 'lib/lutaml/model/xml_adapter/nokogiri_adapter.rb'
68
+ - 'lib/lutaml/model/xml_adapter/oga_adapter.rb'
65
69
  - 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
66
70
  - 'lib/lutaml/model/xml_adapter/xml_document.rb'
67
71
 
68
- # Offense count: 54
72
+ # Offense count: 63
69
73
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
70
74
  Metrics/MethodLength:
71
- Max: 46
75
+ Max: 44
72
76
 
73
77
  # Offense count: 7
74
78
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
75
79
  Metrics/ParameterLists:
76
- Max: 14
80
+ Max: 15
77
81
 
78
- # Offense count: 25
82
+ # Offense count: 30
79
83
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
80
84
  Metrics/PerceivedComplexity:
81
85
  Exclude:
@@ -83,10 +87,19 @@ Metrics/PerceivedComplexity:
83
87
  - 'lib/lutaml/model/comparable_model.rb'
84
88
  - 'lib/lutaml/model/serialize.rb'
85
89
  - 'lib/lutaml/model/type/integer.rb'
90
+ - 'lib/lutaml/model/xml_adapter/builder/oga.rb'
91
+ - 'lib/lutaml/model/xml_adapter/builder/ox.rb'
86
92
  - 'lib/lutaml/model/xml_adapter/nokogiri_adapter.rb'
93
+ - 'lib/lutaml/model/xml_adapter/oga_adapter.rb'
87
94
  - 'lib/lutaml/model/xml_adapter/ox_adapter.rb'
88
95
  - 'lib/lutaml/model/xml_adapter/xml_document.rb'
89
96
 
97
+ # Offense count: 1
98
+ # This cop supports unsafe autocorrection (--autocorrect-all).
99
+ Performance/MapCompact:
100
+ Exclude:
101
+ - 'lib/lutaml/model/serialize.rb'
102
+
90
103
  # Offense count: 8
91
104
  # Configuration parameters: Prefixes, AllowedPatterns.
92
105
  # Prefixes: when, with, without
@@ -105,7 +118,7 @@ RSpec/DescribedClass:
105
118
  Exclude:
106
119
  - 'spec/lutaml/model/xml_mapping_spec.rb'
107
120
 
108
- # Offense count: 133
121
+ # Offense count: 139
109
122
  # Configuration parameters: CountAsOne.
110
123
  RSpec/ExampleLength:
111
124
  Max: 54
@@ -135,7 +148,7 @@ RSpec/MultipleDescribes:
135
148
  - 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
136
149
  - 'spec/lutaml/model/xml_adapter_spec.rb'
137
150
 
138
- # Offense count: 157
151
+ # Offense count: 172
139
152
  RSpec/MultipleExpectations:
140
153
  Max: 14
141
154
 
@@ -144,23 +157,19 @@ RSpec/MultipleExpectations:
144
157
  RSpec/MultipleMemoizedHelpers:
145
158
  Max: 9
146
159
 
147
- # Offense count: 15
160
+ # Offense count: 24
148
161
  # Configuration parameters: AllowedGroups.
149
162
  RSpec/NestedGroups:
150
163
  Max: 4
151
164
 
152
- # Offense count: 13
165
+ # Offense count: 9
153
166
  RSpec/PendingWithoutReason:
154
167
  Exclude:
155
- - 'spec/lutaml/model/mixed_content_spec.rb'
156
168
  - 'spec/lutaml/model/type/date_time_spec.rb'
157
169
  - 'spec/lutaml/model/type/integer_spec.rb'
158
170
  - 'spec/lutaml/model/type/time_spec.rb'
159
171
  - 'spec/lutaml/model/type/time_without_date_spec.rb'
160
172
  - 'spec/lutaml/model/validation_spec.rb'
161
- - 'spec/lutaml/model/xml_adapter/oga_adapter_spec.rb'
162
- - 'spec/lutaml/model/xml_adapter/xml_namespace_spec.rb'
163
- - 'spec/lutaml/model/xml_adapter_spec.rb'
164
173
 
165
174
  # Offense count: 1
166
175
  RSpec/RemoveConst:
@@ -209,3 +218,10 @@ Style/MissingRespondToMissing:
209
218
  Style/OptionalBooleanParameter:
210
219
  Exclude:
211
220
  - 'lib/lutaml/model/comparable_model.rb'
221
+
222
+ # Offense count: 1
223
+ # This cop supports unsafe autocorrection (--autocorrect-all).
224
+ # Configuration parameters: Mode.
225
+ Style/StringConcatenation:
226
+ Exclude:
227
+ - 'spec/lutaml/model/xml_mapping_spec.rb'
data/README.adoc CHANGED
@@ -569,6 +569,12 @@ The values set inside the `values:` option can be of any type, but they must
569
569
  match the type of the attribute. The values are compared using the `==` operator,
570
570
  so the type must implement the `==` method.
571
571
 
572
+ Also, If all the elements in `values` directive are strings then `lutaml-model` add some enum convenience methods, for each of the value the following three methods are added
573
+
574
+ * `value1`: will return value if set
575
+ * `value1?`: will return true if value is set, false otherwise
576
+ * `value1=`: will set the value of `name_of_attribute` equal to `value1` if truthy value is given, and remove it otherwise.
577
+
572
578
  .Using the `values` directive to define acceptable values for an attribute (basic types)
573
579
  [example]
574
580
  ====
@@ -2125,6 +2131,121 @@ end
2125
2131
 
2126
2132
  === Advanced attribute mapping
2127
2133
 
2134
+ ==== Multiple mappings to single attribute
2135
+
2136
+ The mapping methods support multiple names mapping to a single attribute using
2137
+ an array of names.
2138
+
2139
+ Syntax:
2140
+
2141
+ [source,ruby]
2142
+ ----
2143
+ json | yaml | toml | key_value do
2144
+ map ["name1", "name2"], to: :attribute_name
2145
+ end
2146
+
2147
+ xml do
2148
+ map_element ["name1", "name2"], to: :attribute_name
2149
+ map_attribute ["attr1", "attr2"], to: :attribute_name
2150
+ end
2151
+ ----
2152
+
2153
+ When serializing, the first element in the array of mapped names is always used
2154
+ as the output name.
2155
+
2156
+
2157
+ .Using multiple names to map to a single attribute
2158
+ [example]
2159
+ ====
2160
+ [source,ruby]
2161
+ ----
2162
+ class CustomModel < Lutaml::Model::Serializable
2163
+ attribute :full_name, Lutaml::Model::Type::String
2164
+ attribute :color, Lutaml::Model::Type::String
2165
+ attribute :id, Lutaml::Model::Type::String
2166
+
2167
+ json do
2168
+ map ["name", "custom_name"], with: { to: :name_to_json, from: :name_from_json }
2169
+ map ["color", "shade"], with: { to: :color_to_json, from: :color_from_json }
2170
+ end
2171
+
2172
+ xml do
2173
+ root "CustomModel"
2174
+ map_element ["name", "custom-name"], with: { to: :name_to_xml, from: :name_from_xml }
2175
+ map_element ["color", "shade"], with: { to: :color_to_xml, from: :color_from_xml }
2176
+ map_attribute ["id", "identifier"], to: :id
2177
+ end
2178
+
2179
+ # Custom methods for JSON
2180
+ def name_to_json(model, doc)
2181
+ doc["name"] = "JSON Model: #{model.full_name}"
2182
+ end
2183
+
2184
+ def name_from_json(model, value)
2185
+ model.full_name = value&.sub(/^JSON Model: /, "")
2186
+ end
2187
+
2188
+ def color_to_json(model, doc)
2189
+ doc["color"] = model.color.upcase
2190
+ end
2191
+
2192
+ def color_from_json(model, value)
2193
+ model.color = value&.downcase
2194
+ end
2195
+
2196
+ # Custom methods for XML
2197
+ def name_to_xml(model, parent, doc)
2198
+ el = doc.create_element("name")
2199
+ doc.add_text(el, "XML Model: #{model.full_name}")
2200
+ doc.add_element(parent, el)
2201
+ end
2202
+
2203
+ def name_from_xml(model, value)
2204
+ model.full_name = value.sub(/^XML Model: /, "")
2205
+ end
2206
+
2207
+ def color_to_xml(model, parent, doc)
2208
+ el = doc.create_element("color")
2209
+ doc.add_text(el, model.color.upcase)
2210
+ doc.add_element(parent, el)
2211
+ end
2212
+
2213
+ def color_from_xml(model, value)
2214
+ model.color = value.downcase
2215
+ end
2216
+ end
2217
+ ----
2218
+
2219
+ For JSON:
2220
+ [source,json]
2221
+ ----
2222
+ {
2223
+ "custom_name": "JSON Model: Vase",
2224
+ "shade": "BLUE",
2225
+ "identifier": "123"
2226
+ }
2227
+ ----
2228
+
2229
+ For XML:
2230
+ [source,xml]
2231
+ ----
2232
+ <CustomModel id="123">
2233
+ <name>XML Model: Vase</name>
2234
+ <color>BLUE</color>
2235
+ </CustomModel>
2236
+ ----
2237
+
2238
+ [source,ruby]
2239
+ ----
2240
+ > model = CustomModel.from_json(json)
2241
+ > model.full_name
2242
+ > # "Vase"
2243
+ > model.color
2244
+ > # "blue"
2245
+ ----
2246
+ ====
2247
+
2248
+
2128
2249
  ==== Attribute mapping delegation
2129
2250
 
2130
2251
  Delegate attribute mappings to nested objects using the `delegate` option.
@@ -2635,6 +2756,13 @@ klin.validate
2635
2756
  Lutaml::Model uses an adapter pattern to support multiple libraries for each
2636
2757
  serialization format.
2637
2758
 
2759
+ Lutaml::Model supports the following serialization formats:
2760
+
2761
+ * XML (https://www.w3.org/TR/xmlschema-1/[W3C XML Schema (Second Edition)], XML 1.0)
2762
+ * YAML (https://yaml.org/[YAML version 1.2])
2763
+ * JSON (https://www.ecma-international.org/publications-and-standards/standards/ecma-404/[ECMA-404 The JSON Data Interchange Standard], unofficial link: https://www.json.org[JSON])
2764
+ * TOML (https://toml.io/en[TOML version 1.0])
2765
+
2638
2766
  You will need to specify the configuration for the adapter you want to use. The
2639
2767
  easiest way is to copy and paste the following configuration into your code.
2640
2768
 
@@ -2678,9 +2806,25 @@ NOTE: By default `yaml_adapter_type` and `json_adapter_type` are set to
2678
2806
 
2679
2807
  Lutaml::Model supports the following XML adapters:
2680
2808
 
2681
- * Nokogiri (default)
2682
- * Oga (optional, plain Ruby suitable for Opal/JS)
2683
- * Ox (optional)
2809
+ Nokogiri::
2810
+ (default)
2811
+ Popular `libxml` based XML parser for Ruby.
2812
+ Requires native extensions (i.e. compiled C code).
2813
+ Requires the `nokogiri` gem.
2814
+
2815
+ Oga::
2816
+ (optional)
2817
+ Pure Ruby XML parser.
2818
+ Does not require native extensions and is suitable for
2819
+ https://opalrb.com[Opal] (Ruby on JavaScript).
2820
+ Requires the `oga` gem.
2821
+
2822
+ Ox::
2823
+ (optional)
2824
+ Fast XML parser and object serializer for Ruby, implemented partially in C.
2825
+ Requires native extensions (i.e. compiled C code).
2826
+ Requires the `ox` gem.
2827
+
2684
2828
 
2685
2829
  .Using the Nokogiri XML adapter
2686
2830
  [source,ruby]
@@ -2720,7 +2864,10 @@ end
2720
2864
 
2721
2865
  Lutaml::Model supports only one YAML adapter.
2722
2866
 
2723
- * YAML (default)
2867
+ YAML::
2868
+ (default)
2869
+ The Psych YAML parser and emitter for Ruby.
2870
+ Included in the Ruby standard library.
2724
2871
 
2725
2872
  .Using the YAML adapter
2726
2873
  [source,ruby]
@@ -2739,8 +2886,15 @@ end
2739
2886
 
2740
2887
  Lutaml::Model supports the following JSON adapters:
2741
2888
 
2742
- * JSON (default)
2743
- * MultiJson (optional)
2889
+ JSON::
2890
+ (default)
2891
+ The standard JSON library for Ruby.
2892
+ Included in the Ruby standard library.
2893
+
2894
+ MultiJson::
2895
+ (optional)
2896
+ A gem that provides a common interface to multiple JSON libraries.
2897
+ Requires the `multi_json` gem.
2744
2898
 
2745
2899
  .Using the JSON adapter
2746
2900
  [source,ruby]
@@ -2768,8 +2922,18 @@ end
2768
2922
 
2769
2923
  Lutaml::Model supports the following TOML adapters:
2770
2924
 
2771
- * Toml-rb (default)
2772
- * Tomlib (optional)
2925
+ Toml-rb::
2926
+ (default)
2927
+ A TOML parser and serializer for Ruby that is compatible with the TOML v1.0.0
2928
+ specification.
2929
+ Requires the `toml-rb` gem.
2930
+
2931
+ Tomlib::
2932
+ (optional)
2933
+ Toml-rb fork that is compatible with the TOML v1.0.0 specification, but with
2934
+ additional features.
2935
+ Requires the `tomlib` gem.
2936
+
2773
2937
 
2774
2938
  .Using the Toml-rb adapter
2775
2939
  [source,ruby]
@@ -76,6 +76,10 @@ module Lutaml
76
76
  @raw
77
77
  end
78
78
 
79
+ def enum?
80
+ !enum_values.empty?
81
+ end
82
+
79
83
  def default
80
84
  value = if delegate
81
85
  type.attributes[to].default
@@ -98,7 +102,7 @@ module Lutaml
98
102
 
99
103
  def valid_value!(value)
100
104
  return true if value.nil? && !collection?
101
- return true if enum_values.empty?
105
+ return true unless enum?
102
106
 
103
107
  unless valid_value?(value)
104
108
  raise Lutaml::Model::InvalidValueError.new(name, value, enum_values)
@@ -208,7 +212,7 @@ module Lutaml
208
212
  serialize(v, format, options)
209
213
  end
210
214
  elsif type <= Serialize
211
- type.hash_representation(value, format, options)
215
+ type.public_send(:"as_#{format}", value, options)
212
216
  else
213
217
  # Convert to Value instance if not already
214
218
  value = type.new(value) unless value.is_a?(Type::Value)
@@ -19,7 +19,6 @@ module Lutaml
19
19
  child_mappings: nil
20
20
  )
21
21
  validate!(name, to, with)
22
-
23
22
  @mappings << KeyValueMappingRule.new(
24
23
  name,
25
24
  to: to,
@@ -12,7 +12,8 @@ module Lutaml
12
12
  render_default: false,
13
13
  with: {},
14
14
  delegate: nil,
15
- child_mappings: nil
15
+ child_mappings: nil,
16
+ id: nil
16
17
  )
17
18
  super(
18
19
  name,
@@ -21,6 +22,7 @@ module Lutaml
21
22
  render_default: render_default,
22
23
  with: with,
23
24
  delegate: delegate,
25
+ id: id
24
26
  )
25
27
 
26
28
  @child_mappings = child_mappings
@@ -16,7 +16,8 @@ module Lutaml
16
16
  render_default: false,
17
17
  with: {},
18
18
  attribute: false,
19
- delegate: nil
19
+ delegate: nil,
20
+ id: nil
20
21
  )
21
22
  @name = name
22
23
  @to = to
@@ -25,6 +26,7 @@ module Lutaml
25
26
  @custom_methods = with
26
27
  @attribute = attribute
27
28
  @delegate = delegate
29
+ @id = id
28
30
  end
29
31
 
30
32
  alias from name
@@ -42,6 +44,8 @@ module Lutaml
42
44
  if delegate
43
45
  model.public_send(delegate).public_send(to)
44
46
  else
47
+ return if to.nil?
48
+
45
49
  model.public_send(to)
46
50
  end
47
51
  end
@@ -56,7 +60,7 @@ module Lutaml
56
60
 
57
61
  def deserialize(model, value, attributes, mapper_class = nil)
58
62
  if custom_methods[:from]
59
- mapper_class.new.send(custom_methods[:from], model, value)
63
+ mapper_class.new.send(custom_methods[:from], model, value) unless value.nil?
60
64
  elsif delegate
61
65
  if model.public_send(delegate).nil?
62
66
  model.public_send(:"#{delegate}=", attributes[delegate].type.new)
@@ -68,6 +72,14 @@ module Lutaml
68
72
  end
69
73
  end
70
74
 
75
+ def using_custom_methods?
76
+ !custom_methods.empty?
77
+ end
78
+
79
+ def multiple_mappings?
80
+ name.is_a?(Array)
81
+ end
82
+
71
83
  def deep_dup
72
84
  raise NotImplementedError, "Subclasses must implement `deep_dup`."
73
85
  end