sinatra-param 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem 'sinatra', '~> 1.3'
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sinatra-param (0.0.1)
5
+ sinatra (~> 1.3)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ rack (1.4.1)
11
+ rack-protection (1.2.0)
12
+ rack
13
+ rake (0.9.2.2)
14
+ rspec (0.6.4)
15
+ sinatra (1.3.2)
16
+ rack (~> 1.3, >= 1.3.6)
17
+ rack-protection (~> 1.2)
18
+ tilt (~> 1.3, >= 1.3.3)
19
+ tilt (1.3.3)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ rake (~> 0.9.2)
26
+ rspec (~> 0.6.1)
27
+ sinatra (~> 1.3)
28
+ sinatra-param!
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Mattt Thompson (http://mattt.me/)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # sinatra-param
2
+ _Parameter Validation and Typecasting for Sinatra_
3
+
4
+ REST conventions takes the guesswork out of designing and consuming web APIs. `GET` / `POST` / `PATCH` / `DELETE` resource endpoints and you get what you'd expect.
5
+
6
+ But figuring out what parameters are expected... well, all bets are off. This Sinatra extension takes a first step to solving this problem on the developer side
7
+
8
+ **`sinatra-param` allows you to declare, validate, and transform endpoint parameters as you would in frameworks like [DataMapper](http://datamapper.org/) or [ActiveModel](http://rubydoc.info/gems/activemodel/3.2.3/frames).**
9
+
10
+ ## Example
11
+
12
+ ``` ruby
13
+ class App < Sinatra::Base
14
+ helpers Sinatra::Param
15
+
16
+ before do
17
+ content_type :json
18
+ end
19
+
20
+ # GET /search?q=example
21
+ # GET /search?q=example&categories=news
22
+ # GET /search?q=example&sort=created_at&order=ASC
23
+ get '/search' do
24
+ param :q, String, required: true
25
+ param :categories, Array
26
+ param :sort, String, default: "title"
27
+ param :order, String, in: ["ASC", "DESC"], transform: :upcase, default: "ASC"
28
+
29
+ {...}.to_json
30
+ end
31
+ end
32
+ ```
33
+
34
+
35
+ ### Parameter Types
36
+
37
+ 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`.
38
+
39
+ - String
40
+ - Integer
41
+ - Float
42
+ - Boolean _("1/0", "true/false", "t/f", "yes/no", "y/n")_
43
+ - Array _("1,2,3,4,5")_
44
+ - Hash _(key1:value1,key2:value2)_
45
+
46
+ ### Validations
47
+
48
+ Encapsulate business logic in a consistent way with validations. If a parameter does not satisfy a particular condition, a `406` error is returned with a message explaining the failure.
49
+
50
+ - `required`
51
+ - `blank`
52
+ - `is`
53
+ - `in`, `within`, `range`
54
+ - `min` / `max`
55
+
56
+ ### Defaults and Transformations
57
+
58
+ Passing a `default` option will provide a default value for a parameter if none is passed.
59
+
60
+ 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 Procs and symbols) will do.
61
+
62
+ ## Next Steps
63
+
64
+ - [Design by contract](http://en.wikipedia.org/wiki/Design_by_contract) like this is great for developers, and with a little meta-programming, it could probably be exposed to users as well. The self-documenting dream of [Hypermedia folks](http://twitter.com/#!/steveklabnik) could well be within reach.
65
+
66
+ - Another pain point is the awkward way parameters are passed as JSON in HTTP bodies. I'd love to see an elegant, unobtrusive way to do this automatically.
67
+
68
+ - Testing. This will happen soon.
69
+
70
+ ## Contact
71
+
72
+ Mattt Thompson
73
+
74
+ - http://github.com/mattt
75
+ - http://twitter.com/mattt
76
+ - m@mattt.me
77
+
78
+ ## License
79
+
80
+ sinatra-param is available under the MIT license. See the LICENSE file for more info.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ gemspec = eval(File.read("sinatra-param.gemspec"))
5
+
6
+ task :build => "#{gemspec.full_name}.gem"
7
+
8
+ file "#{gemspec.full_name}.gem" => gemspec.files + ["sinatra-param.gemspec"] do
9
+ system "gem build sinatra-param.gemspec"
10
+ system "gem install sinatra-param-#{Sinatra::Param::VERSION}.gem"
11
+ end
data/example/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gem 'sinatra'
4
+ gem 'thin'
@@ -0,0 +1,24 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ daemons (1.1.8)
5
+ eventmachine (0.12.10)
6
+ rack (1.4.1)
7
+ rack-protection (1.2.0)
8
+ rack
9
+ sinatra (1.3.2)
10
+ rack (~> 1.3, >= 1.3.6)
11
+ rack-protection (~> 1.2)
12
+ tilt (~> 1.3, >= 1.3.3)
13
+ thin (1.3.1)
14
+ daemons (>= 1.0.9)
15
+ eventmachine (>= 0.12.6)
16
+ rack (>= 1.0.0)
17
+ tilt (1.3.3)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ sinatra
24
+ thin
data/example/Procfile ADDED
@@ -0,0 +1 @@
1
+ web: bundle exec thin start -p $PORT
data/example/app.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ require '../lib/sinatra/param'
5
+
6
+ class App < Sinatra::Base
7
+ helpers Sinatra::Param
8
+
9
+ before do
10
+ content_type :json
11
+ end
12
+
13
+ # GET /messages
14
+ # GET /messages?sort=name&order=ASC
15
+ get '/messages' do
16
+ param :sort, String, default: "name"
17
+ param :order, String, in: ["ASC", "DESC"], transform: :upcase, default: "ASC"
18
+
19
+ {
20
+ sort: params[:sort],
21
+ order: params[:order]
22
+ }.to_json
23
+ end
24
+
25
+ # GET /messages/1,2,3,4,5
26
+ get '/messages/:ids' do
27
+ param :ids, Array, required: true
28
+
29
+ {
30
+ ids: params[:ids]
31
+ }.to_json
32
+ end
33
+
34
+ # POST /messages/1/response
35
+ post '/messages/:id/response' do
36
+ param :message, String, max: 1024, required: true
37
+
38
+ {
39
+ message: params[:message]
40
+ }.to_json
41
+ end
42
+ end
43
+
data/example/config.ru ADDED
@@ -0,0 +1,3 @@
1
+ require './app'
2
+
3
+ run App
@@ -0,0 +1,70 @@
1
+ require 'sinatra/base'
2
+
3
+ module Sinatra
4
+ module Param
5
+ VERSION = "0.0.1"
6
+
7
+ class InvalidParameterError < StandardError; end
8
+
9
+ def param(name, type, options = {})
10
+ begin
11
+ params[name] = coerce(params[name], type, options) || options[:default]
12
+ params[name] = options[:transform].to_proc.call(params[name]) if options[:transform]
13
+ validate!(params[name], options)
14
+ rescue
15
+ error = "Invalid parameter, #{name}"
16
+ if content_type.match(mime_type(:json))
17
+ error = {message: error}.to_json
18
+ end
19
+
20
+ halt 406, error
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def coerce(param, type, options = {})
27
+ return nil if param.nil?
28
+ return Integer(param) if type == Integer
29
+ return Float(param) if type == Float
30
+ return String(param) if type == String
31
+ return Array(param.split(options[:delimiter] || ",")) if type == Array
32
+ return Hash[param.split(options[:delimiter] || ",").map{|c| c.split(options[:separator] || ":")}] if type == Hash
33
+ return ((/(false|f|no|n|0)$/i === param) ? false : (/(true|t|yes|y|1)$/i === param) ? true : nil) if type == Boolean
34
+ return nil
35
+ end
36
+
37
+ def validate!(param, options)
38
+ options.each do |key, value|
39
+ case key
40
+ when :required
41
+ raise InvalidParameterError if value && param.nil?
42
+ when :blank
43
+ raise InvalidParameterError if !value && case param
44
+ when String
45
+ !(/\S/ === param)
46
+ when Array, Hash
47
+ param.empty?
48
+ else
49
+ param.nil?
50
+ end
51
+ when :is
52
+ raise InvalidParameterError unless value === param
53
+ when :in, :within, :range
54
+ raise InvalidParameterError unless case value
55
+ when Range
56
+ value.include?(param)
57
+ else
58
+ Array(value).include?(param)
59
+ end
60
+ when :min
61
+ raise InvalidParameterError unless value <= param
62
+ when :max
63
+ raise InvalidParameterError unless value >= param
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ helpers Param
70
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "sinatra/param"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "sinatra-param"
7
+ s.authors = ["Mattt Thompson"]
8
+ s.email = "m@mattt.me"
9
+ s.homepage = "http://github.com/mattt/sinatra-param"
10
+ s.version = Sinatra::Param::VERSION
11
+ s.platform = Gem::Platform::RUBY
12
+ s.summary = "sinatra-param"
13
+ s.description = "Parameter Contracts for Sinatra"
14
+
15
+ s.add_dependency "sinatra", "~> 1.3"
16
+
17
+ s.add_development_dependency "rspec", "~> 0.6.1"
18
+ s.add_development_dependency "rake", "~> 0.9.2"
19
+
20
+ s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor)/ }
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ["lib"]
24
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-param
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mattt Thompson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-30 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sinatra
16
+ requirement: &70189725114120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70189725114120
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70189725113620 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.6.1
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70189725113620
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70189725113160 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.2
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70189725113160
47
+ description: Parameter Contracts for Sinatra
48
+ email: m@mattt.me
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - ./example/app.rb
54
+ - ./example/config.ru
55
+ - ./example/Gemfile
56
+ - ./example/Gemfile.lock
57
+ - ./example/Procfile
58
+ - ./Gemfile
59
+ - ./Gemfile.lock
60
+ - ./lib/sinatra/param.rb
61
+ - ./LICENSE
62
+ - ./Rakefile
63
+ - ./README.md
64
+ - ./sinatra-param.gemspec
65
+ homepage: http://github.com/mattt/sinatra-param
66
+ licenses: []
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ segments:
78
+ - 0
79
+ hash: 4481802987950945093
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ segments:
87
+ - 0
88
+ hash: 4481802987950945093
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.15
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: sinatra-param
95
+ test_files: []