shale 0.5.0 → 0.6.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 +11 -0
- data/README.md +208 -28
- data/lib/shale/adapter/nokogiri/document.rb +10 -0
- data/lib/shale/adapter/nokogiri/node.rb +1 -1
- data/lib/shale/adapter/ox/document.rb +10 -0
- data/lib/shale/adapter/ox/node.rb +10 -1
- data/lib/shale/adapter/rexml/document.rb +10 -0
- data/lib/shale/adapter/toml_rb.rb +34 -0
- data/lib/shale/error.rb +19 -2
- data/lib/shale/mapper.rb +59 -7
- data/lib/shale/mapping/descriptor/xml.rb +10 -1
- data/lib/shale/mapping/dict.rb +18 -0
- data/lib/shale/mapping/xml.rb +40 -5
- data/lib/shale/schema/xml_compiler.rb +1 -1
- data/lib/shale/type/complex.rb +128 -35
- data/lib/shale/type/value.rb +31 -2
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +14 -0
- data/shale.gemspec +2 -2
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 243b99a073ac189f66ae0fbfedd94a5715399de731d0e0fd1d970dad749d27a0
|
4
|
+
data.tar.gz: d2f57de2427574d710d6a6fe9ba35868fd162214ce8aa2092ddfb3fe1f5e7c3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9de1be5eccbb647f05b6573d783491f858fb56614f09c7c625e7fa922c7b89b5d38863a57defbe506d42f0b542b326e4ca61ecf308b94f7b35b4056751e0299e
|
7
|
+
data.tar.gz: a1e29fc097c130c55e45837af198e3cd4f7d3ad6a94b17d032eb31b8065f7ea013682836256d12127480965ed3733079e5badd7a8b0060e3bc60f00734fcc215
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## [0.6.0] - 2022-07-05
|
2
|
+
|
3
|
+
### Added
|
4
|
+
- Support for TOML
|
5
|
+
- Support for CDATA nodes in XML documents
|
6
|
+
- Support for using custom models
|
7
|
+
|
8
|
+
### Fixed
|
9
|
+
- Allow to map XML content using methods
|
10
|
+
- Prevent adding default mapping after mapping block was declared
|
11
|
+
|
1
12
|
## [0.5.0] - 2022-06-28
|
2
13
|
|
3
14
|
### Added
|
data/README.md
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# Shale
|
2
2
|
|
3
|
-
Shale is a Ruby object mapper and serializer for JSON, YAML and XML.
|
4
|
-
It allows you to parse JSON, YAML and XML data and convert it into Ruby data structures,
|
5
|
-
as well as serialize data structures into JSON, YAML or XML.
|
3
|
+
Shale is a Ruby object mapper and serializer for JSON, YAML, TOML and XML.
|
4
|
+
It allows you to parse JSON, YAML, TOML and XML data and convert it into Ruby data structures,
|
5
|
+
as well as serialize data structures into JSON, YAML, TOML or XML.
|
6
6
|
|
7
7
|
Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
|
8
8
|
|
9
9
|
## Features
|
10
10
|
|
11
|
-
* Convert JSON, YAML and XML to Ruby data model
|
12
|
-
* Convert Ruby data model to JSON, YAML and XML
|
11
|
+
* Convert JSON, YAML, TOML and XML to Ruby data model
|
12
|
+
* Convert Ruby data model to JSON, YAML, TOML and XML
|
13
13
|
* Generate JSON and XML Schema from Ruby models
|
14
14
|
* Compile JSON and XML Schema into Ruby models
|
15
|
-
* Out of the box support for JSON, YAML, Nokogiri, REXML and Ox parsers
|
15
|
+
* Out of the box support for JSON, YAML, toml-rb, Nokogiri, REXML and Ox parsers
|
16
16
|
* Support for custom adapters
|
17
17
|
|
18
18
|
## Installation
|
@@ -45,17 +45,21 @@ $ gem install shale
|
|
45
45
|
* [Converting object to JSON](#converting-object-to-json)
|
46
46
|
* [Converting YAML to object](#converting-yaml-to-object)
|
47
47
|
* [Converting object to YAML](#converting-object-to-yaml)
|
48
|
+
* [Converting TOML to object](#converting-toml-to-object)
|
49
|
+
* [Converting object to TOML](#converting-object-to-toml)
|
48
50
|
* [Converting Hash to object](#converting-hash-to-object)
|
49
51
|
* [Converting object to Hash](#converting-object-to-hash)
|
50
52
|
* [Converting XML to object](#converting-xml-to-object)
|
51
53
|
* [Converting object to XML](#converting-object-to-xml)
|
52
54
|
* [Mapping JSON keys to object attributes](#mapping-json-keys-to-object-attributes)
|
53
55
|
* [Mapping YAML keys to object attributes](#mapping-yaml-keys-to-object-attributes)
|
56
|
+
* [Mapping TOML keys to object attributes](#mapping-toml-keys-to-object-attributes)
|
54
57
|
* [Mapping Hash keys to object attributes](#mapping-hash-keys-to-object-attributes)
|
55
58
|
* [Mapping XML elements and attributes to object attributes](#mapping-xml-elements-and-attributes-to-object-attributes)
|
56
59
|
* [Using XML namespaces](#using-xml-namespaces)
|
57
60
|
* [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
58
61
|
* [Pretty printing and XML declaration](#pretty-printing-and-xml-declaration)
|
62
|
+
* [Using custom models](#using-custom-models)
|
59
63
|
* [Supported types](#supported-types)
|
60
64
|
* [Writing your own type](#writing-your-own-type)
|
61
65
|
* [Adapters](#adapters)
|
@@ -195,6 +199,62 @@ person.to_yaml
|
|
195
199
|
# zip: E1 6AN
|
196
200
|
```
|
197
201
|
|
202
|
+
### Converting TOML to object
|
203
|
+
|
204
|
+
To use TOML with Shale you have to set adapter you want to use.
|
205
|
+
Shale comes with adapter for [toml-rb](https://github.com/emancu/toml-rb).
|
206
|
+
For details see [Adapters](#adapters) section.
|
207
|
+
|
208
|
+
To set it, first make sure toml-rb gem is installed:
|
209
|
+
|
210
|
+
```
|
211
|
+
$ gem install shale
|
212
|
+
```
|
213
|
+
|
214
|
+
then setup adapter:
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
require 'shale/adapter/toml_rb'
|
218
|
+
Shale.toml_adapter = Shale::Adapter::TomlRB
|
219
|
+
```
|
220
|
+
|
221
|
+
Now you can use TOML with Shale:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
person = Person.from_toml(<<~DATA)
|
225
|
+
first_name = "John"
|
226
|
+
last_name = "Doe"
|
227
|
+
age = 50
|
228
|
+
married = false
|
229
|
+
hobbies = ["Singing", "Dancing"]
|
230
|
+
[address]
|
231
|
+
city = "London"
|
232
|
+
street = "Oxford Street"
|
233
|
+
zip = "E1 6AN"
|
234
|
+
DATA
|
235
|
+
```
|
236
|
+
|
237
|
+
### Converting object to TOML
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
person.to_toml
|
241
|
+
|
242
|
+
# =>
|
243
|
+
#
|
244
|
+
# ---
|
245
|
+
# first_name: John
|
246
|
+
# last_name: Doe
|
247
|
+
# age: 50
|
248
|
+
# married: false
|
249
|
+
# hobbies:
|
250
|
+
# - Singing
|
251
|
+
# - Dancing
|
252
|
+
# address:
|
253
|
+
# city: London
|
254
|
+
# street: Oxford Street
|
255
|
+
# zip: E1 6AN
|
256
|
+
```
|
257
|
+
|
198
258
|
### Converting Hash to object
|
199
259
|
|
200
260
|
```ruby
|
@@ -240,6 +300,8 @@ require 'shale/adapter/rexml'
|
|
240
300
|
Shale.xml_adapter = Shale::Adapter::REXML
|
241
301
|
```
|
242
302
|
|
303
|
+
Now you can use XML with Shale:
|
304
|
+
|
243
305
|
```ruby
|
244
306
|
person = Person.from_xml(<<~DATA)
|
245
307
|
<person>
|
@@ -284,6 +346,8 @@ person.to_xml
|
|
284
346
|
|
285
347
|
By default keys are named the same as attributes. To use custom keys use:
|
286
348
|
|
349
|
+
:warning: **Declaring custom mapping removes default mapping for given format!**
|
350
|
+
|
287
351
|
```ruby
|
288
352
|
class Person < Shale::Mapper
|
289
353
|
attribute :first_name, Shale::Type::String
|
@@ -310,6 +374,20 @@ class Person < Shale::Mapper
|
|
310
374
|
end
|
311
375
|
```
|
312
376
|
|
377
|
+
### Mapping TOML keys to object attributes
|
378
|
+
|
379
|
+
```ruby
|
380
|
+
class Person < Shale::Mapper
|
381
|
+
attribute :first_name, Shale::Type::String
|
382
|
+
attribute :last_name, Shale::Type::String
|
383
|
+
|
384
|
+
toml do
|
385
|
+
map 'firstName', to: :first_name
|
386
|
+
map 'lastName', to: :last_name
|
387
|
+
end
|
388
|
+
end
|
389
|
+
```
|
390
|
+
|
313
391
|
### Mapping Hash keys to object attributes
|
314
392
|
|
315
393
|
```ruby
|
@@ -380,6 +458,37 @@ DATA
|
|
380
458
|
- `map_attribute` - map element's attribute to attribute
|
381
459
|
- `map_content` - map first text node to attribute
|
382
460
|
|
461
|
+
You can use `cdata: true` option on `map_element` and `map_content` to handle CDATA nodes:
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
class Address < Shale::Mapper
|
465
|
+
attribute :content, Shale::Type::String
|
466
|
+
|
467
|
+
xml do
|
468
|
+
map_content to: :content, cdata: true
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
class Person < Shale::Mapper
|
473
|
+
attribute :first_name, Shale::Type::String
|
474
|
+
attribute :address, Address
|
475
|
+
|
476
|
+
xml do
|
477
|
+
root 'Person'
|
478
|
+
|
479
|
+
map_element 'FirstName', to: :first_name, cdata: true
|
480
|
+
map_element 'Address', to: :address
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
person = Person.from_xml(<<~DATA)
|
485
|
+
<Person>
|
486
|
+
<FirstName><![CDATA[John]]></FirstName>
|
487
|
+
<Address><![CDATA[Oxford Street]]></Address>
|
488
|
+
</person>
|
489
|
+
DATA
|
490
|
+
```
|
491
|
+
|
383
492
|
### Using XML namespaces
|
384
493
|
|
385
494
|
To map namespaced elements and attributes use `namespace` and `prefix` properties on
|
@@ -469,42 +578,42 @@ class Person < Shale::Mapper
|
|
469
578
|
map_element 'Address', using: { from: :address_from_xml, to: :address_to_xml }
|
470
579
|
end
|
471
580
|
|
472
|
-
def hobbies_from_json(value)
|
473
|
-
|
581
|
+
def hobbies_from_json(model, value)
|
582
|
+
model.hobbies = value.split(',').map(&:strip)
|
474
583
|
end
|
475
584
|
|
476
|
-
def hobbies_to_json
|
477
|
-
hobbies.join(', ')
|
585
|
+
def hobbies_to_json(model)
|
586
|
+
model.hobbies.join(', ')
|
478
587
|
end
|
479
588
|
|
480
|
-
def address_from_json(value)
|
481
|
-
|
482
|
-
|
589
|
+
def address_from_json(model, value)
|
590
|
+
model.street = value['street']
|
591
|
+
model.city = value['city']
|
483
592
|
end
|
484
593
|
|
485
|
-
def address_to_json
|
486
|
-
{ 'street' => street, 'city' => city }
|
594
|
+
def address_to_json(model)
|
595
|
+
{ 'street' => model.street, 'city' => model.city }
|
487
596
|
end
|
488
597
|
|
489
|
-
def hobbies_from_xml(value)
|
490
|
-
|
598
|
+
def hobbies_from_xml(model, value)
|
599
|
+
model.hobbies = value.split(',').map(&:strip)
|
491
600
|
end
|
492
601
|
|
493
|
-
def hobbies_to_xml(element, doc)
|
494
|
-
doc.add_attribute(element, 'hobbies', hobbies.join(', '))
|
602
|
+
def hobbies_to_xml(model, element, doc)
|
603
|
+
doc.add_attribute(element, 'hobbies', model.hobbies.join(', '))
|
495
604
|
end
|
496
605
|
|
497
|
-
def address_from_xml(node)
|
498
|
-
|
499
|
-
|
606
|
+
def address_from_xml(model, node)
|
607
|
+
model.street = node.children.find { |e| e.name == 'Street' }.text
|
608
|
+
model.city = node.children.find { |e| e.name == 'City' }.text
|
500
609
|
end
|
501
610
|
|
502
|
-
def address_to_xml(parent, doc)
|
611
|
+
def address_to_xml(model, parent, doc)
|
503
612
|
street_element = doc.create_element('Street')
|
504
|
-
doc.add_text(street_element, street.to_s)
|
613
|
+
doc.add_text(street_element, model.street.to_s)
|
505
614
|
|
506
615
|
city_element = doc.create_element('City')
|
507
|
-
doc.add_text(city_element, city.to_s)
|
616
|
+
doc.add_text(city_element, model.city.to_s)
|
508
617
|
|
509
618
|
address_element = doc.create_element('Address')
|
510
619
|
doc.add_element(address_element, street_element)
|
@@ -529,7 +638,7 @@ person = Person.from_xml(<<~DATA)
|
|
529
638
|
<Street>Oxford Street</Street>
|
530
639
|
<City>London</City>
|
531
640
|
</Address>
|
532
|
-
</
|
641
|
+
</Person>
|
533
642
|
DATA
|
534
643
|
|
535
644
|
# =>
|
@@ -570,6 +679,67 @@ person.to_xml(:pretty, :declaration)
|
|
570
679
|
# </Person>
|
571
680
|
```
|
572
681
|
|
682
|
+
### Using custom models
|
683
|
+
|
684
|
+
By default Shale combines mapper and model into one class. If you want to use your own classes
|
685
|
+
as models you can do it by using `model` directive on the mapper:
|
686
|
+
|
687
|
+
```ruby
|
688
|
+
class Address
|
689
|
+
attr_accessor :street, :city
|
690
|
+
end
|
691
|
+
|
692
|
+
class Person
|
693
|
+
attr_accessor :first_name, :last_name, :address
|
694
|
+
end
|
695
|
+
|
696
|
+
class AddressMapper < Shale::Mapper
|
697
|
+
model Address
|
698
|
+
|
699
|
+
attribute :street, Shale::Type::String
|
700
|
+
attribute :city, Shale::Type::String
|
701
|
+
end
|
702
|
+
|
703
|
+
class PersonMapper < Shale::Mapper
|
704
|
+
model Person
|
705
|
+
|
706
|
+
attribute :first_name, Shale::Type::String
|
707
|
+
attribute :last_name, Shale::Type::String
|
708
|
+
attribute :address, AddressMapper
|
709
|
+
end
|
710
|
+
|
711
|
+
person = PersonMapper.from_json(<<~DATA)
|
712
|
+
{
|
713
|
+
"first_name": "John",
|
714
|
+
"last_name": "Doe",
|
715
|
+
"address": {
|
716
|
+
"street": "Oxford Street",
|
717
|
+
"city": "London"
|
718
|
+
}
|
719
|
+
}
|
720
|
+
DATA
|
721
|
+
|
722
|
+
# =>
|
723
|
+
#
|
724
|
+
# #<Person:0x0000000113d7a488
|
725
|
+
# @first_name="John",
|
726
|
+
# @last_name="Doe",
|
727
|
+
# @address=#<Address:0x0000000113d7a140 @street="Oxford Street", @city="London">>
|
728
|
+
|
729
|
+
PersonMapper.to_json(person, :pretty)
|
730
|
+
|
731
|
+
# =>
|
732
|
+
#
|
733
|
+
# {
|
734
|
+
# "first_name": "John",
|
735
|
+
# "last_name": "Doe",
|
736
|
+
# "address": {
|
737
|
+
# "street": "Oxford Street",
|
738
|
+
# "city": "London"
|
739
|
+
# }
|
740
|
+
# }
|
741
|
+
```
|
742
|
+
|
573
743
|
### Supported types
|
574
744
|
|
575
745
|
Shale supports these types out of the box:
|
@@ -598,9 +768,9 @@ end
|
|
598
768
|
### Adapters
|
599
769
|
|
600
770
|
Shale uses adapters for parsing and generating documents.
|
601
|
-
By default Ruby's standard JSON
|
771
|
+
By default Ruby's standard JSON, YAML parsers are used for handling JSON and YAML documents.
|
602
772
|
|
603
|
-
You can change it by providing your own adapter. For JSON and
|
773
|
+
You can change it by providing your own adapter. For JSON, YAML and TOML, adapter must implement
|
604
774
|
`.load` and `.dump` class methods.
|
605
775
|
|
606
776
|
```ruby
|
@@ -611,6 +781,16 @@ Shale.json_adapter = MultiJson
|
|
611
781
|
Shale.yaml_adapter = MyYamlAdapter
|
612
782
|
```
|
613
783
|
|
784
|
+
To handle TOML documents you have to set TOML adapter.
|
785
|
+
Shale provides adapter for `toml-rb` TOML parser:
|
786
|
+
|
787
|
+
```ruby
|
788
|
+
require 'shale'
|
789
|
+
|
790
|
+
require 'shale/adapter/toml_rb'
|
791
|
+
Shale.toml_adapter = Shale::Adapter::TomlRB
|
792
|
+
```
|
793
|
+
|
614
794
|
To handle XML documents you have to explicitly set XML adapter.
|
615
795
|
Shale provides adapters for most popular Ruby XML parsers:
|
616
796
|
|
@@ -41,6 +41,16 @@ module Shale
|
|
41
41
|
::Nokogiri::XML::Element.new(name, @doc)
|
42
42
|
end
|
43
43
|
|
44
|
+
# Create CDATA node and add it to parent
|
45
|
+
#
|
46
|
+
# @param [String] text
|
47
|
+
# @param [::Nokogiri::XML::Element] parent
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
def create_cdata(text, parent)
|
51
|
+
parent.add_child(::Nokogiri::XML::CDATA.new(@doc, text))
|
52
|
+
end
|
53
|
+
|
44
54
|
# Add XML namespace to document
|
45
55
|
#
|
46
56
|
# @param [String] prefix
|
@@ -32,6 +32,16 @@ module Shale
|
|
32
32
|
::Ox::Element.new(name)
|
33
33
|
end
|
34
34
|
|
35
|
+
# Create CDATA node and add it to parent
|
36
|
+
#
|
37
|
+
# @param [String] text
|
38
|
+
# @param [::Ox::Element] parent
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
def create_cdata(text, parent)
|
42
|
+
parent << ::Ox::CData.new(text)
|
43
|
+
end
|
44
|
+
|
35
45
|
# Add XML namespace to document
|
36
46
|
#
|
37
47
|
# Ox doesn't support XML namespaces so this method does nothing.
|
@@ -42,6 +42,16 @@ module Shale
|
|
42
42
|
::REXML::Element.new(name, nil, attribute_quote: :quote)
|
43
43
|
end
|
44
44
|
|
45
|
+
# Create CDATA node and add it to parent
|
46
|
+
#
|
47
|
+
# @param [String] text
|
48
|
+
# @param [::REXML::Element] parent
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
def create_cdata(text, parent)
|
52
|
+
::REXML::CData.new(text, true, parent)
|
53
|
+
end
|
54
|
+
|
45
55
|
# Add XML namespace to document
|
46
56
|
#
|
47
57
|
# @param [String] prefix
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'toml-rb'
|
4
|
+
|
5
|
+
module Shale
|
6
|
+
module Adapter
|
7
|
+
# TOML adapter
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
class TomlRB
|
11
|
+
# Parse TOML into Hash
|
12
|
+
#
|
13
|
+
# @param [String] toml TOML document
|
14
|
+
#
|
15
|
+
# @return [Hash]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
def self.load(toml)
|
19
|
+
::TomlRB.parse(toml)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Serialize Hash into TOML
|
23
|
+
#
|
24
|
+
# @param [Hash] obj Hash object
|
25
|
+
#
|
26
|
+
# @return [String]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
def self.dump(obj)
|
30
|
+
::TomlRB.dump(obj)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/shale/error.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Shale
|
4
|
-
# Error message displayed when adapter is not set
|
4
|
+
# Error message displayed when TOML adapter is not set
|
5
5
|
# @api private
|
6
|
-
|
6
|
+
TOML_ADAPTER_NOT_SET_MESSAGE = <<~MSG
|
7
|
+
TOML Adapter is not set.
|
8
|
+
To use Shale with TOML documents you have to install parser and set adapter.
|
9
|
+
|
10
|
+
# Make sure toml-rb is installed eg. execute: gem install toml-rb
|
11
|
+
require 'shale/adapter/toml_rb'
|
12
|
+
Shale.toml_adapter = Shale::Adapter::TomlRB
|
13
|
+
MSG
|
14
|
+
|
15
|
+
# Error message displayed when XML adapter is not set
|
16
|
+
# @api private
|
17
|
+
XML_ADAPTER_NOT_SET_MESSAGE = <<~MSG
|
7
18
|
XML Adapter is not set.
|
8
19
|
To use Shale with XML documents you have to install parser and set adapter.
|
9
20
|
|
@@ -52,6 +63,12 @@ module Shale
|
|
52
63
|
end
|
53
64
|
end
|
54
65
|
|
66
|
+
# Error for passing incorrect model type
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
class IncorrectModelError < StandardError
|
70
|
+
end
|
71
|
+
|
55
72
|
# Error for passing incorrect arguments to map functions
|
56
73
|
#
|
57
74
|
# @api private
|
data/lib/shale/mapper.rb
CHANGED
@@ -43,10 +43,12 @@ module Shale
|
|
43
43
|
#
|
44
44
|
# @api public
|
45
45
|
class Mapper < Type::Complex
|
46
|
+
@model = nil
|
46
47
|
@attributes = {}
|
47
48
|
@hash_mapping = Mapping::Dict.new
|
48
49
|
@json_mapping = Mapping::Dict.new
|
49
50
|
@yaml_mapping = Mapping::Dict.new
|
51
|
+
@toml_mapping = Mapping::Dict.new
|
50
52
|
@xml_mapping = Mapping::Xml.new
|
51
53
|
|
52
54
|
class << self
|
@@ -78,6 +80,13 @@ module Shale
|
|
78
80
|
# @api public
|
79
81
|
attr_reader :yaml_mapping
|
80
82
|
|
83
|
+
# Return TOML mapping object
|
84
|
+
#
|
85
|
+
# @return [Shale::Mapping::Dict]
|
86
|
+
#
|
87
|
+
# @api public
|
88
|
+
attr_reader :toml_mapping
|
89
|
+
|
81
90
|
# Return XML mapping object
|
82
91
|
#
|
83
92
|
# @return [Shale::Mapping::XML]
|
@@ -88,16 +97,20 @@ module Shale
|
|
88
97
|
# @api private
|
89
98
|
def inherited(subclass)
|
90
99
|
super
|
100
|
+
|
101
|
+
subclass.instance_variable_set('@model', subclass)
|
91
102
|
subclass.instance_variable_set('@attributes', @attributes.dup)
|
92
103
|
|
93
104
|
subclass.instance_variable_set('@__hash_mapping_init', @hash_mapping.dup)
|
94
105
|
subclass.instance_variable_set('@__json_mapping_init', @json_mapping.dup)
|
95
106
|
subclass.instance_variable_set('@__yaml_mapping_init', @yaml_mapping.dup)
|
107
|
+
subclass.instance_variable_set('@__toml_mapping_init', @toml_mapping.dup)
|
96
108
|
subclass.instance_variable_set('@__xml_mapping_init', @xml_mapping.dup)
|
97
109
|
|
98
110
|
subclass.instance_variable_set('@hash_mapping', @hash_mapping.dup)
|
99
111
|
subclass.instance_variable_set('@json_mapping', @json_mapping.dup)
|
100
112
|
subclass.instance_variable_set('@yaml_mapping', @yaml_mapping.dup)
|
113
|
+
subclass.instance_variable_set('@toml_mapping', @toml_mapping.dup)
|
101
114
|
|
102
115
|
xml_mapping = @xml_mapping.dup
|
103
116
|
xml_mapping.root(Utils.underscore(subclass.name || ''))
|
@@ -105,6 +118,15 @@ module Shale
|
|
105
118
|
subclass.instance_variable_set('@xml_mapping', xml_mapping.dup)
|
106
119
|
end
|
107
120
|
|
121
|
+
def model(klass = nil)
|
122
|
+
if klass
|
123
|
+
@model = klass
|
124
|
+
xml_mapping.root(Utils.underscore(@model.name))
|
125
|
+
else
|
126
|
+
@model
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
108
130
|
# Define attribute on class
|
109
131
|
#
|
110
132
|
# @param [Symbol] name Name of the attribute
|
@@ -143,10 +165,11 @@ module Shale
|
|
143
165
|
|
144
166
|
@attributes[name] = Attribute.new(name, type, collection, default)
|
145
167
|
|
146
|
-
@hash_mapping.map(name.to_s, to: name)
|
147
|
-
@json_mapping.map(name.to_s, to: name)
|
148
|
-
@yaml_mapping.map(name.to_s, to: name)
|
149
|
-
@
|
168
|
+
@hash_mapping.map(name.to_s, to: name) unless @hash_mapping.finalized?
|
169
|
+
@json_mapping.map(name.to_s, to: name) unless @json_mapping.finalized?
|
170
|
+
@yaml_mapping.map(name.to_s, to: name) unless @yaml_mapping.finalized?
|
171
|
+
@toml_mapping.map(name.to_s, to: name) unless @toml_mapping.finalized?
|
172
|
+
@xml_mapping.map_element(name.to_s, to: name) unless @xml_mapping.finalized?
|
150
173
|
|
151
174
|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
152
175
|
attr_reader :#{name}
|
@@ -168,7 +191,7 @@ module Shale
|
|
168
191
|
# attribute :age, Shale::Type::Integer
|
169
192
|
#
|
170
193
|
# hsh do
|
171
|
-
# map '
|
194
|
+
# map 'firstName', to: :first_name
|
172
195
|
# map 'lastName', to: :last_name
|
173
196
|
# map 'age', to: :age
|
174
197
|
# end
|
@@ -177,6 +200,7 @@ module Shale
|
|
177
200
|
# @api public
|
178
201
|
def hsh(&block)
|
179
202
|
@hash_mapping = @__hash_mapping_init.dup
|
203
|
+
@hash_mapping.finalize!
|
180
204
|
@hash_mapping.instance_eval(&block)
|
181
205
|
end
|
182
206
|
|
@@ -191,7 +215,7 @@ module Shale
|
|
191
215
|
# attribute :age, Shale::Type::Integer
|
192
216
|
#
|
193
217
|
# json do
|
194
|
-
# map '
|
218
|
+
# map 'firstName', to: :first_name
|
195
219
|
# map 'lastName', to: :last_name
|
196
220
|
# map 'age', to: :age
|
197
221
|
# end
|
@@ -200,6 +224,7 @@ module Shale
|
|
200
224
|
# @api public
|
201
225
|
def json(&block)
|
202
226
|
@json_mapping = @__json_mapping_init.dup
|
227
|
+
@json_mapping.finalize!
|
203
228
|
@json_mapping.instance_eval(&block)
|
204
229
|
end
|
205
230
|
|
@@ -214,7 +239,7 @@ module Shale
|
|
214
239
|
# attribute :age, Shale::Type::Integer
|
215
240
|
#
|
216
241
|
# yaml do
|
217
|
-
# map '
|
242
|
+
# map 'first_name', to: :first_name
|
218
243
|
# map 'last_name', to: :last_name
|
219
244
|
# map 'age', to: :age
|
220
245
|
# end
|
@@ -223,9 +248,34 @@ module Shale
|
|
223
248
|
# @api public
|
224
249
|
def yaml(&block)
|
225
250
|
@yaml_mapping = @__yaml_mapping_init.dup
|
251
|
+
@yaml_mapping.finalize!
|
226
252
|
@yaml_mapping.instance_eval(&block)
|
227
253
|
end
|
228
254
|
|
255
|
+
# Define TOML mapping
|
256
|
+
#
|
257
|
+
# @param [Proc] block
|
258
|
+
#
|
259
|
+
# @example
|
260
|
+
# calss Person < Shale::Mapper
|
261
|
+
# attribute :first_name, Shale::Type::String
|
262
|
+
# attribute :last_name, Shale::Type::String
|
263
|
+
# attribute :age, Shale::Type::Integer
|
264
|
+
#
|
265
|
+
# toml do
|
266
|
+
# map 'first_name', to: :first_name
|
267
|
+
# map 'last_name', to: :last_name
|
268
|
+
# map 'age', to: :age
|
269
|
+
# end
|
270
|
+
# end
|
271
|
+
#
|
272
|
+
# @api public
|
273
|
+
def toml(&block)
|
274
|
+
@toml_mapping = @__toml_mapping_init.dup
|
275
|
+
@toml_mapping.finalize!
|
276
|
+
@toml_mapping.instance_eval(&block)
|
277
|
+
end
|
278
|
+
|
229
279
|
# Define XML mapping
|
230
280
|
#
|
231
281
|
# @param [Proc] block
|
@@ -247,6 +297,8 @@ module Shale
|
|
247
297
|
# @api public
|
248
298
|
def xml(&block)
|
249
299
|
@xml_mapping = @__xml_mapping_init.dup
|
300
|
+
@xml_mapping.finalize!
|
301
|
+
@xml_mapping.root('')
|
250
302
|
@xml_mapping.instance_eval(&block)
|
251
303
|
end
|
252
304
|
end
|
@@ -16,17 +16,26 @@ module Shale
|
|
16
16
|
# @api private
|
17
17
|
attr_reader :namespace
|
18
18
|
|
19
|
+
# Return cdata
|
20
|
+
#
|
21
|
+
# @return [true, false]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
attr_reader :cdata
|
25
|
+
|
19
26
|
# Initialize instance
|
20
27
|
#
|
21
28
|
# @param [String] name
|
22
29
|
# @param [Symbol, String] attribute
|
23
30
|
# @param [Hash, nil] methods
|
24
31
|
# @param [Shale::Mapping::XmlNamespace] namespace
|
32
|
+
# @param [true, false] cdata
|
25
33
|
#
|
26
34
|
# @api private
|
27
|
-
def initialize(name:, attribute:, methods:, namespace:)
|
35
|
+
def initialize(name:, attribute:, methods:, namespace:, cdata:)
|
28
36
|
super(name: name, attribute: attribute, methods: methods)
|
29
37
|
@namespace = namespace
|
38
|
+
@cdata = cdata
|
30
39
|
end
|
31
40
|
|
32
41
|
# Return name with XML prefix
|
data/lib/shale/mapping/dict.rb
CHANGED
@@ -22,6 +22,7 @@ module Shale
|
|
22
22
|
def initialize
|
23
23
|
super
|
24
24
|
@keys = {}
|
25
|
+
@finalized = false
|
25
26
|
end
|
26
27
|
|
27
28
|
# Map key to attribute
|
@@ -38,9 +39,26 @@ module Shale
|
|
38
39
|
@keys[key] = Descriptor::Dict.new(name: key, attribute: to, methods: using)
|
39
40
|
end
|
40
41
|
|
42
|
+
# Set the "finalized" instance variable to true
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
def finalize!
|
46
|
+
@finalized = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# Query the "finalized" instance variable
|
50
|
+
#
|
51
|
+
# @return [truem false]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
def finalized?
|
55
|
+
@finalized
|
56
|
+
end
|
57
|
+
|
41
58
|
# @api private
|
42
59
|
def initialize_dup(other)
|
43
60
|
@keys = other.instance_variable_get('@keys').dup
|
61
|
+
@finalized = false
|
44
62
|
super
|
45
63
|
end
|
46
64
|
end
|
data/lib/shale/mapping/xml.rb
CHANGED
@@ -63,6 +63,7 @@ module Shale
|
|
63
63
|
@content = nil
|
64
64
|
@root = ''
|
65
65
|
@default_namespace = Descriptor::XmlNamespace.new
|
66
|
+
@finalized = false
|
66
67
|
end
|
67
68
|
|
68
69
|
# Map element to attribute
|
@@ -76,7 +77,14 @@ module Shale
|
|
76
77
|
# @raise [IncorrectMappingArgumentsError] when arguments are incorrect
|
77
78
|
#
|
78
79
|
# @api private
|
79
|
-
def map_element(
|
80
|
+
def map_element(
|
81
|
+
element,
|
82
|
+
to: nil,
|
83
|
+
using: nil,
|
84
|
+
namespace: :undefined,
|
85
|
+
prefix: :undefined,
|
86
|
+
cdata: false
|
87
|
+
)
|
80
88
|
Validator.validate_arguments(element, to, using)
|
81
89
|
Validator.validate_namespace(element, namespace, prefix)
|
82
90
|
|
@@ -94,7 +102,8 @@ module Shale
|
|
94
102
|
name: element,
|
95
103
|
attribute: to,
|
96
104
|
methods: using,
|
97
|
-
namespace: Descriptor::XmlNamespace.new(nsp, pfx)
|
105
|
+
namespace: Descriptor::XmlNamespace.new(nsp, pfx),
|
106
|
+
cdata: cdata
|
98
107
|
)
|
99
108
|
end
|
100
109
|
|
@@ -119,7 +128,8 @@ module Shale
|
|
119
128
|
name: attribute,
|
120
129
|
attribute: to,
|
121
130
|
methods: using,
|
122
|
-
namespace: Descriptor::XmlNamespace.new(namespace, prefix)
|
131
|
+
namespace: Descriptor::XmlNamespace.new(namespace, prefix),
|
132
|
+
cdata: false
|
123
133
|
)
|
124
134
|
end
|
125
135
|
|
@@ -128,8 +138,16 @@ module Shale
|
|
128
138
|
# @param [Symbol] to Object's attribute
|
129
139
|
#
|
130
140
|
# @api private
|
131
|
-
def map_content(to:)
|
132
|
-
|
141
|
+
def map_content(to: nil, using: nil, cdata: false)
|
142
|
+
Validator.validate_arguments('content', to, using)
|
143
|
+
|
144
|
+
@content = Descriptor::Xml.new(
|
145
|
+
name: nil,
|
146
|
+
attribute: to,
|
147
|
+
methods: using,
|
148
|
+
namespace: nil,
|
149
|
+
cdata: cdata
|
150
|
+
)
|
133
151
|
end
|
134
152
|
|
135
153
|
# Set the name for root element
|
@@ -152,6 +170,22 @@ module Shale
|
|
152
170
|
@default_namespace.prefix = prefix
|
153
171
|
end
|
154
172
|
|
173
|
+
# Set the "finalized" instance variable to true
|
174
|
+
#
|
175
|
+
# @api private
|
176
|
+
def finalize!
|
177
|
+
@finalized = true
|
178
|
+
end
|
179
|
+
|
180
|
+
# Query the "finalized" instance variable
|
181
|
+
#
|
182
|
+
# @return [truem false]
|
183
|
+
#
|
184
|
+
# @api private
|
185
|
+
def finalized?
|
186
|
+
@finalized
|
187
|
+
end
|
188
|
+
|
155
189
|
# @api private
|
156
190
|
def initialize_dup(other)
|
157
191
|
@elements = other.instance_variable_get('@elements').dup
|
@@ -159,6 +193,7 @@ module Shale
|
|
159
193
|
@content = other.instance_variable_get('@content').dup
|
160
194
|
@root = other.instance_variable_get('@root').dup
|
161
195
|
@default_namespace = other.instance_variable_get('@default_namespace').dup
|
196
|
+
@finalized = false
|
162
197
|
|
163
198
|
super
|
164
199
|
end
|
@@ -200,7 +200,7 @@ module Shale
|
|
200
200
|
# @api public
|
201
201
|
def as_models(schemas)
|
202
202
|
unless Shale.xml_adapter
|
203
|
-
raise AdapterError,
|
203
|
+
raise AdapterError, XML_ADAPTER_NOT_SET_MESSAGE
|
204
204
|
end
|
205
205
|
|
206
206
|
if Shale.xml_adapter.name == 'Shale::Adapter::Ox'
|
data/lib/shale/type/complex.rb
CHANGED
@@ -11,9 +11,9 @@ module Shale
|
|
11
11
|
# @api private
|
12
12
|
class Complex < Value
|
13
13
|
class << self
|
14
|
-
%i[hash json yaml].each do |format|
|
14
|
+
%i[hash json yaml toml].each do |format|
|
15
15
|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
16
|
-
# Convert Hash to Object using Hash/JSON/YAML mapping
|
16
|
+
# Convert Hash to Object using Hash/JSON/YAML/TOML mapping
|
17
17
|
#
|
18
18
|
# @param [Hash] hash Hash to convert
|
19
19
|
#
|
@@ -21,7 +21,12 @@ module Shale
|
|
21
21
|
#
|
22
22
|
# @api public
|
23
23
|
def of_#{format}(hash)
|
24
|
-
instance = new
|
24
|
+
instance = model.new
|
25
|
+
|
26
|
+
attributes
|
27
|
+
.values
|
28
|
+
.select { |attr| attr.default }
|
29
|
+
.each { |attr| instance.send(attr.setter, attr.default.call) }
|
25
30
|
|
26
31
|
mapping_keys = #{format}_mapping.keys
|
27
32
|
|
@@ -30,7 +35,7 @@ module Shale
|
|
30
35
|
next unless mapping
|
31
36
|
|
32
37
|
if mapping.method_from
|
33
|
-
|
38
|
+
new.send(mapping.method_from, instance, value)
|
34
39
|
else
|
35
40
|
attribute = attributes[mapping.attribute]
|
36
41
|
next unless attribute
|
@@ -44,7 +49,7 @@ module Shale
|
|
44
49
|
end
|
45
50
|
else
|
46
51
|
val = attribute.type.of_#{format}(value)
|
47
|
-
instance.send(attribute.setter, val)
|
52
|
+
instance.send(attribute.setter, attribute.type.cast(val))
|
48
53
|
end
|
49
54
|
end
|
50
55
|
end
|
@@ -52,21 +57,28 @@ module Shale
|
|
52
57
|
instance
|
53
58
|
end
|
54
59
|
|
55
|
-
# Convert Object to Hash using Hash/JSON/YAML mapping
|
60
|
+
# Convert Object to Hash using Hash/JSON/YAML/TOML mapping
|
61
|
+
#
|
62
|
+
# @param [any] instance Object to convert
|
56
63
|
#
|
57
|
-
# @
|
64
|
+
# @raise [IncorrectModelError]
|
58
65
|
#
|
59
66
|
# @return [Hash]
|
60
67
|
#
|
61
68
|
# @api public
|
62
69
|
def as_#{format}(instance)
|
70
|
+
unless instance.is_a?(model)
|
71
|
+
msg = "argument is a '\#{instance.class}' but should be a '\#{model}'"
|
72
|
+
raise IncorrectModelError, msg
|
73
|
+
end
|
74
|
+
|
63
75
|
hash = {}
|
64
76
|
|
65
|
-
|
77
|
+
#{format}_mapping.keys.each_value do |mapping|
|
66
78
|
if mapping.method_to
|
67
|
-
hash[mapping.name] =
|
79
|
+
hash[mapping.name] = new.send(mapping.method_to, instance)
|
68
80
|
else
|
69
|
-
attribute =
|
81
|
+
attribute = attributes[mapping.attribute]
|
70
82
|
next unless attribute
|
71
83
|
|
72
84
|
value = instance.send(attribute.name)
|
@@ -137,6 +149,30 @@ module Shale
|
|
137
149
|
Shale.yaml_adapter.dump(as_yaml(instance))
|
138
150
|
end
|
139
151
|
|
152
|
+
# Convert TOML to Object
|
153
|
+
#
|
154
|
+
# @param [String] toml TOML to convert
|
155
|
+
#
|
156
|
+
# @return [Shale::Mapper]
|
157
|
+
#
|
158
|
+
# @api public
|
159
|
+
def from_toml(toml)
|
160
|
+
validate_toml_adapter
|
161
|
+
of_toml(Shale.toml_adapter.load(toml))
|
162
|
+
end
|
163
|
+
|
164
|
+
# Convert Object to TOML
|
165
|
+
#
|
166
|
+
# @param [Shale::Mapper] instance Object to convert
|
167
|
+
#
|
168
|
+
# @return [String]
|
169
|
+
#
|
170
|
+
# @api public
|
171
|
+
def to_toml(instance)
|
172
|
+
validate_toml_adapter
|
173
|
+
Shale.toml_adapter.dump(as_toml(instance))
|
174
|
+
end
|
175
|
+
|
140
176
|
# Convert XML document to Object
|
141
177
|
#
|
142
178
|
# @param [Shale::Adapter::<XML adapter>::Node] xml XML to convert
|
@@ -145,14 +181,19 @@ module Shale
|
|
145
181
|
#
|
146
182
|
# @api public
|
147
183
|
def of_xml(element)
|
148
|
-
instance = new
|
184
|
+
instance = model.new
|
185
|
+
|
186
|
+
attributes
|
187
|
+
.values
|
188
|
+
.select { |attr| attr.default }
|
189
|
+
.each { |attr| instance.send(attr.setter, attr.default.call) }
|
149
190
|
|
150
191
|
element.attributes.each do |key, value|
|
151
192
|
mapping = xml_mapping.attributes[key.to_s]
|
152
193
|
next unless mapping
|
153
194
|
|
154
195
|
if mapping.method_from
|
155
|
-
|
196
|
+
new.send(mapping.method_from, instance, value)
|
156
197
|
else
|
157
198
|
attribute = attributes[mapping.attribute]
|
158
199
|
next unless attribute
|
@@ -160,16 +201,23 @@ module Shale
|
|
160
201
|
if attribute.collection?
|
161
202
|
instance.send(attribute.name) << attribute.type.cast(value)
|
162
203
|
else
|
163
|
-
instance.send(attribute.setter, value)
|
204
|
+
instance.send(attribute.setter, attribute.type.cast(value))
|
164
205
|
end
|
165
206
|
end
|
166
207
|
end
|
167
208
|
|
168
|
-
|
169
|
-
|
209
|
+
content_mapping = xml_mapping.content
|
210
|
+
|
211
|
+
if content_mapping
|
212
|
+
if content_mapping.method_from
|
213
|
+
new.send(content_mapping.method_from, instance, element)
|
214
|
+
else
|
215
|
+
attribute = attributes[content_mapping.attribute]
|
170
216
|
|
171
|
-
|
172
|
-
|
217
|
+
if attribute
|
218
|
+
value = attribute.type.of_xml(element)
|
219
|
+
instance.send(attribute.setter, attribute.type.cast(value))
|
220
|
+
end
|
173
221
|
end
|
174
222
|
end
|
175
223
|
|
@@ -178,16 +226,17 @@ module Shale
|
|
178
226
|
next unless mapping
|
179
227
|
|
180
228
|
if mapping.method_from
|
181
|
-
|
229
|
+
new.send(mapping.method_from, instance, node)
|
182
230
|
else
|
183
231
|
attribute = attributes[mapping.attribute]
|
184
232
|
next unless attribute
|
185
233
|
|
234
|
+
value = attribute.type.of_xml(node)
|
235
|
+
|
186
236
|
if attribute.collection?
|
187
|
-
value = attribute.type.of_xml(node)
|
188
237
|
instance.send(attribute.name) << attribute.type.cast(value)
|
189
238
|
else
|
190
|
-
instance.send(attribute.setter, attribute.type.
|
239
|
+
instance.send(attribute.setter, attribute.type.cast(value))
|
191
240
|
end
|
192
241
|
end
|
193
242
|
end
|
@@ -211,14 +260,21 @@ module Shale
|
|
211
260
|
|
212
261
|
# Convert Object to XML document
|
213
262
|
#
|
214
|
-
# @param [
|
263
|
+
# @param [any] instance Object to convert
|
215
264
|
# @param [String, nil] node_name XML node name
|
216
265
|
# @param [Shale::Adapter::<xml adapter>::Document, nil] doc Object to convert
|
217
266
|
#
|
267
|
+
# @raise [IncorrectModelError]
|
268
|
+
#
|
218
269
|
# @return [::REXML::Document, ::Nokogiri::Document, ::Ox::Document]
|
219
270
|
#
|
220
271
|
# @api public
|
221
|
-
def as_xml(instance, node_name = nil, doc = nil)
|
272
|
+
def as_xml(instance, node_name = nil, doc = nil, _cdata = nil)
|
273
|
+
unless instance.is_a?(model)
|
274
|
+
msg = "argument is a '#{instance.class}' but should be a '#{model}'"
|
275
|
+
raise IncorrectModelError, msg
|
276
|
+
end
|
277
|
+
|
222
278
|
unless doc
|
223
279
|
doc = Shale.xml_adapter.create_document
|
224
280
|
doc.add_element(doc.doc, as_xml(instance, xml_mapping.prefixed_root, doc))
|
@@ -226,13 +282,17 @@ module Shale
|
|
226
282
|
end
|
227
283
|
|
228
284
|
element = doc.create_element(node_name)
|
229
|
-
|
285
|
+
|
286
|
+
doc.add_namespace(
|
287
|
+
xml_mapping.default_namespace.prefix,
|
288
|
+
xml_mapping.default_namespace.name
|
289
|
+
)
|
230
290
|
|
231
291
|
xml_mapping.attributes.each_value do |mapping|
|
232
292
|
if mapping.method_to
|
233
|
-
|
293
|
+
new.send(mapping.method_to, instance, element, doc)
|
234
294
|
else
|
235
|
-
attribute =
|
295
|
+
attribute = attributes[mapping.attribute]
|
236
296
|
next unless attribute
|
237
297
|
|
238
298
|
value = instance.send(attribute.name)
|
@@ -243,20 +303,33 @@ module Shale
|
|
243
303
|
end
|
244
304
|
end
|
245
305
|
|
246
|
-
|
247
|
-
attribute = instance.class.attributes[xml_mapping.content]
|
306
|
+
content_mapping = xml_mapping.content
|
248
307
|
|
249
|
-
|
250
|
-
|
251
|
-
|
308
|
+
if content_mapping
|
309
|
+
if content_mapping.method_to
|
310
|
+
new.send(content_mapping.method_to, instance, element, doc)
|
311
|
+
else
|
312
|
+
attribute = attributes[content_mapping.attribute]
|
313
|
+
|
314
|
+
if attribute
|
315
|
+
value = instance.send(attribute.name)
|
316
|
+
|
317
|
+
# rubocop:disable Metrics/BlockNesting
|
318
|
+
if content_mapping.cdata
|
319
|
+
doc.create_cdata(value.to_s, element)
|
320
|
+
else
|
321
|
+
doc.add_text(element, value.to_s)
|
322
|
+
end
|
323
|
+
# rubocop:enable Metrics/BlockNesting
|
324
|
+
end
|
252
325
|
end
|
253
326
|
end
|
254
327
|
|
255
328
|
xml_mapping.elements.each_value do |mapping|
|
256
329
|
if mapping.method_to
|
257
|
-
|
330
|
+
new.send(mapping.method_to, instance, element, doc)
|
258
331
|
else
|
259
|
-
attribute =
|
332
|
+
attribute = attributes[mapping.attribute]
|
260
333
|
next unless attribute
|
261
334
|
|
262
335
|
value = instance.send(attribute.name)
|
@@ -267,10 +340,12 @@ module Shale
|
|
267
340
|
if attribute.collection?
|
268
341
|
[*value].each do |v|
|
269
342
|
next if v.nil?
|
270
|
-
|
343
|
+
child = attribute.type.as_xml(v, mapping.prefixed_name, doc, mapping.cdata)
|
344
|
+
doc.add_element(element, child)
|
271
345
|
end
|
272
346
|
else
|
273
|
-
|
347
|
+
child = attribute.type.as_xml(value, mapping.prefixed_name, doc, mapping.cdata)
|
348
|
+
doc.add_element(element, child)
|
274
349
|
end
|
275
350
|
end
|
276
351
|
end
|
@@ -295,13 +370,22 @@ module Shale
|
|
295
370
|
|
296
371
|
private
|
297
372
|
|
373
|
+
# Validate TOML adapter
|
374
|
+
#
|
375
|
+
# @raise [AdapterError]
|
376
|
+
#
|
377
|
+
# @api private
|
378
|
+
def validate_toml_adapter
|
379
|
+
raise AdapterError, TOML_ADAPTER_NOT_SET_MESSAGE unless Shale.toml_adapter
|
380
|
+
end
|
381
|
+
|
298
382
|
# Validate XML adapter
|
299
383
|
#
|
300
384
|
# @raise [AdapterError]
|
301
385
|
#
|
302
386
|
# @api private
|
303
387
|
def validate_xml_adapter
|
304
|
-
raise AdapterError,
|
388
|
+
raise AdapterError, XML_ADAPTER_NOT_SET_MESSAGE unless Shale.xml_adapter
|
305
389
|
end
|
306
390
|
end
|
307
391
|
|
@@ -334,6 +418,15 @@ module Shale
|
|
334
418
|
self.class.to_yaml(self)
|
335
419
|
end
|
336
420
|
|
421
|
+
# Convert Object to TOML
|
422
|
+
#
|
423
|
+
# @return [String]
|
424
|
+
#
|
425
|
+
# @api public
|
426
|
+
def to_toml
|
427
|
+
self.class.to_toml(self)
|
428
|
+
end
|
429
|
+
|
337
430
|
# Convert Object to XML
|
338
431
|
#
|
339
432
|
# @param [Array<Symbol>] options
|
data/lib/shale/type/value.rb
CHANGED
@@ -89,6 +89,28 @@ module Shale
|
|
89
89
|
value
|
90
90
|
end
|
91
91
|
|
92
|
+
# Extract value from TOML document
|
93
|
+
#
|
94
|
+
# @param [any] value
|
95
|
+
#
|
96
|
+
# @return [any]
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
def of_toml(value)
|
100
|
+
value
|
101
|
+
end
|
102
|
+
|
103
|
+
# Convert value to form accepted by TOML document
|
104
|
+
#
|
105
|
+
# @param [any] value
|
106
|
+
#
|
107
|
+
# @return [any]
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
def as_toml(value)
|
111
|
+
value
|
112
|
+
end
|
113
|
+
|
92
114
|
# Extract value from XML document
|
93
115
|
#
|
94
116
|
# @param [Shale::Adapter::<XML adapter>::Node] value
|
@@ -116,11 +138,18 @@ module Shale
|
|
116
138
|
# @param [#to_s] value Value to convert to XML
|
117
139
|
# @param [String] name Name of the element
|
118
140
|
# @param [Shale::Adapter::<XML adapter>::Document] doc Document
|
141
|
+
# @param [true, false] cdata
|
119
142
|
#
|
120
143
|
# @api private
|
121
|
-
def as_xml(value, name, doc)
|
144
|
+
def as_xml(value, name, doc, cdata = false)
|
122
145
|
element = doc.create_element(name)
|
123
|
-
|
146
|
+
|
147
|
+
if cdata
|
148
|
+
doc.create_cdata(as_xml_value(value), element)
|
149
|
+
else
|
150
|
+
doc.add_text(element, as_xml_value(value))
|
151
|
+
end
|
152
|
+
|
124
153
|
element
|
125
154
|
end
|
126
155
|
end
|
data/lib/shale/version.rb
CHANGED
data/lib/shale.rb
CHANGED
@@ -72,6 +72,20 @@ module Shale
|
|
72
72
|
# @api public
|
73
73
|
attr_writer :yaml_adapter
|
74
74
|
|
75
|
+
# TOML adapter accessor.
|
76
|
+
#
|
77
|
+
# @param [@see Shale::Adapter::TomlRB] adapter
|
78
|
+
#
|
79
|
+
# @example setting adapter
|
80
|
+
# Shale.toml_adapter = Shale::Adapter::TomlRB
|
81
|
+
#
|
82
|
+
# @example getting adapter
|
83
|
+
# Shale.toml_adapter
|
84
|
+
# # => Shale::Adapter::TomlRB
|
85
|
+
#
|
86
|
+
# @api public
|
87
|
+
attr_accessor :toml_adapter
|
88
|
+
|
75
89
|
# XML adapter accessor. Available adapters are Shale::Adapter::REXML,
|
76
90
|
# Shale::Adapter::Nokogiri and Shale::Adapter::Ox
|
77
91
|
#
|
data/shale.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ['Kamil Giszczak']
|
9
9
|
spec.email = ['beerkg@gmail.com']
|
10
10
|
|
11
|
-
spec.summary = 'Ruby object mapper and serializer for XML, JSON and YAML.'
|
12
|
-
spec.description = 'Ruby object mapper and serializer for XML, JSON and YAML.'
|
11
|
+
spec.summary = 'Ruby object mapper and serializer for XML, JSON, TOML and YAML.'
|
12
|
+
spec.description = 'Ruby object mapper and serializer for XML, JSON, TOML and YAML.'
|
13
13
|
spec.homepage = 'https://shalerb.org'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shale
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.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-
|
11
|
+
date: 2022-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Ruby object mapper and serializer for XML, JSON and YAML.
|
13
|
+
description: Ruby object mapper and serializer for XML, JSON, TOML and YAML.
|
14
14
|
email:
|
15
15
|
- beerkg@gmail.com
|
16
16
|
executables:
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- lib/shale/adapter/rexml.rb
|
34
34
|
- lib/shale/adapter/rexml/document.rb
|
35
35
|
- lib/shale/adapter/rexml/node.rb
|
36
|
+
- lib/shale/adapter/toml_rb.rb
|
36
37
|
- lib/shale/attribute.rb
|
37
38
|
- lib/shale/error.rb
|
38
39
|
- lib/shale/mapper.rb
|
@@ -117,5 +118,5 @@ requirements: []
|
|
117
118
|
rubygems_version: 3.3.7
|
118
119
|
signing_key:
|
119
120
|
specification_version: 4
|
120
|
-
summary: Ruby object mapper and serializer for XML, JSON and YAML.
|
121
|
+
summary: Ruby object mapper and serializer for XML, JSON, TOML and YAML.
|
121
122
|
test_files: []
|