Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
decanter (5.0.0)
decanter (5.1.0)
actionpack (>= 7.1.3.2)
activesupport
rails (>= 7.1.3.2)
Expand Down
46 changes: 31 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,31 @@ gem 'decanter', '~> 5.0'

## Contents

- [Basic Usage](#basic-usage)
- [Decanters](#decanters)
- [Generators](#generators)
- [Decanting Collections](#decanting-collections)
- [Nested resources](#nested-resources)
- [Default parsers](#default-parsers)
- [Parser options](#parser-options)
- [Exceptions](#exceptions)
- [Advanced usage](#advanced-usage)
- [Custom parsers](#custom-parsers)
- [Squashing inputs](#squashing-inputs)
- [Chaining parsers](#chaining-parsers)
- [Requiring params](#requiring-params)
- [Global configuration](#global-configuration)
- [Contributing](#contributing)
- [Decanter](#decanter)
- [Migration Guides](#migration-guides)
- [Contents](#contents)
- [Basic Usage](#basic-usage)
- [Decanters](#decanters)
- [Generators](#generators)
- [Decanters](#decanters-1)
- [Parsers](#parsers)
- [Resources](#resources)
- [Decanting Collections](#decanting-collections)
- [Control Over Decanting Collections](#control-over-decanting-collections)
- [Nested resources](#nested-resources)
- [Default parsers](#default-parsers)
- [Parser options](#parser-options)
- [Exceptions](#exceptions)
- [Advanced Usage](#advanced-usage)
- [Custom Parsers](#custom-parsers)
- [Custom parser methods](#custom-parser-methods)
- [Custom parser base classes](#custom-parser-base-classes)
- [Squashing inputs](#squashing-inputs)
- [Chaining parsers](#chaining-parsers)
- [Requiring params](#requiring-params)
- [Default values](#default-values)
- [Global configuration](#global-configuration)
- [Contributing](#contributing)
Comment on lines +15 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just formatting


## Basic Usage

Expand Down Expand Up @@ -163,13 +173,19 @@ Decanter comes with the following parsers out of the box:
- `:phone`
- `:string`
- `:array`
- `:json`

Note: these parsers are designed to operate on a single value, except for `:array`. This parser expects an array, and will use the `parse_each` option to call a given parser on each of its elements:

```ruby
input :ids, :array, parse_each: :integer
```

The `:json` parser may also accept an array, but the array must be provided as a single JSON-encoded string value:
```
'["abc", "def"]'
```

### Parser options

Some parsers can receive options that modify their behavior. These options are passed in as named arguments to `input`:
Expand Down
20 changes: 20 additions & 0 deletions lib/decanter/parser/json_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Decanter
module Parser
class JsonParser < ValueParser
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should inherit from HashParser

See https://github.com/LaunchPadLab/decanter#custom-parser-base-classes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that doesn't account for the fact that it could be an array. NVM!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea it turns out that JSON is anything lol


Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since json is not a native Ruby data type, there is no specific allowed types. Instead all values passed to this parser will be parsed by JSON.parse(val), unless they are nil or blank strings.

parser do |val, options|
next if val.nil? || val === ''
raise Decanter::ParseError.new 'Expects a JSON string' unless val.is_a?(String)
parse_json(val)
end

def self.parse_json(val)
begin
JSON.parse(val)
rescue
raise Decanter::ParseError.new 'Invalid JSON string'
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/decanter/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Decanter
VERSION = '5.0.0'.freeze
VERSION = '5.1.0'.freeze
end
48 changes: 48 additions & 0 deletions spec/decanter/parser/json_parser_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'spec_helper'

describe 'JsonParser' do

let(:name) { :foo }

let(:parser) { Decanter::Parser::JsonParser }

describe '#parse' do

context 'with a valid JSON string' do
it 'parses the string value and returns a parsed JSON' do
expect(parser.parse(name, '{"key": "value"}')).to match({name => {"key" => "value"}})
expect(parser.parse(name, '["hello", "goodbye"]')).to match({name => ["hello", "goodbye"]})
end
end

context 'with empty string' do
it 'returns nil' do
expect(parser.parse(name, '')).to match({name => nil})
end
end

context 'with nil' do
it 'returns nil' do
expect(parser.parse(name, nil)).to match({name => nil})
end
end

context 'with a non-string value' do
it 'raises a Decanter::ParseError' do
expect { parser.parse(name, 1) }.to raise_error(Decanter::ParseError, 'Expects a JSON string')
expect { parser.parse(name, true) }.to raise_error(Decanter::ParseError, 'Expects a JSON string')
expect { parser.parse(name, {}) }.to raise_error(Decanter::ParseError, 'Expects a JSON string')
end
end

context 'with a string that is invalid JSON' do
json_parser_error = 'Invalid JSON string'
it 'raises a Decanter::ParseError' do
expect { parser.parse(name, 'invalid') }.to raise_error(Decanter::ParseError, json_parser_error)
expect { parser.parse(name, '{ name: "John Smith", age: 30 }') }.to raise_error(Decanter::ParseError, json_parser_error)
expect { parser.parse(name, '{\"bio\": \"Line1 \n Line2\"}') }.to raise_error(Decanter::ParseError, json_parser_error)
expect { parser.parse(name, '{ "name": "John Smith", "age": 30, }') }.to raise_error(Decanter::ParseError, json_parser_error)
end
end
end
end