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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aaa3043e612d332fab30ff87ecab722e3812e7769eba982db27c38f74c205ce1
4
- data.tar.gz: bb5cdb963bce5756c48edb37d28bddc40a816901e87b4714ea512f07f8ec4c28
3
+ metadata.gz: 468fc4f3fa1ccd796958748eea653aaa9aec0dbf223c2e5486ddba00350d79fc
4
+ data.tar.gz: 4b78746e97bc6fd080b8a6566be2534c3a1c05017acacabd3935f7e2ea81b097
5
5
  SHA512:
6
- metadata.gz: ed1f1ffc88cabb5f9403ff957c02efc4565aee73b9a8a1fd2297ff13bfbb6bdf0e94664b865f8d2d812ddd66fe97d154e34982eea3318ba01c6d16b4a6922c70
7
- data.tar.gz: d41392de36bcace9efee12a869f49beffba235ae09e09f33c6973159b96320e3f657a6edd4d634e53da430f8127e74fa1025fa2f5c75dad2e7568abe6a0794ce
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
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021 TODO: Write your name
3
+ Copyright (c) 2021 Kamil Giszczak
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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
- * [Pretty printing and XML declaration](#pretty-printing-and-xml-declaration)
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
- self.hobbies = value.split(',').map(&:strip)
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
- self.street = value['street']
482
- self.city = value['city']
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
- self.hobbies = value.split(',').map(&:strip)
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
- self.street = node.children.find { |e| e.name == 'Street' }.text
499
- self.city = node.children.find { |e| e.name == 'City' }.text
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
- </person>
691
+ </Person>
533
692
  DATA
534
693
 
535
694
  # =>
@@ -540,12 +699,100 @@ DATA
540
699
  # @city="London">
541
700
  ```
542
701
 
543
- ### Pretty printing and XML declaration
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
- If you need formatted output you can pass `:pretty` parameter to `#to_json` and `#to_xml`
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
- person.to_json(:pretty)
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 `:declaration` to `#to_xml`
807
+ You can also add an XML declaration by passing `declaration: true` to `#to_xml`
561
808
 
562
809
  ```ruby
563
- person.to_xml(:pretty, :declaration)
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 and YAML parsers are used for handling JSON and YAML documents.
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 YAML, adapter must implement
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
 
@@ -22,13 +22,13 @@ module Shale
22
22
  # Serialize Hash into JSON
23
23
  #
24
24
  # @param [Hash] obj Hash object
25
- # @param [Array<Symbol>] options
25
+ # @param [true, false] pretty
26
26
  #
27
27
  # @return [String]
28
28
  #
29
29
  # @api private
30
- def self.dump(obj, *options)
31
- if options.include?(:pretty)
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
@@ -89,7 +89,7 @@ module Shale
89
89
  first = @node
90
90
  .children
91
91
  .to_a
92
- .filter(&:text?)
92
+ .filter { |e| e.text? || e.cdata? }
93
93
  .first
94
94
 
95
95
  first&.text
@@ -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 [Array<Symbol>] options
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, *options)
45
+ def self.dump(doc, pretty: false, declaration: false)
45
46
  save_with = ::Nokogiri::XML::Node::SaveOptions::AS_XML
46
47
 
47
- if options.include?(:pretty)
48
+ if pretty
48
49
  save_with |= ::Nokogiri::XML::Node::SaveOptions::FORMAT
49
50
  end
50
51
 
51
- unless options.include?(:declaration)
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 options.include?(:pretty)
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.
@@ -80,7 +80,16 @@ module Shale
80
80
  #
81
81
  # @api private
82
82
  def text
83
- @node.text
83
+ texts = @node.nodes.map do |e|
84
+ case e
85
+ when ::Ox::CData
86
+ e.value
87
+ when ::String
88
+ e
89
+ end
90
+ end
91
+
92
+ texts.compact.first
84
93
  end
85
94
  end
86
95
  end