shale 0.9.0 → 1.1.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 +29 -0
- data/README.md +277 -50
- data/exe/shaleb +19 -4
- data/lib/shale/adapter/nokogiri.rb +1 -1
- data/lib/shale/adapter/ox.rb +2 -1
- data/lib/shale/error.rb +32 -8
- data/lib/shale/mapper.rb +7 -7
- data/lib/shale/mapping/delegates.rb +95 -0
- data/lib/shale/mapping/descriptor/dict.rb +19 -1
- data/lib/shale/mapping/descriptor/xml.rb +13 -2
- data/lib/shale/mapping/dict.rb +15 -4
- data/lib/shale/mapping/dict_base.rb +32 -4
- data/lib/shale/mapping/dict_group.rb +1 -1
- data/lib/shale/mapping/validator.rb +10 -3
- data/lib/shale/mapping/xml.rb +22 -6
- data/lib/shale/mapping/xml_base.rb +21 -12
- data/lib/shale/schema/compiler/complex.rb +52 -8
- data/lib/shale/schema/compiler/xml_complex.rb +5 -4
- data/lib/shale/schema/json_compiler.rb +27 -13
- data/lib/shale/schema/json_generator/base.rb +9 -3
- data/lib/shale/schema/json_generator/collection.rb +17 -2
- data/lib/shale/schema/json_generator/float.rb +6 -1
- data/lib/shale/schema/json_generator/integer.rb +6 -1
- data/lib/shale/schema/json_generator/object.rb +10 -2
- data/lib/shale/schema/json_generator/string.rb +5 -1
- data/lib/shale/schema/json_generator.rb +8 -4
- data/lib/shale/schema/xml_compiler.rb +58 -30
- data/lib/shale/schema/xml_generator.rb +3 -3
- data/lib/shale/schema.rb +10 -4
- data/lib/shale/type/complex.rb +176 -24
- data/lib/shale/utils.rb +22 -4
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +12 -16
- data/shale.gemspec +3 -1
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60a0f059693d5ea371ffca8b475ebb261ee99096509e588d2f1163a96bf8fbc0
|
4
|
+
data.tar.gz: c1af0c61c7d9a93bd601188c50916d4f702228052541adee34456c4d7dac8b9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31bd59c352febaf287eda07a79f56e5fe942fd86623f532e48c25ff5e946bb53fc879c3f8bb13121989268057beb4ee740f8aac7b1275dda8b9a2d21a5f75aaf
|
7
|
+
data.tar.gz: 127b46cdeb0960643aa60410597f7ace1815dd19e3845cd0cb7c2ea3d2d44b4326333656bdf96209effcf17daabbc5a70de9f430acd42e21d961e2c356d9be9f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
## [1.1.0] - 2024-02-17
|
2
|
+
|
3
|
+
### Added
|
4
|
+
- [bkjohnson] Add support for JSON Schema validation keywords (#29)
|
5
|
+
- Add support for Ruby 3.3
|
6
|
+
|
7
|
+
### Changed
|
8
|
+
- Drop support for Ruby 2.6 and Ruby 2.7
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
- Fix Ox adapter incorrectly handling documents with XML declaration
|
12
|
+
|
13
|
+
## [1.0.0] - 2023-07-15
|
14
|
+
|
15
|
+
### Added
|
16
|
+
- Support for Ruby 3.2
|
17
|
+
- Support for delegating fields to nested attributes
|
18
|
+
- JSON and XML schema namespace mapping support
|
19
|
+
- Allow to set render_nil defaults
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
- Use `ShaleError` as a base class for exceptions
|
23
|
+
- Use model instead of mapper names for schema types
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
- Fix compilation error for bundled JSON schemas
|
27
|
+
- Fix type inference for XML schema when default namespace is used
|
28
|
+
- Fix XML schema handling with a period in the element name
|
29
|
+
|
1
30
|
## [0.9.0] - 2022-10-31
|
2
31
|
|
3
32
|
### Added
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ Documentation with interactive examples is available at [Shale website](https://
|
|
17
17
|
|
18
18
|
## Installation
|
19
19
|
|
20
|
-
Shale supports Ruby (MRI)
|
20
|
+
Shale supports Ruby (MRI) 3.0+
|
21
21
|
|
22
22
|
Add this line to your application's Gemfile:
|
23
23
|
|
@@ -63,6 +63,7 @@ $ gem install shale
|
|
63
63
|
* [Using XML namespaces](#using-xml-namespaces)
|
64
64
|
* [Rendering nil values](#rendering-nil-values)
|
65
65
|
* [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
66
|
+
* [Delegating fields to child attributes](#delegating-fields-to-child-attributes)
|
66
67
|
* [Additional options](#additional-options)
|
67
68
|
* [Using custom models](#using-custom-models)
|
68
69
|
* [Supported types](#supported-types)
|
@@ -352,6 +353,25 @@ person.to_xml
|
|
352
353
|
|
353
354
|
### Converting CSV to object
|
354
355
|
|
356
|
+
To use CSV with Shale you have to set adapter.
|
357
|
+
Shale comes with adapter for [csv](https://github.com/ruby/csv).
|
358
|
+
For details see [Adapters](#adapters) section.
|
359
|
+
|
360
|
+
To set it, first make sure CSV gem is installed:
|
361
|
+
|
362
|
+
```
|
363
|
+
$ gem install csv
|
364
|
+
```
|
365
|
+
|
366
|
+
then setup adapter:
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
require 'shale/adapter/csv'
|
370
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
371
|
+
```
|
372
|
+
|
373
|
+
Now you can use CSV with Shale.
|
374
|
+
|
355
375
|
CSV represents a flat data structure, so you can't map properties to complex types directly,
|
356
376
|
but you can use methods to map properties to complex types
|
357
377
|
(see [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
|
@@ -692,6 +712,49 @@ puts person.to_xml(pretty: true)
|
|
692
712
|
# </person>
|
693
713
|
```
|
694
714
|
|
715
|
+
If you want to change how nil values are rendered for all mappings you can use `render_nil` method:
|
716
|
+
|
717
|
+
```ruby
|
718
|
+
class Base < Shale::Mapper
|
719
|
+
json do
|
720
|
+
# change render_nil default for all JSON mappings inheriting from Base class
|
721
|
+
render_nil true
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
class Person < Base
|
726
|
+
attribute :first_name, Shale::Type::String
|
727
|
+
attribute :last_name, Shale::Type::String
|
728
|
+
attribute :age, Shale::Type::Integer
|
729
|
+
|
730
|
+
json do
|
731
|
+
# override default from Base class
|
732
|
+
render_nil false
|
733
|
+
|
734
|
+
map 'first_name', to: :first_name
|
735
|
+
map 'last_name', to: :last_name
|
736
|
+
map 'age', to: :age, render_nil: true # override default
|
737
|
+
end
|
738
|
+
end
|
739
|
+
```
|
740
|
+
|
741
|
+
:warning: The default affects only the mappings declared after setting the default value e.g.
|
742
|
+
|
743
|
+
```ruby
|
744
|
+
class Person < Base
|
745
|
+
attribute :first_name, Shale::Type::String
|
746
|
+
attribute :last_name, Shale::Type::String
|
747
|
+
|
748
|
+
json do
|
749
|
+
render_nil false
|
750
|
+
map 'first_name', to: :first_name # render_nil will be false for this mapping
|
751
|
+
|
752
|
+
render_nil true
|
753
|
+
map 'last_name', to: :last_name # render_nil will be true for this mapping
|
754
|
+
end
|
755
|
+
end
|
756
|
+
```
|
757
|
+
|
695
758
|
### Using methods to extract and generate data
|
696
759
|
|
697
760
|
If you need full controll over extracting and generating data from/to document,
|
@@ -865,6 +928,42 @@ DATA
|
|
865
928
|
# => #<Person:0x00007f9bc3086d60 @name="John Doe">
|
866
929
|
```
|
867
930
|
|
931
|
+
### Delegating fields to child attributes
|
932
|
+
|
933
|
+
To delegate fields to child complex types you can use `receiver: :child` declaration:
|
934
|
+
|
935
|
+
```ruby
|
936
|
+
class Address < Shale::Mapper
|
937
|
+
attribute :city, Shale::Type::String
|
938
|
+
attribute :street, Shale::Type::String
|
939
|
+
end
|
940
|
+
|
941
|
+
class Person < Shale::Mapper
|
942
|
+
attribute :name, Shale::Type::String
|
943
|
+
attribute :address, Address
|
944
|
+
|
945
|
+
json do
|
946
|
+
map 'name', to: :name
|
947
|
+
map 'city', to: :city, receiver: :address
|
948
|
+
map 'street', to: :street, receiver: :address
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
person = Person.from_json(<<~DATA)
|
953
|
+
{
|
954
|
+
"name": "John Doe",
|
955
|
+
"city": "London",
|
956
|
+
"street": "Oxford Street"
|
957
|
+
}
|
958
|
+
DATA
|
959
|
+
|
960
|
+
# =>
|
961
|
+
#
|
962
|
+
# #<Person:0x00007f9bc3086d60
|
963
|
+
# @name="John Doe",
|
964
|
+
# @address=#<Address:0x0000000102cbd218 @city="London", @street="Oxford Street">>
|
965
|
+
```
|
966
|
+
|
868
967
|
### Additional options
|
869
968
|
|
870
969
|
You can control which attributes to render and parse by
|
@@ -1075,7 +1174,7 @@ end
|
|
1075
1174
|
### Adapters
|
1076
1175
|
|
1077
1176
|
Shale uses adapters for parsing and generating documents.
|
1078
|
-
By default Ruby's standard JSON
|
1177
|
+
By default Ruby's standard JSON and YAML parsers are used for handling JSON and YAML documents.
|
1079
1178
|
|
1080
1179
|
You can change it by providing your own adapter. For JSON, YAML, TOML and CSV adapter must
|
1081
1180
|
implement `.load` and `.dump` class methods.
|
@@ -1103,6 +1202,14 @@ require 'shale/adapter/toml_rb'
|
|
1103
1202
|
Shale.toml_adapter = Shale::Adapter::TomlRB
|
1104
1203
|
```
|
1105
1204
|
|
1205
|
+
To handle CSV documents you have to set CSV adapter. Shale provides adapter for `csv` parser:
|
1206
|
+
|
1207
|
+
```ruby
|
1208
|
+
require 'shale'
|
1209
|
+
require 'shale/adapter/csv'
|
1210
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
1211
|
+
```
|
1212
|
+
|
1106
1213
|
To handle XML documents you have to explicitly set XML adapter.
|
1107
1214
|
Shale provides adapters for most popular Ruby XML parsers:
|
1108
1215
|
|
@@ -1208,11 +1315,82 @@ end
|
|
1208
1315
|
Shale::Schema::JSONGenerator.register_json_type(MyEmailType, MyEmailJSONType)
|
1209
1316
|
```
|
1210
1317
|
|
1318
|
+
To add validation keywords to the schema, you can use a custom model and do this:
|
1319
|
+
|
1320
|
+
```ruby
|
1321
|
+
require 'shale/schema'
|
1322
|
+
|
1323
|
+
class PersonMapper < Shale::Mapper
|
1324
|
+
model Person
|
1325
|
+
|
1326
|
+
attribute :first_name, Shale::Type::String
|
1327
|
+
attribute :last_name, Shale::Type::String
|
1328
|
+
attribute :address, Shale::Type::String
|
1329
|
+
attribute :age, Shale::Type::Integer
|
1330
|
+
|
1331
|
+
json do
|
1332
|
+
properties max_properties: 5
|
1333
|
+
|
1334
|
+
map "first_name", to: :first_name, schema: { required: true }
|
1335
|
+
map "last_name", to: :last_name, schema: { required: true }
|
1336
|
+
map "address", to: :age, schema: { max_length: 128 }
|
1337
|
+
map "age", to: :age, schema: { minimum: 1, maximum: 150 }
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
Shale::Schema.to_json(
|
1342
|
+
PersonMapper,
|
1343
|
+
pretty: true
|
1344
|
+
)
|
1345
|
+
|
1346
|
+
# =>
|
1347
|
+
#
|
1348
|
+
# {
|
1349
|
+
# "$schema": "https://json-schema.org/draft/2020-12/schema",
|
1350
|
+
# "description": "My description",
|
1351
|
+
# "$ref": "#/$defs/Person",
|
1352
|
+
# "$defs": {
|
1353
|
+
# "Person": {
|
1354
|
+
# "type": "object",
|
1355
|
+
# "maxProperties": 5,
|
1356
|
+
# "properties": {
|
1357
|
+
# "first_name": {
|
1358
|
+
# "type": "string"
|
1359
|
+
# },
|
1360
|
+
# "last_name": {
|
1361
|
+
# "type": "string"
|
1362
|
+
# },
|
1363
|
+
# "age": {
|
1364
|
+
# "type": [
|
1365
|
+
# "integer",
|
1366
|
+
# "null"
|
1367
|
+
# ],
|
1368
|
+
# "minimum": 1,
|
1369
|
+
# "maximum": 150
|
1370
|
+
# },
|
1371
|
+
# "address": {
|
1372
|
+
# "type": [
|
1373
|
+
# "string",
|
1374
|
+
# "null"
|
1375
|
+
# ],
|
1376
|
+
# "maxLength": 128
|
1377
|
+
# }
|
1378
|
+
# },
|
1379
|
+
# "required": ["first_name", "last_name"]
|
1380
|
+
# }
|
1381
|
+
# }
|
1382
|
+
# }
|
1383
|
+
```
|
1384
|
+
|
1385
|
+
Validation keywords are supported for all types, only the global `enum` and `const` types are not supported.
|
1386
|
+
|
1211
1387
|
### Compiling JSON Schema into Shale model
|
1212
1388
|
|
1213
1389
|
:warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
|
1214
1390
|
|
1215
|
-
To generate Shale data model from JSON Schema use
|
1391
|
+
To generate Shale data model from JSON Schema use `Shale::Schema.from_json`.
|
1392
|
+
You can pass `root_name: 'Foobar'` to change the name of the root type and
|
1393
|
+
`namespace_mapping: {}` to map schemas to Ruby modules:
|
1216
1394
|
|
1217
1395
|
```ruby
|
1218
1396
|
require 'shale/schema'
|
@@ -1223,7 +1401,11 @@ schema = <<~SCHEMA
|
|
1223
1401
|
"properties": {
|
1224
1402
|
"firstName": { "type": "string" },
|
1225
1403
|
"lastName": { "type": "string" },
|
1226
|
-
"address": {
|
1404
|
+
"address": { "$ref": "http://bar.com" }
|
1405
|
+
},
|
1406
|
+
"$defs": {
|
1407
|
+
"Address": {
|
1408
|
+
"$id": "http://bar.com",
|
1227
1409
|
"type": "object",
|
1228
1410
|
"properties": {
|
1229
1411
|
"street": { "type": "string" },
|
@@ -1234,38 +1416,53 @@ schema = <<~SCHEMA
|
|
1234
1416
|
}
|
1235
1417
|
SCHEMA
|
1236
1418
|
|
1237
|
-
Shale::Schema.from_json(
|
1419
|
+
Shale::Schema.from_json(
|
1420
|
+
[schema],
|
1421
|
+
root_name: 'Person',
|
1422
|
+
namespace_mapping: {
|
1423
|
+
nil => 'Api::Foo', # default schema (without ID)
|
1424
|
+
'http://bar.com' => 'Api::Bar',
|
1425
|
+
}
|
1426
|
+
)
|
1238
1427
|
|
1239
1428
|
# =>
|
1240
1429
|
#
|
1241
1430
|
# {
|
1242
|
-
# "address" => "
|
1431
|
+
# "api/bar/address" => "
|
1243
1432
|
# require 'shale'
|
1244
1433
|
#
|
1245
|
-
#
|
1246
|
-
#
|
1247
|
-
#
|
1434
|
+
# module Api
|
1435
|
+
# module Bar
|
1436
|
+
# class Address < Shale::Mapper
|
1437
|
+
# attribute :street, Shale::Type::String
|
1438
|
+
# attribute :city, Shale::Type::String
|
1248
1439
|
#
|
1249
|
-
#
|
1250
|
-
#
|
1251
|
-
#
|
1440
|
+
# json do
|
1441
|
+
# map 'street', to: :street
|
1442
|
+
# map 'city', to: :city
|
1443
|
+
# end
|
1444
|
+
# end
|
1252
1445
|
# end
|
1253
1446
|
# end
|
1254
1447
|
# ",
|
1255
|
-
# "person" => "
|
1448
|
+
# "api/foo/person" => "
|
1256
1449
|
# require 'shale'
|
1257
1450
|
#
|
1258
|
-
# require_relative 'address'
|
1451
|
+
# require_relative '../bar/address'
|
1259
1452
|
#
|
1260
|
-
#
|
1261
|
-
#
|
1262
|
-
#
|
1263
|
-
#
|
1453
|
+
# module Api
|
1454
|
+
# module Foo
|
1455
|
+
# class Person < Shale::Mapper
|
1456
|
+
# attribute :first_name, Shale::Type::String
|
1457
|
+
# attribute :last_name, Shale::Type::String
|
1458
|
+
# attribute :address, Api::Bar::Address
|
1264
1459
|
#
|
1265
|
-
#
|
1266
|
-
#
|
1267
|
-
#
|
1268
|
-
#
|
1460
|
+
# json do
|
1461
|
+
# map 'firstName', to: :first_name
|
1462
|
+
# map 'lastName', to: :last_name
|
1463
|
+
# map 'address', to: :address
|
1464
|
+
# end
|
1465
|
+
# end
|
1269
1466
|
# end
|
1270
1467
|
# end
|
1271
1468
|
# "
|
@@ -1275,7 +1472,7 @@ Shale::Schema.from_json([schema], root_name: 'Person')
|
|
1275
1472
|
You can also use a command line tool to do it:
|
1276
1473
|
|
1277
1474
|
```
|
1278
|
-
$ shaleb -c -i schema.json -r Person
|
1475
|
+
$ shaleb -c -i schema.json -r Person -m http://bar.com=Api::Bar,=Api::Foo
|
1279
1476
|
```
|
1280
1477
|
|
1281
1478
|
### Generating XML Schema
|
@@ -1346,22 +1543,39 @@ Shale::Schema::XMLGenerator.register_xml_type(MyEmailType, 'myEmailXMLType')
|
|
1346
1543
|
|
1347
1544
|
### Compiling XML Schema into Shale model
|
1348
1545
|
|
1349
|
-
To generate Shale data model from XML Schema use
|
1546
|
+
To generate Shale data model from XML Schema use `Shale::Schema.from_xml`.
|
1547
|
+
You can pass `namespace_mapping: {}` to map XML namespaces to Ruby modules:
|
1350
1548
|
|
1351
1549
|
```ruby
|
1352
1550
|
require 'shale/schema'
|
1353
1551
|
|
1354
|
-
|
1355
|
-
<xs:schema
|
1552
|
+
schema1 = <<~SCHEMA
|
1553
|
+
<xs:schema
|
1554
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
1555
|
+
xmlns:bar="http://bar.com"
|
1556
|
+
elementFormDefault="qualified"
|
1557
|
+
>
|
1558
|
+
<xs:import namespace="http://bar.com" />
|
1559
|
+
|
1356
1560
|
<xs:element name="Person" type="Person" />
|
1357
1561
|
|
1358
1562
|
<xs:complexType name="Person">
|
1359
1563
|
<xs:sequence>
|
1360
|
-
<xs:element name="
|
1361
|
-
<xs:element
|
1362
|
-
<xs:element name="Address" type="Address" />
|
1564
|
+
<xs:element name="Name" type="xs:string" />
|
1565
|
+
<xs:element ref="bar:Address" />
|
1363
1566
|
</xs:sequence>
|
1364
1567
|
</xs:complexType>
|
1568
|
+
</xs:schema>
|
1569
|
+
SCHEMA
|
1570
|
+
|
1571
|
+
schema2 = <<~SCHEMA
|
1572
|
+
<xs:schema
|
1573
|
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
1574
|
+
xmlns:bar="http://bar.com"
|
1575
|
+
targetNamespace="http://bar.com"
|
1576
|
+
elementFormDefault="qualified"
|
1577
|
+
>
|
1578
|
+
<xs:element name="Address" type="bar:Address" />
|
1365
1579
|
|
1366
1580
|
<xs:complexType name="Address">
|
1367
1581
|
<xs:sequence>
|
@@ -1372,42 +1586,55 @@ schema = <<~SCHEMA
|
|
1372
1586
|
</xs:schema>
|
1373
1587
|
SCHEMA
|
1374
1588
|
|
1375
|
-
Shale::Schema.from_xml(
|
1589
|
+
Shale::Schema.from_xml(
|
1590
|
+
[schema1, schema2],
|
1591
|
+
namespace_mapping: {
|
1592
|
+
nil => 'Api::Foo', # no namespace
|
1593
|
+
'http://bar.com' => 'Api::Bar',
|
1594
|
+
}
|
1595
|
+
)
|
1376
1596
|
|
1377
1597
|
# =>
|
1378
1598
|
#
|
1379
1599
|
# {
|
1380
|
-
# "address" => "
|
1600
|
+
# "api/bar/address" => "
|
1381
1601
|
# require 'shale'
|
1382
1602
|
#
|
1383
|
-
#
|
1384
|
-
#
|
1385
|
-
#
|
1603
|
+
# module Api
|
1604
|
+
# module Bar
|
1605
|
+
# class Address < Shale::Mapper
|
1606
|
+
# attribute :street, Shale::Type::String
|
1607
|
+
# attribute :city, Shale::Type::String
|
1386
1608
|
#
|
1387
|
-
#
|
1388
|
-
#
|
1609
|
+
# xml do
|
1610
|
+
# root 'Address'
|
1611
|
+
# namespace 'http://bar.com', 'bar'
|
1389
1612
|
#
|
1390
|
-
#
|
1391
|
-
#
|
1613
|
+
# map_element 'Street', to: :street
|
1614
|
+
# map_element 'City', to: :city
|
1615
|
+
# end
|
1616
|
+
# end
|
1392
1617
|
# end
|
1393
1618
|
# end
|
1394
1619
|
# ",
|
1395
|
-
# "person" => "
|
1620
|
+
# "api/foo/person" => "
|
1396
1621
|
# require 'shale'
|
1397
1622
|
#
|
1398
|
-
# require_relative 'address'
|
1623
|
+
# require_relative '../bar/address'
|
1399
1624
|
#
|
1400
|
-
#
|
1401
|
-
#
|
1402
|
-
#
|
1403
|
-
#
|
1625
|
+
# module Api
|
1626
|
+
# module Foo
|
1627
|
+
# class Person < Shale::Mapper
|
1628
|
+
# attribute :name, Shale::Type::String
|
1629
|
+
# attribute :address, Api::Bar::Address
|
1404
1630
|
#
|
1405
|
-
#
|
1406
|
-
#
|
1631
|
+
# xml do
|
1632
|
+
# root 'Person'
|
1407
1633
|
#
|
1408
|
-
#
|
1409
|
-
#
|
1410
|
-
#
|
1634
|
+
# map_element 'Name', to: :name
|
1635
|
+
# map_element 'Address', to: :address, prefix: 'bar', namespace: 'http://bar.com'
|
1636
|
+
# end
|
1637
|
+
# end
|
1411
1638
|
# end
|
1412
1639
|
# end
|
1413
1640
|
# "
|
@@ -1417,7 +1644,7 @@ Shale::Schema.from_xml([schema])
|
|
1417
1644
|
You can also use a command line tool to do it:
|
1418
1645
|
|
1419
1646
|
```
|
1420
|
-
$ shaleb -c -f xml -i schema.xml
|
1647
|
+
$ shaleb -c -f xml -i schema.xml -m http://bar.com=Api::Bar,=Api::Foo
|
1421
1648
|
```
|
1422
1649
|
|
1423
1650
|
## Contributing
|
data/exe/shaleb
CHANGED
@@ -36,8 +36,8 @@ ARGV << '-h' if ARGV.empty?
|
|
36
36
|
OptionParser.new do |opts|
|
37
37
|
opts.banner = <<~BANNER
|
38
38
|
Usage: shaleb [options]
|
39
|
-
example generate schema from Shale model: shaleb -g -i data_model.rb -
|
40
|
-
example generate Shale model from schema: shaleb -c -i schema1.json,schema2.json -
|
39
|
+
example generate schema from Shale model: shaleb -g -i data_model.rb -r MyRoot
|
40
|
+
example generate Shale model from schema: shaleb -c -i schema1.json,schema2.json -r MyRoot
|
41
41
|
BANNER
|
42
42
|
|
43
43
|
opts.on('-g', '--generate', 'generate schema from Shale model')
|
@@ -47,6 +47,7 @@ OptionParser.new do |opts|
|
|
47
47
|
opts.on('-r ROOT', '--root ROOT', 'Shale model class name')
|
48
48
|
opts.on('-f FORMAT', '--format FORMAT', 'Schema format: JSON (default), XML')
|
49
49
|
opts.on('-p', '--pretty', 'Pretty print generated schema')
|
50
|
+
opts.on('-m MAPPING', '--mapping', Array, 'Namespace mapping')
|
50
51
|
|
51
52
|
opts.on('-v', '--version', 'Show version') do
|
52
53
|
puts "shaleb version #{Shale::VERSION}"
|
@@ -71,11 +72,24 @@ if params[:compile]
|
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
75
|
+
if params[:mapping]
|
76
|
+
namespace_mapping = params[:mapping]
|
77
|
+
.to_h { |e| [*e.split('='), nil][0, 2] }
|
78
|
+
.transform_keys { |key| key.empty? ? nil : key }
|
79
|
+
end
|
80
|
+
|
74
81
|
if params[:format] == 'xml'
|
75
82
|
load_xml_parser
|
76
|
-
models = Shale::Schema.from_xml(
|
83
|
+
models = Shale::Schema.from_xml(
|
84
|
+
schemas,
|
85
|
+
namespace_mapping: namespace_mapping
|
86
|
+
)
|
77
87
|
else
|
78
|
-
models = Shale::Schema.from_json(
|
88
|
+
models = Shale::Schema.from_json(
|
89
|
+
schemas,
|
90
|
+
root_name: params[:root],
|
91
|
+
namespace_mapping: namespace_mapping
|
92
|
+
)
|
79
93
|
end
|
80
94
|
|
81
95
|
if params[:output]
|
@@ -84,6 +98,7 @@ if params[:compile]
|
|
84
98
|
|
85
99
|
models.each do |name, model|
|
86
100
|
output_path = File.join(dir, "#{name}.rb")
|
101
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
87
102
|
File.write(output_path, model)
|
88
103
|
end
|
89
104
|
else
|
data/lib/shale/adapter/ox.rb
CHANGED
@@ -22,7 +22,8 @@ module Shale
|
|
22
22
|
#
|
23
23
|
# @api private
|
24
24
|
def self.load(xml)
|
25
|
-
|
25
|
+
element = ::Ox.parse(xml)
|
26
|
+
Node.new(element.respond_to?(:root) ? element.root : element)
|
26
27
|
rescue ::Ox::ParseError => e
|
27
28
|
raise ParseError, "Document is invalid: #{e.message}"
|
28
29
|
end
|
data/lib/shale/error.rb
CHANGED
@@ -38,6 +38,18 @@ module Shale
|
|
38
38
|
Shale.xml_adapter = Shale::Adapter::Ox
|
39
39
|
MSG
|
40
40
|
|
41
|
+
# Error message displayed when CSV adapter is not set
|
42
|
+
# @api private
|
43
|
+
CSV_ADAPTER_NOT_SET_MESSAGE = <<~MSG
|
44
|
+
CSV Adapter is not set.
|
45
|
+
To use Shale with CSV documents you have to install parser and set adapter.
|
46
|
+
|
47
|
+
# To use csv gem:
|
48
|
+
# Make sure csv is installed eg. execute: gem install csv
|
49
|
+
require 'shale/adapter/csv'
|
50
|
+
Shale.csv_adapter = Shale::Adapter::CSV
|
51
|
+
MSG
|
52
|
+
|
41
53
|
# Error for assigning value to not existing attribute
|
42
54
|
#
|
43
55
|
# @api private
|
@@ -53,10 +65,16 @@ module Shale
|
|
53
65
|
end
|
54
66
|
end
|
55
67
|
|
68
|
+
# Shale base error class
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
class ShaleError < StandardError
|
72
|
+
end
|
73
|
+
|
56
74
|
# Error for trying to assign not callable object as an attribute's default
|
57
75
|
#
|
58
76
|
# @api private
|
59
|
-
class DefaultNotCallableError <
|
77
|
+
class DefaultNotCallableError < ShaleError
|
60
78
|
# Initialize error object
|
61
79
|
#
|
62
80
|
# @param [String] record
|
@@ -71,36 +89,42 @@ module Shale
|
|
71
89
|
# Error for passing incorrect model type
|
72
90
|
#
|
73
91
|
# @api private
|
74
|
-
class IncorrectModelError <
|
92
|
+
class IncorrectModelError < ShaleError
|
75
93
|
end
|
76
94
|
|
77
95
|
# Error for passing incorrect arguments to map functions
|
78
96
|
#
|
79
97
|
# @api private
|
80
|
-
class IncorrectMappingArgumentsError <
|
98
|
+
class IncorrectMappingArgumentsError < ShaleError
|
99
|
+
end
|
100
|
+
|
101
|
+
# Error for using incorrect type
|
102
|
+
#
|
103
|
+
# @api private
|
104
|
+
class NotAShaleMapperError < ShaleError
|
81
105
|
end
|
82
106
|
|
83
|
-
#
|
107
|
+
# Raised when receiver attribute is not defined
|
84
108
|
#
|
85
109
|
# @api private
|
86
|
-
class
|
110
|
+
class AttributeNotDefinedError < ShaleError
|
87
111
|
end
|
88
112
|
|
89
113
|
# Schema compilation error
|
90
114
|
#
|
91
115
|
# @api private
|
92
|
-
class SchemaError <
|
116
|
+
class SchemaError < ShaleError
|
93
117
|
end
|
94
118
|
|
95
119
|
# Parsing error
|
96
120
|
#
|
97
121
|
# @api private
|
98
|
-
class ParseError <
|
122
|
+
class ParseError < ShaleError
|
99
123
|
end
|
100
124
|
|
101
125
|
# Adapter error
|
102
126
|
#
|
103
127
|
# @api private
|
104
|
-
class AdapterError <
|
128
|
+
class AdapterError < ShaleError
|
105
129
|
end
|
106
130
|
end
|