shale 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- class <%= type.name %> < Shale::Mapper
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.name = format("#{type.name}%d", duplicates[type.name])
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(id, name, prefix, namespace)
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(schemas, root_name: root_name)
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
@@ -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
- attribute = attributes[mapping.attribute]
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
- instance.send(attribute.setter, nil)
88
+ casted_value = nil
84
89
  elsif attribute.collection?
85
- [*value].each do |val|
86
- if val
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
- instance.send(attribute.name) << attribute.type.cast(val)
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
- instance.send(attribute.setter, attribute.type.cast(val))
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
- attribute = attributes[mapping.attribute]
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 = instance.send(attribute.name)
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
- attribute = attributes[mapping.attribute]
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
- instance.send(attribute.name) << attribute.type.cast(value)
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, attribute.type.cast(value))
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
- attribute = attributes[content_mapping.attribute]
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
- instance.send(attribute.setter, attribute.type.cast(value))
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
- attribute = attributes[mapping.attribute]
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
- instance.send(attribute.name) << attribute.type.cast(value)
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, attribute.type.cast(value))
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
- attribute = attributes[mapping.attribute]
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 = instance.send(attribute.name)
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
- attribute = attributes[content_mapping.attribute]
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 = instance.send(attribute.name)
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
- attribute = attributes[mapping.attribute]
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 = instance.send(attribute.name)
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
- str = str.to_s.sub(/.*\./, '')
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.capitalize || 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.capitalize || 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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Shale
4
4
  # @api private
5
- VERSION = '0.9.0'
5
+ VERSION = '1.0.0'
6
6
  end
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.9.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: 2022-10-31 00:00:00.000000000 Z
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.3.7
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.