shale 0.3.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +398 -41
  4. data/exe/shaleb +108 -36
  5. data/lib/shale/adapter/nokogiri/document.rb +97 -0
  6. data/lib/shale/adapter/nokogiri/node.rb +100 -0
  7. data/lib/shale/adapter/nokogiri.rb +11 -151
  8. data/lib/shale/adapter/ox/document.rb +90 -0
  9. data/lib/shale/adapter/ox/node.rb +97 -0
  10. data/lib/shale/adapter/ox.rb +9 -134
  11. data/lib/shale/adapter/rexml/document.rb +98 -0
  12. data/lib/shale/adapter/rexml/node.rb +99 -0
  13. data/lib/shale/adapter/rexml.rb +9 -150
  14. data/lib/shale/adapter/toml_rb.rb +34 -0
  15. data/lib/shale/attribute.rb +6 -0
  16. data/lib/shale/error.rb +56 -0
  17. data/lib/shale/mapper.rb +67 -13
  18. data/lib/shale/mapping/descriptor/xml.rb +10 -1
  19. data/lib/shale/mapping/dict.rb +18 -0
  20. data/lib/shale/mapping/xml.rb +40 -5
  21. data/lib/shale/schema/compiler/boolean.rb +21 -0
  22. data/lib/shale/schema/compiler/complex.rb +88 -0
  23. data/lib/shale/schema/compiler/date.rb +21 -0
  24. data/lib/shale/schema/compiler/float.rb +21 -0
  25. data/lib/shale/schema/compiler/integer.rb +21 -0
  26. data/lib/shale/schema/compiler/property.rb +70 -0
  27. data/lib/shale/schema/compiler/string.rb +21 -0
  28. data/lib/shale/schema/compiler/time.rb +21 -0
  29. data/lib/shale/schema/compiler/value.rb +21 -0
  30. data/lib/shale/schema/compiler/xml_complex.rb +50 -0
  31. data/lib/shale/schema/compiler/xml_property.rb +73 -0
  32. data/lib/shale/schema/json_compiler.rb +331 -0
  33. data/lib/shale/schema/{json → json_generator}/base.rb +2 -2
  34. data/lib/shale/schema/{json → json_generator}/boolean.rb +1 -1
  35. data/lib/shale/schema/{json → json_generator}/collection.rb +2 -2
  36. data/lib/shale/schema/{json → json_generator}/date.rb +1 -1
  37. data/lib/shale/schema/{json → json_generator}/float.rb +1 -1
  38. data/lib/shale/schema/{json → json_generator}/integer.rb +1 -1
  39. data/lib/shale/schema/{json → json_generator}/object.rb +5 -2
  40. data/lib/shale/schema/{json → json_generator}/ref.rb +1 -1
  41. data/lib/shale/schema/{json → json_generator}/schema.rb +6 -4
  42. data/lib/shale/schema/{json → json_generator}/string.rb +1 -1
  43. data/lib/shale/schema/{json → json_generator}/time.rb +1 -1
  44. data/lib/shale/schema/json_generator/value.rb +23 -0
  45. data/lib/shale/schema/{json.rb → json_generator.rb} +36 -36
  46. data/lib/shale/schema/xml_compiler.rb +919 -0
  47. data/lib/shale/schema/{xml → xml_generator}/attribute.rb +1 -1
  48. data/lib/shale/schema/{xml → xml_generator}/complex_type.rb +5 -2
  49. data/lib/shale/schema/{xml → xml_generator}/element.rb +1 -1
  50. data/lib/shale/schema/{xml → xml_generator}/import.rb +1 -1
  51. data/lib/shale/schema/{xml → xml_generator}/ref_attribute.rb +1 -1
  52. data/lib/shale/schema/{xml → xml_generator}/ref_element.rb +1 -1
  53. data/lib/shale/schema/{xml → xml_generator}/schema.rb +5 -5
  54. data/lib/shale/schema/{xml → xml_generator}/typed_attribute.rb +1 -1
  55. data/lib/shale/schema/{xml → xml_generator}/typed_element.rb +1 -1
  56. data/lib/shale/schema/{xml.rb → xml_generator.rb} +25 -26
  57. data/lib/shale/schema.rb +44 -5
  58. data/lib/shale/type/{composite.rb → complex.rb} +156 -51
  59. data/lib/shale/type/value.rb +31 -2
  60. data/lib/shale/utils.rb +42 -7
  61. data/lib/shale/version.rb +1 -1
  62. data/lib/shale.rb +22 -19
  63. data/shale.gemspec +3 -3
  64. metadata +50 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36678c1f4afd6e0cf2d6a9a9e4b5becebf11e76404cb50dba7dc5269b5ca42cc
