shale 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +98 -2
- data/lib/shale/adapter/nokogiri.rb +1 -1
- data/lib/shale/adapter/ox.rb +2 -1
- data/lib/shale/error.rb +12 -0
- data/lib/shale/mapping/descriptor/dict.rb +10 -1
- data/lib/shale/mapping/dict.rb +4 -3
- data/lib/shale/mapping/dict_base.rb +27 -2
- 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 +7 -3
- data/lib/shale/schema/xml_compiler.rb +12 -12
- data/lib/shale/type/complex.rb +11 -0
- data/lib/shale/utils.rb +1 -1
- data/lib/shale/version.rb +1 -1
- data/lib/shale.rb +12 -16
- data/shale.gemspec +3 -1
- metadata +19 -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,15 @@ | |
| 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 | 
            +
             | 
| 1 13 | 
             
            ## [1.0.0] - 2023-07-15
         | 
| 2 14 |  | 
| 3 15 | 
             
            ### 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 |  | 
| @@ -353,6 +353,25 @@ person.to_xml | |
| 353 353 |  | 
| 354 354 | 
             
            ### Converting CSV to object
         | 
| 355 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 | 
            +
             | 
| 356 375 | 
             
            CSV represents a flat data structure, so you can't map properties to complex types directly,
         | 
| 357 376 | 
             
            but you can use methods to map properties to complex types
         | 
