Skip to content

Commit 6107b97

Browse files
author
Michael Bleigh
committed
And the plan begins to reveal itself.
1 parent f7728b8 commit 6107b97

File tree

17 files changed

+310
-36
lines changed

17 files changed

+310
-36
lines changed

.rspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
--color
22
--format=nested
3-
--backtrace
3+
--fail-fast

.rvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
rvm use ree@rails3 --passenger
1+
rvm use ree@rails3

Gemfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ gem 'rack'
22
gem 'rack-mount'
33
gem 'rack-jsonp'
44

5-
gem 'activesupport', '~> 3.0.0'
5+
gem 'multi_json'
6+
gem 'multi_xml'
67

78
group :development do
89
gem 'rake'
910
gem 'jeweler'
1011
end
1112

1213
group :test do
13-
gem 'rspec', '>= 2.0.0.beta.20'
14+
gem 'rspec', '>= 2.1.0'
1415
gem 'rack-test'
1516
gem 'cucumber', '>= 0.8.5'
1617
end

Gemfile.lock

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
GEM
22
specs:
3-
activesupport (3.0.0)
43
builder (2.1.2)
54
cucumber (0.8.5)
65
builder (~> 2.1.2)
@@ -18,21 +17,23 @@ GEM
1817
git (>= 1.2.5)
1918
rubyforge (>= 2.0.0)
2019
json_pure (1.4.3)
20+
multi_json (0.0.4)
21+
multi_xml (0.0.1)
2122
rack (1.2.1)
2223
rack-jsonp (1.0.0)
2324
rack-mount (0.6.9)
2425
rack (>= 1.0.0)
2526
rack-test (0.5.4)
2627
rack (>= 1.0)
2728
rake (0.8.7)
28-
rspec (2.0.0.beta.20)
29-
rspec-core (= 2.0.0.beta.20)
30-
rspec-expectations (= 2.0.0.beta.20)
31-
rspec-mocks (= 2.0.0.beta.20)
32-
rspec-core (2.0.0.beta.20)
33-
rspec-expectations (2.0.0.beta.20)
34-
diff-lcs (>= 1.1.2)
35-
rspec-mocks (2.0.0.beta.20)
29+
rspec (2.1.0)
30+
rspec-core (~> 2.1.0)
31+
rspec-expectations (~> 2.1.0)
32+
rspec-mocks (~> 2.1.0)
33+
rspec-core (2.1.0)
34+
rspec-expectations (2.1.0)
35+
diff-lcs (~> 1.1.2)
36+
rspec-mocks (2.1.0)
3637
rubyforge (2.0.4)
3738
json_pure (>= 1.1.7)
3839
term-ansicolor (1.0.5)
@@ -42,12 +43,13 @@ PLATFORMS
4243
ruby
4344

4445
DEPENDENCIES
45-
activesupport (~> 3.0.0)
4646
cucumber (>= 0.8.5)
4747
jeweler
48+
multi_json
49+
multi_xml
4850
rack
4951
rack-jsonp
5052
rack-mount
5153
rack-test
5254
rake
53-
rspec (>= 2.0.0.beta.20)
55+
rspec (>= 2.1.0)

README.rdoc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
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.
66

7-
class Twitter < Grape::Base
7+
class Twitter::API < Grape::Base
88
subdomain 'api'
99
version '1'
1010
formats :xml, :json
@@ -30,6 +30,12 @@ Grape is a REST-like API micro-framework for Ruby. It is built to complement exi
3030
end
3131
end
3232

33+
class Twitter::API::User < Grape::Resource::ActiveRecord
34+
represents ::User
35+
36+
property :status, lambda{|u| u.latest_status}, Twitter::API::Status
37+
end
38+
3339
== Note on Patches/Pull Requests
3440

3541
* Fork the project.

lib/grape.rb

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
require 'rack'
22
require 'rack/builder'
33

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'
4+
module Grape
5+
autoload :API, 'grape/api'
6+
autoload :Endpoint, 'grape/endpoint'
7+
autoload :MiddlewareStack, 'grape/middleware_stack'
8+
9+
module Middleware
10+
autoload :Base, 'grape/middleware/base'
11+
autoload :Prefixer, 'grape/middleware/prefixer'
12+
autoload :Versioner, 'grape/middleware/versioner'
13+
autoload :Formatter, 'grape/middleware/formatter'
14+
autoload :Error, 'grape/middleware/error'
15+
16+
module Auth
17+
autoload :OAuth2, 'grape/middleware/auth/oauth2'
18+
autoload :Basic, 'grape/middleware/auth/basic'
19+
end
20+
end
21+
end

