shale 0.5.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/LICENSE.txt +1 -1
- data/README.md +357 -34
- data/lib/shale/adapter/json.rb +3 -3
- data/lib/shale/adapter/nokogiri/document.rb +10 -0
- data/lib/shale/adapter/nokogiri/node.rb +1 -1
- data/lib/shale/adapter/nokogiri.rb +6 -5
- data/lib/shale/adapter/ox/document.rb +10 -0
- data/lib/shale/adapter/ox/node.rb +10 -1
- data/lib/shale/adapter/ox.rb +5 -4
- data/lib/shale/adapter/rexml/document.rb +11 -1
- data/lib/shale/adapter/rexml.rb +5 -4
- data/lib/shale/adapter/toml_rb.rb +34 -0
- data/lib/shale/error.rb +27 -5
- data/lib/shale/mapper.rb +59 -7
- data/lib/shale/mapping/descriptor/dict.rb +12 -1
- data/lib/shale/mapping/descriptor/xml.rb +12 -2
- data/lib/shale/mapping/dict.rb +26 -2
- data/lib/shale/mapping/xml.rb +52 -6
- data/lib/shale/schema/json_generator.rb +1 -3
- data/lib/shale/schema/xml_compiler.rb +1 -1
- data/lib/shale/schema/xml_generator/import.rb +2 -2
- data/lib/shale/schema/xml_generator.rb +4 -6
- data/lib/shale/type/complex.rb +498 -84
- data/lib/shale/type/date.rb +2 -2
- data/lib/shale/type/time.rb +2 -2
- data/lib/shale/type/value.rb +38 -9
- 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: 468fc4f3fa1ccd796958748eea653aaa9aec0dbf223c2e5486ddba00350d79fc
|
4
|
+
data.tar.gz: 4b78746e97bc6fd080b8a6566be2534c3a1c05017acacabd3935f7e2ea81b097
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 776a30c22e95f8c85e150b64ec7df09e89aeb4e86fb2f6f0fcec67a438b13b73926c3d5419b8194f457a2f09fc8eb64bf491e8b1ea5c5d6957e1e1b5cfab9549
|
7
|
+
data.tar.gz: 0d236bde4f3b5aaf9b3ea5a5b8380b3861b24f5d0b310430329c68d010c368890dedbd7f6fad8649b71cd443362c8c6272ebb9c7a234998fa546ecb99e728f44
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
## [0.7.1] - [2022-08-12]
|
2
|
+
|
3
|
+
### Fixed
|
4
|
+
- Fix broken handling of Date and Time types
|
5
|
+
|
6
|
+
## [0.7.0] - [2022-08-09]
|
7
|
+
|
8
|
+
### Added
|
9
|
+
- `only: []` and `except: []` options that allow to controll what attributes are rendered/parsed
|
10
|
+
- `render_nil: true` option that allows to render nil values
|
11
|
+
- Allow to pass a context object to extractor/generator methods
|
12
|
+
|
13
|
+
### Changed
|
14
|
+
- Pass whole document to methods for JSON/YAML/TOML so its behavior is consistent with XML mapping
|
15
|
+
- Convert splat arguments to keyword arguments
|
16
|
+
- RSpec: enable random spec execution and warnings
|
17
|
+
|
18
|
+
## [0.6.0] - 2022-07-05
|
19
|
+
|
20
|
+
### Added
|
21
|
+
- Support for TOML
|
22
|
+
- Support for CDATA nodes in XML documents
|
23
|
+
- Support for using custom models
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
- Allow to map XML content using methods
|
27
|
+
- Prevent adding default mapping after mapping block was declared
|
28
|
+
|
1
29
|
## [0.5.0] - 2022-06-28
|
2
30
|
|
3
31
|
### Added
|
data/LICENSE.txt
CHANGED
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, Tomlib, toml-rb, Nokogiri, REXML and Ox parsers
|
16
16
|
* Support for custom adapters
|
17
17
|
|
18
18
|
## Installation
|
@@ -45,17 +45,22 @@ $ 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)
|
60
|
+
* [Rendering nil values](#rendering-nil-values)
|
57
61
|
* [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
58
|
-
* [
|
62
|
+
* [Additional options](#additional-options)
|
63
|
+
* [Using custom models](#using-custom-models)
|
59
64
|
* [Supported types](#supported-types)
|
60
65
|
* [Writing your own type](#writing-your-own-type)
|
61
66
|
* [Adapters](#adapters)
|
@@ -195,6 +200,65 @@ person.to_yaml
|
|
195
200
|
# zip: E1 6AN
|
196
201
|
```
|
197
202
|
|
203
|
+
### Converting TOML to object
|
204
|
+
|
205
|
+
To use TOML with Shale you have to set adapter you want to use.
|
206
|
+
Out of the box Shale suports [Tomlib](https://github.com/kgiszczak/tomlib).
|
207
|
+
It also comes with adapter for [toml-rb](https://github.com/emancu/toml-rb) if you prefer that.
|
208
|
+
For details see [Adapters](#adapters) section.
|
209
|
+
|
210
|
+
To set it, first make sure Tomlib gem is installed:
|
211
|
+
|
212
|
+
```
|
213
|
+
$ gem install tomlib
|
214
|
+
```
|
215
|
+
|
216
|
+
then setup adapter:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
require 'tomlib'
|
220
|
+
Shale.toml_adapter = Tomlib
|
221
|
+
|
222
|
+
# Alternatively if you'd like to use toml-rb, use:
|
223
|
+
require 'shale/adapter/toml_rb'
|
224
|
+
Shale.toml_adapter = Shale::Adapter::TomlRB
|
225
|
+
```
|
226
|
+
|
227
|
+
Now you can use TOML with Shale:
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
person = Person.from_toml(<<~DATA)
|
231
|
+
first_name = "John"
|
232
|
+
last_name = "Doe"
|
233
|
+
age = 50
|
234
|
+
married = false
|
235
|
+
hobbies = ["Singing", "Dancing"]
|
236
|
+
[address]
|
237
|
+
city = "London"
|
238
|
+
street = "Oxford Street"
|
239
|
+
zip = "E1 6AN"
|
240
|
+
DATA
|
241
|
+
```
|
242
|
+
|
243
|
+
### Converting object to TOML
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
person.to_toml
|
247
|
+
|
248
|
+
# =>
|
249
|
+
#
|
250
|
+
# first_name = "John"
|
251
|
+
# last_name = "Doe"
|
252
|
+
# age = 50
|
253
|
+
# married = false
|
254
|
+
# hobbies = [ "Singing", "Dancing" ]
|
255
|
+
#
|
256
|
+
# [address]
|
257
|
+
# city = "London"
|
258
|
+
# street = "Oxford Street"
|
259
|
+
# zip = "E1 6AN"
|
260
|
+
```
|
261
|
+
|
198
262
|
### Converting Hash to object
|
199
263
|
|
200
264
|
```ruby
|
@@ -240,6 +304,8 @@ require 'shale/adapter/rexml'
|
|
240
304
|
Shale.xml_adapter = Shale::Adapter::REXML
|
241
305
|
```
|
242
306
|
|
307
|
+
Now you can use XML with Shale:
|
308
|
+
|
243
309
|
```ruby
|
244
310
|
person = Person.from_xml(<<~DATA)
|
245
311
|
<person>
|
@@ -284,6 +350,8 @@ person.to_xml
|
|
284
350
|
|
285
351
|
By default keys are named the same as attributes. To use custom keys use:
|
286
352
|
|
353
|
+
:warning: **Declaring custom mapping removes default mapping for given format!**
|
354
|
+
|
287
355
|
```ruby
|
288
356
|
class Person < Shale::Mapper
|
289
357
|
attribute :first_name, Shale::Type::String
|
@@ -310,6 +378,20 @@ class Person < Shale::Mapper
|
|
310
378
|
end
|
311
379
|
```
|
312
380
|
|
381
|
+
### Mapping TOML keys to object attributes
|
382
|
+
|
383
|
+
```ruby
|
384
|
+
class Person < Shale::Mapper
|
385
|
+
attribute :first_name, Shale::Type::String
|
386
|
+
attribute :last_name, Shale::Type::String
|
387
|
+
|
388
|
+
toml do
|
389
|
+
map 'firstName', to: :first_name
|
390
|
+
map 'lastName', to: :last_name
|
391
|
+
end
|
392
|
+
end
|
393
|
+
```
|
394
|
+
|
313
395
|
### Mapping Hash keys to object attributes
|
314
396
|
|
315
397
|
```ruby
|
@@ -380,6 +462,37 @@ DATA
|
|
380
462
|
- `map_attribute` - map element's attribute to attribute
|
381
463
|
- `map_content` - map first text node to attribute
|
382
464
|
|
465
|
+
You can use `cdata: true` option on `map_element` and `map_content` to handle CDATA nodes:
|
466
|
+
|
467
|
+
```ruby
|
468
|
+
class Address < Shale::Mapper
|
469
|
+
attribute :content, Shale::Type::String
|
470
|
+
|
471
|
+
xml do
|
472
|
+
map_content to: :content, cdata: true
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
class Person < Shale::Mapper
|
477
|
+
attribute :first_name, Shale::Type::String
|
478
|
+
attribute :address, Address
|
479
|
+
|
480
|
+
xml do
|
481
|
+
root 'Person'
|
482
|
+
|
483
|
+
map_element 'FirstName', to: :first_name, cdata: true
|
484
|
+
map_element 'Address', to: :address
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
person = Person.from_xml(<<~DATA)
|
489
|
+
<Person>
|
490
|
+
<FirstName><![CDATA[John]]></FirstName>
|
491
|
+
<Address><![CDATA[Oxford Street]]></Address>
|
492
|
+
</person>
|
493
|
+
DATA
|
494
|
+
```
|
495
|
+
|
383
496
|
### Using XML namespaces
|
384
497
|
|
385
498
|
To map namespaced elements and attributes use `namespace` and `prefix` properties on
|
@@ -446,6 +559,52 @@ person = Person.from_xml(<<~DATA)
|
|
446
559
|
DATA
|
447
560
|
```
|
448
561
|
|
562
|
+
### Rendering nil values
|
563
|
+
|
564
|
+
By default elements with `nil` value are not rendered. You can change this behavior
|
565
|
+
by using `render_nil: true` on a mapping.
|
566
|
+
|
567
|
+
```ruby
|
568
|
+
class Person < Shale::Mapper
|
569
|
+
attribute :first_name, Shale::Type::String
|
570
|
+
attribute :last_name, Shale::Type::String
|
571
|
+
attribute :age, Shale::Type::Integer
|
572
|
+
|
573
|
+
json do
|
574
|
+
map 'first_name', to: :first_name, render_nil: true
|
575
|
+
map 'last_name', to: :last_name, render_nil: false
|
576
|
+
map 'age', to: :age, render_nil: true
|
577
|
+
end
|
578
|
+
|
579
|
+
xml do
|
580
|
+
root 'person'
|
581
|
+
|
582
|
+
map_element 'first_name', to: :first_name, render_nil: true
|
583
|
+
map_element 'last_name', to: :last_name, render_nil: false
|
584
|
+
map_attribute 'age', to: :age, render_nil: true
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
person = Person.new(first_name: nil, last_name: nil, age: nil)
|
589
|
+
|
590
|
+
puts person.to_json(pretty: true)
|
591
|
+
|
592
|
+
# =>
|
593
|
+
#
|
594
|
+
# {
|
595
|
+
# "first_name": null,
|
596
|
+
# "age": "null"
|
597
|
+
# }
|
598
|
+
|
599
|
+
puts person.to_xml(pretty: true)
|
600
|
+
|
601
|
+
# =>
|
602
|
+
#
|
603
|
+
# <person age="">
|
604
|
+
# <first_name/>
|
605
|
+
# </person>
|
606
|
+
```
|
607
|
+
|
449
608
|
### Using methods to extract and generate data
|
450
609
|
|
451
610
|
If you need full controll over extracting and generating data from/to document,
|
@@ -469,42 +628,42 @@ class Person < Shale::Mapper
|
|
469
628
|
map_element 'Address', using: { from: :address_from_xml, to: :address_to_xml }
|
470
629
|
end
|
471
630
|
|
472
|
-
def hobbies_from_json(value)
|
473
|
-
|
631
|
+
def hobbies_from_json(model, value)
|
632
|
+
model.hobbies = value.split(',').map(&:strip)
|
474
633
|
end
|
475
634
|
|
476
|
-
def hobbies_to_json
|
477
|
-
hobbies.join(', ')
|
635
|
+
def hobbies_to_json(model, doc)
|
636
|
+
doc['hobbies'] = model.hobbies.join(', ')
|
478
637
|
end
|
479
638
|
|
480
|
-
def address_from_json(value)
|
481
|
-
|
482
|
-
|
639
|
+
def address_from_json(model, value)
|
640
|
+
model.street = value['street']
|
641
|
+
model.city = value['city']
|
483
642
|
end
|
484
643
|
|
485
|
-
def address_to_json
|
486
|
-
{ 'street' => street, 'city' => city }
|
644
|
+
def address_to_json(model, doc)
|
645
|
+
doc['address'] = { 'street' => model.street, 'city' => model.city }
|
487
646
|
end
|
488
647
|
|
489
|
-
def hobbies_from_xml(value)
|
490
|
-
|
648
|
+
def hobbies_from_xml(model, value)
|
649
|
+
model.hobbies = value.split(',').map(&:strip)
|
491
650
|
end
|
492
651
|
|
493
|
-
def hobbies_to_xml(element, doc)
|
494
|
-
doc.add_attribute(element, 'hobbies', hobbies.join(', '))
|
652
|
+
def hobbies_to_xml(model, element, doc)
|
653
|
+
doc.add_attribute(element, 'hobbies', model.hobbies.join(', '))
|
495
654
|
end
|
496
655
|
|
497
|
-
def address_from_xml(node)
|
498
|
-
|
499
|
-
|
656
|
+
def address_from_xml(model, node)
|
657
|
+
model.street = node.children.find { |e| e.name == 'Street' }.text
|
658
|
+
model.city = node.children.find { |e| e.name == 'City' }.text
|
500
659
|
end
|
501
660
|
|
502
|
-
def address_to_xml(parent, doc)
|
661
|
+
def address_to_xml(model, parent, doc)
|
503
662
|
street_element = doc.create_element('Street')
|
504
|
-
doc.add_text(street_element, street.to_s)
|
663
|
+
doc.add_text(street_element, model.street.to_s)
|
505
664
|
|
506
665
|
city_element = doc.create_element('City')
|
507
|
-
doc.add_text(city_element, city.to_s)
|
666
|
+
doc.add_text(city_element, model.city.to_s)
|
508
667
|
|
509
668
|
address_element = doc.create_element('Address')
|
510
669
|
doc.add_element(address_element, street_element)
|
@@ -529,7 +688,7 @@ person = Person.from_xml(<<~DATA)
|
|
529
688
|
<Street>Oxford Street</Street>
|
530
689
|
<City>London</City>
|
531
690
|
</Address>
|
532
|
-
</
|
691
|
+
</Person>
|
533
692
|
DATA
|
534
693
|
|
535
694
|
# =>
|
@@ -540,12 +699,100 @@ DATA
|
|
540
699
|
# @city="London">
|
541
700
|
```
|
542
701
|
|
543
|
-
|
702
|
+
You can also pass a `context` object that will be available in extractor/generator methods:
|
703
|
+
|
704
|
+
```ruby
|
705
|
+
class Person < Shale::Mapper
|
706
|
+
attribute :password, Shale::Type::String
|
544
707
|
|
545
|
-
|
708
|
+
json do
|
709
|
+
map 'password', using: { from: :password_from_json, to: :password_to_json }
|
710
|
+
end
|
711
|
+
|
712
|
+
def password_from_json(model, value, context)
|
713
|
+
if context.admin?
|
714
|
+
model.password = value
|
715
|
+
else
|
716
|
+
model.password = '*****'
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
def password_to_json(model, doc, context)
|
721
|
+
if context.admin?
|
722
|
+
doc['password'] = model.password
|
723
|
+
else
|
724
|
+
doc['password'] = '*****'
|
725
|
+
end
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
Person.new(password: 'secret').to_json(context: current_user)
|
730
|
+
```
|
731
|
+
|
732
|
+
### Additional options
|
733
|
+
|
734
|
+
You can control which attributes to render and parse by
|
735
|
+
using `only: []` and `except: []` parameters.
|
546
736
|
|
547
737
|
```ruby
|
548
|
-
|
738
|
+
# e.g. if you have this model graph:
|
739
|
+
person = Person.new(
|
740
|
+
first_name: 'John'
|
741
|
+
last_name: 'Doe',
|
742
|
+
address: Address.new(city: 'London', street: 'Oxford Street')
|
743
|
+
)
|
744
|
+
|
745
|
+
# if you want to render only `first_name` and `address.city` do:
|
746
|
+
person.to_json(only: [:first_name, address: [:city]], pretty: true)
|
747
|
+
|
748
|
+
# =>
|
749
|
+
#
|
750
|
+
# {
|
751
|
+
# "first_name": "John",
|
752
|
+
# "address": {
|
753
|
+
# "city": "London"
|
754
|
+
# }
|
755
|
+
# }
|
756
|
+
|
757
|
+
# and if you don't need an address you can do:
|
758
|
+
person.to_json(except: [:address], pretty: true)
|
759
|
+
|
760
|
+
# =>
|
761
|
+
#
|
762
|
+
# {
|
763
|
+
# "first_name": "John",
|
764
|
+
# "last_name": "Doe"
|
765
|
+
# }
|
766
|
+
```
|
767
|
+
|
768
|
+
It works the same for parsing:
|
769
|
+
|
770
|
+
```ruby
|
771
|
+
# e.g. if you want to parse only `address.city` do:
|
772
|
+
Person.from_json(doc, only: [address: [:city]])
|
773
|
+
|
774
|
+
# =>
|
775
|
+
#
|
776
|
+
# #<Person:0x0000000113d7a488
|
777
|
+
# @first_name=nil,
|
778
|
+
# @last_name=nil,
|
779
|
+
# @address=#<Address:0x0000000113d7a140 @street=nil, @city="London">>
|
780
|
+
|
781
|
+
# and if you don't need an `address`:
|
782
|
+
Person.from_json(doc, except: [:address])
|
783
|
+
|
784
|
+
# =>
|
785
|
+
#
|
786
|
+
# #<Person:0x0000000113d7a488
|
787
|
+
# @first_name="John",
|
788
|
+
# @last_name="Doe",
|
789
|
+
# @address=nil>
|
790
|
+
```
|
791
|
+
|
792
|
+
If you need formatted output you can pass `pretty: true` parameter to `#to_json` and `#to_xml`
|
793
|
+
|
794
|
+
```ruby
|
795
|
+
person.to_json(pretty: true)
|
549
796
|
|
550
797
|
# =>
|
551
798
|
#
|
@@ -557,10 +804,10 @@ person.to_json(:pretty)
|
|
557
804
|
# }
|
558
805
|
```
|
559
806
|
|
560
|
-
You can also add an XML declaration by passing
|
807
|
+
You can also add an XML declaration by passing `declaration: true` to `#to_xml`
|
561
808
|
|
562
809
|
```ruby
|
563
|
-
person.to_xml(:
|
810
|
+
person.to_xml(pretty: true, declaration: true)
|
564
811
|
|
565
812
|
# =>
|
566
813
|
#
|
@@ -570,6 +817,67 @@ person.to_xml(:pretty, :declaration)
|
|
570
817
|
# </Person>
|
571
818
|
```
|
572
819
|
|
820
|
+
### Using custom models
|
821
|
+
|
822
|
+
By default Shale combines mapper and model into one class. If you want to use your own classes
|
823
|
+
as models you can do it by using `model` directive on the mapper:
|
824
|
+
|
825
|
+
```ruby
|
826
|
+
class Address
|
827
|
+
attr_accessor :street, :city
|
828
|
+
end
|
829
|
+
|
830
|
+
class Person
|
831
|
+
attr_accessor :first_name, :last_name, :address
|
832
|
+
end
|
833
|
+
|
834
|
+
class AddressMapper < Shale::Mapper
|
835
|
+
model Address
|
836
|
+
|
837
|
+
attribute :street, Shale::Type::String
|
838
|
+
attribute :city, Shale::Type::String
|
839
|
+
end
|
840
|
+
|
841
|
+
class PersonMapper < Shale::Mapper
|
842
|
+
model Person
|
843
|
+
|
844
|
+
attribute :first_name, Shale::Type::String
|
845
|
+
attribute :last_name, Shale::Type::String
|
846
|
+
attribute :address, AddressMapper
|
847
|
+
end
|
848
|
+
|
849
|
+
person = PersonMapper.from_json(<<~DATA)
|
850
|
+
{
|
851
|
+
"first_name": "John",
|
852
|
+
"last_name": "Doe",
|
853
|
+
"address": {
|
854
|
+
"street": "Oxford Street",
|
855
|
+
"city": "London"
|
856
|
+
}
|
857
|
+
}
|
858
|
+
DATA
|
859
|
+
|
860
|
+
# =>
|
861
|
+
#
|
862
|
+
# #<Person:0x0000000113d7a488
|
863
|
+
# @first_name="John",
|
864
|
+
# @last_name="Doe",
|
865
|
+
# @address=#<Address:0x0000000113d7a140 @street="Oxford Street", @city="London">>
|
866
|
+
|
867
|
+
PersonMapper.to_json(person, pretty: true)
|
868
|
+
|
869
|
+
# =>
|
870
|
+
#
|
871
|
+
# {
|
872
|
+
# "first_name": "John",
|
873
|
+
# "last_name": "Doe",
|
874
|
+
# "address": {
|
875
|
+
# "street": "Oxford Street",
|
876
|
+
# "city": "London"
|
877
|
+
# }
|
878
|
+
# }
|
879
|
+
```
|
880
|
+
|
573
881
|
### Supported types
|
574
882
|
|
575
883
|
Shale supports these types out of the box:
|
@@ -598,9 +906,9 @@ end
|
|
598
906
|
### Adapters
|
599
907
|
|
600
908
|
Shale uses adapters for parsing and generating documents.
|
601
|
-
By default Ruby's standard JSON
|
909
|
+
By default Ruby's standard JSON, YAML parsers are used for handling JSON and YAML documents.
|
602
910
|
|
603
|
-
You can change it by providing your own adapter. For JSON and
|
911
|
+
You can change it by providing your own adapter. For JSON, YAML and TOML, adapter must implement
|
604
912
|
`.load` and `.dump` class methods.
|
605
913
|
|
606
914
|
```ruby
|
@@ -611,6 +919,21 @@ Shale.json_adapter = MultiJson
|
|
611
919
|
Shale.yaml_adapter = MyYamlAdapter
|
612
920
|
```
|
613
921
|
|
922
|
+
To handle TOML documents you have to set TOML adapter. Out of the box `Tomlib` is supported.
|
923
|
+
Shale also provides adapter for `toml-rb` parser:
|
924
|
+
|
925
|
+
```ruby
|
926
|
+
require 'shale'
|
927
|
+
|
928
|
+
# if you want to use Tomlib
|
929
|
+
require 'tomlib'
|
930
|
+
Shale.toml_adapter = Tomlib
|
931
|
+
|
932
|
+
# if you want to use toml-rb
|
933
|
+
require 'shale/adapter/toml_rb'
|
934
|
+
Shale.toml_adapter = Shale::Adapter::TomlRB
|
935
|
+
```
|
936
|
+
|
614
937
|
To handle XML documents you have to explicitly set XML adapter.
|
615
938
|
Shale provides adapters for most popular Ruby XML parsers:
|
616
939
|
|
data/lib/shale/adapter/json.rb
CHANGED
@@ -22,13 +22,13 @@ module Shale
|
|
22
22
|
# Serialize Hash into JSON
|
23
23
|
#
|
24
24
|
# @param [Hash] obj Hash object
|
25
|
-
# @param [
|
25
|
+
# @param [true, false] pretty
|
26
26
|
#
|
27
27
|
# @return [String]
|
28
28
|
#
|
29
29
|
# @api private
|
30
|
-
def self.dump(obj,
|
31
|
-
if
|
30
|
+
def self.dump(obj, pretty: false)
|
31
|
+
if pretty
|
32
32
|
::JSON.pretty_generate(obj)
|
33
33
|
else
|
34
34
|
::JSON.generate(obj)
|
@@ -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
|
@@ -36,25 +36,26 @@ module Shale
|
|
36
36
|
# Serialize Nokogiri document into XML
|
37
37
|
#
|
38
38
|
# @param [::Nokogiri::XML::Document] doc Nokogiri document
|
39
|
-
# @param [
|
39
|
+
# @param [true, false] pretty
|
40
|
+
# @param [true, false] declaration
|
40
41
|
#
|
41
42
|
# @return [String]
|
42
43
|
#
|
43
44
|
# @api private
|
44
|
-
def self.dump(doc,
|
45
|
+
def self.dump(doc, pretty: false, declaration: false)
|
45
46
|
save_with = ::Nokogiri::XML::Node::SaveOptions::AS_XML
|
46
47
|
|
47
|
-
if
|
48
|
+
if pretty
|
48
49
|
save_with |= ::Nokogiri::XML::Node::SaveOptions::FORMAT
|
49
50
|
end
|
50
51
|
|
51
|
-
unless
|
52
|
+
unless declaration
|
52
53
|
save_with |= ::Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
53
54
|
end
|
54
55
|
|
55
56
|
result = doc.to_xml(save_with: save_with)
|
56
57
|
|
57
|
-
unless
|
58
|
+
unless pretty
|
58
59
|
result = result.sub(/\n/, '')
|
59
60
|
end
|
60
61
|
|
@@ -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.
|