4
- data.tar.gz: 51c6c94abafe1767c579c270e3c3cb4da2ca79a2a29a9d28ea6bfe09bc4b53fb
3
+ metadata.gz: 243b99a073ac189f66ae0fbfedd94a5715399de731d0e0fd1d970dad749d27a0
4
+ data.tar.gz: d2f57de2427574d710d6a6fe9ba35868fd162214ce8aa2092ddfb3fe1f5e7c3d
5
5
  SHA512:
6
- metadata.gz: ea21dff00b6ea2663d20f9f377140250f78c29214a93f226047fe29d47680ae526652010ae268e4cf694ca1877cd8d19bfe8f0bbd767fa871fa80afaefee1c83
7
- data.tar.gz: 414d45b7bcd2477bc276eee17c598efba40350e0234c32f783c73217bee65ae4260d07e8a7bcfc7f48e1f76c9af4852de1c1c109c5b807e99a945305e2de6286
6
+ metadata.gz: 9de1be5eccbb647f05b6573d783491f858fb56614f09c7c625e7fa922c7b89b5d38863a57defbe506d42f0b542b326e4ca61ecf308b94f7b35b4056751e0299e
7
+ data.tar.gz: a1e29fc097c130c55e45837af198e3cd4f7d3ad6a94b17d032eb31b8065f7ea013682836256d12127480965ed3733079e5badd7a8b0060e3bc60f00734fcc215
data/CHANGELOG.md CHANGED
@@ -1,3 +1,40 @@
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
+
12
+ ## [0.5.0] - 2022-06-28
13
+
14
+ ### Added
15
+ - Allow to generate Shale model from XML Schema
16
+
17
+ ### Changed
18
+ - Shale doesn't defaults to REXML anymore - XML adapter needs to be set explicitly
19
+ - Rename "JSONSchemaError" to "SchemaError"
20
+ - Rename "Composite" type to "Complex"
21
+ - Drop support for Ruby 2.6
22
+
23
+ ## [0.4.0] - 2022-05-30
24
+
25
+ ### Added
26
+ - Allow to add title to JSON Schema
27
+ - Map Shale::Type::Value to "anyType" XML Schema type
28
+ - Map Shale::Type::Value to "any" JSON Schema type
29
+ - Allow to generate Shale model from JSON Schema
30
+
31
+ ### Changed
32
+ - Performance improvements
33
+ - Reformat README a little bit and fix typos
34
+
35
+ ### Fixed
36
+ - Fix stack overflow caused by circular dependency when generating JSON and XML schemas
37
+
1
38
  ## [0.3.1] - 2022-04-29
2
39
 
3
40
  ### Changed
data/README.md CHANGED
@@ -1,10 +1,23 @@
1
1
  # Shale
2
2
 
3
- Shale is a object mapper and serializer for JSON, YAML and 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
+
7
+ Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
8
+
9
+ ## Features
10
+
11
+ * Convert JSON, YAML, TOML and XML to Ruby data model
12
+ * Convert Ruby data model to JSON, YAML, TOML and XML
13
+ * Generate JSON and XML Schema from Ruby models
14
+ * Compile JSON and XML Schema into Ruby models
15
+ * Out of the box support for JSON, YAML, toml-rb, Nokogiri, REXML and Ox parsers
16
+ * Support for custom adapters
4
17
 
5
18
  ## Installation
6
19
 
7
- Shale supports Ruby (MRI) 2.6+
20
+ Shale supports Ruby (MRI) 2.7+
8
21
 
9
22
  Add this line to your application's Gemfile:
10
23
 