lib/grape/api.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
require 'rack/mount'
2+
3+
module Grape
4+
class API
5+
class << self
6+
attr_reader :route_set
7+
8+
def reset!
9+
@settings = [{}]
10+
@route_set = Rack::Mount::RouteSet.new
11+
@prototype = nil
12+
end
13+
14+
def call(env)
15+
route_set.freeze.call(env)
16+
end
17+
18+
# Settings are a stack, so when we
19+
# want to access them they are merged
20+
# in the order pushed.
21+
def settings
22+
@settings.inject({}){|f,h| f.merge!(h); f}
23+
end
24+
25+
def set(key, value)
26+
@settings.last[key.to_sym] = value
27+
end
28+
29+
# Define a root prefix for your entire
30+
# API. For instance, if you had an api
31+
# that you wanted to be namespaced at
32+
# `/api/` you would do this:
33+
#
34+
# prefix '/api'
35+
def prefix(prefix = nil)
36+
prefix ? set(:root_prefix, prefix) : settings[:root_prefix]
37+
end
38+
39+
def version(new_version = nil)
40+
new_version ? set(:version, new_version) : settings[:version]
41+
end
42+
43+
def default_format(new_format = nil)
44+
new_format ? set(:default_format, new_format.to_sym) : settings[:default_format]
45+
end
46+
47+
def route_set
48+
@route_set ||= Rack::Mount::RouteSet.new
49+
end
50+
51+
def compile_path(path)
52+
parts = []
53+
parts << prefix if prefix
54+
parts << version if version
55+
parts << path
56+
Rack::Mount::Utils.normalize_path(parts.join('/'))
57+
end
58+
59+
def route(method, path_info, &block)
60+
route_set.add_route(build_endpoint(&block), :path_info => compile_path(path_info))
61+
end
62+
63+
def build_endpoint(&block)
64+
builder = Rack::Builder.new
65+
builder.use Grape::Middleware::Error
66+
builder.use Grape::Middleware::Prefixer, :prefix => prefix if prefix
67+
builder.use Grape::Middleware::Versioner if version
68+
builder.use Grape::Middleware::Formatter, :default_format => default_format || :json
69+
builder.run Grape::Endpoint.new(&block)
70+
builder.to_app
71+
end
72+
73+
def get(path_info, &block); route('GET', path_info, &block) end
74+
def post(path_info, &block); route('POST', path_info, &block) end
75+
def put(path_info, &block); route('PUT', path_info, &block) end
76+
77+
def inherited(subclass)
78+
subclass.reset!
79+
end
80+
end
81+
82+
reset!
83+
end
84+
end

lib/grape/endpoint.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require 'rack'
2+
require 'grape'
3+
4+
module Grape
5+
class Endpoint
6+
def initialize(&block)
7+
@block = block
8+
end
9+
10+
attr_reader :env, :request
11+
12+
def call(env)
13+
@env = env
14+
@request = Rack::Request.new(@env)
15+
@headers = {}
16+
17+
response_text = instance_eval &@block
18+
[200, {}, [response_text]]
19+
end
20+
end
21+
end

lib/grape/middleware/base.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module Middleware
33
class Base
44
attr_reader :app, :env, :options
55

6+
# @param [Rack Application] app The standard argument for a Rack middleware.
7+
# @param [Hash] options A hash of options, simply stored for use by subclasses.
68
def initialize(app, options = {})
79
@app = app
810
@options = default_options.merge(options)
@@ -21,7 +23,12 @@ def call!(env)
2123
after || @app_response
2224
end
2325

26+
# @abstract
27+
# Called before the application is called in the middleware lifecycle.
2428
def before; end
29+
# @abstract
30+
# Called after the application is called in the middleware lifecycle.
31+
# @returns [Response, nil] a Rack SPEC response or nil to call the application afterwards.
2532
def after; end
2633

2734
def request

lib/grape/middleware/error.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ module Middleware
55
class Error < Base
66
def call!(env)
77
@env = env
8-
err = catch :error do
8+
result = catch :error do
99
@app.call(@env)
1010
end
1111

12-
error_response(err)
12+
result ||= {}
13+
result.is_a?(Hash) ? error_response(result) : result
1314
end
1415

1516
def error_response(error = {})

0 commit comments

Comments
 (0)