rails_param 0.0.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 62719118e57a8eed3bd8b7cc8ff2f095d8e4dc73
4
- data.tar.gz: da4a112bbd5252ef8c204c56c474764f7c55f7f7
3
+ metadata.gz: 372c36387af839acafd00fac76073bcdd666b19e
4
+ data.tar.gz: 2d9d467a8352bf7f0e671ab8324af3993fcc64f1
5
5
  SHA512:
6
- metadata.gz: 25b3186f4eddf85cc8a7a0b7e3c0d7b1622e6f5109aeb83ed6480f517a07ef9ad97938ef166e3a92b3b1d1c8935a047518141bf5780cc913010fcf0707c15e69
7
- data.tar.gz: faaeb8f5bc57ae2a25493d171901f516c934713b7b0748ad07b093459db444bc4641884d45322cc34b874d45c791caa7b136a301b4608dd4f334a45f2d0d8127
6
+ metadata.gz: c616739e789c723637b6f1b545ecf261a957645f8d92c7bafe456850e49d99420be36d775c3b1af7727ed4d1eac307658390215d94e6e49cfdfec01ee0c66849
7
+ data.tar.gz: 5079e1ba2ff3c5f1b634ad8cc0e9760633a07fa449d601030e079eeb7505512293de6a45559303885e8ae2e9708bb105e609b89fe132916ef1b2e07ecbfc9cf2
data/README.md CHANGED
@@ -3,17 +3,35 @@ _Parameter Validation & Type Coercion for Rails_
3
3
 
