rails_param 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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.
@@ -0,0 +1,5 @@
1
+ require 'rails_param/param'
2
+
3
+ ActiveSupport.on_load(:action_controller) do
4
+ include RailsParam::Param
5
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module RailsParam #:nodoc
2
+ VERSION = "0.0.1"
3
+ 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: []