shale 0.9.0 → 1.0.0
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 +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +179 -48
- data/exe/shaleb +19 -4
- data/lib/shale/error.rb +20 -8
- data/lib/shale/mapper.rb +7 -7
- data/lib/shale/mapping/delegates.rb +95 -0
- data/lib/shale/mapping/descriptor/dict.rb +10 -1
- data/lib/shale/mapping/descriptor/xml.rb +13 -2
- data/lib/shale/mapping/dict.rb +14 -4
- data/lib/shale/mapping/dict_base.rb +6 -3
- data/lib/shale/mapping/dict_group.rb +1 -1
- data/lib/shale/mapping/validator.rb +10 -3
- data/lib/shale/mapping/xml.rb +22 -6
- data/lib/shale/mapping/xml_base.rb +21 -12
- data/lib/shale/schema/compiler/complex.rb +52 -8
- data/lib/shale/schema/compiler/xml_complex.rb +5 -4
- data/lib/shale/schema/json_compiler.rb +27 -13
- data/lib/shale/schema/json_generator.rb +2 -2
- data/lib/shale/schema/xml_compiler.rb +46 -18
- data/lib/shale/schema/xml_generator.rb +3 -3
- data/lib/shale/schema.rb +10 -4
- data/lib/shale/type/complex.rb +165 -24
- data/lib/shale/utils.rb +22 -4
- data/lib/shale/version.rb +1 -1
- metadata +4 -3
@@ -139,55 +139,63 @@ module Shale
|
|
139
139
|
<%- unless type.references.empty? -%>
|
140
140
|
|
141
141
|
<%- type.references.each do |property| -%>
|
142
|
-
require_relative '<%= property.type.file_name %>'
|
142
|
+
require_relative '<%= type.relative_path(property.type.file_name) %>'
|
143
143
|
<%- end -%>
|
144
144
|
<%- end -%>
|
145
145
|
|
146
|
-
|
146
|
+
<%- type.modules.each_with_index do |name, i| -%>
|
147
|
+
<%= ' ' * i %>module <%= name %>
|
148
|
+
<%- end -%>
|
149
|
+
<%- indent = ' ' * type.modules.length -%>
|
150
|
+
<%= indent %>class <%= type.root_name %> < Shale::Mapper
|
147
151
|
<%- type.properties.select(&:content?).each do |property| -%>
|
148
|
-
attribute :<%= property.attribute_name %>, <%= property.type.name -%>
|
152
|
+
<%= indent %>attribute :<%= property.attribute_name %>, <%= property.type.name -%>
|
149
153
|
<%- if property.collection? %>, collection: true<% end -%>
|
150
154
|
<%- unless property.default.nil? %>, default: -> { <%= property.default %> }<% end %>
|
151
155
|
<%- end -%>
|
152
156
|
<%- type.properties.select(&:attribute?).each do |property| -%>
|
153
|
-
attribute :<%= property.attribute_name %>, <%= property.type.name -%>
|
157
|
+
<%= indent %>attribute :<%= property.attribute_name %>, <%= property.type.name -%>
|
154
158
|
<%- if property.collection? %>, collection: true<% end -%>
|
155
159
|
<%- unless property.default.nil? %>, default: -> { <%= property.default %> }<% end %>
|
156
160
|
<%- end -%>
|
157
161
|
<%- type.properties.select(&:element?).each do |property| -%>
|
158
|
-
attribute :<%= property.attribute_name %>, <%= property.type.name -%>
|
162
|
+
<%= indent %>attribute :<%= property.attribute_name %>, <%= property.type.name -%>
|
159
163
|
<%- if property.collection? %>, collection: true<% end -%>
|
160
164
|
<%- unless property.default.nil? %>, default: -> { <%= property.default %> }<% end %>
|
161
165
|
<%- end -%>
|
162
166
|
|
163
|
-
xml do
|
164
|
-
root '<%= type.root %>'
|
167
|
+
<%= indent %>xml do
|
168
|
+
<%= indent %>root '<%= type.root %>'
|
165
169
|
<%- if type.namespace -%>
|
166
|
-
namespace '<%= type.namespace %>', '<%= type.prefix %>'
|
170
|
+
<%= indent %>namespace '<%= type.namespace %>', '<%= type.prefix %>'
|
167
171
|
<%- end -%>
|
168
172
|
<%- unless type.properties.empty? -%>
|
169
173
|
|
170
174
|
<%- type.properties.select(&:content?).each do |property| -%>
|
171
|
-
map_content to: :<%= property.attribute_name %>
|
175
|
+
<%= indent %>map_content to: :<%= property.attribute_name %>
|
172
176
|
<%- end -%>
|
173
177
|
<%- type.properties.select(&:attribute?).each do |property| -%>
|
174
|
-
map_attribute '<%= property.mapping_name %>', to: :<%= property.attribute_name -%>
|
178
|
+
<%= indent %>map_attribute '<%= property.mapping_name %>', to: :<%= property.attribute_name -%>
|
175
179
|
<%- if property.namespace %>, prefix: '<%= property.prefix %>'<%- end -%>
|
176
180
|
<%- if property.namespace %>, namespace: '<%= property.namespace %>'<% end %>
|
177
181
|
<%- end -%>
|
178
182
|
<%- type.properties.select(&:element?).each do |property| -%>
|
179
|
-
map_element '<%= property.mapping_name %>', to: :<%= property.attribute_name -%>
|
183
|
+
<%= indent %>map_element '<%= property.mapping_name %>', to: :<%= property.attribute_name -%>
|
180
184
|
<%- if type.namespace != property.namespace %>, prefix: <%= property.prefix ? "'\#{property.prefix}'" : 'nil' %><%- end -%>
|
181
185
|
<%- if type.namespace != property.namespace %>, namespace: <%= property.namespace ? "'\#{property.namespace}'" : 'nil' %><% end %>
|
182
186
|
<%- end -%>
|
183
187
|
<%- end -%>
|
184
|
-
end
|
185
|
-
end
|
188
|
+
<%= indent %>end
|
189
|
+
<%= indent %>end
|
190
|
+
<%- type.modules.length.times do |i| -%>
|
191
|
+
<%= ' ' * (type.modules.length - i - 1) %>end
|
192
|
+
<%- end -%>
|
186
193
|
TEMPLATE
|
187
194
|
|
188
195
|
# Generate Shale models from XML Schema and return them as a Ruby Array of objects
|
189
196
|
#
|
190
197
|
# @param [Array<String>] schemas
|
198
|
+
# @param [Hash<String, String>, nil] namespace_mapping
|
191
199
|
#
|
192
200
|
# @raise [AdapterError] when XML adapter is not set or Ox adapter is used
|
193
201
|
# @raise [SchemaError] when XML Schema has errors
|
@@ -198,7 +206,7 @@ module Shale
|
|
198
206
|
# Shale::Schema::XMLCompiler.new.as_models([schema1, schema2])
|
199
207
|
#
|
200
208
|
# @api public
|
201
|
-
def as_models(schemas)
|
209
|
+
def as_models(schemas, namespace_mapping: nil)
|
202
210
|
unless Shale.xml_adapter
|
203
211
|
raise AdapterError, XML_ADAPTER_NOT_SET_MESSAGE
|
204
212
|
end
|
@@ -212,6 +220,7 @@ module Shale
|
|
212
220
|
Shale.xml_adapter.load(schema)
|
213
221
|
end
|
214
222
|
|
223
|
+
@namespace_mapping = namespace_mapping || {}
|
215
224
|
@elements_repository = {}
|
216
225
|
@attributes_repository = {}
|
217
226
|
@simple_types_repository = {}
|
@@ -244,7 +253,7 @@ module Shale
|
|
244
253
|
duplicates[type.name] += 1
|
245
254
|
|
246
255
|
if total_duplicates[type.name] > 1
|
247
|
-
type.
|
256
|
+
type.root_name = format("#{type.root_name}%d", duplicates[type.name])
|
248
257
|
end
|
249
258
|
end
|
250
259
|
|
@@ -256,6 +265,7 @@ module Shale
|
|
256
265
|
# Generate Shale models from XML Schema
|
257
266
|
#
|
258
267
|
# @param [Array<String>] schemas
|
268
|
+
# @param [Hash<String, String>, nil] namespace_mapping
|
259
269
|
#
|
260
270
|
# @raise [SchemaError] when XML Schema has errors
|
261
271
|
#
|
@@ -265,8 +275,8 @@ module Shale
|
|
265
275
|
# Shale::Schema::XMLCompiler.new.to_models([schema1, schema2])
|
266
276
|
#
|
267
277
|
# @api public
|
268
|
-
def to_models(schemas)
|
269
|
-
types = as_models(schemas)
|
278
|
+
def to_models(schemas, namespace_mapping: nil)
|
279
|
+
types = as_models(schemas, namespace_mapping: namespace_mapping)
|
270
280
|
|
271
281
|
types.to_h do |type|
|
272
282
|
[type.file_name, MODEL_TEMPLATE.result(binding)]
|
@@ -415,6 +425,10 @@ module Shale
|
|
415
425
|
type = type.sub(/^#{prefix}/, name)
|
416
426
|
end
|
417
427
|
|
428
|
+
if namespaces.key?('xmlns') && !type.include?(':')
|
429
|
+
type = "#{namespaces['xmlns']}:#{type}"
|
430
|
+
end
|
431
|
+
|
418
432
|
type
|
419
433
|
end
|
420
434
|
|
@@ -535,7 +549,13 @@ module Shale
|
|
535
549
|
name = node.attributes['name'] || node.parent.attributes['name']
|
536
550
|
prefix, namespace = resolve_complex_type_namespace(node)
|
537
551
|
|
538
|
-
@complex_types[id] = Compiler::XMLComplex.new(
|
552
|
+
@complex_types[id] = Compiler::XMLComplex.new(
|
553
|
+
id,
|
554
|
+
name,
|
555
|
+
prefix,
|
556
|
+
namespace,
|
557
|
+
@namespace_mapping[namespace]
|
558
|
+
)
|
539
559
|
end
|
540
560
|
end
|
541
561
|
end
|
@@ -571,6 +591,14 @@ module Shale
|
|
571
591
|
infer_type_from_xs_type(type, namespaces)
|
572
592
|
end
|
573
593
|
|
594
|
+
# Infer type from XSD type
|
595
|
+
#
|
596
|
+
# @param [String] type
|
597
|
+
# @param [Hash<String, String>] namespaces
|
598
|
+
#
|
599
|
+
# @return [Shale::Schema::Compiler::<any>]
|
600
|
+
#
|
601
|
+
# @api private
|
574
602
|
def infer_type_from_xs_type(type, namespaces)
|
575
603
|
type = replace_ns_prefixes(type, namespaces)
|
576
604
|
|
@@ -84,7 +84,7 @@ module Shale
|
|
84
84
|
|
85
85
|
root_element = TypedElement.new(
|
86
86
|
name: klass.xml_mapping.unprefixed_root,
|
87
|
-
type: [default_namespace.prefix, schematize(klass.name)].compact.join(':'),
|
87
|
+
type: [default_namespace.prefix, schematize(klass.model.name)].compact.join(':'),
|
88
88
|
required: true
|
89
89
|
)
|
90
90
|
|
@@ -195,7 +195,7 @@ module Shale
|
|
195
195
|
end
|
196
196
|
|
197
197
|
complex = ComplexType.new(
|
198
|
-
schematize(type.name),
|
198
|
+
schematize(type.model.name),
|
199
199
|
children,
|
200
200
|
mixed: !type.xml_mapping.content.nil?
|
201
201
|
)
|
@@ -287,7 +287,7 @@ module Shale
|
|
287
287
|
# @api private
|
288
288
|
def get_xml_type_for_attribute(type, namespace)
|
289
289
|
if mapper_type?(type)
|
290
|
-
[namespace.prefix, schematize(type.name)].compact.join(':')
|
290
|
+
[namespace.prefix, schematize(type.model.name)].compact.join(':')
|
291
291
|
else
|
292
292
|
"xs:#{self.class.get_xml_type(type)}"
|
293
293
|
end
|
data/lib/shale/schema.rb
CHANGED
@@ -38,6 +38,7 @@ module Shale
|
|
38
38
|
#
|
39
39
|
# @param [Array<String>] schemas
|
40
40
|
# @param [String, nil] root_name
|
41
|
+
# @param [Hash<String, String>, nil] namespace_mapping
|
41
42
|
#
|
42
43
|
# @return [Array<String>]
|
43
44
|
#
|
@@ -46,8 +47,12 @@ module Shale
|
|
46
47
|
# # => [model1, model2, model3]
|
47
48
|
#
|
48
49
|
# @api public
|
49
|
-
def self.from_json(schemas, root_name: nil)
|
50
|
-
JSONCompiler.new.to_models(
|
50
|
+
def self.from_json(schemas, root_name: nil, namespace_mapping: nil)
|
51
|
+
JSONCompiler.new.to_models(
|
52
|
+
schemas,
|
53
|
+
root_name: root_name,
|
54
|
+
namespace_mapping: namespace_mapping
|
55
|
+
)
|
51
56
|
end
|
52
57
|
|
53
58
|
# Generate XML Schema from Shale model
|
@@ -71,6 +76,7 @@ module Shale
|
|
71
76
|
# Generate Shale model from XML Schema
|
72
77
|
#
|
73
78
|
# @param [Array<String>] schemas
|
79
|
+
# @param [Hash<String, String>, nil] namespace_mapping
|
74
80
|
#
|
75
81
|
# @return [Array<String>]
|
76
82
|
#
|
@@ -79,8 +85,8 @@ module Shale
|
|
79
85
|
# # => [model1, model2, model3]
|
80
86
|
#
|
81
87
|
# @api public
|
82
|
-
def self.from_xml(schemas)
|
83
|
-
XMLCompiler.new.to_models(schemas)
|
88
|
+
def self.from_xml(schemas, namespace_mapping: nil)
|
89
|
+
XMLCompiler.new.to_models(schemas, namespace_mapping: namespace_mapping)
|
84
90
|
end
|
85
91
|
end
|
86
92
|
end
|
data/lib/shale/type/complex.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../error'
|
4
|
+
require_relative '../mapping/delegates'
|
4
5
|
require_relative '../mapping/group/dict_grouping'
|
5
6
|
require_relative '../mapping/group/xml_grouping'
|
6
7
|
require_relative 'value'
|
@@ -47,6 +48,7 @@ module Shale
|
|
47
48
|
|
48
49
|
mapping_keys = #{format}_mapping.keys
|
49
50
|
grouping = Shale::Mapping::Group::DictGrouping.new
|
51
|
+
delegates = Shale::Mapping::Delegates.new
|
50
52
|
|
51
53
|
only = to_partial_render_attributes(only)
|
52
54
|
except = to_partial_render_attributes(except)
|
@@ -66,7 +68,8 @@ module Shale
|
|
66
68
|
mapper.send(mapping.method_from, instance, value)
|
67
69
|
end
|
68
70
|
else
|
69
|
-
|
71
|
+
receiver_attributes = get_receiver_attributes(mapping)
|
72
|
+
attribute = receiver_attributes[mapping.attribute]
|
70
73
|
next unless attribute
|
71
74
|
|
72
75
|
if only
|
@@ -79,20 +82,22 @@ module Shale
|
|
79
82
|
next if except.key?(attribute.name) && attribute_except.nil?
|
80
83
|
end
|
81
84
|
|
85
|
+
casted_value = nil
|
86
|
+
|
82
87
|
if value.nil?
|
83
|
-
|
88
|
+
casted_value = nil
|
84
89
|
elsif attribute.collection?
|
85
|
-
[
|
86
|
-
|
90
|
+
casted_value = (value.is_a?(Array) ? value : [value]).map do |val|
|
91
|
+
unless val.nil?
|
87
92
|
val = attribute.type.of_#{format}(
|
88
93
|
val,
|
89
94
|
only: attribute_only,
|
90
95
|
except: attribute_except,
|
91
96
|
context: context
|
92
97
|
)
|
93
|
-
end
|
94
98
|
|
95
|
-
|
99
|
+
attribute.type.cast(val)
|
100
|
+
end
|
96
101
|
end
|
97
102
|
else
|
98
103
|
val = attribute.type.of_#{format}(
|
@@ -101,11 +106,23 @@ module Shale
|
|
101
106
|
except: attribute_except,
|
102
107
|
context: context
|
103
108
|
)
|
104
|
-
|
109
|
+
|
110
|
+
casted_value = attribute.type.cast(val)
|
111
|
+
end
|
112
|
+
|
113
|
+
if mapping.receiver
|
114
|
+
delegates.add(attributes[mapping.receiver], attribute.setter, casted_value)
|
115
|
+
else
|
116
|
+
instance.send(attribute.setter, casted_value)
|
105
117
|
end
|
106
118
|
end
|
107
119
|
end
|
108
120
|
|
121
|
+
delegates.each do |delegate|
|
122
|
+
receiver = get_receiver(instance, delegate.receiver_attribute)
|
123
|
+
receiver.send(delegate.setter, delegate.value)
|
124
|
+
end
|
125
|
+
|
109
126
|
grouping.each do |group|
|
110
127
|
mapper = new
|
111
128
|
|
@@ -167,7 +184,14 @@ module Shale
|
|
167
184
|
mapper.send(mapping.method_to, instance, hash)
|
168
185
|
end
|
169
186
|
else
|
170
|
-
|
187
|
+
if mapping.receiver
|
188
|
+
receiver = instance.send(mapping.receiver)
|
189
|
+
else
|
190
|
+
receiver = instance
|
191
|
+
end
|
192
|
+
|
193
|
+
receiver_attributes = get_receiver_attributes(mapping)
|
194
|
+
attribute = receiver_attributes[mapping.attribute]
|
171
195
|
next unless attribute
|
172
196
|
|
173
197
|
if only
|
@@ -180,7 +204,7 @@ module Shale
|
|
180
204
|
next if except.key?(attribute.name) && attribute_except.nil?
|
181
205
|
end
|
182
206
|
|
183
|
-
value =
|
207
|
+
value = receiver.send(attribute.name) if receiver
|
184
208
|
|
185
209
|
if value.nil?
|
186
210
|
hash[mapping.name] = nil if mapping.render_nil?
|
@@ -414,6 +438,7 @@ module Shale
|
|
414
438
|
.each { |attr| instance.send(attr.setter, attr.default.call) }
|
415
439
|
|
416
440
|
grouping = Shale::Mapping::Group::XmlGrouping.new
|
441
|
+
delegates = Shale::Mapping::Delegates.new
|
417
442
|
|
418
443
|
only = to_partial_render_attributes(only)
|
419
444
|
except = to_partial_render_attributes(except)
|
@@ -433,16 +458,29 @@ module Shale
|
|
433
458
|
mapper.send(mapping.method_from, instance, value)
|
434
459
|
end
|
435
460
|
else
|
436
|
-
|
461
|
+
receiver_attributes = get_receiver_attributes(mapping)
|
462
|
+
attribute = receiver_attributes[mapping.attribute]
|
437
463
|
next unless attribute
|
438
464
|
|
439
465
|
next if only && !only.key?(attribute.name)
|
440
466
|
next if except&.key?(attribute.name)
|
441
467
|
|
468
|
+
casted_value = attribute.type.cast(value)
|
469
|
+
|
442
470
|
if attribute.collection?
|
443
|
-
|
471
|
+
if mapping.receiver
|
472
|
+
delegates.add_collection(
|
473
|
+
attributes[mapping.receiver],
|
474
|
+
attribute.setter,
|
475
|
+
casted_value
|
476
|
+
)
|
477
|
+
else
|
478
|
+
instance.send(attribute.name) << casted_value
|
479
|
+
end
|
480
|
+
elsif mapping.receiver
|
481
|
+
delegates.add(attributes[mapping.receiver], attribute.setter, casted_value)
|
444
482
|
else
|
445
|
-
instance.send(attribute.setter,
|
483
|
+
instance.send(attribute.setter, casted_value)
|
446
484
|
end
|
447
485
|
end
|
448
486
|
end
|
@@ -461,7 +499,8 @@ module Shale
|
|
461
499
|
mapper.send(content_mapping.method_from, instance, element)
|
462
500
|
end
|
463
501
|
else
|
464
|
-
|
502
|
+
receiver_attributes = get_receiver_attributes(content_mapping)
|
503
|
+
attribute = receiver_attributes[content_mapping.attribute]
|
465
504
|
|
466
505
|
if attribute
|
467
506
|
skip = false
|
@@ -471,8 +510,13 @@ module Shale
|
|
471
510
|
skip = true if except&.key?(attribute.name)
|
472
511
|
|
473
512
|
unless skip
|
474
|
-
value = attribute.type.of_xml(element)
|
475
|
-
|
513
|
+
value = attribute.type.cast(attribute.type.of_xml(element))
|
514
|
+
|
515
|
+
if content_mapping.receiver
|
516
|
+
delegates.add(attributes[content_mapping.receiver], attribute.setter, value)
|
517
|
+
else
|
518
|
+
instance.send(attribute.setter, value)
|
519
|
+
end
|
476
520
|
end
|
477
521
|
# rubocop:enable Metrics/BlockNesting
|
478
522
|
end
|
@@ -494,7 +538,8 @@ module Shale
|
|
494
538
|
mapper.send(mapping.method_from, instance, node)
|
495
539
|
end
|
496
540
|
else
|
497
|
-
|
541
|
+
receiver_attributes = get_receiver_attributes(mapping)
|
542
|
+
attribute = receiver_attributes[mapping.attribute]
|
498
543
|
next unless attribute
|
499
544
|
|
500
545
|
if only
|
@@ -514,14 +559,31 @@ module Shale
|
|
514
559
|
context: context
|
515
560
|
)
|
516
561
|
|
562
|
+
casted_value = attribute.type.cast(value)
|
563
|
+
|
517
564
|
if attribute.collection?
|
518
|
-
|
565
|
+
if mapping.receiver
|
566
|
+
delegates.add_collection(
|
567
|
+
attributes[mapping.receiver],
|
568
|
+
attribute.setter,
|
569
|
+
casted_value
|
570
|
+
)
|
571
|
+
else
|
572
|
+
instance.send(attribute.name) << casted_value
|
573
|
+
end
|
574
|
+
elsif mapping.receiver
|
575
|
+
delegates.add(attributes[mapping.receiver], attribute.setter, casted_value)
|
519
576
|
else
|
520
|
-
instance.send(attribute.setter,
|
577
|
+
instance.send(attribute.setter, casted_value)
|
521
578
|
end
|
522
579
|
end
|
523
580
|
end
|
524
581
|
|
582
|
+
delegates.each do |delegate|
|
583
|
+
receiver = get_receiver(instance, delegate.receiver_attribute)
|
584
|
+
receiver.send(delegate.setter, delegate.value)
|
585
|
+
end
|
586
|
+
|
525
587
|
grouping.each do |group|
|
526
588
|
mapper = new
|
527
589
|
|
@@ -626,13 +688,20 @@ module Shale
|
|
626
688
|
mapper.send(mapping.method_to, instance, element, doc)
|
627
689
|
end
|
628
690
|
else
|
629
|
-
|
691
|
+
if mapping.receiver
|
692
|
+
receiver = instance.send(mapping.receiver)
|
693
|
+
else
|
694
|
+
receiver = instance
|
695
|
+
end
|
696
|
+
|
697
|
+
receiver_attributes = get_receiver_attributes(mapping)
|
698
|
+
attribute = receiver_attributes[mapping.attribute]
|
630
699
|
next unless attribute
|
631
700
|
|
632
701
|
next if only && !only.key?(attribute.name)
|
633
702
|
next if except&.key?(attribute.name)
|
634
703
|
|
635
|
-
value =
|
704
|
+
value = receiver.send(attribute.name) if receiver
|
636
705
|
|
637
706
|
if mapping.render_nil? || !value.nil?
|
638
707
|
doc.add_namespace(mapping.namespace.prefix, mapping.namespace.name)
|
@@ -655,7 +724,14 @@ module Shale
|
|
655
724
|
mapper.send(content_mapping.method_to, instance, element, doc)
|
656
725
|
end
|
657
726
|
else
|
658
|
-
|
727
|
+
if content_mapping.receiver
|
728
|
+
receiver = instance.send(content_mapping.receiver)
|
729
|
+
else
|
730
|
+
receiver = instance
|
731
|
+
end
|
732
|
+
|
733
|
+
receiver_attributes = get_receiver_attributes(content_mapping)
|
734
|
+
attribute = receiver_attributes[content_mapping.attribute]
|
659
735
|
|
660
736
|
if attribute
|
661
737
|
skip = false
|
@@ -665,7 +741,7 @@ module Shale
|
|
665
741
|
skip = true if except&.key?(attribute.name)
|
666
742
|
|
667
743
|
unless skip
|
668
|
-
value =
|
744
|
+
value = receiver.send(attribute.name) if receiver
|
669
745
|
|
670
746
|
if content_mapping.cdata
|
671
747
|
doc.create_cdata(value.to_s, element)
|
@@ -690,7 +766,14 @@ module Shale
|
|
690
766
|
mapper.send(mapping.method_to, instance, element, doc)
|
691
767
|
end
|
692
768
|
else
|
693
|
-
|
769
|
+
if mapping.receiver
|
770
|
+
receiver = instance.send(mapping.receiver)
|
771
|
+
else
|
772
|
+
receiver = instance
|
773
|
+
end
|
774
|
+
|
775
|
+
receiver_attributes = get_receiver_attributes(mapping)
|
776
|
+
attribute = receiver_attributes[mapping.attribute]
|
694
777
|
next unless attribute
|
695
778
|
|
696
779
|
if only
|
@@ -703,7 +786,7 @@ module Shale
|
|
703
786
|
next if except.key?(attribute.name) && attribute_except.nil?
|
704
787
|
end
|
705
788
|
|
706
|
-
value =
|
789
|
+
value = receiver.send(attribute.name) if receiver
|
707
790
|
|
708
791
|
if mapping.render_nil? || !value.nil?
|
709
792
|
doc.add_namespace(mapping.namespace.prefix, mapping.namespace.name)
|
@@ -827,6 +910,64 @@ module Shale
|
|
827
910
|
end
|
828
911
|
end.to_h
|
829
912
|
end
|
913
|
+
|
914
|
+
# Get receiver attributes for given mapping
|
915
|
+
#
|
916
|
+
# @param [Shale::Mapping::Descriptor::Dict] mapping
|
917
|
+
#
|
918
|
+
# @raise [AttributeNotDefinedError]
|
919
|
+
# @raise [NotAShaleMapperError]
|
920
|
+
#
|
921
|
+
# @return [Hash<Symbol, Shale::Attribute>]
|
922
|
+
#
|
923
|
+
# @api private
|
924
|
+
def get_receiver_attributes(mapping)
|
925
|
+
return attributes unless mapping.receiver
|
926
|
+
|
927
|
+
receiver_attribute = attributes[mapping.receiver]
|
928
|
+
|
929
|
+
unless receiver_attribute
|
930
|
+
msg = "attribute '#{mapping.receiver}' is not defined on #{self} mapper"
|
931
|
+
raise AttributeNotDefinedError, msg
|
932
|
+
end
|
933
|
+
|
934
|
+
unless receiver_attribute.type < Mapper
|
935
|
+
msg = "attribute '#{mapping.receiver}' is not a descendant of Shale::Mapper type"
|
936
|
+
raise NotAShaleMapperError, msg
|
937
|
+
end
|
938
|
+
|
939
|
+
if receiver_attribute.collection?
|
940
|
+
msg = "attribute '#{mapping.receiver}' can't be a collection"
|
941
|
+
raise NotAShaleMapperError, msg
|
942
|
+
end
|
943
|
+
|
944
|
+
receiver_attribute.type.attributes
|
945
|
+
end
|
946
|
+
|
947
|
+
# Get receiver for given mapping
|
948
|
+
#
|
949
|
+
# @param [any] instance
|
950
|
+
# @param [Shale::Attribute] receiver_attribute
|
951
|
+
#
|
952
|
+
# @return [Array]
|
953
|
+
#
|
954
|
+
# @api private
|
955
|
+
def get_receiver(instance, receiver_attribute)
|
956
|
+
receiver = instance.send(receiver_attribute.name)
|
957
|
+
|
958
|
+
unless receiver
|
959
|
+
receiver = receiver_attribute.type.model.new
|
960
|
+
|
961
|
+
receiver_attribute.type.attributes
|
962
|
+
.values
|
963
|
+
.select { |attr| attr.default }
|
964
|
+
.each { |attr| receiver.send(attr.setter, attr.default.call) }
|
965
|
+
|
966
|
+
instance.send(receiver_attribute.setter, receiver)
|
967
|
+
end
|
968
|
+
|
969
|
+
receiver
|
970
|
+
end
|
830
971
|
end
|
831
972
|
|
832
973
|
# Convert Object to Hash
|
data/lib/shale/utils.rb
CHANGED
@@ -5,6 +5,21 @@ module Shale
|
|
5
5
|
#
|
6
6
|
# @api private
|
7
7
|
module Utils
|
8
|
+
# Upcase first letter of a string
|
9
|
+
#
|
10
|
+
# @param [String] val
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# Shale::Utils.upcase_first('fooBar')
|
14
|
+
# # => 'FooBar'
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def self.upcase_first(str)
|
18
|
+
return '' unless str
|
19
|
+
return '' if str.empty?
|
20
|
+
str[0].upcase + str[1..-1]
|
21
|
+
end
|
22
|
+
|
8
23
|
# Convert string to Ruby's class naming convention
|
9
24
|
#
|
10
25
|
# @param [String] val
|
@@ -15,13 +30,14 @@ module Shale
|
|
15
30
|
#
|
16
31
|
# @api private
|
17
32
|
def self.classify(str)
|
18
|
-
|
33
|
+
# names may include a period, which will need to be stripped out
|
34
|
+
str = str.to_s.gsub(/\./, '')
|
19
35
|
|
20
|
-
str = str.sub(/^[a-z\d]*/) { |match| match
|
36
|
+
str = str.sub(/^[a-z\d]*/) { |match| upcase_first(match) || match }
|
21
37
|
|
22
|
-
str.gsub(%r{(?:_|-|(/))([a-z\d]*)}i) do
|
38
|
+
str.gsub('::', '/').gsub(%r{(?:_|-|(/))([a-z\d]*)}i) do
|
23
39
|
word = Regexp.last_match(2)
|
24
|
-
substituted = word
|
40
|
+
substituted = upcase_first(word) || word
|
25
41
|
Regexp.last_match(1) ? "::#{substituted}" : substituted
|
26
42
|
end
|
27
43
|
end
|
@@ -36,6 +52,8 @@ module Shale
|
|
36
52
|
#
|
37
53
|
# @api private
|
38
54
|
def self.snake_case(str)
|
55
|
+
# XML elements allow periods and hyphens
|
56
|
+
str = str.to_s.gsub('.', '_')
|
39
57
|
return str.to_s unless /[A-Z-]|::/.match?(str)
|
40
58
|
word = str.to_s.gsub('::', '/')
|
41
59
|
word = word.gsub(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) do
|
data/lib/shale/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shale
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kamil Giszczak
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Ruby object mapper and serializer for XML, JSON, TOML, CSV and YAML.
|
14
14
|
email:
|
@@ -38,6 +38,7 @@ files:
|
|
38
38
|
- lib/shale/attribute.rb
|
39
39
|
- lib/shale/error.rb
|
40
40
|
- lib/shale/mapper.rb
|
41
|
+
- lib/shale/mapping/delegates.rb
|
41
42
|
- lib/shale/mapping/descriptor/dict.rb
|
42
43
|
- lib/shale/mapping/descriptor/xml.rb
|
43
44
|
- lib/shale/mapping/descriptor/xml_namespace.rb
|
@@ -124,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
125
|
- !ruby/object:Gem::Version
|
125
126
|
version: '0'
|
126
127
|
requirements: []
|
127
|
-
rubygems_version: 3.
|
128
|
+
rubygems_version: 3.4.10
|
128
129
|
signing_key:
|
129
130
|
specification_version: 4
|
130
131
|
summary: Ruby object mapper and serializer for XML, JSON, TOML, CSV and YAML.
|