grape 0.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+ .rvmrc
21
+ .bundle
22
+
23
+ ## PROJECT::SPECIFIC
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format=nested
3
+ --backtrace
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ gem 'rack'
2
+ gem 'rack-mount'
3
+ gem 'rack-jsonp'
4
+
5
+ gem 'activesupport', '>= 3.0.0.rc2'
6
+
7
+ group :development do
8
+ gem 'rake'
9
+ gem 'jeweler'
10
+ end
11
+
12
+ group :test do
13
+ gem 'rspec', '>= 2.0.0.beta.19'
14
+ gem 'rack-test'
15
+ gem 'cucumber', '>= 0.8.5'
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ GEM
2
+ specs:
3
+ activesupport (3.0.0.rc2)
4
+ builder (2.1.2)
5
+ cucumber (0.8.5)
6
+ builder (~> 2.1.2)
7
+ diff-lcs (~> 1.1.2)
8
+ gherkin (~> 2.1.4)
9
+ json_pure (~> 1.4.3)
10
+ term-ansicolor (~> 1.0.4)
11
+ diff-lcs (1.1.2)
12
+ gemcutter (0.6.1)
13
+ gherkin (2.1.5)
14
+ trollop (~> 1.16.2)
15
+ git (1.2.5)
16
+ jeweler (1.4.0)
17
+ gemcutter (>= 0.1.0)
18
+ git (>= 1.2.5)
19
+ rubyforge (>= 2.0.0)
20
+ json_pure (1.4.3)
21
+ rack (1.2.1)
22
+ rack-jsonp (1.0.0)
23
+ rack-mount (0.6.9)
24
+ rack (>= 1.0.0)
25
+ rack-test (0.5.4)
26
+ rack (>= 1.0)
27
+ rake (0.8.7)
28
+ rspec (2.0.0.beta.19)
29
+ rspec-core (= 2.0.0.beta.19)
30
+ rspec-expectations (= 2.0.0.beta.19)
31
+ rspec-mocks (= 2.0.0.beta.19)
32
+ rspec-core (2.0.0.beta.19)
33
+ rspec-expectations (2.0.0.beta.19)
34
+ diff-lcs (>= 1.1.2)
35
+ rspec-mocks (2.0.0.beta.19)
36
+ rubyforge (2.0.4)
37
+ json_pure (>= 1.1.7)
38
+ term-ansicolor (1.0.5)
39
+ trollop (1.16.2)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ activesupport (>= 3.0.0.rc2)
46
+ cucumber (>= 0.8.5)
47
+ jeweler
48
+ rack
49
+ rack-jsonp
50
+ rack-mount
51
+ rack-test
52
+ rake
53
+ rspec (>= 2.0.0.beta.19)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael Bleigh
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,43 @@
1
+ = UNDER CONSTRUCTION. DO NOT USE
2
+
3
+ = Grape
4
+
5
+ Grape is a REST-like API micro-framework for Ruby. It is built to complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily provide APIs. It has built-in support for common conventions such as multiple formats, subdomain/prefix restriction, and versioning.
6
+
7
+ class Twitter < Grape::Base
8
+ subdomain 'api'
9
+ version '1'
10
+ formats :xml, :json
11
+ authorization :oauth, User
12
+
13
+ resource :statuses do
14
+ group :timelines do
15
+ formats :rss, :atom
16
+
17
+ get :public_timeline do
18
+ optional :trim_user, Boolean
19
+ optional :include_entities, Boolean
20
+
21
+ Tweet.limit(20)
22
+ end
23
+
24
+ get :home_timeline do
25
+ authorized
26
+
27
+ user.home_timeline
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ == Note on Patches/Pull Requests
34
+
35
+ * Fork the project.
36
+ * Make your feature addition or bug fix.
37
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
38
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
39
+ * Send me a pull request. Bonus points for topic branches.
40
+
41
+ == Copyright
42
+
43
+ Copyright (c) 2010 Michael Bleigh and Intridea, Inc. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.setup :default, :test, :development
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "grape"
10
+ gem.summary = %Q{A Ruby framework for rapid API development.}
11
+ gem.description = %Q{A Ruby framework for rapid API development with great conventions.}
12
+ gem.email = "michael@intridea.com"
13
+ gem.homepage = "http://github.com/intridea/grape"
14
+ gem.authors = ["Michael Bleigh"]
15
+ gem.add_bundler_dependencies
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'rspec/core/rake_task'
24
+ RSpec::Core::RakeTask.new(:spec) do |spec|
25
+ spec.pattern = 'spec/**/*_spec.rb'
26
+ end
27
+
28
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+ task :default => :spec
35
+
36
+ require 'rake/rdoctask'
37
+ Rake::RDocTask.new do |rdoc|
38
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
39
+
40
+ rdoc.rdoc_dir = 'rdoc'
41
+ rdoc.title = "grape #{version}"
42
+ rdoc.rdoc_files.include('README*')
43
+ rdoc.rdoc_files.include('lib/**/*.rb')
44
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0.alpha.1
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/grape.gemspec ADDED
@@ -0,0 +1,92 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{grape}
8
+ s.version = "0.0.0.alpha.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Bleigh"]
12
+ s.date = %q{2010-08-27}
13
+ s.description = %q{A Ruby framework for rapid API development with great conventions.}
14
+ s.email = %q{michael@intridea.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ ".rspec",
23
+ ".rvmrc",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "autotest/discover.rb",
31
+ "grape.gemspec",
32
+ "lib/grape.rb",
33
+ "lib/grape/middleware/auth/oauth2.rb",
34
+ "lib/grape/middleware/base.rb",
35
+ "lib/grape/middleware/error.rb",
36
+ "lib/grape/middleware/formatter.rb",
37
+ "lib/grape/middleware/prefixer.rb",
38
+ "lib/grape/middleware/versioner.rb",
39
+ "spec/grape/middleware/auth/oauth2_spec.rb",
40
+ "spec/grape/middleware/base_spec.rb",
41
+ "spec/grape/middleware/error_spec.rb",
42
+ "spec/grape/middleware/formatter_spec.rb",
43
+ "spec/grape/middleware/prefixer_spec.rb",
44
+ "spec/grape/middleware/versioner_spec.rb",
45
+ "spec/grape_spec.rb",
46
+ "spec/spec_helper.rb"
47
+ ]
48
+ s.homepage = %q{http://github.com/intridea/grape}
49
+ s.rdoc_options = ["--charset=UTF-8"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = %q{1.3.7}
52
+ s.summary = %q{A Ruby framework for rapid API development.}
53
+ s.test_files = [
54
+ "spec/grape/middleware/auth/oauth2_spec.rb",
55
+ "spec/grape/middleware/base_spec.rb",
56
+ "spec/grape/middleware/error_spec.rb",
57
+ "spec/grape/middleware/formatter_spec.rb",
58
+ "spec/grape/middleware/prefixer_spec.rb",
59
+ "spec/grape/middleware/versioner_spec.rb",
60
+ "spec/grape_spec.rb",
61
+ "spec/spec_helper.rb"
62
+ ]
63
+
64
+ if s.respond_to? :specification_version then
65
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
69
+ s.add_runtime_dependency(%q<rack>, [">= 0"])
70
+ s.add_runtime_dependency(%q<rack-mount>, [">= 0"])
71
+ s.add_runtime_dependency(%q<rack-jsonp>, [">= 0"])
72
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0.rc2"])
73
+ s.add_development_dependency(%q<rake>, [">= 0"])
74
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
75
+ else
76
+ s.add_dependency(%q<rack>, [">= 0"])
77
+ s.add_dependency(%q<rack-mount>, [">= 0"])
78
+ s.add_dependency(%q<rack-jsonp>, [">= 0"])
79
+ s.add_dependency(%q<activesupport>, [">= 3.0.0.rc2"])
80
+ s.add_dependency(%q<rake>, [">= 0"])
81
+ s.add_dependency(%q<jeweler>, [">= 0"])
82
+ end
83
+ else
84
+ s.add_dependency(%q<rack>, [">= 0"])
85
+ s.add_dependency(%q<rack-mount>, [">= 0"])
86
+ s.add_dependency(%q<rack-jsonp>, [">= 0"])
87
+ s.add_dependency(%q<activesupport>, [">= 3.0.0.rc2"])
88
+ s.add_dependency(%q<rake>, [">= 0"])
89
+ s.add_dependency(%q<jeweler>, [">= 0"])
90
+ end
91
+ end
92
+
data/lib/grape.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rack'
2
+ require 'rack/builder'
3
+
4
+ require 'grape/middleware/base'
5
+ require 'grape/middleware/prefixer'
6
+ require 'grape/middleware/versioner'
7
+ require 'grape/middleware/formatter'
8
+ require 'grape/middleware/error'
9
+
10
+ require 'grape/middleware/auth/oauth2'
@@ -0,0 +1,55 @@
1
+ module Grape::Middleware::Auth
2
+ class OAuth2 < Grape::Middleware::Base
3
+ def default_options
4
+ {
5
+ :token_class => 'AccessToken',
6
+ :realm => 'OAuth API'
7
+ }
8
+ end
9
+
10
+ def before
11
+ if request['oauth_token']
12
+ verify_token(request['oauth_token'])
13
+ elsif env['Authorization'] && t = parse_authorization_header
14
+ verify_token(t)
15
+ end
16
+ end
17
+
18
+ def token_class
19
+ @klass ||= eval(options[:token_class])
20
+ end
21
+
22
+ def verify_token(token)
23
+ if token = token_class.verify(token)
24
+ if token.expired?
25
+ error_out(401, 'expired_token')
26
+ else
27
+ if token.permission_for?(env)
28
+ env['api.token'] = token
29
+ else
30
+ error_out(403, 'insufficient_scope')
31
+ end
32
+ end
33
+ else
34
+ error_out(401, 'invalid_token')
35
+ end
36
+ end
37
+
38
+ def parse_authorization_header
39
+ if env['Authorization'] =~ /oauth (.*)/i
40
+ $1
41
+ end
42
+ end
43
+
44
+ def error_out(status, error)
45
+ throw :error, {
46
+ :message => 'The token provided has expired.',
47
+ :status => status,
48
+ :headers => {
49
+ 'WWW-Authenticate' => "OAuth realm='#{options[:realm]}', error='#{error}'"
50
+ }
51
+ }
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,36 @@
1
+ module Grape
2
+ module Middleware
3
+ class Base
4
+ attr_reader :app, :env, :options
5
+
6
+ def initialize(app, options = {})
7
+ @app = app
8
+ @options = default_options.merge(options)
9
+ end
10
+
11
+ def default_options; {} end
12
+
13
+ def call(env)
14
+ dup.call!(env)
15
+ end
16
+
17
+ def call!(env)
18
+ @env = env
19
+ before
20
+ @app_response = @app.call(@env)
21
+ after || @app_response
22
+ end
23
+
24
+ def before; end
25
+ def after; end
26
+
27
+ def request
28
+ Rack::Request.new(self.env)
29
+ end
30
+
31
+ def response
32
+ Rack::Response.new(@app_response)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ require 'grape/middleware/base'
2
+
3
+ module Grape
4
+ module Middleware
5
+ class Error < Base
6
+ def call!(env)
7
+ @env = env
8
+ err = catch :error do
9
+ @app.call(@env)
10
+ end
11
+
12
+ error_response(err)
13
+ end
14
+
15
+ def error_response(error = {})
16
+ Rack::Response.new([(error[:message] || options[:default_message])], error[:status] || 403, error[:headers] || {}).finish
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,59 @@
1
+ require 'grape/middleware/base'
2
+ require 'active_support/json'
3
+
4
+ module Grape
5
+ module Middleware
6
+ class Formatter < Base
7
+ CONTENT_TYPES = {
8
+ :xml => 'application/xml',
9
+ :json => 'application/json',
10
+ :atom => 'application/atom+xml',
11
+ :rss => 'application/rss+xml'
12
+ }
13
+
14
+ def default_options
15
+ {
16
+ :default_format => :json,
17
+ :content_types => {}
18
+ }
19
+ end
20
+
21
+ def content_types
22
+ CONTENT_TYPES.merge(options[:content_types])
23
+ end
24
+
25
+ def before
26
+ fmt = format_from_extension || format_from_header || options[:default_format]
27
+
28
+ if content_types.key?(fmt)
29
+ env['api.format'] = fmt
30
+ else
31
+ throw :error, :status => 406, :message => 'The requested format is not supported.'
32
+ end
33
+ end
34
+
35
+ def format_from_extension
36
+ parts = request.path.split('.')
37
+ hit = parts.last.to_sym
38
+
39
+ if parts.size <= 1
40
+ nil
41
+ else
42
+ hit
43
+ end
44
+ end
45
+
46
+ def format_from_header
47
+ # TODO: Implement Accept header parsing.
48
+ end
49
+
50
+ def after
51
+ status, headers, bodies = *@app_response
52
+ bodies.map! do |body|
53
+ ActiveSupport::JSON.encode(body)
54
+ end
55
+ [status, headers, bodies]
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,20 @@
1
+ require 'grape/middleware/base'
2
+
3
+ module Grape
4
+ module Middleware
5
+ class Prefixer < Base
6
+ def prefix
7
+ prefix = options[:prefix] || ""
8
+ prefix.insert(0, '/') unless prefix.index('/') == 0
9
+ prefix
10
+ end
11
+
12
+ def before
13
+ if env['PATH_INFO'].index(prefix) == 0
14
+ env['PATH_INFO'].gsub!(prefix, '')
15
+ env['PATH_INFO'].insert(0, '/') unless env['PATH_INFO'].index('/') == 0
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require 'grape/middleware/base'
2
+
3
+ module Grape
4
+ module Middleware
5
+ class Versioner < Base
6
+ def default_options
7
+ {
8
+ :pattern => /.*/i
9
+ }
10
+ end
11
+
12
+ def before
13
+ pieces = env['PATH_INFO'].split('/')
14
+ potential_version = pieces[1]
15
+ if potential_version =~ options[:pattern]
16
+ truncated_path = "/#{pieces[2..-1].join('/')}"
17
+ env['api.version'] = potential_version
18
+ env['PATH_INFO'] = truncated_path
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Middleware::Auth::OAuth2 do
4
+ class FakeToken
5
+ def self.verify(token)
6
+ FakeToken.new(token) if %w(g e).include?(token[0..0])
7
+ end
8
+
9
+ def initialize(token)
10
+ self.token = token
11
+ end
12
+
13
+ def expired?
14
+ self.token[0..0] == 'e'
15
+ end
16
+
17
+ def permission_for?(env)
18
+ env['PATH_INFO'] == '/forbidden' ? false : true
19
+ end
20
+
21
+ attr_accessor :token
22
+ end
23
+
24
+ def app
25
+ Rack::Builder.app do
26
+ use Grape::Middleware::Auth::OAuth2, :token_class => 'FakeToken'
27
+ run lambda{|env| [200, {}, [ (env['api.token'].token rescue '') ]]}
28
+ end
29
+ end
30
+
31
+ context 'with the token in the query string' do
32
+ context 'and a valid token' do
33
+ before { get '/awesome?oauth_token=g123' }
34
+
35
+ it 'should set env["api.token"]' do
36
+ last_response.body.should == 'g123'
37
+ end
38
+ end
39
+
40
+ context 'and an invalid token' do
41
+ before do
42
+ @err = catch :error do
43
+ get '/awesome?oauth_token=b123'
44
+ end
45
+ end
46
+
47
+ it 'should throw an error' do
48
+ @err[:status].should == 401
49
+ end
50
+
51
+ it 'should set the WWW-Authenticate header in the response' do
52
+ @err[:headers]['WWW-Authenticate'].should == "OAuth realm='OAuth API', error='invalid_token'"
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'with an expired token' do
58
+ before do
59
+ @err = catch :error do
60
+ get '/awesome?oauth_token=e123'
61
+ end
62
+ end
63
+
64
+ it { @err[:status].should == 401 }
65
+ it { @err[:headers]['WWW-Authenticate'].should == "OAuth realm='OAuth API', error='expired_token'" }
66
+ end
67
+
68
+ context 'with the token in the header' do
69
+ before { get '/awesome', {}, 'Authorization' => 'OAuth g123' }
70
+ it { last_response.body.should == 'g123' }
71
+ end
72
+
73
+ context 'with the token in the POST body' do
74
+ before { post '/awesome', {'oauth_token' => 'g123'} }
75
+ it { last_response.body.should == 'g123'}
76
+ end
77
+
78
+ context 'when accessing something outside its scope' do
79
+ before do
80
+ @err = catch :error do
81
+ get '/forbidden?oauth_token=g123'
82
+ end
83
+ end
84
+
85
+ it { @err[:headers]['WWW-Authenticate'].should == "OAuth realm='OAuth API', error='insufficient_scope'" }
86
+ it { @err[:status].should == 403 }
87
+ end
88
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Middleware::Base do
4
+ subject { Grape::Middleware::Base.new(blank_app) }
5
+ let(:blank_app) { lambda{|env| [200, {}, 'Hi there.']} }
6
+
7
+ before do
8
+ # Keep it one object for testing.
9
+ subject.stub!(:dup).and_return(subject)
10
+ end
11
+
12
+ it 'should have the app as an accessor' do
13
+ subject.app.should == blank_app
14
+ end
15
+
16
+ it 'should be able to access the request' do
17
+ subject.call({})
18
+ subject.request.should be_kind_of(Rack::Request)
19
+ end
20
+
21
+ it 'should call through to the app' do
22
+ subject.call({}).should == [200, {}, 'Hi there.']
23
+ end
24
+
25
+ context 'callbacks' do
26
+ it 'should call #before' do
27
+ subject.should_receive(:before)
28
+ end
29
+
30
+ it 'should call #after' do
31
+ subject.should_receive(:after)
32
+ end
33
+
34
+ after{ subject.call!({}) }
35
+ end
36
+
37
+ it 'should be able to access the response' do
38
+ subject.call({})
39
+ subject.response.should be_kind_of(Rack::Response)
40
+ end
41
+
42
+ context 'options' do
43
+ it 'should persist options passed at initialization' do
44
+ Grape::Middleware::Base.new(blank_app, {:abc => true}).options[:abc].should be_true
45
+ end
46
+
47
+ context 'defaults' do
48
+ class ExampleWare < Grape::Middleware::Base
49
+ def default_options
50
+ {:monkey => true}
51
+ end
52
+ end
53
+
54
+ it 'should persist the default options' do
55
+ ExampleWare.new(blank_app).options[:monkey].should be_true
56
+ end
57
+
58
+ it 'should override default options when provided' do
59
+ ExampleWare.new(blank_app, :monkey => false).options[:monkey].should be_false
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Middleware::Error do
4
+ class ErrApp
5
+ class << self
6
+ attr_accessor :error
7
+ attr_accessor :format
8
+
9
+ def call(env)
10
+ throw :error, self.error
11
+ end
12
+ end
13
+ end
14
+
15
+ def app
16
+ Rack::Builder.app do
17
+ use Grape::Middleware::Error, :default_message => 'Aww, hamburgers.'
18
+ run ErrApp
19
+ end
20
+ end
21
+
22
+ it 'should set the status code appropriately' do
23
+ ErrApp.error = {:status => 410}
24
+ get '/'
25
+ last_response.status.should == 410
26
+ end
27
+
28
+ it 'should set the error message appropriately' do
29
+ ErrApp.error = {:message => 'Awesome stuff.'}
30
+ get '/'
31
+ last_response.body.should == 'Awesome stuff.'
32
+ end
33
+
34
+ it 'should default to a 403 status' do
35
+ ErrApp.error = {}
36
+ get '/'
37
+ last_response.status.should == 403
38
+ end
39
+
40
+ it 'should have a default message' do
41
+ ErrApp.error = {}
42
+ get '/'
43
+ last_response.body.should == 'Aww, hamburgers.'
44
+ end
45
+
46
+ context 'with formatting' do
47
+
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Middleware::Formatter do
4
+ subject{ Grape::Middleware::Formatter.new(app)}
5
+ before{ subject.stub!(:dup).and_return(subject) }
6
+
7
+ let(:app){ lambda{|env| [200, {}, [@body]]} }
8
+
9
+ context 'serialization' do
10
+ it 'should look at the bodies for possibly serializable data' do
11
+ @body = {"abc" => "def"}
12
+ status, headers, bodies = *subject.call({'PATH_INFO' => '/somewhere'})
13
+ bodies.first.should == ActiveSupport::JSON.encode(@body)
14
+ end
15
+ end
16
+
17
+ context 'detection' do
18
+ it 'should use the extension if one is provided' do
19
+ subject.call({'PATH_INFO' => '/info.xml'})
20
+ subject.env['api.format'].should == :xml
21
+ subject.call({'PATH_INFO' => '/info.json'})
22
+ subject.env['api.format'].should == :json
23
+ end
24
+
25
+ it 'should use the default format if none is provided' do
26
+ subject.call({'PATH_INFO' => '/info'})
27
+ subject.env['api.format'].should == :json
28
+ end
29
+
30
+ it 'should throw an error on an unrecognized format' do
31
+ err = catch(:error){ subject.call({'PATH_INFO' => '/info.barklar'}) }
32
+ err.should == {:status => 406, :message => "The requested format is not supported."}
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Middleware::Prefixer do
4
+ let(:app){ lambda{|env| [200, {}, env['PATH_INFO']]} }
5
+ subject{ Grape::Middleware::Prefixer.new(app, @options || {}) }
6
+
7
+ it 'should lop off a prefix (without a slash)' do
8
+ @options = {:prefix => 'monkey'}
9
+ subject.call('PATH_INFO' => '/monkey/beeswax').last.should == '/beeswax'
10
+ end
11
+
12
+ it 'should lop off a prefix (with a slash)' do
13
+ @options = {:prefix => '/banana'}
14
+ subject.call('PATH_INFO' => '/banana/peel').last.should == '/peel'
15
+ end
16
+
17
+ it 'should not lop off non-prefixes' do
18
+ @options = {:prefix => '/monkey'}
19
+ subject.call('PATH_INFO' => '/banana/peel').last.should == '/banana/peel'
20
+ end
21
+
22
+ it 'should pass through unaltered if there is no prefix' do
23
+ subject.call('PATH_INFO' => '/awesome').last.should == '/awesome'
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Middleware::Versioner do
4
+ let(:app) { lambda{|env| [200, env, env['api.version']]} }
5
+ subject { Grape::Middleware::Versioner.new(app, @options || {}) }
6
+
7
+ it 'should set the API version based on the first path' do
8
+ subject.call('PATH_INFO' => '/v1/awesome').last.should == 'v1'
9
+ end
10
+
11
+ it 'should cut the version out of the path' do
12
+ subject.call('PATH_INFO' => '/v1/awesome')[1]['PATH_INFO'].should == '/awesome'
13
+ end
14
+
15
+ it 'should provide a nil version if no path is given' do
16
+ subject.call('PATH_INFO' => '/').last.should be_nil
17
+ end
18
+
19
+ context 'with a pattern' do
20
+ before{ @options = {:pattern => /v./i} }
21
+ it 'should set the version if it matches' do
22
+ subject.call('PATH_INFO' => '/v1/awesome').last.should == 'v1'
23
+ end
24
+
25
+ it 'should ignore the version if it fails to match' do
26
+ subject.call('PATH_INFO' => '/awesome/radical').last.should be_nil
27
+ end
28
+ end
29
+ end
@@ -0,0 +1 @@
1
+ require 'spec_helper'
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'grape'
5
+
6
+ require 'rubygems'
7
+ require 'bundler'
8
+ Bundler.setup :default, :test
9
+
10
+ require 'rspec'
11
+ require 'rack/test'
12
+
13
+ RSpec.configure do |config|
14
+ config.include Rack::Test::Methods
15
+ end
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grape
3
+ version: !ruby/object:Gem::Version
4
+ hash: -3702664354
5
+ prerelease: true
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 0
10
+ - alpha
11
+ - 1
12
+ version: 0.0.0.alpha.1
13
+ platform: ruby
14
+ authors:
15
+ - Michael Bleigh
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2010-08-27 00:00:00 -05:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ prerelease: false
25
+ type: :runtime
26
+ name: rack
27
+ version_requirements: &id001 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ hash: 3
33
+ segments:
34
+ - 0
35
+ version: "0"
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
39
+ type: :runtime
40
+ name: rack-mount
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ requirement: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ prerelease: false
53
+ type: :runtime
54
+ name: rack-jsonp
55
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ requirement: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ prerelease: false
67
+ type: :runtime
68
+ name: activesupport
69
+ version_requirements: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 977940607
75
+ segments:
76
+ - 3
77
+ - 0
78
+ - 0
79
+ - rc2
80
+ version: 3.0.0.rc2
81
+ requirement: *id004
82
+ - !ruby/object:Gem::Dependency
83
+ prerelease: false
84
+ type: :development
85
+ name: rake
86
+ version_requirements: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ requirement: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ prerelease: false
98
+ type: :development
99
+ name: jeweler
100
+ version_requirements: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ requirement: *id006
110
+ description: A Ruby framework for rapid API development with great conventions.
111
+ email: michael@intridea.com
112
+ executables: []
113
+
114
+ extensions: []
115
+
116
+ extra_rdoc_files:
117
+ - LICENSE
118
+ - README.rdoc
119
+ files:
120
+ - .document
121
+ - .gitignore
122
+ - .rspec
123
+ - .rvmrc
124
+ - Gemfile
125
+ - Gemfile.lock
126
+ - LICENSE
127
+ - README.rdoc
128
+ - Rakefile
129
+ - VERSION
130
+ - autotest/discover.rb
131
+ - grape.gemspec
132
+ - lib/grape.rb
133
+ - lib/grape/middleware/auth/oauth2.rb
134
+ - lib/grape/middleware/base.rb
135
+ - lib/grape/middleware/error.rb
136
+ - lib/grape/middleware/formatter.rb
137
+ - lib/grape/middleware/prefixer.rb
138
+ - lib/grape/middleware/versioner.rb
139
+ - spec/grape/middleware/auth/oauth2_spec.rb
140
+ - spec/grape/middleware/base_spec.rb
141
+ - spec/grape/middleware/error_spec.rb
142
+ - spec/grape/middleware/formatter_spec.rb
143
+ - spec/grape/middleware/prefixer_spec.rb
144
+ - spec/grape/middleware/versioner_spec.rb
145
+ - spec/grape_spec.rb
146
+ - spec/spec_helper.rb
147
+ has_rdoc: true
148
+ homepage: http://github.com/intridea/grape
149
+ licenses: []
150
+
151
+ post_install_message:
152
+ rdoc_options:
153
+ - --charset=UTF-8
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ hash: 3
162
+ segments:
163
+ - 0
164
+ version: "0"
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ">"
169
+ - !ruby/object:Gem::Version
170
+ hash: 25
171
+ segments:
172
+ - 1
173
+ - 3
174
+ - 1
175
+ version: 1.3.1
176
+ requirements: []
177
+
178
+ rubyforge_project:
179
+ rubygems_version: 1.3.7
180
+ signing_key:
181
+ specification_version: 3
182
+ summary: A Ruby framework for rapid API development.
183
+ test_files:
184
+ - spec/grape/middleware/auth/oauth2_spec.rb
185
+ - spec/grape/middleware/base_spec.rb
186
+ - spec/grape/middleware/error_spec.rb
187
+ - spec/grape/middleware/formatter_spec.rb
188
+ - spec/grape/middleware/prefixer_spec.rb
189
+ - spec/grape/middleware/versioner_spec.rb
190
+ - spec/grape_spec.rb
191
+ - spec/spec_helper.rb