4
4
  [![Build Status](https://travis-ci.org/nicolasblanco/rails_param.svg?branch=master)](https://travis-ci.org/nicolasblanco/rails_param)
5
5
 
6
- This is a port of the gem [sinatra-param](https://github.com/mattt/sinatra-param) for the Rails framework.
6
+ ## Introduction
7
+
8
+ This library is handy if you want to validate a few numbers of parameters directly inside your controller.
9
+
10
+ For example : you are building a search action and want to validate that the `sort` parameter is set and only set to something like `desc` or `asc`.
11
+
12
+ ## Important
13
+
14
+ This library should not be used to validate a large number of parameters or parameters sent via a form or namespaced (like `params[:user][:first_name]`). There is already a great framework included in Rails (ActiveModel::Model) which can be used to create virtual classes with all the validations you already know and love from Rails. Remember to always try to stay in the “thin controller” rule.
15
+
16
+ See [this](http://blog.remarkablelabs.com/2012/12/activemodel-model-rails-4-countdown-to-2013) page to see an example on how to build a contact form using ActiveModel::Model.
17
+
18
+ But sometimes, it’s not practical to create an external class just to validate and convert a few parameters. In this case, you may use this gem. It allows you to easily do validations and conversion of the parameters directly in your controller actions using a simple method call.
19
+
20
+ ## Credits
21
+
22
+ This is originally a port of the gem [sinatra-param](https://github.com/mattt/sinatra-param) for the Rails framework.
23
+
7
24
  All the credits go to [@mattt](https://twitter.com/mattt).
8
- It has all the features of the sinatra-param gem, I used bang methods (like param!) to indicate that they are destructive as they change the controller params object and may raise an exception.
9
25
 
10
- 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.
26
+ It has all the features of the sinatra-param gem, I used bang methods (like param!) to indicate that they are destructive as they change the controller params object and may raise an exception.
11
27
 
12
- However, when it comes to figuring out what parameters are expected... well, all bets are off.
28
+ ## Installation
13
29
 
14
- This Rails extension takes a first step to solving this problem on the developer side.
30
+ As usual, in your Gemfile...
15
31
 
16
- **`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/).**
32
+ ``` ruby
33
+ gem 'rails_param'
34
+ ```
17
35
 
18
36
  ## Example
19
37
 
@@ -26,16 +44,16 @@ This Rails extension takes a first step to solving this problem on the developer
26
44
  param! :categories, Array
27
45
  param! :sort, String, default: "title"
28
46
  param! :order, String, in: %w(asc desc), transform: :downcase, default: "asc"
29
- param! :price, String, format: "[<\=>]\s*\$\d+"
47
+ param! :price, String, format: /[<\=>]\s*\$\d+/
30
48
 
31
- {...}
49
+ # Access the parameters using the params object (like params[:q]) as you usually do...
32
50
  end
33
51
  end
34
52
  ```
35
53
 
36
54
  ### Parameter Types
37
55
 
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`.
56
+ 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`. `BigDecimal` defaults to a precision of 14, but this can but changed by passing in the optional `precision:` argument. Any `$` and `,` are automatically stripped when converting to `BigDecimal`.
39
57
 
40
58
  - `String`
41
59
  - `Integer`
@@ -44,6 +62,7 @@ By declaring parameter types, incoming parameters will automatically be transfor
44
62
  - `Array` _("1,2,3,4,5")_
45
63
  - `Hash` _("key1:value1,key2:value2")_
46
64
  - `Date`, `Time`, & `DateTime`
65
+ - `BigDecimal` _("$1,000,000")_
47
66
 
48
67
  ### Validations
49
68
 
@@ -73,6 +92,44 @@ param! :order, String, in: ["ASC", "DESC"], transform: :upcase, default: "ASC"
73
92
  param! :offset, Integer, min: 0, transform: lambda {|n| n - (n % 10)}
74
93
  ```
75
94
 
95
+ ### Nested Attributes
96
+
97
+ rails_param allows you to apply any of the above mentioned validations to attributes nested in hashes:
98
+
99
+ ```ruby
100
+ param! :book, Hash do |b|
101
+ b.param! :title, String, blank: false
102
+ b.param! :price, BigDecimal, precision: 4, required: true
103
+ b.param! :author, Hash, required: true do |a|
104
+ a.param! :first_name, String
105
+ a.param! :last_name, String, blank: false
106
+ end
107
+ end
108
+ ```
109
+
110
+ ### Arrays
111
+
112
+ Validate every element of your array, including nested hashes and arrays:
113
+
114
+ ```ruby
115
+ # primitive datatype syntax
116
+ param! :integer_array, Array do |array,index|
117
+ array.param! index, Integer, required: true
118
+ end
119
+
120
+ # complex array
121
+ param! :books_array, Array, required: true do |b|
122
+ b.param! :title, String, blank: false
123
+ b.param! :author, Hash, required: true do |a|
124
+ a.param! :first_name, String
125
+ a.param! :last_name, String, required: true
126
+ end
127
+ b.param! :subjects, Array do |s,i|
128
+ s.param! i, String, blank: false
129
+ end
130
+ end
131
+ ```
132
+
76
133
  ## Thank you
77
134
 
78
135
  Many thanks to:
@@ -1,22 +1,46 @@
1
1
  module RailsParam
2
2
  module Param
3
3
 
4
+ DEFAULT_PRECISION = 14
5
+
4
6
  class InvalidParameterError < StandardError
5
7
  attr_accessor :param, :options
6
8
  end
7
9
 
8
- def param!(name, type, options = {})
9
- name = name.to_s
10
+ class MockController
11
+ include RailsParam::Param
12
+ attr_accessor :params
13
+ end
10
14
 
11
- return unless params.member?(name) || options[:default].present? || options[:required]
15
+ def param!(name, type, options = {}, &block)
16
+ name = name.to_s unless name.is_a? Integer # keep index for validating elements
17
+
18
+ return unless params.member?(name) || check_param_presence?(options[:default]) || options[:required]
12
19
 
13
20
  begin
14
21
  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]
22
+ params[name] = (options[:default].call if options[:default].respond_to?(:call)) || options[:default] if params[name].nil? and check_param_presence?(options[:default])
16
23
  params[name] = options[:transform].to_proc.call(params[name]) if params[name] and options[:transform]
17
24
  validate!(params[name], options)
25
+
26
+ if block_given?
27
+ if type == Array
28
+ params[name].each_with_index do |element, i|
29
+ if element.is_a?(Hash)
30
+ recurse element, &block
31
+ else
32
+ params[name][i] = recurse({ i => element }, i, &block) # supply index as key unless value is hash
33
+ end
34
+ end
35
+ else
36
+ recurse params[name], &block
37
+ end
38
+ end
39
+ params[name]
40
+
18
41
  rescue InvalidParameterError => exception
19
- exception.param, exception.options = name, options
42
+ exception.param ||= name
43
+ exception.options ||= options
20
44
  raise exception
21
45
  end
22
46
  end
@@ -41,6 +65,17 @@ module RailsParam
41
65
 
42
66
  private
43
67
 
68
+ def check_param_presence? param
69
+ not param.nil?
70
+ end
71
+
72
+ def recurse(params, index = nil)
73
+ raise InvalidParameterError, 'no block given' unless block_given?
74
+ controller = RailsParam::Param::MockController.new
75
+ controller.params = params
76
+ yield(controller, index)
77
+ end
78
+
44
79
  def coerce(param, type, options = {})
45
80
  begin
46
81
  return nil if param.nil?
@@ -52,8 +87,12 @@ module RailsParam
52
87
  return Time.parse(param) if type == Time
53
88
  return DateTime.parse(param) if type == DateTime
54
89
  return Array(param.split(options[:delimiter] || ",")) if type == Array
55
- return Hash[param.split(options[:delimiter] || ",").map{|c| c.split(options[:separator] || ":")}] if type == Hash
56
- 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
90
+ return Hash[param.split(options[:delimiter] || ",").map { |c| c.split(options[:separator] || ":") }] if type == Hash
91
+ return (/^(false|f|no|n|0)$/i === param.to_s ? false : (/^(true|t|yes|y|1)$/i === param.to_s ? true : (raise ArgumentError))) if type == TrueClass || type == FalseClass || type == :boolean
92
+ if type == BigDecimal
93
+ param = param.delete('$,').strip.to_f if param.is_a?(String)
94
+ return BigDecimal.new(param, (options[:precision] || DEFAULT_PRECISION))
95
+ end
57
96
  return nil
58
97
  rescue ArgumentError
59
98
  raise InvalidParameterError, "'#{param}' is not a valid #{type}"
@@ -63,37 +102,37 @@ module RailsParam
63
102
  def validate!(param, options)
64
103
  options.each do |key, value|
65
104
  case key
66
- when :required
67
- raise InvalidParameterError, "Parameter is required" if value && param.nil?
68
- when :blank
69
- raise InvalidParameterError, "Parameter cannot be blank" if !value && case param
70
- when String
71
- !(/\S/ === param)
72
- when Array, Hash
73
- param.empty?
74
- else
75
- param.nil?
76
- end
77
- when :format
78
- raise InvalidParameterError, "Parameter must be a string if using the format validation" unless param.kind_of?(String)
79
- raise InvalidParameterError, "Parameter must match format #{value}" unless param =~ value
80
- when :is
81
- raise InvalidParameterError, "Parameter must be #{value}" unless param === value
82
- when :in, :within, :range
83
- raise InvalidParameterError, "Parameter must be within #{value}" unless param.nil? || case value
84
- when Range
85
- value.include?(param)
86
- else
87
- Array(value).include?(param)
88
- end
89
- when :min
90
- raise InvalidParameterError, "Parameter cannot be less than #{value}" unless param.nil? || value <= param
91
- when :max
92
- raise InvalidParameterError, "Parameter cannot be greater than #{value}" unless param.nil? || value >= param
93
- when :min_length
94
- raise InvalidParameterError, "Parameter cannot have length less than #{value}" unless param.nil? || value <= param.length
95
- when :max_length
96
- raise InvalidParameterError, "Parameter cannot have length greater than #{value}" unless param.nil? || value >= param.length
105
+ when :required
106
+ raise InvalidParameterError, "Parameter is required" if value && param.nil?
107
+ when :blank
108
+ raise InvalidParameterError, "Parameter cannot be blank" if !value && case param
109
+ when String
110
+ !(/\S/ === param)
111
+ when Array, Hash
112
+ param.empty?
113
+ else
114
+ param.nil?
115
+ end
116
+ when :format
117
+ raise InvalidParameterError, "Parameter must be a string if using the format validation" unless param.kind_of?(String)
118
+ raise InvalidParameterError, "Parameter must match format #{value}" unless param =~ value
119
+ when :is
120
+ raise InvalidParameterError, "Parameter must be #{value}" unless param === value
121
+ when :in, :within, :range
122
+ raise InvalidParameterError, "Parameter must be within #{value}" unless param.nil? || case value
123
+ when Range
124
+ value.include?(param)
125
+ else
126
+ Array(value).include?(param)
127
+ end
128
+ when :min
129
+ raise InvalidParameterError, "Parameter cannot be less than #{value}" unless param.nil? || value <= param
130
+ when :max
131
+ raise InvalidParameterError, "Parameter cannot be greater than #{value}" unless param.nil? || value >= param
132
+ when :min_length
133
+ raise InvalidParameterError, "Parameter cannot have length less than #{value}" unless param.nil? || value <= param.length
134
+ when :max_length
135
+ raise InvalidParameterError, "Parameter cannot have length greater than #{value}" unless param.nil? || value >= param.length
97
136
  end
98
137
  end
99
138
  end
@@ -1,3 +1,3 @@
1
1
  module RailsParam #:nodoc
2
- VERSION = "0.0.3"
2
+ VERSION = "0.9.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_param
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicolas Blanco
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-07 00:00:00.000000000 Z
11
+ date: 2015-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -97,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
97
  version: 1.3.6
98
98
  requirements: []
99
99
  rubyforge_project:
100
- rubygems_version: 2.2.2
100
+ rubygems_version: 2.4.8
101
101
  signing_key:
102
102
  specification_version: 4
103
103
  summary: Parameter Validation and Type Coercion for Rails