rack-param 0.1.0

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: 9b2edee1664ad9b019933bc685bf5f46cbeac16e
4
+ data.tar.gz: fc27ecd3dee2e3d1a510f118ffff495ba7de9cbd
5
+ SHA512:
6
+ metadata.gz: f40aab970852ee0aec2b0dce37ff7308ad04924801ddbc8a05ae945da5d59c646cc1d10a7df02d194b9fced920d442461ef4309a7413de2af3280a79015d9c11
7
+ data.tar.gz: 141fcefcaecb4637d94a073ebd7feb0081e37f511d5555269daa8340460e634651a5e35050b66277f3c342ef32fa227494b0277d5934d6c3cddfb0ac81af956f
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ #Changelog
2
+
3
+ v 0.0.1
4
+
5
+ - Initial release
6
+
7
+ v 0.1.0
8
+
9
+ - Complete rewrite
10
+ * Write tests
11
+ * Make rules more readable in `param.rb`
12
+ * `Rack::Request#params` now points to coerced and validated parameters
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rack-param.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Nathaniel Symer
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # Rack::Param
2
+
3
+ Parameter checking and validation for `Rack::Request`. Originally designed to be used with [`Sansom`](http://github.com/fhsjaagshs/fhsjaagshs), but it also works with [`Rack`](http://github.com/rack/rack).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rack-param'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it through `gem`:
16
+
17
+ $ gem install rack-param
18
+
19
+ ## Usage
20
+
21
+ require "rack/param"
22
+
23
+ r = Rack::Request env # pass your env
24
+ r.param :param_name, Integer, :required => true ...
25
+
26
+ Now, `r.params` should contain a single entry:
27
+
28
+ { :param_name => <some Integer> }
29
+
30
+ `Rack::Param` patches `Rack::Request#params` to contain only the validated parameters, in coerced form.
31
+
32
+ Here's a list of options:
33
+
34
+ `:required` => `true`/`false`<br />
35
+ `:blank` => `true`/`false`<br />
36
+ `:greater_than` => Any `Numeric`<br />
37
+ `:less_than` => Any `Numeric`<br />
38
+ `:min` => Any `Numeric`<br />
39
+ `:max` => Any `Numeric`<br />
40
+ `:length` => Any `Numeric`<br />
41
+ `:min_length` => Any `Numeric`<br />
42
+ `:max_length` => Any `Numeric`<br />
43
+ `:in` => Something that responds to `include?`<br />
44
+ `:regex` => A `Regexp`<br />
45
+ `:validator` => A block: `{ |param| true }`<br />
46
+
47
+ ## Contributing
48
+
49
+ 1. Fork it ( https://github.com/sansomrb/rack-param/fork )
50
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
51
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
52
+ 4. Push to the branch (`git push origin my-new-feature`)
53
+ 5. Create a new Pull Request
data/lib/rack/param.rb ADDED
@@ -0,0 +1,136 @@
1
+ #/usr/bin/env ruby
2
+
3
+ require "rack"
4
+ require "time"
5
+ require "date"
6
+
7
+ Boolean = "Boolean" # A boldfaced hack
8
+
9
+ module Rack
10
+ ParameterError = Class.new StandardError
11
+
12
+ class ::String
13
+ def truthy?
14
+ (/^(true|t|yes|y|1|on)$/ =~ downcase) != nil
15
+ end
16
+
17
+ def falsey?
18
+ (/^(false|f|no|n|0|off)$/ =~ downcase) != nil
19
+ end
20
+ end
21
+
22
+ class Request
23
+ alias_method :params_original, :params
24
+ def params
25
+ @processed_parameters ||= {}
26
+ end
27
+
28
+ def param name, type, opts={}
29
+ _name = name.to_s
30
+
31
+ p = Rack::Parameter.new(
32
+ :name => _name,
33
+ :value => params_original[_name] || params[_name],
34
+ :type => type,
35
+ :conditions => opts
36
+ )
37
+
38
+ raise ParameterError, p.error unless p.valid?
39
+ params[_name] = p.value
40
+ end
41
+ end
42
+
43
+ class Parameter
44
+ attr_reader :error, :value
45
+
46
+ class Rule
47
+ def initialize message, &block
48
+ @block = block
49
+ @message = message
50
+ end
51
+
52
+ def self.rule message, &block
53
+ new message, &block
54
+ end
55
+
56
+ def validate param, value
57
+ return @message.sub("$",param.to_s).sub("#",value.to_s) unless @block.call(param,value)
58
+ end
59
+ end
60
+
61
+ def initialize(opts={})
62
+ opts[:value].inspect
63
+ _opts = Hash[opts.dup.map { |k,v| [k.to_sym,v] }]
64
+ _opts.merge! _opts.delete(:conditions)
65
+ @default = _opts.delete :default
66
+ @required = _opts.delete :required
67
+ @transform = _opts.delete :transform
68
+ @delimiter = _opts.delete(:delimiter) || ","
69
+ @separator = _opts.delete(:separator) || ":"
70
+ @name = _opts.delete :name
71
+ @type = _opts.delete :type
72
+ @value = _opts.delete(:value) || @default
73
+ @error = process(_opts) unless default?
74
+ end
75
+
76
+ def valid?
77
+ @error.nil?
78
+ end
79
+
80
+ def default?
81
+ @default == @value && !@value.nil?
82
+ end
83
+
84
+ def required?
85
+ @required
86
+ end
87
+
88
+ def nil?
89
+ @value.nil?
90
+ end
91
+
92
+ def process opts
93
+ return "Parameter #{@name} is required." if @value.nil? && required?
94
+
95
+ unless @value.class == @type
96
+ begin
97
+ @value = case @type.to_s.downcase.to_sym
98
+ when :date then Date.parse @value
99
+ when :time then Time.parse @value
100
+ when :datetime then DateTime.parse @value
101
+ when :array then @value.split(@delimiter)
102
+ when :hash then Hash[@value.split(@delimiter).map { |c| c.split @separator, 2 }]
103
+ when :boolean then (@value.falsey? ? false : @value.truthy? ? true : raise(StandardError))
104
+ else method(@type.to_s.to_sym).call @value end
105
+ rescue StandardError => e
106
+ return "Parameter `#{@name}` is not a valid #{@type.to_s}."
107
+ end
108
+ end
109
+
110
+ validate_error = opts.detect { |k,v| rules[k].validate @value, v }
111
+ return validate_error unless validate_error.nil?
112
+
113
+ @value = @transform.to_proc.call @value if @transform
114
+ nil
115
+ end
116
+
117
+ def rules
118
+ @rules ||= {}
119
+ if @rules.empty?
120
+ @rules[:blank] = Rule.rule("$ cannot be blank.") { |p,v| v == (p.empty? rescue false) }
121
+ @rules[:greater_than] = Rule.rule("$ can't be less than #.") { |p,v| p > v }
122
+ @rules[:less_than] = Rule.rule("$ can't be greater than #.") { |p,v| p < v }
123
+ @rules[:min] = Rule.rule("$ can't be less than #.") { |p,v| p >= v }
124
+ @rules[:max] = Rule.rule("$ can't be greater than #.") { |p,v| p <= v }
125
+ @rules[:length] = Rule.rule("$ can't be longer or shorter than #.") { |p,v| p.length == v }
126
+ @rules[:min_length] = Rule.rule("$ must be longer than #.") { |p,v| p.length >= v }
127
+ @rules[:max_length] = Rule.rule("$ must be shorter than #.") { |p,v| p.length <= v }
128
+ @rules[:in] = Rule.rule("$ must be included in #.") { |p,v| v.include? p }
129
+ @rules[:contains] = Rule.rule("$ must include #") { |p,v| p.include? v }
130
+ @rules[:regex] = Rule.rule("$ failed validation.") { |p,v| v.match p }
131
+ @rules[:validator] = Rule.rule("$ failed validation.") { |p,v| v.call p }
132
+ end
133
+ @rules
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rack-param"
7
+ spec.version = "0.1.0"
8
+ spec.authors = ["Nathaniel Symer"]
9
+ spec.email = ["nate@natesymer.com"]
10
+ spec.summary = "Sane parameter validation for Rack::Request."
11
+ spec.description = spec.summary + " Originally written for use with Sansom."
12
+ spec.homepage = "https://github.com/sansomrb/rack-param"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_dependency "rack", "~> 1.0"
22
+ end
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "./spec_helper.rb"
4
+
5
+ describe Rack::Parameter do
6
+ before :all do
7
+ @p = {
8
+ :date => "2014/8/4",
9
+ :time => "Thu Nov 29 14:33:20 GMT 2001",
10
+ :array => "asdf,asdf,asdf",
11
+ :datetime => "2012-02-09 20:05:33",
12
+ :hash => "key:value,this:that,foo:bar",
13
+ :true => "true",
14
+ :t => "t",
15
+ :yes => "yes",
16
+ :y => "y",
17
+ :one => "1",
18
+ :integer => "42",
19
+ :float => "420.42",
20
+ :string => "foo bar baz",
21
+ :should_fail => "asdfasdf"
22
+ }
23
+ end
24
+
25
+ context "when coercing types" do
26
+ it "parses a Date" do
27
+ @r.param :date, Date
28
+
29
+ expect(@r.params["date"]).to eq(Date.new(2014, 8, 4))
30
+ end
31
+
32
+ it "parses a Time" do
33
+ @r.param :time, Time
34
+
35
+ expect(@r.params["time"].to_i).to eq(1007044400)
36
+ end
37
+
38
+ it "parses a DateTime" do
39
+ @r.param :datetime, DateTime
40
+
41
+ expect(@r.params["datetime"].to_s).to eq("2012-02-09T20:05:33+00:00")
42
+ end
43
+
44
+ it "parses an Array" do
45
+ @r.param :array, Array
46
+
47
+ expect(@r.params["array"]).to eq(["asdf", "asdf", "asdf"])
48
+ end
49
+
50
+ it "parses a Hash" do
51
+ @r.param :hash, Hash
52
+
53
+ expect(@r.params["hash"]).to eq({"key" => "value", "this" => "that", "foo" => "bar"})
54
+ end
55
+
56
+ it "coerces a Boolean" do
57
+ @r.param :true, Boolean
58
+ @r.param :t, Boolean
59
+ @r.param :yes, Boolean
60
+ @r.param :y, Boolean
61
+ @r.param :one, Boolean
62
+
63
+ expect(@r.params["true"]).to eq(true)
64
+ expect(@r.params["t"]).to eq(true)
65
+ expect(@r.params["yes"]).to eq(true)
66
+ expect(@r.params["y"]).to eq(true)
67
+ expect(@r.params["one"]).to eq(true)
68
+ end
69
+
70
+ it "coerces an Integer" do
71
+ @r.param :integer, Integer
72
+
73
+ expect(@r.params["integer"]).to eq(42)
74
+ end
75
+
76
+ it "coerces a Float" do
77
+ @r.param :float, Float
78
+
79
+ expect(@r.params["float"]).to eq(420.42)
80
+ end
81
+
82
+ it "\"coerces\" a String" do
83
+ @r.param :string, String
84
+
85
+ expect(@r.params["string"]).to eq("foo bar baz")
86
+ end
87
+
88
+ it "errors out on unrecognized types" do
89
+ expect { @r.param :should_fail, Date }.to raise_error(Rack::ParameterError)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "./spec_helper.rb"
4
+
5
+ describe Rack::Parameter do
6
+ before :all do
7
+ @p = {
8
+ :int_three => "3",
9
+ :int_six => "6",
10
+ :string => "mary had a little lamb",
11
+ :callback_url => "http://www.example.com/",
12
+ :blank => "",
13
+ :required => "This is very important data",
14
+ :array => "one,two,three,four"
15
+ }
16
+ end
17
+
18
+ context "when given rules" do
19
+ it "checks a parameter based on :required" do
20
+ expect { @r.param :not_a_param, String, :required => true }.to raise_error(Rack::ParameterError)
21
+ expect { @r.param :required, String, :required => true }.to_not raise_error
22
+ end
23
+
24
+ it "checks a parameter based on :blank" do
25
+ expect { @r.param :blank, String, :blank => true }.to_not raise_error
26
+ expect { @r.param :string, String, :blank => false }.to_not raise_error
27
+ end
28
+
29
+ it "checks a parameter based on :greater_than" do
30
+ expect { @r.param :int_six, Integer, :greater_than => 5 }.to_not raise_error
31
+ end
32
+
33
+ it "checks a parameter based on :less_than" do
34
+ expect { @r.param :int_three, Integer, :less_than => 4 }.to_not raise_error
35
+ end
36
+
37
+ it "checks a parameter based on :min" do
38
+ expect { @r.param :int_three, Integer, :min => 3 }.to_not raise_error
39
+ expect { @r.param :int_three, Integer, :min => 4 }.to raise_error(Rack::ParameterError)
40
+ end
41
+
42
+ it "checks a parameter based on :max" do
43
+ expect { @r.param :int_three, Integer, :max => 3 }.to_not raise_error
44
+ expect { @r.param :int_three, Integer, :max => 2 }.to raise_error(Rack::ParameterError)
45
+ end
46
+
47
+ it "checks a parameter based on :length" do
48
+ expect { @r.param :string, String, :length => 22 }.to_not raise_error
49
+ expect { @r.param :string, String, :length => 10 }.to raise_error(Rack::ParameterError)
50
+ end
51
+
52
+ it "checks a parameter based on :min_length" do
53
+ expect { @r.param :string, String, :min_length => 20 }.to_not raise_error
54
+ expect { @r.param :string, String, :min_length => 30 }.to raise_error(Rack::ParameterError)
55
+ end
56
+
57
+ it "checks a parameter based on :max_length" do
58
+ expect { @r.param :string, String, :max_length => 25 }.to_not raise_error
59
+ expect { @r.param :string, String, :max_length => 20 }.to raise_error(Rack::ParameterError)
60
+ end
61
+
62
+ it "checks a parameter based on :in" do
63
+ expect { @r.param :int_three, Integer, :in => [3] }.to_not raise_error
64
+ expect { @r.param :int_three, Integer, :in => [] }.to raise_error(Rack::ParameterError)
65
+ end
66
+
67
+ it "checks a parameter based on :contains" do
68
+ expect { @r.param :array, Array, :contains => "one" }.to_not raise_error
69
+ expect { @r.param :array, Array, :contains => "three hundred" }.to raise_error(Rack::ParameterError)
70
+ end
71
+
72
+ it "checks a parameter based on :regex" do
73
+ expect { @r.param :string, String, :regex => /^mary.+lamb$/ }.to_not raise_error
74
+ expect { @r.param :string, String, :regex => /^bo.+peep$/ }.to raise_error(Rack::ParameterError)
75
+ end
76
+
77
+ it "checks a parameter based on :validator" do
78
+ expect { @r.param :int_three, Integer, :validator => lambda { |p| p < 5 && p > 0 } }.to_not raise_error
79
+ expect { @r.param :int_three, Integer, :validator => lambda { |p| p < 0 } }.to raise_error(Rack::ParameterError)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rspec"
4
+
5
+ module TestHelpers
6
+ require_relative File.dirname(File.dirname(__FILE__)) + "/lib/rack/param.rb"
7
+
8
+ require "rack"
9
+ require "cgi"
10
+ require "stringio"
11
+
12
+ def env params
13
+ {
14
+ "CONTENT_TYPE" => "text/plain",
15
+ "QUERY_STRING" => params.map { |k,v| "#{k.to_s}=#{CGI.escape(v.to_s)}" }.join('&'),
16
+ "REQUEST_METHOD" => "GET",
17
+ "REQUEST_PATH" => "/",
18
+ "REQUEST_URI" => "/",
19
+ "HTTP_HOST" => "localhost:2000",
20
+ "SERVER_NAME" => "localhost",
21
+ "SERVER_PORT" => "2000",
22
+ "PATH_INFO" => "/",
23
+ "rack.url_scheme" => "http",
24
+ "rack.input" => StringIO.new("")
25
+ }
26
+ end
27
+ end
28
+
29
+ RSpec.configure do |c|
30
+ c.include TestHelpers
31
+
32
+ c.before :each do
33
+ @p ||= {}
34
+ @r = Rack::Request.new env(@p.dup)
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-param
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nathaniel Symer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-11 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ description: Sane parameter validation for Rack::Request. Originally written for use
42
+ with Sansom.
43
+ email:
44
+ - nate@natesymer.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - CHANGELOG.md
51
+ - Gemfile
52
+ - LICENSE.txt
53
+ - README.md
54
+ - lib/rack/param.rb
55
+ - rack-param.gemspec
56
+ - spec/coercion_spec.rb
57
+ - spec/rules_spec.rb
58
+ - spec/spec_helper.rb
59
+ homepage: https://github.com/sansomrb/rack-param
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.2.2
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Sane parameter validation for Rack::Request.
83
+ test_files:
84
+ - spec/coercion_spec.rb
85
+ - spec/rules_spec.rb
86
+ - spec/spec_helper.rb