Skip to content

Commit

Permalink
Allow to pass adapter specific options
Browse files Browse the repository at this point in the history
  • Loading branch information
kgiszczak committed Feb 24, 2024
1 parent 7d15e89 commit 7c787b3
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 40 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## [1.2.0] - [unreleased]

### Added
- Allow to pass adapter specific options

## [1.1.0] - 2024-02-17

### Added
Expand Down
31 changes: 27 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ person.to_yaml
### Converting TOML to object

To use TOML with Shale you have to set adapter you want to use.
Out of the box Shale suports [Tomlib](https://github.com/kgiszczak/tomlib).
It also comes with adapter for [toml-rb](https://github.com/emancu/toml-rb) if you prefer that.
It comes with adapters for [Tomlib](https://github.com/kgiszczak/tomlib) and
[toml-rb](https://github.com/emancu/toml-rb).
For details see [Adapters](#adapters) section.

To set it, first make sure Tomlib gem is installed:
Expand All @@ -221,8 +221,8 @@ $ gem install tomlib
then setup adapter:

```ruby
require 'tomlib'
Shale.toml_adapter = Tomlib
require 'sahle/adapter/tomlib'
Shale.toml_adapter = Shale::Adapter::Tomlib

# Alternatively if you'd like to use toml-rb, use:
require 'shale/adapter/toml_rb'
Expand Down Expand Up @@ -1085,6 +1085,29 @@ Person.to_csv(people, headers: true, col_sep: '|')
# James|Sixpack
```

Most adapters accept options specific to them. Eg. if you want to be able to work
with NaN values in JSON:

```ruby
class Person
attribute :age, Shale::Type::Float
end

person = Person.from_jsom('{"age": NaN}', allow_nan: true)

# =>
#
# #<Person:0x0000000113d7a488 @age=Float::NAN>

Person.to_json(person, allow_nan: true)

# =>
#
# {
# "age": NaN
# }
```

### Using custom models

By default Shale combines mapper and model into one class. If you want to use your own classes
Expand Down
9 changes: 5 additions & 4 deletions lib/shale.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,17 @@ class << self
# @api public
attr_writer :yaml_adapter

# TOML adapter accessor.
# TOML adapter accessor. Available adapters are Shale::Adapter::Tomlib
# and Shale::Adapter::TomRB
#
# @param [@see Shale::Adapter::TomlRB] adapter
# @param [@see Shale::Adapter::Tomlib] adapter
#
# @example setting adapter
# Shale.toml_adapter = Shale::Adapter::TomlRB
# Shale.toml_adapter = Shale::Adapter::Tomlib
#
# @example getting adapter
# Shale.toml_adapter
# # => Shale::Adapter::TomlRB
# # => Shale::Adapter::Tomlib
#
# @api public
attr_accessor :toml_adapter
Expand Down
17 changes: 10 additions & 7 deletions lib/shale/adapter/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,30 @@ class JSON
# Parse JSON into Hash
#
# @param [String] json JSON document
# @param [Hash] options
#
# @return [Hash]
#
# @api private
def self.load(json)
::JSON.parse(json)
def self.load(json, **options)
::JSON.parse(json, **options)
end

# Serialize Hash into JSON
#
# @param [Hash] obj Hash object
# @param [true, false] pretty
# @param [Hash] options
#
# @return [String]
#
# @api private
def self.dump(obj, pretty: false)
if pretty
::JSON.pretty_generate(obj)
def self.dump(obj, **options)
json_options = options.except(:pretty)

if options[:pretty]
::JSON.pretty_generate(obj, **json_options)
else
::JSON.generate(obj)
::JSON.generate(obj, **json_options)
end
end
end
Expand Down
8 changes: 5 additions & 3 deletions lib/shale/adapter/toml_rb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,31 @@

module Shale
module Adapter
# TOML adapter
# TomlRB adapter
#
# @api public
class TomlRB
# Parse TOML into Hash
#
# @param [String] toml TOML document
# @param [Hash] options
#
# @return [Hash]
#
# @api private
def self.load(toml)
def self.load(toml, **_options)
::TomlRB.parse(toml)
end

# Serialize Hash into TOML
#
# @param [Hash] obj Hash object
# @param [Hash] options
#
# @return [String]
#
# @api private
def self.dump(obj)
def self.dump(obj, **_options)
::TomlRB.dump(obj)
end
end
Expand Down
36 changes: 36 additions & 0 deletions lib/shale/adapter/tomlib.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

require 'tomlib'

module Shale
module Adapter
# Tomlib adapter
#
# @api public
class Tomlib
# Parse TOML into Hash
#
# @param [String] toml TOML document
# @param [Hash] options
#
# @return [Hash]
#
# @api private
def self.load(toml, **_options)
::Tomlib.load(toml)
end

# Serialize Hash into TOML
#
# @param [Hash] obj Hash object
# @param [Hash] options
#
# @return [String]
#
# @api private
def self.dump(obj, **options)
::Tomlib.dump(obj, **options)
end
end
end
end
3 changes: 2 additions & 1 deletion lib/shale/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ module Shale
# To use Tomlib:
# Make sure tomlib is installed eg. execute: gem install tomlib
Shale.toml_adapter = Tomlib
require 'shale/adapter/tomlib'
Shale.toml_adapter = Shale::Adapter::Tomlib
# To use toml-rb:
# Make sure toml-rb is installed eg. execute: gem install toml-rb
Expand Down
50 changes: 32 additions & 18 deletions lib/shale/type/complex.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,14 @@ def as_#{format}(instance, only: nil, except: nil, context: nil)
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [Hash] json_options
#
# @return [model instance]
#
# @api public
def from_json(json, only: nil, except: nil, context: nil)
def from_json(json, only: nil, except: nil, context: nil, **json_options)
of_json(
Shale.json_adapter.load(json),
Shale.json_adapter.load(json, **json_options),
only: only,
except: except,
context: context
Expand All @@ -277,14 +278,15 @@ def from_json(json, only: nil, except: nil, context: nil)
# @param [Array<Symbol>] except
# @param [any] context
# @param [true, false] pretty
# @param [Hash] json_options
#
# @return [String]
#
# @api public
def to_json(instance, only: nil, except: nil, context: nil, pretty: false)
def to_json(instance, only: nil, except: nil, context: nil, pretty: false, **json_options)
Shale.json_adapter.dump(
as_json(instance, only: only, except: except, context: context),
pretty: pretty
**json_options.merge(pretty: pretty)
)
end
Expand All @@ -294,13 +296,14 @@ def to_json(instance, only: nil, except: nil, context: nil, pretty: false)
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [Hash] yaml_options
#
# @return [model instance]
#
# @api public
def from_yaml(yaml, only: nil, except: nil, context: nil)
def from_yaml(yaml, only: nil, except: nil, context: nil, **yaml_options)
of_yaml(
Shale.yaml_adapter.load(yaml),
Shale.yaml_adapter.load(yaml, **yaml_options),
only: only,
except: except,
context: context
Expand All @@ -313,13 +316,15 @@ def from_yaml(yaml, only: nil, except: nil, context: nil)
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [Hash] yaml_options
#
# @return [String]
#
# @api public
def to_yaml(instance, only: nil, except: nil, context: nil)
def to_yaml(instance, only: nil, except: nil, context: nil, **yaml_options)
Shale.yaml_adapter.dump(
as_yaml(instance, only: only, except: except, context: context)
as_yaml(instance, only: only, except: except, context: context),
**yaml_options
)
end
Expand All @@ -329,14 +334,15 @@ def to_yaml(instance, only: nil, except: nil, context: nil)
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [Hash] toml_options
#
# @return [model instance]
#
# @api public
def from_toml(toml, only: nil, except: nil, context: nil)
def from_toml(toml, only: nil, except: nil, context: nil, **toml_options)
validate_toml_adapter
of_toml(
Shale.toml_adapter.load(toml),
Shale.toml_adapter.load(toml, **toml_options),
only: only,
except: except,
context: context
Expand All @@ -349,14 +355,16 @@ def from_toml(toml, only: nil, except: nil, context: nil)
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [Hash] toml_options
#
# @return [String]
#
# @api public
def to_toml(instance, only: nil, except: nil, context: nil)
def to_toml(instance, only: nil, except: nil, context: nil, **toml_options)
validate_toml_adapter
Shale.toml_adapter.dump(
as_toml(instance, only: only, except: except, context: context)
as_toml(instance, only: only, except: except, context: context),
**toml_options
)
end
Expand Down Expand Up @@ -1000,17 +1008,19 @@ def to_hash(only: nil, except: nil, context: nil)
# @param [Array<Symbol>] except
# @param [any] context
# @param [true, false] pretty
# @param [Hash] json_options
#
# @return [String]
#
# @api public
def to_json(only: nil, except: nil, context: nil, pretty: false)
def to_json(only: nil, except: nil, context: nil, pretty: false, **json_options)
self.class.to_json(
self,
only: only,
except: except,
context: context,
pretty: pretty
pretty: pretty,
**json_options
)
end
Expand All @@ -1019,32 +1029,36 @@ def to_json(only: nil, except: nil, context: nil, pretty: false)
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [Hash] yaml_options
#
# @return [String]
#
# @api public
def to_yaml(only: nil, except: nil, context: nil)
self.class.to_yaml(self, only: only, except: except, context: context)
def to_yaml(only: nil, except: nil, context: nil, **yaml_options)
self.class.to_yaml(self, only: only, except: except, context: context, **yaml_options)
end
# Convert Object to TOML
#
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [Hash] toml_options
#
# @return [String]
#
# @api public
def to_toml(only: nil, except: nil, context: nil)
self.class.to_toml(self, only: only, except: except, context: context)
def to_toml(only: nil, except: nil, context: nil, **toml_options)
self.class.to_toml(self, only: only, except: except, context: context, **toml_options)
end
# Convert Object to CSV
#
# @param [Array<Symbol>] only
# @param [Array<Symbol>] except
# @param [any] context
# @param [true, false] headers
# @param [Hash] csv_options
#
# @return [String]
#
Expand Down
10 changes: 10 additions & 0 deletions spec/shale/adapter/json_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
doc = described_class.load('{"foo": "bar"}')
expect(doc).to eq({ 'foo' => 'bar' })
end

it 'accepts extra options' do
doc = described_class.load('{"foo": NaN}', allow_nan: true)
expect(doc['foo'].nan?).to eq(true)
end
end

describe '.dump' do
Expand All @@ -30,5 +35,10 @@
expect(json).to eq(expected)
end
end

it 'accepts extra options' do
json = described_class.dump({ 'foo' => Float::NAN }, allow_nan: true)
expect(json).to eq('{"foo":NaN}')
end
end
end
Loading

0 comments on commit 7c787b3

Please sign in to comment.