shale 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|