sinatra-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.
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: []