| 358 377 | 
             
            (see [Using methods to extract and generate data](#using-methods-to-extract-and-generate-data)
         | 
| @@ -1155,7 +1174,7 @@ end | |
| 1155 1174 | 
             
            ### Adapters
         | 
| 1156 1175 |  | 
| 1157 1176 | 
             
            Shale uses adapters for parsing and generating documents.
         | 
| 1158 | 
            -
            By default Ruby's standard JSON | 
| 1177 | 
            +
            By default Ruby's standard JSON and YAML parsers are used for handling JSON and YAML documents.
         | 
| 1159 1178 |  | 
| 1160 1179 | 
             
            You can change it by providing your own adapter. For JSON, YAML, TOML and CSV adapter must
         | 
| 1161 1180 | 
             
            implement `.load` and `.dump` class methods.
         | 
| @@ -1183,6 +1202,14 @@ require 'shale/adapter/toml_rb' | |
| 1183 1202 | 
             
            Shale.toml_adapter = Shale::Adapter::TomlRB
         | 
| 1184 1203 | 
             
            ```
         | 
| 1185 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 | 
            +
             | 
| 1186 1213 | 
             
            To handle XML documents you have to explicitly set XML adapter.
         | 
| 1187 1214 | 
             
            Shale provides adapters for most popular Ruby XML parsers:
         | 
| 1188 1215 |  | 
| @@ -1288,6 +1315,75 @@ end | |
| 1288 1315 | 
             
            Shale::Schema::JSONGenerator.register_json_type(MyEmailType, MyEmailJSONType)
         | 
| 1289 1316 | 
             
            ```
         | 
| 1290 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 | 
            +
             | 
| 1291 1387 | 
             
            ### Compiling JSON Schema into Shale model
         | 
| 1292 1388 |  | 
| 1293 1389 | 
             
            :warning: Only **[Draft 2020-12](https://json-schema.org/draft/2020-12/schema)** JSON Schema is supported
         | 
    
        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
         | 
| @@ -49,6 +49,13 @@ module Shale | |
| 49 49 | 
             
                    # @api private
         | 
| 50 50 | 
             
                    attr_reader :group
         | 
| 51 51 |  | 
| 52 | 
            +
                    # Return schema hash
         | 
| 53 | 
            +
                    #
         | 
| 54 | 
            +
                    # @return [Hash]
         | 
| 55 | 
            +
                    #
         | 
| 56 | 
            +
                    # @api private
         | 
| 57 | 
            +
                    attr_reader :schema
         | 
| 58 | 
            +
             | 
| 52 59 | 
             
                    # Initialize instance
         | 
| 53 60 | 
             
                    #
         | 
| 54 61 | 
             
                    # @param [String] name
         | 
| @@ -57,14 +64,16 @@ module Shale | |
| 57 64 | 
             
                    # @param [Hash, nil] methods
         | 
| 58 65 | 
             
                    # @param [String, nil] group
         | 
| 59 66 | 
             
                    # @param [true, false] render_nil
         | 
| 67 | 
            +
                    # @param [Hash, nil] schema
         | 
| 60 68 | 
             
                    #
         | 
| 61 69 | 
             
                    # @api private
         | 
| 62 | 
            -
                    def initialize(name:, attribute:, receiver:, methods:, group:, render_nil:)
         | 
| 70 | 
            +
                    def initialize(name:, attribute:, receiver:, methods:, group:, render_nil:, schema: nil)
         | 
| 63 71 | 
             
                      @name = name
         | 
| 64 72 | 
             
                      @attribute = attribute
         | 
| 65 73 | 
             
                      @receiver = receiver
         | 
| 66 74 | 
             
                      @group = group
         | 
| 67 75 | 
             
                      @render_nil = render_nil
         | 
| 76 | 
            +
                      @schema = schema
         | 
| 68 77 |  | 
| 69 78 | 
             
                      if methods
         | 
| 70 79 | 
             
                        @method_from = methods[:from]
         | 
    
        data/lib/shale/mapping/dict.rb
    CHANGED
    
    | @@ -16,12 +16,13 @@ module Shale | |
| 16 16 | 
             
                  # @param [Symbol, nil] receiver
         | 
| 17 17 | 
             
                  # @param [Hash, nil] using
         | 
| 18 18 | 
             
                  # @param [true, false, nil] render_nil
         | 
| 19 | 
            +
                  # @param [Hash, nil] schema
         | 
| 19 20 | 
             
                  #
         | 
| 20 21 | 
             
                  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
         | 
| 21 22 | 
             
                  #
         | 
| 22 | 
            -
                  # @api  | 
| 23 | 
            -
                  def map(key, to: nil, receiver: nil, using: nil, render_nil: nil)
         | 
| 24 | 
            -
                    super(key, to: to, receiver: receiver, using: using, render_nil: render_nil)
         | 
| 23 | 
            +
                  # @api public
         | 
| 24 | 
            +
                  def map(key, to: nil, receiver: nil, using: nil, render_nil: nil, schema: nil)
         | 
| 25 | 
            +
                    super(key, to: to, receiver: receiver, using: using, render_nil: render_nil, schema: schema)
         | 
| 25 26 | 
             
                  end
         | 
| 26 27 |  | 
| 27 28 | 
             
                  # Set render_nil default
         | 
| @@ -16,6 +16,13 @@ module Shale | |
| 16 16 | 
             
                  # @api private
         | 
| 17 17 | 
             
                  attr_reader :keys
         | 
| 18 18 |  | 
| 19 | 
            +
                  # Return hash for hash with properties for root Object
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  # @return [Hash]
         | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  # @api private
         | 
| 24 | 
            +
                  attr_reader :root
         | 
| 25 | 
            +
             | 
| 19 26 | 
             
                  # Initialize instance
         | 
| 20 27 | 
             
                  #
         | 
| 21 28 | 
             
                  # @param [true, false] render_nil_default
         | 
| @@ -23,6 +30,7 @@ module Shale | |
| 23 30 | 
             
                  # @api private
         | 
| 24 31 | 
             
                  def initialize(render_nil_default: false)
         | 
| 25 32 | 
             
                    @keys = {}
         | 
| 33 | 
            +
                    @root = {}
         | 
| 26 34 | 
             
                    @finalized = false
         | 
| 27 35 | 
             
                    @render_nil_default = render_nil_default
         | 
| 28 36 | 
             
                  end
         | 
| @@ -35,11 +43,12 @@ module Shale | |
| 35 43 | 
             
                  # @param [Hash, nil] using
         | 
| 36 44 | 
             
                  # @param [String, nil] group
         | 
| 37 45 | 
             
                  # @param [true, false, nil] render_nil
         | 
| 46 | 
            +
                  # @param [Hash, nil] schema
         | 
| 38 47 | 
             
                  #
         | 
| 39 48 | 
             
                  # @raise [IncorrectMappingArgumentsError] when arguments are incorrect
         | 
| 40 49 | 
             
                  #
         | 
| 41 50 | 
             
                  # @api private
         | 
| 42 | 
            -
                  def map(key, to: nil, receiver: nil, using: nil, group: nil, render_nil: nil)
         | 
| 51 | 
            +
                  def map(key, to: nil, receiver: nil, using: nil, group: nil, render_nil: nil, schema: nil)
         | 
| 43 52 | 
             
                    Validator.validate_arguments(key, to, receiver, using)
         | 
| 44 53 |  | 
| 45 54 | 
             
                    @keys[key] = Descriptor::Dict.new(
         | 
| @@ -48,10 +57,26 @@ module Shale | |
| 48 57 | 
             
                      receiver: receiver,
         | 
| 49 58 | 
             
                      methods: using,
         | 
| 50 59 | 
             
                      group: group,
         | 
| 51 | 
            -
                      render_nil: render_nil.nil? ? @render_nil_default : render_nil
         | 
| 60 | 
            +
                      render_nil: render_nil.nil? ? @render_nil_default : render_nil,
         | 
| 61 | 
            +
                      schema: schema
         | 
| 52 62 | 
             
                    )
         | 
| 53 63 | 
             
                  end
         | 
| 54 64 |  | 
| 65 | 
            +
                  # Allow schema properties to be set on the object
         | 
| 66 | 
            +
                  #
         | 
| 67 | 
            +
                  # @param [Integer] min_properties
         | 
| 68 | 
            +
                  # @param [Integer] max_properties
         | 
| 69 | 
            +
                  # @param [Hash] dependent_required
         | 
| 70 | 
            +
                  #
         | 
| 71 | 
            +
                  # @api public
         | 
| 72 | 
            +
                  def properties(min_properties: nil, max_properties: nil, dependent_required: nil)
         | 
| 73 | 
            +
                    @root = {
         | 
| 74 | 
            +
                      min_properties: min_properties,
         | 
| 75 | 
            +
                      max_properties: max_properties,
         | 
| 76 | 
            +
                      dependent_required: dependent_required,
         | 
| 77 | 
            +
                    }
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 55 80 | 
             
                  # Set the "finalized" instance variable to true
         | 
| 56 81 | 
             
                  #
         | 
| 57 82 | 
             
                  # @api private
         | 
| @@ -12,15 +12,21 @@ module Shale | |
| 12 12 | 
             
                    # @api private
         | 
| 13 13 | 
             
                    attr_reader :name
         | 
| 14 14 |  | 
| 15 | 
            -
                    # Return  | 
| 15 | 
            +
                    # Return schema hash
         | 
| 16 | 
            +
                    #
         | 
| 17 | 
            +
                    # @api private
         | 
| 18 | 
            +
                    attr_reader :schema
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    # Set nullable
         | 
| 16 21 | 
             
                    #
         | 
| 17 22 | 
             
                    # @api private
         | 
| 18 23 | 
             
                    attr_writer :nullable
         | 
| 19 24 |  | 
| 20 | 
            -
                    def initialize(name, default: nil)
         | 
| 25 | 
            +
                    def initialize(name, default: nil, schema: nil)
         | 
| 21 26 | 
             
                      @name = name.gsub('::', '_')
         | 
| 22 27 | 
             
                      @default = default
         | 
| 23 | 
            -
                      @ | 
| 28 | 
            +
                      @schema = schema || {}
         | 
| 29 | 
            +
                      @nullable = !schema&.[](:required)
         | 
| 24 30 | 
             
                    end
         | 
| 25 31 |  | 
| 26 32 | 
             
                    # Return JSON Schema fragment as Ruby Hash
         | 
| @@ -7,13 +7,20 @@ module Shale | |
| 7 7 | 
             
                  #
         | 
| 8 8 | 
             
                  # @api private
         | 
| 9 9 | 
             
                  class Collection
         | 
| 10 | 
            +
                    # Return schema hash
         | 
| 11 | 
            +
                    #
         | 
| 12 | 
            +
                    # @api private
         | 
| 13 | 
            +
                    attr_reader :schema
         | 
| 14 | 
            +
             | 
| 10 15 | 
             
                    # Initialize Collection object
         | 
| 11 16 | 
             
                    #
         | 
| 12 17 | 
             
                    # @param [Shale::Schema::JSONGenerator::Base] type
         | 
| 18 | 
            +
                    # @param [Hash] schema
         | 
| 13 19 | 
             
                    #
         | 
| 14 20 | 
             
                    # @api private
         | 
| 15 | 
            -
                    def initialize(type)
         | 
| 21 | 
            +
                    def initialize(type, schema: nil)
         | 
| 16 22 | 
             
                      @type = type
         | 
| 23 | 
            +
                      @schema = schema
         | 
| 17 24 | 
             
                    end
         | 
| 18 25 |  | 
| 19 26 | 
             
                    # Delegate name to wrapped type object
         | 
| @@ -31,7 +38,15 @@ module Shale | |
| 31 38 | 
             
                    #
         | 
| 32 39 | 
             
                    # @api private
         | 
| 33 40 | 
             
                    def as_json
         | 
| 34 | 
            -
                       | 
| 41 | 
            +
                      schema = @schema || {}
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                      { 'type' => 'array',
         | 
| 44 | 
            +
                        'items' => @type.as_type,
         | 
| 45 | 
            +
                        'minItems' => schema[:min_items],
         | 
| 46 | 
            +
                        'maxItems' => schema[:max_items],
         | 
| 47 | 
            +
                        'uniqueItems' => schema[:unique],
         | 
| 48 | 
            +
                        'minContains' => schema[:min_contains],
         | 
| 49 | 
            +
                        'maxContains' => schema[:max_contains] }.compact
         | 
| 35 50 | 
             
                    end
         | 
| 36 51 | 
             
                  end
         | 
| 37 52 | 
             
                end
         | 
| @@ -15,7 +15,12 @@ module Shale | |
| 15 15 | 
             
                    #
         | 
| 16 16 | 
             
                    # @api private
         | 
| 17 17 | 
             
                    def as_type
         | 
| 18 | 
            -
                      { 'type' => 'number' | 
| 18 | 
            +
                      { 'type' => 'number',
         | 
| 19 | 
            +
                        'exclusiveMinimum' => schema[:exclusive_minimum],
         | 
| 20 | 
            +
                        'exclusiveMaximum' => schema[:exclusive_maximum],
         | 
| 21 | 
            +
                        'minimum' => schema[:minimum],
         | 
| 22 | 
            +
                        'maximum' => schema[:maximum],
         | 
| 23 | 
            +
                        'multipleOf' => schema[:multiple_of] }.compact
         | 
| 19 24 | 
             
                    end
         | 
| 20 25 | 
             
                  end
         | 
| 21 26 | 
             
                end
         | 
| @@ -15,7 +15,12 @@ module Shale | |
| 15 15 | 
             
                    #
         | 
| 16 16 | 
             
                    # @api private
         | 
| 17 17 | 
             
                    def as_type
         | 
| 18 | 
            -
                      { 'type' => 'integer' | 
| 18 | 
            +
                      { 'type' => 'integer',
         | 
| 19 | 
            +
                        'exclusiveMinimum' => schema[:exclusive_minimum],
         | 
| 20 | 
            +
                        'exclusiveMaximum' => schema[:exclusive_maximum],
         | 
| 21 | 
            +
                        'minimum' => schema[:minimum],
         | 
| 22 | 
            +
                        'maximum' => schema[:maximum],
         | 
| 23 | 
            +
                        'multipleOf' => schema[:multiple_of] }.compact
         | 
| 19 24 | 
             
                    end
         | 
| 20 25 | 
             
                  end
         | 
| 21 26 | 
             
                end
         | 
| @@ -16,10 +16,12 @@ module Shale | |
| 16 16 | 
             
                    #   Array<Shale::Schema::JSONGenerator::Base,
         | 
| 17 17 | 
             
                    #   Shale::Schema::JSONGenerator::Collection>
         | 
| 18 18 | 
             
                    # ] properties
         | 
| 19 | 
            +
                    # @param [Hash] root
         | 
| 19 20 | 
             
                    #
         | 
| 20 21 | 
             
                    # @api private
         | 
| 21 | 
            -
                    def initialize(name, properties)
         | 
| 22 | 
            +
                    def initialize(name, properties, root)
         | 
| 22 23 | 
             
                      super(name)
         | 
| 24 | 
            +
                      @root = root
         | 
| 23 25 | 
             
                      @properties = properties
         | 
| 24 26 | 
             
                    end
         | 
| 25 27 |  | 
| @@ -29,10 +31,16 @@ module Shale | |
| 29 31 | 
             
                    #
         | 
| 30 32 | 
             
                    # @api private
         | 
| 31 33 | 
             
                    def as_type
         | 
| 34 | 
            +
                      required_props = @properties.filter_map { |prop| prop.name if prop&.schema&.[](:required) }
         | 
| 35 | 
            +
             | 
| 32 36 | 
             
                      {
         | 
| 33 37 | 
             
                        'type' => 'object',
         | 
| 34 38 | 
             
                        'properties' => @properties.to_h { |el| [el.name, el.as_json] },
         | 
| 35 | 
            -
             | 
| 39 | 
            +
                        'required' => required_props.empty? ? nil : required_props,
         | 
| 40 | 
            +
                        'minProperties' => @root[:min_properties],
         | 
| 41 | 
            +
                        'maxProperties' => @root[:max_properties],
         | 
| 42 | 
            +
                        'dependentRequired' => @root[:dependent_required],
         | 
| 43 | 
            +
                      }.compact
         | 
| 36 44 | 
             
                    end
         | 
| 37 45 | 
             
                  end
         | 
| 38 46 | 
             
                end
         | 
| @@ -15,7 +15,11 @@ module Shale | |
| 15 15 | 
             
                    #
         | 
| 16 16 | 
             
                    # @api private
         | 
| 17 17 | 
             
                    def as_type
         | 
| 18 | 
            -
                      { 'type' => 'string' | 
| 18 | 
            +
                      { 'type' => 'string',
         | 
| 19 | 
            +
                        'format' => schema[:format],
         | 
| 20 | 
            +
                        'minLength' => schema[:min_length],
         | 
| 21 | 
            +
                        'maxLength' => schema[:max_length],
         | 
| 22 | 
            +
                        'pattern' => schema[:pattern] }.compact
         | 
| 19 23 | 
             
                    end
         | 
| 20 24 | 
             
                  end
         | 
| 21 25 | 
             
                end
         | 
| @@ -96,14 +96,18 @@ module Shale | |
| 96 96 | 
             
                            default = attribute.type.as_json(value)
         | 
| 97 97 | 
             
                          end
         | 
| 98 98 |  | 
| 99 | 
            -
                          json_type = json_klass.new( | 
| 99 | 
            +
                          json_type = json_klass.new(
         | 
| 100 | 
            +
                            mapping.name,
         | 
| 101 | 
            +
                            default: default,
         | 
| 102 | 
            +
                            schema: mapping.schema
         | 
| 103 | 
            +
                          )
         | 
| 100 104 | 
             
                        end
         | 
| 101 105 |  | 
| 102 | 
            -
                        json_type = Collection.new(json_type) if attribute.collection?
         | 
| 106 | 
            +
                        json_type = Collection.new(json_type, schema: mapping.schema) if attribute.collection?
         | 
| 103 107 | 
             
                        properties << json_type
         | 
| 104 108 | 
             
                      end
         | 
| 105 109 |  | 
| 106 | 
            -
                      objects << Object.new(type.model.name, properties)
         | 
| 110 | 
            +
                      objects << Object.new(type.model.name, properties, type.json_mapping.root)
         | 
| 107 111 | 
             
                    end
         | 
| 108 112 |  | 
| 109 113 | 
             
                    Schema.new(objects, id: id, title: title, description: description).as_json
         | 
| @@ -34,51 +34,51 @@ module Shale | |
| 34 34 |  | 
| 35 35 | 
             
                  # XML Schema "schema" element name
         | 
| 36 36 | 
             
                  # @api private
         | 
| 37 | 
            -
                  XS_SCHEMA = "#{XS_NAMESPACE_URI}:schema"
         | 
| 37 | 
            +
                  XS_SCHEMA = "#{XS_NAMESPACE_URI}:schema".freeze
         | 
| 38 38 |  | 
| 39 39 | 
             
                  # XML Schema "element" element name
         | 
| 40 40 | 
             
                  # @api private
         | 
| 41 | 
            -
                  XS_ELEMENT = "#{XS_NAMESPACE_URI}:element"
         | 
| 41 | 
            +
                  XS_ELEMENT = "#{XS_NAMESPACE_URI}:element".freeze
         | 
| 42 42 |  | 
| 43 43 | 
             
                  # XML Schema "attribute" element name
         | 
| 44 44 | 
             
                  # @api private
         | 
| 45 | 
            -
                  XS_ATTRIBUTE = "#{XS_NAMESPACE_URI}:attribute"
         | 
| 45 | 
            +
                  XS_ATTRIBUTE = "#{XS_NAMESPACE_URI}:attribute".freeze
         | 
| 46 46 |  | 
| 47 47 | 
             
                  # XML Schema "attribute" element name
         | 
| 48 48 | 
             
                  # @api private
         | 
| 49 | 
            -
                  XS_SIMPLE_TYPE = "#{XS_NAMESPACE_URI}:simpleType"
         | 
| 49 | 
            +
                  XS_SIMPLE_TYPE = "#{XS_NAMESPACE_URI}:simpleType".freeze
         | 
| 50 50 |  | 
| 51 51 | 
             
                  # XML Schema "simpleContent" element name
         | 
| 52 52 | 
             
                  # @api private
         | 
| 53 | 
            -
                  XS_SIMPLE_CONTENT = "#{XS_NAMESPACE_URI}:simpleContent"
         | 
| 53 | 
            +
                  XS_SIMPLE_CONTENT = "#{XS_NAMESPACE_URI}:simpleContent".freeze
         | 
| 54 54 |  | 
| 55 55 | 
             
                  # XML Schema "restriction" element name
         | 
| 56 56 | 
             
                  # @api private
         | 
| 57 | 
            -
                  XS_RESTRICTION = "#{XS_NAMESPACE_URI}:restriction"
         | 
| 57 | 
            +
                  XS_RESTRICTION = "#{XS_NAMESPACE_URI}:restriction".freeze
         | 
| 58 58 |  | 
| 59 59 | 
             
                  # XML Schema "group" element name
         | 
| 60 60 | 
             
                  # @api private
         | 
| 61 | 
            -
                  XS_GROUP = "#{XS_NAMESPACE_URI}:group"
         | 
| 61 | 
            +
                  XS_GROUP = "#{XS_NAMESPACE_URI}:group".freeze
         | 
| 62 62 |  | 
| 63 63 | 
             
                  # XML Schema "attributeGroup" element name
         | 
| 64 64 | 
             
                  # @api private
         | 
| 65 | 
            -
                  XS_ATTRIBUTE_GROUP = "#{XS_NAMESPACE_URI}:attributeGroup"
         | 
| 65 | 
            +
                  XS_ATTRIBUTE_GROUP = "#{XS_NAMESPACE_URI}:attributeGroup".freeze
         | 
| 66 66 |  | 
| 67 67 | 
             
                  # XML Schema "complexType" element name
         | 
| 68 68 | 
             
                  # @api private
         | 
| 69 | 
            -
                  XS_COMPLEX_TYPE = "#{XS_NAMESPACE_URI}:complexType"
         | 
| 69 | 
            +
                  XS_COMPLEX_TYPE = "#{XS_NAMESPACE_URI}:complexType".freeze
         | 
| 70 70 |  | 
| 71 71 | 
             
                  # XML Schema "complexContent" element name
         | 
| 72 72 | 
             
                  # @api private
         | 
| 73 | 
            -
                  XS_COMPLEX_CONTENT = "#{XS_NAMESPACE_URI}:complexContent"
         | 
| 73 | 
            +
                  XS_COMPLEX_CONTENT = "#{XS_NAMESPACE_URI}:complexContent".freeze
         | 
| 74 74 |  | 
| 75 75 | 
             
                  # XML Schema "extension" element name
         | 
| 76 76 | 
             
                  # @api private
         | 
| 77 | 
            -
                  XS_EXTENSION = "#{XS_NAMESPACE_URI}:extension"
         | 
| 77 | 
            +
                  XS_EXTENSION = "#{XS_NAMESPACE_URI}:extension".freeze
         | 
| 78 78 |  | 
| 79 79 | 
             
                  # XML Schema "anyType" type
         | 
| 80 80 | 
             
                  # @api private
         | 
| 81 | 
            -
                  XS_TYPE_ANY = "#{XS_NAMESPACE_URI}:anyType"
         | 
| 81 | 
            +
                  XS_TYPE_ANY = "#{XS_NAMESPACE_URI}:anyType".freeze
         | 
| 82 82 |  | 
| 83 83 | 
             
                  # XML Schema "date" types
         | 
| 84 84 | 
             
                  # @api private
         | 
    
        data/lib/shale/type/complex.rb
    CHANGED
    
    | @@ -373,6 +373,7 @@ module Shale | |
| 373 373 | 
             
                    #
         | 
| 374 374 | 
             
                    # @api public
         | 
| 375 375 | 
             
                    def from_csv(csv, only: nil, except: nil, context: nil, headers: false, **csv_options)
         | 
| 376 | 
            +
                      validate_csv_adapter
         | 
| 376 377 | 
             
                      data = Shale.csv_adapter.load(csv, **csv_options.merge(headers: csv_mapping.keys.keys))
         | 
| 377 378 |  | 
| 378 379 | 
             
                      data.shift if headers
         | 
| @@ -398,6 +399,7 @@ module Shale | |
| 398 399 | 
             
                    #
         | 
| 399 400 | 
             
                    # @api public
         | 
| 400 401 | 
             
                    def to_csv(instance, only: nil, except: nil, context: nil, headers: false, **csv_options)
         | 
| 402 | 
            +
                      validate_csv_adapter
         | 
| 401 403 | 
             
                      data = as_csv([*instance], only: only, except: except, context: context)
         | 
| 402 404 |  | 
| 403 405 | 
             
                      cols = csv_mapping.keys.values
         | 
| @@ -892,6 +894,15 @@ module Shale | |
| 892 894 | 
             
                      raise AdapterError, XML_ADAPTER_NOT_SET_MESSAGE unless Shale.xml_adapter
         | 
| 893 895 | 
             
                    end
         | 
| 894 896 |  | 
| 897 | 
            +
                    # Validate CSV adapter
         | 
| 898 | 
            +
                    #
         | 
| 899 | 
            +
                    # @raise [AdapterError]
         | 
| 900 | 
            +
                    #
         | 
| 901 | 
            +
                    # @api private
         | 
| 902 | 
            +
                    def validate_csv_adapter
         | 
| 903 | 
            +
                      raise AdapterError, CSV_ADAPTER_NOT_SET_MESSAGE unless Shale.csv_adapter
         | 
| 904 | 
            +
                    end
         | 
| 905 | 
            +
             | 
| 895 906 | 
             
                    # Convert array with attributes to a hash
         | 
| 896 907 | 
             
                    #
         | 
| 897 908 | 
             
                    # @param [Array] ary
         | 
    
        data/lib/shale/utils.rb
    CHANGED
    
    | @@ -31,7 +31,7 @@ module Shale | |
| 31 31 | 
             
                # @api private
         | 
| 32 32 | 
             
                def self.classify(str)
         | 
| 33 33 | 
             
                  # names may include a period, which will need to be stripped out
         | 
| 34 | 
            -
                  str = str.to_s.gsub( | 
| 34 | 
            +
                  str = str.to_s.gsub('.', '')
         | 
| 35 35 |  | 
| 36 36 | 
             
                  str = str.sub(/^[a-z\d]*/) { |match| upcase_first(match) || match }
         | 
| 37 37 |  | 
    
        data/lib/shale/version.rb
    CHANGED
    
    
    
        data/lib/shale.rb
    CHANGED
    
    | @@ -3,7 +3,6 @@ | |
| 3 3 | 
             
            require 'yaml'
         | 
| 4 4 |  | 
| 5 5 | 
             
            require_relative 'shale/mapper'
         | 
| 6 | 
            -
            require_relative 'shale/adapter/csv'
         | 
| 7 6 | 
             
            require_relative 'shale/adapter/json'
         | 
| 8 7 | 
             
            require_relative 'shale/type/boolean'
         | 
| 9 8 | 
             
            require_relative 'shale/type/date'
         | 
| @@ -52,6 +51,12 @@ require_relative 'shale/version' | |
| 52 51 | 
             
            #   Shale.xml_adapter = Shale::Adapter::Ox
         | 
| 53 52 | 
             
            #   Shale.xml_adapter # => Shale::Adapter::Ox
         | 
| 54 53 | 
             
            #
         | 
| 54 | 
            +
            # @example setting CSV adapter for handling CSV documents
         | 
| 55 | 
            +
            #   require 'shale/adapter/csv'
         | 
| 56 | 
            +
            #
         | 
| 57 | 
            +
            #   Shale.csv_adapter = Shale::Adapter::CSV
         | 
| 58 | 
            +
            #   Shale.csv_adapter # => Shale::Adapter::CSV
         | 
| 59 | 
            +
            #
         | 
| 55 60 | 
             
            # @api public
         | 
| 56 61 | 
             
            module Shale
         | 
| 57 62 | 
             
              class << self
         | 
| @@ -93,11 +98,15 @@ module Shale | |
| 93 98 | 
             
                #
         | 
| 94 99 | 
             
                # @param [.load, .dump] adapter
         | 
| 95 100 | 
             
                #
         | 
| 96 | 
            -
                # @example
         | 
| 101 | 
            +
                # @example setting adapter
         | 
| 97 102 | 
             
                #   Shale.csv_adapter = Shale::Adapter::CSV
         | 
| 98 103 | 
             
                #
         | 
| 104 | 
            +
                # @example getting adapter
         | 
| 105 | 
            +
                #   Shale.csv_adapter
         | 
| 106 | 
            +
                #   # => Shale::Adapter::CSV
         | 
| 107 | 
            +
                #
         | 
| 99 108 | 
             
                # @api public
         | 
| 100 | 
            -
                 | 
| 109 | 
            +
                attr_accessor :csv_adapter
         | 
| 101 110 |  | 
| 102 111 | 
             
                # XML adapter accessor. Available adapters are Shale::Adapter::REXML,
         | 
| 103 112 | 
             
                # Shale::Adapter::Nokogiri and Shale::Adapter::Ox
         | 
| @@ -139,18 +148,5 @@ module Shale | |
| 139 148 | 
             
                def yaml_adapter
         | 
| 140 149 | 
             
                  @yaml_adapter || YAML
         | 
| 141 150 | 
             
                end
         | 
| 142 | 
            -
             | 
| 143 | 
            -
                # Return CSV adapter. By default CSV is used
         | 
| 144 | 
            -
                #
         | 
| 145 | 
            -
                # @return [.load, .dump]
         | 
| 146 | 
            -
                #
         | 
| 147 | 
            -
                # @example
         | 
| 148 | 
            -
                #   Shale.csv_adapter
         | 
| 149 | 
            -
                #   # => Shale::Adapter::CSV
         | 
| 150 | 
            -
                #
         | 
| 151 | 
            -
                # @api public
         | 
| 152 | 
            -
                def csv_adapter
         | 
| 153 | 
            -
                  @csv_adapter || Adapter::CSV
         | 
| 154 | 
            -
                end
         | 
| 155 151 | 
             
              end
         | 
| 156 152 | 
             
            end
         | 
    
        data/shale.gemspec
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,15 +1,29 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: shale
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Kamil Giszczak
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 12 | 
            -
            dependencies: | 
| 11 | 
            +
            date: 2024-02-17 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: bigdecimal
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 13 27 | 
             
            description: Ruby object mapper and serializer for XML, JSON, TOML, CSV and YAML.
         | 
| 14 28 | 
             
            email:
         | 
| 15 29 | 
             
            - beerkg@gmail.com
         | 
| @@ -118,14 +132,14 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 118 132 | 
             
              requirements:
         | 
| 119 133 | 
             
              - - ">="
         | 
| 120 134 | 
             
                - !ruby/object:Gem::Version
         | 
| 121 | 
            -
                  version:  | 
| 135 | 
            +
                  version: 3.0.0
         | 
| 122 136 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 123 137 | 
             
              requirements:
         | 
| 124 138 | 
             
              - - ">="
         | 
| 125 139 | 
             
                - !ruby/object:Gem::Version
         | 
| 126 140 | 
             
                  version: '0'
         | 
| 127 141 | 
             
            requirements: []
         | 
| 128 | 
            -
            rubygems_version: 3. | 
| 142 | 
            +
            rubygems_version: 3.5.3
         | 
| 129 143 | 
             
            signing_key:
         | 
| 130 144 | 
             
            specification_version: 4
         | 
| 131 145 | 
             
            summary: Ruby object mapper and serializer for XML, JSON, TOML, CSV and YAML.
         |