Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for JSON #10

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ By declaring parameter types, incoming parameters will automatically be transfor
- `:boolean/TrueClass/FalseClass` _("1/0", "true/false", "t/f", "yes/no", "y/n")_
- `Array` _("1,2,3,4,5")_
- `Hash` _("key1:value1,key2:value2")_
- `JSON` _("{ "key1": "foo", "key2": "bar"}")_
- `Date`, `Time`, & `DateTime`
- `BigDecimal` _("$1,000,000")_

Expand Down Expand Up @@ -101,6 +102,19 @@ param! :book, Hash do |b|
end
```

And JSON also:

```ruby
param! :book, JSON do |b|
b.param! :title, String, blank: false
b.param! :price, BigDecimal, precision: 4, required: true
b.param! :author, JSON, required: true do |a|
a.param! :first_name, String
a.param! :last_name, String, blank: false
end
end
```

### Arrays

Validate every element of your array, including nested hashes and arrays:
Expand Down
4 changes: 2 additions & 2 deletions lib/rails_param/param.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module RailsParam
module Param

DEFAULT_PRECISION = 14

class InvalidParameterError < StandardError
Expand Down Expand Up @@ -84,13 +83,14 @@ def coerce(param, type, options = {})
return DateTime.parse(param) if type == DateTime
return Array(param.split(options[:delimiter] || ",")) if type == Array
return Hash[param.split(options[:delimiter] || ",").map { |c| c.split(options[:separator] || ":") }] if type == Hash
return JSON(param) if type == JSON
return (/(false|f|no|n|0)$/i === param.to_s ? false : (/(true|t|yes|y|1)$/i === param.to_s ? true : nil)) if type == TrueClass || type == FalseClass || type == :boolean
if type == BigDecimal
param = param.delete('$,').strip.to_f if param.is_a?(String)
return BigDecimal.new(param, (options[:precision] || DEFAULT_PRECISION))
end
return nil
rescue ArgumentError
rescue ArgumentError, JSON::ParserError
raise InvalidParameterError, "'#{param}' is not a valid #{type}"
end
end
Expand Down
47 changes: 47 additions & 0 deletions spec/rails_param/param_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ def params;
expect(controller.params["foo"]).to eql({"key1" => "foo", "key2" => "bar"})
end

it "converts to JSON" do
allow(controller).to receive(:params).and_return({"foo" => '{ "key1": "foo", "key2": "bar"}'.gsub("\"", '"') })
controller.param! 'foo', JSON
expect(controller.params["foo"]).to eql({"key1" => "foo", "key2" => "bar"})
end

it "converts to Date" do
allow(controller).to receive(:params).and_return({"foo" => "1984-01-10"})
controller.param! :foo, Date
Expand Down Expand Up @@ -221,6 +227,47 @@ def params;
end
end

describe 'validating nested json' do
it 'typecasts nested attributes' do
allow(controller).to receive(:params).and_return('foo' => '{ "bar" : 1, "baz" : 2}'.gsub("\"", '"'))
controller.param! :foo, JSON do |p|
p.param! :bar, BigDecimal
p.param! :baz, Float
end
expect(controller.params['foo']['bar']).to be_instance_of BigDecimal
expect(controller.params['foo']['baz']).to be_instance_of Float
end

it 'does not raise exception if hash is not required but nested attributes are, and no hash is provided' do
allow(controller).to receive(:params).and_return(foo: nil)
controller.param! :foo, JSON do |p|
p.param! :bar, BigDecimal, required: true
p.param! :baz, Float, required: true
end
expect(controller.params['foo']).to be_nil
end

it 'raises exception if hash is required, nested attributes are not required, and no hash is provided' do
allow(controller).to receive(:params).and_return(foo: nil)
expect {
controller.param! :foo, JSON, required: true do |p|
p.param! :bar, BigDecimal
p.param! :baz, Float
end
}.to raise_exception
end

it 'raises exception if hash is not required but nested attributes are, and hash has missing attributes' do
allow(controller).to receive(:params).and_return("{'foo' : {'bar' : 1, 'baz' : nil}}")
expect {
controller.param! :foo, JSON do |p|
p.param! :bar, BigDecimal, required: true
p.param! :baz, Float, required: true
end
}.to raise_exception
end
end

describe 'validating arrays' do
it 'typecasts array of primitive elements' do
allow(controller).to receive(:params).and_return({'array' => ['1', '2']})
Expand Down