@@ -32,27 +45,31 @@ $ gem install shale
32
45
  * [Converting object to JSON](#converting-object-to-json)
33
46
  * [Converting YAML to object](#converting-yaml-to-object)
34
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)
35
50
  * [Converting Hash to object](#converting-hash-to-object)
36
51
  * [Converting object to Hash](#converting-object-to-hash)
37
52
  * [Converting XML to object](#converting-xml-to-object)
38
53
  * [Converting object to XML](#converting-object-to-xml)
39
54
  * [Mapping JSON keys to object attributes](#mapping-json-keys-to-object-attributes)
40
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)
41
57
  * [Mapping Hash keys to object attributes](#mapping-hash-keys-to-object-attributes)
42
58
  * [Mapping XML elements and attributes to object attributes](#mapping-xml-elements-and-attributes-to-object-attributes)
43
59
  * [Using XML namespaces](#using-xml-namespaces)
44
60
  * [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
45
61
  * [Pretty printing and XML declaration](#pretty-printing-and-xml-declaration)
62
+ * [Using custom models](#using-custom-models)
46
63
  * [Supported types](#supported-types)
47
64
  * [Writing your own type](#writing-your-own-type)
48
65
  * [Adapters](#adapters)
49
66
  * [Generating JSON Schema](#generating-json-schema)
67
+ * [Compiling JSON Schema into Shale model](#compiling-json-schema-into-shale-model)
50
68
  * [Generating XML Schema](#generating-xml-schema)
69
+ * [Compiling XML Schema into Shale model](#compiling-xml-schema-into-shale-model)
51
70
 
52
71
  ## Usage
53
72
 
54
- Documentation with interactive examples is available at [Shale website](https://www.shalerb.org)
55
-
56
73
  ### Simple use case
57
74
 
58
75
  ```ruby
@@ -126,6 +143,7 @@ DATA
126
143
 
127
144
  ```ruby
128
145
  person.to_json
146
+
129
147
  # =>
130
148
  #
131
149
  # {
@@ -164,6 +182,63 @@ DATA
164
182
 
165
183
  ```ruby
166
184
  person.to_yaml
185
+
186
+ # =>
187
+ #
188
+ # ---
189
+ # first_name: John
190
+ # last_name: Doe
191
+ # age: 50
192
+ # married: false
193
+ # hobbies:
194
+ # - Singing
195
+ # - Dancing
196
+ # address:
197
+ # city: London
198
+ # street: Oxford Street
199
+ # zip: E1 6AN
200
+ ```
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
+
167
242
  # =>
168
243
  #
169
244
  # ---
@@ -201,6 +276,7 @@ person = Person.from_hash(
201
276
 
202
277
  ```ruby
203
278
  person.to_hash
279
+
204
280
  # =>
205
281
  #
206
282
  # {
@@ -215,6 +291,17 @@ person.to_hash
215
291
 
216
292
  ### Converting XML to object
217
293
 
294
+ To use XML with Shale you have to set adapter you want to use.
295
+ Shale comes with adapters for REXML, Nokogiri and OX parsers.
296
+ For details see [Adapters](#adapters) section.
297
+
298
+ ```ruby
299
+ require 'shale/adapter/rexml'
300
+ Shale.xml_adapter = Shale::Adapter::REXML
301
+ ```
302
+
303
+ Now you can use XML with Shale:
304
+
218
305
  ```ruby
219
306
  person = Person.from_xml(<<~DATA)
220
307
  <person>
@@ -237,6 +324,7 @@ DATA
237
324
 
238
325
  ```ruby
239
326
  person.to_xml
327
+
240
328
  # =>
241
329
  #
242
330
  # <person>
@@ -256,7 +344,9 @@ person.to_xml
256
344
 
257
345
  ### Mapping JSON keys to object attributes
258
346
 
259
- By default keys are named the same as attributes. To use custom key names use:
347
+ By default keys are named the same as attributes. To use custom keys use:
348
+
349
+ :warning: **Declaring custom mapping removes default mapping for given format!**
260
350
 
261
351
  ```ruby
262
352
  class Person < Shale::Mapper
@@ -284,6 +374,20 @@ class Person < Shale::Mapper
284
374
  end
285
375
  ```
286
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
+
287
391
  ### Mapping Hash keys to object attributes
288
392
 
289
393
  ```ruby
@@ -300,7 +404,7 @@ end
300
404
 
301
405
  ### Mapping XML elements and attributes to object attributes
302
406
 
303
- XML is more complcated format than JSON or YAML. To map elements, attributes and content use:
407
+ XML is more complicated format than JSON or YAML. To map elements, attributes and content use:
304
408
 
305
409
  ```ruby
306
410
  class Address < Shale::Mapper
@@ -354,9 +458,38 @@ DATA
354
458
  - `map_attribute` - map element's attribute to attribute
355
459
  - `map_content` - map first text node to attribute
356
460
 
357
- ### Using XML namespaces
461
+ You can use `cdata: true` option on `map_element` and `map_content` to handle CDATA nodes:
358
462
 
359
- :warning: **Ox doesn't support XML namespaces**
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
+
492
+ ### Using XML namespaces
360
493
 
361
494
  To map namespaced elements and attributes use `namespace` and `prefix` properties on
362
495
  `map_element` and `map_attribute`
@@ -385,7 +518,7 @@ DATA
385
518
  ```
386
519
 
387
520
  To define default namespace for all elements use `namespace` declaration
388
- (this will define namespace only on elements, if you want to define namespace on an attribute
521
+ (this will define namespace on elements only, if you want to define namespace on an attribute
389
522
  explicitly declare it on `map_attribute`).
390
523
 
391
524
  ```ruby
@@ -445,42 +578,42 @@ class Person < Shale::Mapper
445
578
  map_element 'Address', using: { from: :address_from_xml, to: :address_to_xml }
446
579
  end
447
580
 
448
- def hobbies_from_json(value)
449
- self.hobbies = value.split(',').map(&:strip)
581
+ def hobbies_from_json(model, value)
582
+ model.hobbies = value.split(',').map(&:strip)
450
583
  end
451
584
 
452
- def hobbies_to_json
453
- hobbies.join(', ')
585
+ def hobbies_to_json(model)
586
+ model.hobbies.join(', ')
454
587
  end
455
588
 
456
- def address_from_json(value)
457
- self.street = value['street']
458
- self.city = value['city']
589
+ def address_from_json(model, value)
590
+ model.street = value['street']
591
+ model.city = value['city']
459
592
  end
460
593
 
461
- def address_to_json
462
- { 'street' => street, 'city' => city }
594
+ def address_to_json(model)
595
+ { 'street' => model.street, 'city' => model.city }
463
596
  end
464
597
 
465
- def hobbies_from_xml(value)
466
- self.hobbies = value.split(',').map(&:strip)
598
+ def hobbies_from_xml(model, value)
599
+ model.hobbies = value.split(',').map(&:strip)
467
600
  end
468
601
 
469
- def hobbies_to_xml(element, doc)
470
- doc.add_attribute(element, 'hobbies', hobbies.join(', '))
602
+ def hobbies_to_xml(model, element, doc)
603
+ doc.add_attribute(element, 'hobbies', model.hobbies.join(', '))
471
604
  end
472
605
 
473
- def address_from_xml(node)
474
- self.street = node.children.find { |e| e.name == 'Street' }.text
475
- self.city = node.children.find { |e| e.name == 'City' }.text
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
476
609
  end
477
610
 
478
- def address_to_xml(parent, doc)
611
+ def address_to_xml(model, parent, doc)
479
612
  street_element = doc.create_element('Street')
480
- doc.add_text(street_element, street.to_s)
613
+ doc.add_text(street_element, model.street.to_s)
481
614
 
482
615
  city_element = doc.create_element('City')
483
- doc.add_text(city_element, city.to_s)
616
+ doc.add_text(city_element, model.city.to_s)
484
617
 
485
618
  address_element = doc.create_element('Address')
486
619
  doc.add_element(address_element, street_element)
@@ -505,7 +638,7 @@ person = Person.from_xml(<<~DATA)
505
638
  <Street>Oxford Street</Street>
506
639
  <City>London</City>
507
640
  </Address>
508
- </person>
641
+ </Person>
509
642
  DATA
510
643
 
511
644
  # =>
@@ -546,6 +679,67 @@ person.to_xml(:pretty, :declaration)
546
679
  # </Person>
547
680
  ```
548
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
+
549
743
  ### Supported types
550
744
 
551
745
  Shale supports these types out of the box:
@@ -574,10 +768,9 @@ end
574
768
  ### Adapters
575
769
 
576
770
  Shale uses adapters for parsing and generating documents.
577
- By default Ruby's standard JSON parser is used for handling JSON documents, YAML for YAML and
578
- REXML for XML.
771
+ By default Ruby's standard JSON, YAML parsers are used for handling JSON and YAML documents.
579
772
 
580
- You can change it by providing your own adapter. For JSON and YAML, adapter must implement
773
+ You can change it by providing your own adapter. For JSON, YAML and TOML, adapter must implement
581
774
  `.load` and `.dump` class methods.
582
775
 
583
776
  ```ruby
@@ -588,12 +781,25 @@ Shale.json_adapter = MultiJson
588
781
  Shale.yaml_adapter = MyYamlAdapter
589
782
  ```
590
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
+
794
+ To handle XML documents you have to explicitly set XML adapter.
591
795
  Shale provides adapters for most popular Ruby XML parsers:
592
796
 
797
+ :warning: **Ox doesn't support XML namespaces**
798
+
593
799
  ```ruby
594
800
  require 'shale'
595
801
 
596
- # REXML is used by default:
802
+ # if you want to use REXML:
597
803
 
598
804
  require 'shale/adapter/rexml'
599
805
  Shale.xml_adapter = Shale::Adapter::REXML
@@ -611,14 +817,19 @@ Shale.xml_adapter = Shale::Adapter::Ox
611
817
 
612
818
  ### Generating JSON Schema
613
819
 
614
- To generate JSON Schema from you Shale data model use:
820
+ :warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
615
821
 
616
- :warning: Shale only supports **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema
822
+ To generate JSON Schema from your Shale data model use:
617
823
 
618
824
  ```ruby
619
825
  require 'shale/schema'
620
826
 
621
- Shale::Schema.to_json(Person, id: 'http://foo.bar/schema/person', description: 'My description', pretty: true)
827
+ Shale::Schema.to_json(
828
+ Person,
829
+ id: 'http://foo.bar/schema/person',
830
+ description: 'My description',
831
+ pretty: true
832
+ )
622
833
 
623
834
  # =>
624
835
  #
@@ -663,7 +874,7 @@ Shale::Schema.to_json(Person, id: 'http://foo.bar/schema/person', description: '
663
874
  You can also use a command line tool to do it:
664
875
 
665
876
  ```
666
- $ shaleb -i data_model.rb -c Person -p
877
+ $ shaleb -i data_model.rb -r Person -p
667
878
  ```
668
879
 
669
880
  If you want to convert your own types to JSON Schema types use:
@@ -676,13 +887,83 @@ class MyEmailType < Shale::Type::Value
676
887
  ...
677
888
  end
678
889
 
679
- class MyEmailJSONType < Shale::Schema::JSON::Base
890
+ class MyEmailJSONType < Shale::Schema::JSONGenerator::Base
680
891
  def as_type
681
892
  { 'type' => 'string', 'format' => 'email' }
682
893
  end
683
894
  end
684
895
 
685
- Shale::Schema::JSON.register_json_type(MyEmailType, MyEmailJSONType)
896
+ Shale::Schema::JSONGenerator.register_json_type(MyEmailType, MyEmailJSONType)
897
+ ```
898
+
899
+ ### Compiling JSON Schema into Shale model
900
+
901
+ :warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
902
+
903
+ To generate Shale data model from JSON Schema use:
904
+
905
+ ```ruby
906
+ require 'shale/schema'
907
+
908
+ schema = <<~SCHEMA
909
+ {
910
+ "type": "object",
911
+ "properties": {
912
+ "firstName": { "type": "string" },
913
+ "lastName": { "type": "string" },
914
+ "address": {
915
+ "type": "object",
916
+ "properties": {
917
+ "street": { "type": "string" },
918
+ "city": { "type": "string" }
919
+ }
920
+ }
921
+ }
922
+ }
923
+ SCHEMA
924
+
925
+ Shale::Schema.from_json([schema], root_name: 'Person')
926
+
927
+ # =>
928
+ #
929
+ # {
930
+ # "address" => "
931
+ # require 'shale'
932
+ #
933
+ # class Address < Shale::Mapper
934
+ # attribute :street, Shale::Type::String
935
+ # attribute :city, Shale::Type::String
936
+ #
937
+ # json do
938
+ # map 'street', to: :street
939
+ # map 'city', to: :city
940
+ # end
941
+ # end
942
+ # ",
943
+ # "person" => "
944
+ # require 'shale'
945
+ #
946
+ # require_relative 'address'
947
+ #
948
+ # class Person < Shale::Mapper
949
+ # attribute :first_name, Shale::Type::String
950
+ # attribute :last_name, Shale::Type::String
951
+ # attribute :address, Address
952
+ #
953
+ # json do
954
+ # map 'firstName', to: :first_name
955
+ # map 'lastName', to: :last_name
956
+ # map 'address', to: :address
957
+ # end
958
+ # end
959
+ # "
960
+ # }
961
+ ```
962
+
963
+ You can also use a command line tool to do it:
964
+
965
+ ```
966
+ $ shaleb -c -i schema.json -r Person
686
967
  ```
687
968
 
688
969
  ### Generating XML Schema
@@ -735,7 +1016,7 @@ Shale::Schema.to_xml(Person, pretty: true)
735
1016
  You can also use a command line tool to do it:
736
1017
 
737
1018
  ```
738
- $ shaleb -i data_model.rb -c Person -p -f xml
1019
+ $ shaleb -i data_model.rb -r Person -p -f xml
739
1020
  ```
740
1021
 
741
1022
  If you want to convert your own types to XML Schema types use:
@@ -748,7 +1029,83 @@ class MyEmailType < Shale::Type::Value
748
1029
  ...
749
1030
  end
750
1031
 
751
- Shale::Schema::XML.register_xml_type(MyEmailType, 'myEmailXMLType')
1032
+ Shale::Schema::XMLGenerator.register_xml_type(MyEmailType, 'myEmailXMLType')
1033
+ ```
1034
+
1035
+ ### Compiling XML Schema into Shale model
1036
+
1037
+ To generate Shale data model from XML Schema use:
1038
+
1039
+ ```ruby
1040
+ require 'shale/schema'
1041
+
1042
+ schema = <<~SCHEMA
1043
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
1044
+ <xs:element name="Person" type="Person" />
1045
+
1046
+ <xs:complexType name="Person">
1047
+ <xs:sequence>
1048
+ <xs:element name="FirstName" type="xs:string" />
1049
+ <xs:element name="LastName" type="xs:string" />
1050
+ <xs:element name="Address" type="Address" />
1051
+ </xs:sequence>
1052
+ </xs:complexType>
1053
+
1054
+ <xs:complexType name="Address">
1055
+ <xs:sequence>
1056
+ <xs:element name="Street" type="xs:string" />
1057
+ <xs:element name="City" type="xs:string" />
1058
+ </xs:sequence>
1059
+ </xs:complexType>
1060
+ </xs:schema>
1061
+ SCHEMA
1062
+
1063
+ Shale::Schema.from_xml([schema])
1064
+
1065
+ # =>
1066
+ #
1067
+ # {
1068
+ # "address" => "
1069
+ # require 'shale'
1070
+ #
1071
+ # class Address < Shale::Mapper
1072
+ # attribute :street, Shale::Type::String
1073
+ # attribute :city, Shale::Type::String
1074
+ #
1075
+ # xml do
1076
+ # root 'Address'
1077
+ #
1078
+ # map_element 'Street', to: :street
1079
+ # map_element 'City', to: :city
1080
+ # end
1081
+ # end
1082
+ # ",
1083
+ # "person" => "
1084
+ # require 'shale'
1085
+ #
1086
+ # require_relative 'address'
1087
+ #
1088
+ # class Person < Shale::Mapper
1089
+ # attribute :first_name, Shale::Type::String
1090
+ # attribute :last_name, Shale::Type::String
1091
+ # attribute :address, Address
1092
+ #
1093
+ # xml do
1094
+ # root 'Person'
1095
+ #
1096
+ # map_element 'FirstName', to: :first_name
1097
+ # map_element 'LastName', to: :last_name
1098
+ # map_element 'Address', to: :address
1099
+ # end
1100
+ # end
1101
+ # "
1102
+ # }
1103
+ ```
1104
+
1105
+ You can also use a command line tool to do it:
1106
+
1107
+ ```
1108
+ $ shaleb -c -f xml -i schema.xml
752
1109
  ```
753
1110
 
754
1111
  ## Contributing