rails_param 0.0.1
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 +7 -0
- data/README.md +92 -0
- data/lib/rails_param.rb +5 -0
- data/lib/rails_param/param.rb +110 -0
- data/lib/rails_param/version.rb +3 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 79d1fa666d9f249c4e2758fff4fe24be7856eeb8
|
4
|
+
data.tar.gz: c65e6e4d12a12a57667c659157229da75b9ce6c9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a3c7b0fbafd0072dd049879f47b3c0d892411712dac4ca3c2a0d34d0221b42c5a40c90b732005998c3798920ec964b68961accfccabd3fb6996a88b77a331172
|
7
|
+
data.tar.gz: e0901f1e7eb5bb94f91480925f6b4876b63e3d85168159edf34c3fa4aec6fc98c137b89b7932825e2e323981b185351a17db70a87e56483464d964c26f9a9ab2
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# rails-param
|
2
|
+
_Parameter Validation & Type Coercion for Rails_
|
3
|
+
|
4
|
+
This is a port of the gem [sinatra-param](https://github.com/mattt/sinatra-param) for the Rails framework.
|
5
|
+
All the credits go to [@mattt](https://twitter.com/mattt).
|
6
|
+
It has all the features of the sinatra-param gem, I used bang methods (param! and one_of!) to indicate that they are destructive as they change the controller params object and may raise an exception.
|
7
|
+
|
8
|
+
REST conventions take the guesswork out of designing and consuming web APIs. Simply `GET`, `POST`, `PATCH`, or `DELETE` resource endpoints, and you get what you'd expect.
|
9
|
+
|
10
|
+
However, when it comes to figuring out what parameters are expected... well, all bets are off.
|
11
|
+
|
12
|
+
This Rails extension takes a first step to solving this problem on the developer side
|
13
|
+
|
14
|
+
**`rails-param` allows you to declare, validate, and transform endpoint parameters as you would in frameworks like [ActiveModel](http://rubydoc.info/gems/activemodel/3.2.3/frames) or [DataMapper](http://datamapper.org/).**
|
15
|
+
|
16
|
+
> Use `rails-param` in combination with [`Rack::PostBodyContentTypeParser` and `Rack::NestedParams`](https://github.com/rack/rack-contrib) to automatically parameterize JSON `POST` bodies and nested parameters.
|
17
|
+
|
18
|
+
## Example
|
19
|
+
|
20
|
+
``` ruby
|
21
|
+
# GET /search?q=example
|
22
|
+
# GET /search?q=example&categories=news
|
23
|
+
# GET /search?q=example&sort=created_at&order=ASC
|
24
|
+
def search
|
25
|
+
param! :q, String, required: true
|
26
|
+
param! :categories, Array
|
27
|
+
param! :sort, String, default: "title"
|
28
|
+
param! :order, String, in: ["ASC", "DESC"], transform: :upcase, default: "ASC"
|
29
|
+
param! :price, String, format: "[<\=>]\s*\$\d+"
|
30
|
+
|
31
|
+
{...}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
### Parameter Types
|
37
|
+
|
38
|
+
By declaring parameter types, incoming parameters will automatically be transformed into an object of that type. For instance, if a param is `Boolean`, values of `'1'`, `'true'`, `'t'`, `'yes'`, and `'y'` will be automatically transformed into `true`.
|
39
|
+
|
40
|
+
- `String`
|
41
|
+
- `Integer`
|
42
|
+
- `Float`
|
43
|
+
- `Boolean` _("1/0", "true/false", "t/f", "yes/no", "y/n")_
|
44
|
+
- `Array` _("1,2,3,4,5")_
|
45
|
+
- `Hash` _(key1:value1,key2:value2)_
|
46
|
+
- `Date`, `Time`, & `DateTime`
|
47
|
+
|
48
|
+
### Validations
|
49
|
+
|
50
|
+
Encapsulate business logic in a consistent way with validations. If a parameter does not satisfy a particular condition, a `400` error is returned with a message explaining the failure.
|
51
|
+
|
52
|
+
- `required`
|
53
|
+
- `blank`
|
54
|
+
- `is`
|
55
|
+
- `in`, `within`, `range`
|
56
|
+
- `min` / `max`
|
57
|
+
- `format`
|
58
|
+
|
59
|
+
### Defaults and Transformations
|
60
|
+
|
61
|
+
Passing a `default` option will provide a default value for a parameter if none is passed. A `default` can defined as either a default or as a `Proc`:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
param! :attribution, String, default: "©"
|
65
|
+
param! :year, Integer, default: lambda { Time.now.year }
|
66
|
+
```
|
67
|
+
|
68
|
+
Use the `transform` option to take even more of the business logic of parameter I/O out of your code. Anything that responds to `to_proc` (including `Proc` and symbols) will do.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
param! :order, String, in: ["ASC", "DESC"], transform: :upcase, default: "ASC"
|
72
|
+
param! :offset, Integer, min: 0, transform: lambda {|n| n - (n % 10)}
|
73
|
+
```
|
74
|
+
|
75
|
+
## Thank you
|
76
|
+
|
77
|
+
Many thanks to:
|
78
|
+
|
79
|
+
* [Mattt Thompson (@mattt)](https://twitter.com/mattt)
|
80
|
+
* [Vincent Ollivier (@vinc686)](https://twitter.com/vinc686)
|
81
|
+
|
82
|
+
## Contact
|
83
|
+
|
84
|
+
Nicolas Blanco
|
85
|
+
|
86
|
+
- http://github.com/nicolasblanco
|
87
|
+
- http://twitter.com/nblanco_fr
|
88
|
+
- nicolas@nicolasblanco.fr
|
89
|
+
|
90
|
+
## License
|
91
|
+
|
92
|
+
rails-param is available under the MIT license. See the LICENSE file for more info.
|
data/lib/rails_param.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
module RailsParam
|
2
|
+
module Param
|
3
|
+
|
4
|
+
class InvalidParameterError < StandardError
|
5
|
+
attr_accessor :param, :options
|
6
|
+
end
|
7
|
+
|
8
|
+
def param!(name, type, options = {})
|
9
|
+
name = name.to_s
|
10
|
+
|
11
|
+
return unless params.member?(name) || options[:default].present? || options[:required]
|
12
|
+
|
13
|
+
begin
|
14
|
+
params[name] = coerce(params[name], type, options)
|
15
|
+
params[name] = (options[:default].call if options[:default].respond_to?(:call)) || options[:default] if params[name].nil? and options[:default]
|
16
|
+
params[name] = options[:transform].to_proc.call(params[name]) if params[name] and options[:transform]
|
17
|
+
validate!(params[name], options)
|
18
|
+
# rescue InvalidParameterError => exception
|
19
|
+
# if options[:raise]
|
20
|
+
# exception.param, exception.options = name, options
|
21
|
+
# raise exception
|
22
|
+
# end
|
23
|
+
|
24
|
+
# error = "Invalid Parameter: #{name}"
|
25
|
+
# if content_type and content_type.match(mime_type(:json))
|
26
|
+
# error = {message: error, errors: {name => exception.message}}.to_json
|
27
|
+
# end
|
28
|
+
|
29
|
+
# # do something with error object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# def one_of!(*names)
|
34
|
+
# count = 0
|
35
|
+
# names.each do |name|
|
36
|
+
# if params[name] and params[name].present?
|
37
|
+
# count += 1
|
38
|
+
# next unless count > 1
|
39
|
+
#
|
40
|
+
# error = "Parameters #{names.join(', ')} are mutually exclusive"
|
41
|
+
# if content_type and content_type.match(mime_type(:json))
|
42
|
+
# error = {message: error}.to_json
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # do something with error object
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def coerce(param, type, options = {})
|
53
|
+
begin
|
54
|
+
return nil if param.nil?
|
55
|
+
return param if (param.is_a?(type) rescue false)
|
56
|
+
return Integer(param) if type == Integer
|
57
|
+
return Float(param) if type == Float
|
58
|
+
return String(param) if type == String
|
59
|
+
return Date.parse(param) if type == Date
|
60
|
+
return Time.parse(param) if type == Time
|
61
|
+
return DateTime.parse(param) if type == DateTime
|
62
|
+
return Array(param.split(options[:delimiter] || ",")) if type == Array
|
63
|
+
return Hash[param.split(options[:delimiter] || ",").map{|c| c.split(options[:separator] || ":")}] if type == Hash
|
64
|
+
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
|
65
|
+
return nil
|
66
|
+
rescue ArgumentError
|
67
|
+
raise InvalidParameterError, "'#{param}' is not a valid #{type}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def validate!(param, options)
|
72
|
+
options.each do |key, value|
|
73
|
+
case key
|
74
|
+
when :required
|
75
|
+
raise InvalidParameterError, "Parameter is required" if value && param.nil?
|
76
|
+
when :blank
|
77
|
+
raise InvalidParameterError, "Parameter cannot be blank" if !value && case param
|
78
|
+
when String
|
79
|
+
!(/\S/ === param)
|
80
|
+
when Array, Hash
|
81
|
+
param.empty?
|
82
|
+
else
|
83
|
+
param.nil?
|
84
|
+
end
|
85
|
+
when :format
|
86
|
+
raise InvalidParameterError, "Parameter must be a string if using the format validation" unless param.kind_of?(String)
|
87
|
+
raise InvalidParameterError, "Parameter must match format #{value}" unless param =~ value
|
88
|
+
when :is
|
89
|
+
raise InvalidParameterError, "Parameter must be #{value}" unless param === value
|
90
|
+
when :in, :within, :range
|
91
|
+
raise InvalidParameterError, "Parameter must be within #{value}" unless param.nil? || case value
|
92
|
+
when Range
|
93
|
+
value.include?(param)
|
94
|
+
else
|
95
|
+
Array(value).include?(param)
|
96
|
+
end
|
97
|
+
when :min
|
98
|
+
raise InvalidParameterError, "Parameter cannot be less than #{value}" unless param.nil? || value <= param
|
99
|
+
when :max
|
100
|
+
raise InvalidParameterError, "Parameter cannot be greater than #{value}" unless param.nil? || value >= param
|
101
|
+
when :min_length
|
102
|
+
raise InvalidParameterError, "Parameter cannot have length less than #{value}" unless param.nil? || value <= param.length
|
103
|
+
when :max_length
|
104
|
+
raise InvalidParameterError, "Parameter cannot have length greater than #{value}" unless param.nil? || value >= param.length
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rails_param
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicolas Blanco
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: actionpack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.1.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 4.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.1.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 4.1.0
|
69
|
+
description: "\n Parameter Validation & Type Coercion for Rails\n "
|
70
|
+
email: nicolas@nicolasblanco.fr
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- README.md
|
76
|
+
- lib/rails_param.rb
|
77
|
+
- lib/rails_param/param.rb
|
78
|
+
- lib/rails_param/version.rb
|
79
|
+
homepage: http://github.com/nicolasblanco/rails_param
|
80
|
+
licenses:
|
81
|
+
- WTFPL
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options:
|
85
|
+
- "--charset=UTF-8"
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 1.3.6
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.2.2
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Parameter Validation & Type Coercion for Rails
|
104
|
+
test_files: []
|