smart_params 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +153 -0
- data/Rakefile +12 -0
- data/lib/smart_params/error/invalid_property_type.rb +27 -0
- data/lib/smart_params/error.rb +5 -0
- data/lib/smart_params/field.rb +61 -0
- data/lib/smart_params/version.rb +3 -0
- data/lib/smart_params/version_spec.rb +7 -0
- data/lib/smart_params.rb +92 -0
- data/lib/smart_params_spec.rb +147 -0
- metadata +179 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7ee27024729173b4bbeb45827db79738a4ed84b07da26c315b57ba0fcca313cc
|
4
|
+
data.tar.gz: 0a65e6f80959a389e55d492735f0a6c8fcfa9c06397acaf9468c83a2e8db4670
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4580e4078efacdf5b01d334b4f943b8a8426cc375a08180970715187de761595dce15c9b62599f259f769f31bd503f25781da895e1a8dbba0778d37d151ac414
|
7
|
+
data.tar.gz: 9e78ae9f84d8541b5ddebde79346e54dcec97b1bc2b055c00f7fa7d34aae03175b05dbf7e32a96ccad047e8be7c6f340c004384a27437e7d17eb5d8e9f710088
|
data/README.md
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
# smart_params
|
2
|
+
|
3
|
+
- [![Build](http://img.shields.io/travis-ci/krainboltgreene/smart_params.svg?style=flat-square)](https://travis-ci.org/krainboltgreene/smart_params)
|
4
|
+
- [![Downloads](http://img.shields.io/gem/dtv/smart_params.svg?style=flat-square)](https://rubygems.org/gems/smart_params)
|
5
|
+
- [![Version](http://img.shields.io/gem/v/smart_params.svg?style=flat-square)](https://rubygems.org/gems/smart_params)
|
6
|
+
|
7
|
+
|
8
|
+
Work smart, not strong. This gem gives developers an easy to understand and easy to maintain schema for request parameters. Meant as a drop-in replacement for strong_params.
|
9
|
+
|
10
|
+
|
11
|
+
## Using
|
12
|
+
|
13
|
+
So lets say you have a complex set of incoming data, say a JSON:API-specification compliant payload that contains the data to create an account on your server. Of course, your e-commerce platform is pretty flexible; You don't stop users from creating an account just because they don't have an email or password. So let's see how this would play out:
|
14
|
+
|
15
|
+
``` ruby
|
16
|
+
class CreateAccountSchema
|
17
|
+
include SmartParams
|
18
|
+
|
19
|
+
schema type: Strict::Hash do
|
20
|
+
need :data, type: Strict::Hash do
|
21
|
+
allow :id, type: Coercible::String.optional
|
22
|
+
need :type, type: Strict::String
|
23
|
+
allow :attributes, type: Strict::Hash.optional do
|
24
|
+
allow :email, type: Strict::String.optional
|
25
|
+
allow :username, type: Strict::String.optional
|
26
|
+
allow :name, type: Strict::String.optional
|
27
|
+
allow :password, type: Strict::String.optional.default { SecureRandom.hex(32) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
allow :meta, type: Strict::Hash.optional
|
31
|
+
allow :included, type: Strict::Array.optional
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
And now using that schema in the controller:
|
37
|
+
|
38
|
+
``` ruby
|
39
|
+
class AccountsController < ApplicationController
|
40
|
+
def create
|
41
|
+
schema = CreateAccountSchema.new(params)
|
42
|
+
# parameters will be a SmartParams::Dataset, which will respond to the various fields you defined
|
43
|
+
|
44
|
+
# Here we're pulling out the id and data properties defined above
|
45
|
+
record = Account.create({id: schema.data.id, **schema.data.attributes})
|
46
|
+
|
47
|
+
redirect_to account_url(record)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
Okay, so lets look at some scenarios.
|
53
|
+
|
54
|
+
First, lets try an empty payload:
|
55
|
+
|
56
|
+
``` ruby
|
57
|
+
CreateAccountSchema.new({})
|
58
|
+
# raises SmartParams::Error::InvalidPropertyType, keychain: [:data], wanted: Hash, raw: nil
|
59
|
+
|
60
|
+
# You can return the exception directly by providing :safe => false
|
61
|
+
|
62
|
+
CreateAccountSchema.new({}, safe: false).payload
|
63
|
+
# return #<SmartParams::Error::InvalidPropertyType... keychain: [:data], wanted: Hash, raw: nil>
|
64
|
+
```
|
65
|
+
|
66
|
+
Great, we've told SmartParams we need `data` and it enforced this! The exception class knows the "key chain" path to the property that was missing and the value that was given. Lets experiment with that:
|
67
|
+
|
68
|
+
``` ruby
|
69
|
+
CreateAccountSchema.new({data: ""})
|
70
|
+
# raise SmartParams::Error::InvalidPropertyType, keychain: [:data], wanted: Hash, raw: ""
|
71
|
+
```
|
72
|
+
|
73
|
+
Sweet, we can definitely catch this and give the client a meaningful error! Okay, so to show off a good payload I'm going to do two things: Examine the properties and turn it to a JSON compatible structure. Lets see a minimum viable account according to our schema:
|
74
|
+
|
75
|
+
|
76
|
+
``` ruby
|
77
|
+
schema = CreateAccountSchema.new({
|
78
|
+
data: {
|
79
|
+
type: "accounts"
|
80
|
+
}
|
81
|
+
})
|
82
|
+
|
83
|
+
schema.payload.data.type
|
84
|
+
# "accounts"
|
85
|
+
|
86
|
+
schema.data.type
|
87
|
+
# "accounts"
|
88
|
+
|
89
|
+
schema.as_json
|
90
|
+
# {
|
91
|
+
# "data" => {
|
92
|
+
# "type" => "accounts",
|
93
|
+
# "attributes" => {
|
94
|
+
# "password" => "1a6c3ffa4e96ad1660cb819f52a3393d924ac20073e84a9a6943a721d49bab38"
|
95
|
+
# }
|
96
|
+
# }
|
97
|
+
# }
|
98
|
+
```
|
99
|
+
|
100
|
+
Wait, what happened here? Well we told SmartParams that we're going to want a default password, so it delivered!
|
101
|
+
|
102
|
+
|
103
|
+
### Types
|
104
|
+
|
105
|
+
For more information on what types and options you can use, please read: http://dry-rb.org/gems/dry-types/
|
106
|
+
|
107
|
+
|
108
|
+
### Why not strong_params?
|
109
|
+
|
110
|
+
Okay so sure strong_params exists and it's definitely better than `attr_accessible` (if you remember that mess), but it often leaves you with code like this:
|
111
|
+
|
112
|
+
https://github.com/diaspora/diaspora/blob/develop/app/controllers/users_controller.rb#L140-L158
|
113
|
+
|
114
|
+
Which while fine to start with usually evolves into:
|
115
|
+
|
116
|
+
https://github.com/discourse/discourse/blob/master/app/controllers/posts_controller.rb#L592-L677
|
117
|
+
|
118
|
+
None of this is very maintainable and it's definitely not easy to teach. So my solution is to follow the wake of other libraries: Define a maintainable interface that can be easily tested and easily integrated. It doesn't require wholesale adoption nor is it hard to remove.
|
119
|
+
|
120
|
+
|
121
|
+
### Why not have this in the controller?
|
122
|
+
|
123
|
+
First and foremost because the controller already has a job: Determining the course of action for a request. Why complicate it with yet another responsibility? Second because it makes testing that much harder. Instead of just testing the correctness of your schema, you now have to mock authentication and authorization.
|
124
|
+
|
125
|
+
|
126
|
+
### Why not use before_validation or before_save?
|
127
|
+
|
128
|
+
Your model is already complex enough and it doesn't need the added baggage of figuring out how to transform incoming data. We learned that lesson the hard way with `attr_accessible`. Further, it's not vary sharable or understandable over large time periods.
|
129
|
+
|
130
|
+
|
131
|
+
## Installing
|
132
|
+
|
133
|
+
Add this line to your application's Gemfile:
|
134
|
+
|
135
|
+
gem "smart_params", "1.0.0"
|
136
|
+
|
137
|
+
And then execute:
|
138
|
+
|
139
|
+
$ bundle
|
140
|
+
|
141
|
+
Or install it yourself with:
|
142
|
+
|
143
|
+
$ gem install smart_params
|
144
|
+
|
145
|
+
|
146
|
+
## Contributing
|
147
|
+
|
148
|
+
1. Read the [Code of Conduct](/CONDUCT.md)
|
149
|
+
2. Fork it
|
150
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
151
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
152
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
153
|
+
6. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
|
6
|
+
desc "Run all the tests in spec"
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |let|
|
8
|
+
let.pattern = "lib/**{,/*/**}/*_spec.rb"
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Default: run tests"
|
12
|
+
task default: :spec
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SmartParams
|
2
|
+
class Error
|
3
|
+
class InvalidPropertyType < Error
|
4
|
+
attr_reader :keychain
|
5
|
+
attr_reader :wanted
|
6
|
+
attr_reader :raw
|
7
|
+
|
8
|
+
def initialize(keychain:, wanted:, raw:)
|
9
|
+
@keychain = keychain
|
10
|
+
@wanted = type
|
11
|
+
@raw = raw
|
12
|
+
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
"expected #{keychain.inspect} to be wanted of #{wanted.type.name}, but was #{raw.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def as_json
|
19
|
+
{
|
20
|
+
"keychain" => keychain,
|
21
|
+
"wanted" => wanted.type.name,
|
22
|
+
"raw" => raw
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module SmartParams
|
2
|
+
class Field
|
3
|
+
RECURSIVE_TREE = ->(accumulated, key) {accumulated[key] = Hash.new(&RECURSIVE_TREE)}
|
4
|
+
|
5
|
+
attr_reader :keychain
|
6
|
+
attr_reader :value
|
7
|
+
attr_reader :subfields
|
8
|
+
attr_reader :type
|
9
|
+
|
10
|
+
def initialize(keychain:, type:, &nesting)
|
11
|
+
@keychain = Array(keychain)
|
12
|
+
@subfields = Set.new
|
13
|
+
@type = type
|
14
|
+
|
15
|
+
if block_given?
|
16
|
+
instance_eval(&nesting)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def allow(key, type:, &subfield)
|
21
|
+
@subfields << self.class.new(keychain: [*keychain, key], type: type, &subfield)
|
22
|
+
end
|
23
|
+
|
24
|
+
def need(key, type:, &subfield)
|
25
|
+
@subfields << self.class.new(keychain: [*keychain, key], type: type, &subfield)
|
26
|
+
end
|
27
|
+
|
28
|
+
def deep?
|
29
|
+
subfields.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def claim(raw)
|
33
|
+
if keychain.empty?
|
34
|
+
@value = type[raw]
|
35
|
+
else
|
36
|
+
@value = type[raw.dig(*keychain)]
|
37
|
+
end
|
38
|
+
rescue Dry::Types::ConstraintError => bad_type_exception
|
39
|
+
raise SmartParams::Error::InvalidPropertyType, keychain: keychain, wanted: type, raw: raw.dig(*keychain)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_hash
|
43
|
+
*chain, key = keychain
|
44
|
+
Hash.new(&RECURSIVE_TREE).tap do |tree|
|
45
|
+
if chain.any?
|
46
|
+
tree.dig(*chain)[key] = value
|
47
|
+
else
|
48
|
+
tree[key] = value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def empty?
|
54
|
+
value.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
def weight
|
58
|
+
keychain.length
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/smart_params.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "dry-types"
|
3
|
+
require "recursive-open-struct"
|
4
|
+
require "active_support/concern"
|
5
|
+
require "active_support/core_ext/object"
|
6
|
+
|
7
|
+
module SmartParams
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
include Dry::Types.module
|
10
|
+
|
11
|
+
RECURSIVE_TREE = ->(accumulated, key) {accumulated[key] = Hash.new(&RECURSIVE_TREE)}
|
12
|
+
|
13
|
+
require_relative "smart_params/field"
|
14
|
+
require_relative "smart_params/error"
|
15
|
+
require_relative "smart_params/version"
|
16
|
+
|
17
|
+
attr_reader :raw
|
18
|
+
attr_reader :schema
|
19
|
+
attr_reader :fields
|
20
|
+
|
21
|
+
def initialize(raw, safe: true)
|
22
|
+
@raw = raw
|
23
|
+
@schema = self.class.instance_variable_get(:@schema)
|
24
|
+
@fields = [@schema, *unfold(@schema.subfields)]
|
25
|
+
.sort_by(&:weight)
|
26
|
+
.each { |field| field.claim(raw) }
|
27
|
+
@safe = safe
|
28
|
+
rescue SmartParams::Error::InvalidPropertyType => invalid_property_type_exception
|
29
|
+
if safe?
|
30
|
+
raise invalid_property_type_exception
|
31
|
+
else
|
32
|
+
@exception = invalid_property_type_exception
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def payload
|
37
|
+
if @exception.present?
|
38
|
+
@exception
|
39
|
+
else
|
40
|
+
RecursiveOpenStruct.new(structure)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def as_json
|
45
|
+
if @exception.present?
|
46
|
+
@exception.as_json
|
47
|
+
else
|
48
|
+
structure.deep_stringify_keys
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(name, *arguments, &block)
|
53
|
+
if payload.respond_to?(name)
|
54
|
+
payload.public_send(name)
|
55
|
+
else
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# This function basically takes a list of fields and reduces them into a tree of values
|
61
|
+
private def structure
|
62
|
+
fields
|
63
|
+
.reject(&:empty?)
|
64
|
+
.map(&:to_hash)
|
65
|
+
.map do |hash|
|
66
|
+
# NOTE: okay, so this looks weird, but it's because the root type has no key
|
67
|
+
if hash.key?(nil) then hash.fetch(nil) else hash end
|
68
|
+
end
|
69
|
+
.reduce(&:deep_merge)
|
70
|
+
end
|
71
|
+
|
72
|
+
# This funcion takes a nested field tree and turns it into a list of fields
|
73
|
+
private def unfold(subfields)
|
74
|
+
subfields.to_a.reduce([]) do |list, field|
|
75
|
+
if field.deep?
|
76
|
+
[*list, field, *unfold(field.subfields)]
|
77
|
+
else
|
78
|
+
[*list, field]
|
79
|
+
end
|
80
|
+
end.flatten
|
81
|
+
end
|
82
|
+
|
83
|
+
private def safe?
|
84
|
+
@safe
|
85
|
+
end
|
86
|
+
|
87
|
+
class_methods do
|
88
|
+
def schema(type:, &subfield)
|
89
|
+
@schema = Field.new(keychain: [], type: type, &subfield)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe SmartParams do
|
4
|
+
let(:schema) { CreateAccountSchema.new(params) }
|
5
|
+
|
6
|
+
describe ".new" do
|
7
|
+
context "with an empty params" do
|
8
|
+
let(:params) { {} }
|
9
|
+
|
10
|
+
it "throws an error with a message detailing the invalid property type and given properties" do
|
11
|
+
expect {schema}.to raise_exception(SmartParams::Error::InvalidPropertyType, "expected [:data] to be kind of Hash, but was nil")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "throws an error with the missing property and given properties" do
|
15
|
+
expect {schema}.to raise_exception do |exception|
|
16
|
+
expect(exception).to have_attributes(keychain: [:data], wanted: SmartParams::Strict::Hash, raw: nil)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with a good key but bad type" do
|
22
|
+
let(:params) { {data: ""} }
|
23
|
+
|
24
|
+
it "throws an error with a message detailing the invalid property, expected type, given type, and given value" do
|
25
|
+
expect { schema }.to raise_exception(SmartParams::Error::InvalidPropertyType, "expected [:data] to be kind of Hash, but was \"\"")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "throws an error with the invalid property, expected type, given type, and given value" do
|
29
|
+
expect {schema }.to raise_exception do |exception|
|
30
|
+
expect(exception).to have_attributes(keychain: [:data], wanted: SmartParams::Strict::Hash, raw: "")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#payload" do
|
37
|
+
context "with a reasonably good params" do
|
38
|
+
let(:params) do
|
39
|
+
{
|
40
|
+
data: {
|
41
|
+
type: "accounts",
|
42
|
+
attributes: {
|
43
|
+
email: "kurtis@example.com"
|
44
|
+
}
|
45
|
+
},
|
46
|
+
meta: {
|
47
|
+
jsonapi_version: "1.0"
|
48
|
+
},
|
49
|
+
included: [
|
50
|
+
{
|
51
|
+
data: {
|
52
|
+
id: "a",
|
53
|
+
type: "widget",
|
54
|
+
attributes: {
|
55
|
+
title: "Widget A",
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
]
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns the type" do
|
64
|
+
expect(schema.payload.data.type).to eq("accounts")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns the email" do
|
68
|
+
expect(schema.data.attributes.email).to eq("kurtis@example.com")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns the password" do
|
72
|
+
expect(schema.data.attributes.password).to be_kind_of(String)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "returns the jsonapi version" do
|
76
|
+
expect(schema.meta.jsonapi_version).to eq("1.0")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#as_json" do
|
82
|
+
subject {schema.as_json}
|
83
|
+
|
84
|
+
context "with a reasonably good params" do
|
85
|
+
let(:params) do
|
86
|
+
{
|
87
|
+
data: {
|
88
|
+
type: "accounts",
|
89
|
+
attributes: {
|
90
|
+
email: "kurtis@example.com"
|
91
|
+
}
|
92
|
+
},
|
93
|
+
meta: {
|
94
|
+
jsonapi_version: "1.0"
|
95
|
+
},
|
96
|
+
included: [
|
97
|
+
{
|
98
|
+
data: {
|
99
|
+
id: "a",
|
100
|
+
type: "widget",
|
101
|
+
attributes: {
|
102
|
+
title: "Widget A",
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
]
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
it "returns as json" do
|
111
|
+
expect(
|
112
|
+
subject
|
113
|
+
).to eq(
|
114
|
+
hash_including(
|
115
|
+
{
|
116
|
+
"data" => hash_including(
|
117
|
+
{
|
118
|
+
"type" => "accounts",
|
119
|
+
"attributes" => hash_including(
|
120
|
+
{
|
121
|
+
"email" => "kurtis@example.com",
|
122
|
+
"password" => an_instance_of(String)
|
123
|
+
}
|
124
|
+
)
|
125
|
+
}
|
126
|
+
),
|
127
|
+
"meta" => {
|
128
|
+
"jsonapi_version" => "1.0"
|
129
|
+
},
|
130
|
+
"included" => [
|
131
|
+
{
|
132
|
+
"data" => {
|
133
|
+
"id" => "a",
|
134
|
+
"type" => "widget",
|
135
|
+
"attributes" => {
|
136
|
+
"title" => "Widget A"
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
]
|
141
|
+
}
|
142
|
+
)
|
143
|
+
)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
metadata
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smart_params
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kurtis Rainbolt-Greene
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '12.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '12.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.11'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.11'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-doc
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.11'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.11'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '5.1'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '5.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: dry-monads
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.4'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.4'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: dry-types
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.12'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.12'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: recursive-open-struct
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.1'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.1'
|
139
|
+
description: Apply an organized and easy to maintain schema to request params
|
140
|
+
email:
|
141
|
+
- kurtis@rainbolt-greene.online
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- README.md
|
147
|
+
- Rakefile
|
148
|
+
- lib/smart_params.rb
|
149
|
+
- lib/smart_params/error.rb
|
150
|
+
- lib/smart_params/error/invalid_property_type.rb
|
151
|
+
- lib/smart_params/field.rb
|
152
|
+
- lib/smart_params/version.rb
|
153
|
+
- lib/smart_params/version_spec.rb
|
154
|
+
- lib/smart_params_spec.rb
|
155
|
+
homepage: http://krainboltgreene.github.io/smart_params
|
156
|
+
licenses:
|
157
|
+
- ISC
|
158
|
+
metadata: {}
|
159
|
+
post_install_message:
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
requirements: []
|
174
|
+
rubyforge_project:
|
175
|
+
rubygems_version: 2.7.6
|
176
|
+
signing_key:
|
177
|
+
specification_version: 4
|
178
|
+
summary: Apply an organized and easy to maintain schema to request params
|
179
|
+
test_files: []
|