optionsful 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -34,9 +34,13 @@ Link: <http://baurets.net/api/resources>; type=text/html; rel=help
34
34
  h2. INSTALLATION:
35
35
 
36
36
  # Change directory to your Ruby on Rails web application,
37
- # Run:
37
+ # Add gem dependency to @config/environment.rb@:
38
38
  <pre>
39
- $ script/plugin install git://github.com/kayaman/optionsful.git
39
+ config.gem "optionsful"
40
+ </pre>
41
+ # To install it, run:
42
+ <pre>
43
+ $ gem install optionsful
40
44
  </pre>
41
45
  # Have fun!
42
46
 
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'metric_fu'
2
+ require 'rubygems'
3
+ require 'spec/rake/spectask'
4
+
5
+ Spec::Rake::SpecTask.new(:spec) do |t|
6
+ t.spec_files = Dir.glob('spec/**/*_spec.rb')
7
+ t.spec_opts << '--format specdoc'
8
+ t.rcov = true
9
+ end
10
+
11
+ task :default => :spec
@@ -0,0 +1,93 @@
1
+ module Baurets
2
+
3
+ class Optionsful
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ unless env["REQUEST_METHOD"] == "OPTIONS"
11
+ @app.call(env)
12
+ else
13
+ extract_options_information(env)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def extract_options_information(env)
20
+ [204, {"Allow" => extract_allowed_methods(env), "Link" => build_help_link}, ""]
21
+ end
22
+
23
+ def extract_allowed_methods(env)
24
+ # do routing introspection:
25
+ routes = do_routing_introspection
26
+ # do request path investigation
27
+ route_guess = guess_route(routes, env["PATH_INFO"])
28
+ allows = ""
29
+ # do the matches:
30
+ routes.each do |route|
31
+ if route.first == route_guess
32
+ allows += route[1].to_s.upcase! + "|"
33
+ end
34
+ end
35
+ allows = allows.split("|").join(", ")
36
+ end
37
+
38
+ def build_help_link
39
+ #PENDING
40
+ "<http://baurets.net/api/resources>; type=text/html; rel=help"
41
+ end
42
+
43
+ def guess_route(routes, path)
44
+ parts = prepare_request_path(path)
45
+ guess = []
46
+ index = 0
47
+ parts.each do |part|
48
+ if is_part_static?(routes, index, part)
49
+ guess << part
50
+ else
51
+ guess << :dynamic
52
+ end
53
+ index += 1
54
+ end
55
+ guess
56
+ end
57
+
58
+ def is_part_static?(routes, index, value)
59
+ routes.each do |route|
60
+ if route[0][index] == value
61
+ return true
62
+ end
63
+ end
64
+ return false
65
+ end
66
+
67
+ def do_routing_introspection
68
+ routes = []
69
+ ActionController::Routing::Routes.routes.each do |route|
70
+ static_path = []
71
+ route.segments.each do |segment|
72
+ if segment.kind_of?(ActionController::Routing::StaticSegment)
73
+ static_path << segment.value if (segment.respond_to?(:value) && segment.value != "/")
74
+ elsif segment.kind_of?(ActionController::Routing::DynamicSegment)
75
+ #TODO ignoring (.:format), think about it:
76
+ static_path << :dynamic unless (segment.respond_to?(:key) && segment.key == :format)
77
+ end
78
+ end
79
+ routes << [static_path, route.conditions[:method]] unless route.conditions[:method].nil?
80
+ end
81
+ routes
82
+ end
83
+
84
+ def prepare_request_path(path)
85
+ path = path[0..(path.rindex('.')-1)] if path.include?('.') #TODO ignoring (.:format), think about it
86
+ path_parts = path.split("/")
87
+ path_parts.delete("")
88
+ path_parts
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :optionsful do
3
+ # # Task goes here
4
+ # end
data/rails/init.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  # Adding Optionsful to the Rack middleware stack:
2
- ActionController::Dispatcher.middleware.use "Optionsful"
2
+ ActionController::Dispatcher.middleware.use Baurets::Optionsful
@@ -0,0 +1,115 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+
4
+ describe "Baurets::Optionsful," do
5
+
6
+ include Rack::Test::Methods
7
+
8
+ before(:all) do
9
+ ActionController::Routing::Routes.draw do |map|
10
+ map.resources :posts, :has_many => :comments
11
+ end
12
+ end
13
+
14
+
15
+ describe "as a Rack middleware" do
16
+
17
+ it "is a Ruby object that responds to call;" do
18
+ assert Baurets::Optionsful.new(app).respond_to? :call
19
+ end
20
+
21
+ it "takes exactly one argument, (the environment) and returns an Array;" do
22
+ response = Baurets::Optionsful.new(app).call(mock_env({"REQUEST_METHOD" => "OPTIONS", "PATH_INFO" => "/posts"}))
23
+ assert response.kind_of?(Array)
24
+ end
25
+
26
+ it "the returned Array must have exactly three values: the status, the headers and the body;" do
27
+ response = Baurets::Optionsful.new(app).call(mock_env({"REQUEST_METHOD" => "OPTIONS", "PATH_INFO" => "/posts"}))
28
+ assert response.size.should == 3
29
+ assert response[0].kind_of? Fixnum
30
+ assert response[1].kind_of? Hash
31
+ assert response[2].kind_of? String
32
+ end
33
+
34
+ it "must be nice, acting somewhere on a Rack middleware stack." do
35
+ response = fake_app.call(mock_env({"REQUEST_METHOD" => "OPTIONS", "PATH_INFO" => "/posts"}))
36
+ assert response.size.should == 3
37
+ assert response[0].kind_of? Fixnum
38
+ assert response[0].should == 204
39
+ assert response[1].kind_of? Hash
40
+ assert response[1]["Allow"]
41
+ end
42
+
43
+ end
44
+
45
+
46
+ describe "to collect the allowed HTTP methods" do
47
+
48
+ describe "overrides Rails routing recognition " do
49
+
50
+ describe "must understand the default Rails resource routing: " do
51
+
52
+ it "the index action displays a list of all posts in response of a GET request;" do
53
+ response = http_options_request("/posts")
54
+ assert response.kind_of?(Array)
55
+ assert allows?(response[1], "GET")
56
+ end
57
+
58
+ it "the new action return from a GET request an HTML form for creating a new post;" do
59
+ response = http_options_request("/posts/new")
60
+ assert response.kind_of?(Array)
61
+ assert allows?(response[1], "GET")
62
+ end
63
+
64
+ it "the create action uses POST to create a new post instance;" do
65
+ response = http_options_request("/posts")
66
+ assert response.kind_of?(Array)
67
+ assert allows?(response[1], "POST")
68
+ end
69
+
70
+ it "the show action display a specific post in response of a GET request;" do
71
+ response = http_options_request("/posts/1")
72
+ assert response.kind_of?(Array)
73
+ assert allows?(response[1], "GET")
74
+ end
75
+
76
+ it "the edit action return an HTML form for editing a post in response of a GET request;" do
77
+ response = http_options_request("/posts/1/edit")
78
+ assert response.kind_of?(Array)
79
+ assert allows?(response[1], "GET")
80
+ end
81
+
82
+ it "the update action uses PUT to update a specific post;" do
83
+ response = http_options_request("/posts/1")
84
+ assert response.kind_of?(Array)
85
+ assert allows?(response[1], "PUT")
86
+ end
87
+
88
+ it "the destroy action uses DELETE to delete a specific post." do
89
+ response = http_options_request("/posts/1")
90
+ assert response.kind_of?(Array)
91
+ assert allows?(response[1], "DELETE")
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+
100
+ describe " dispatch the call to the application unless HTTP method equals OPTIONS " do
101
+
102
+ it " method GET example" do
103
+ complex_env = mock_env({"REQUEST_METHOD" => "GET", "PATH_INFO" => "/lobster" })
104
+ response = fake_app.call(complex_env)
105
+ assert response.kind_of?(Array)
106
+ assert response.size.should == 3
107
+ end
108
+
109
+ end
110
+
111
+ after(:all) do
112
+ ActionController::Routing::Routes.reload!
113
+ end
114
+
115
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,67 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'baurets','optionsful.rb')
2
+
3
+ require 'rubygems'
4
+ require 'sinatra'
5
+ require 'rack/test'
6
+ require 'rack'
7
+ require 'rack/lobster'
8
+ require 'spec'
9
+ require 'spec/autorun'
10
+ require 'spec/interop/test'
11
+ require 'action_controller'
12
+ require 'ruby-debug'
13
+ # require 'baurets/optionsful'
14
+
15
+ # set test environment set :environment, :test set :run, false set :raise_errors, true set :logging, false
16
+
17
+ DEFAULT_ENV = { "rack.version" => Rack::VERSION, "rack.input" => StringIO.new, "rack.errors" => StringIO.new,
18
+ "rack.multithread" => true, "rack.multiprocess" => true, "rack.run_once" => false, }
19
+
20
+ SAMPLE_ENV = {"rack.session"=>{:session_id=>"f66c8af1e89f318775e923159e046e71"}, "SERVER_NAME"=>"localhost",
21
+ "HTTP_HOST"=>"localhost:3332", "REMOTE_HOST"=>"localhost", "HTTP_USER_AGENT"=>"HTTP%20Client0.9.1
22
+ CFNetwork/438.14 Darwin/9.8.0 (i386) (MacBook4%2C1)", "rack.url_scheme"=>"http", "REQUEST_PATH"=>"/",
23
+ "SERVER_PROTOCOL"=>"HTTP/1.1", "rack.errors"=>"", "PATH_INFO"=>"/", "REMOTE_ADDR"=>"127.0.0.1",
24
+ "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.7/2010-06-23)", "rack.run_once"=>false, "rack.version"=>[1, 1],
25
+ "SCRIPT_NAME"=>"", "rack.multithread"=>false, "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_URI"=>"",
26
+ "rack.multiprocess"=>false, "SERVER_PORT"=>"3332", "rack.session.options"=>{:domain=>"nilly", :path=>"/",
27
+ :key=>"_session_id", :httponly=>true, :expire_after=>300, :id=>"f66c8af1e89f318775e923159e046e71"},
28
+ "REQUEST_METHOD"=>"HEAD", "GATEWAY_INTERFACE"=>"CGI/1.1", "QUERY_STRING"=>"", "HTTP_CONNECTION"=>"close"}
29
+
30
+ FAKE_ENV = SAMPLE_ENV.merge!(DEFAULT_ENV)
31
+
32
+ def app
33
+ app = Rack::Builder.new {
34
+ use Rack::CommonLogger
35
+ use Rack::ShowExceptions
36
+ }
37
+ end
38
+
39
+
40
+ def fake_app
41
+ app = Rack::Builder.new {
42
+ use Rack::CommonLogger
43
+ use Rack::ShowExceptions
44
+ use Baurets::Optionsful
45
+ map "/lobster" do
46
+ use Rack::Lint
47
+ run Rack::Lobster.new
48
+ end
49
+ }
50
+ end
51
+
52
+ def mock_env(options = {})
53
+ FAKE_ENV.merge!(options)
54
+ end
55
+
56
+ def http_options_request(path)
57
+ complex_env = mock_env({"REQUEST_METHOD" => "OPTIONS", "PATH_INFO" => path })
58
+ response = Baurets::Optionsful.new(app).call(complex_env)
59
+ response
60
+ end
61
+
62
+ def allows?(headers, method)
63
+ headers["Allow"].include?(method)
64
+ end
65
+
66
+
67
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: optionsful
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Marco Antonio Gonzalez Junior
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-15 00:00:00 -03:00
18
+ date: 2010-07-19 00:00:00 -03:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -30,8 +30,13 @@ extra_rdoc_files: []
30
30
  files:
31
31
  - README.textile
32
32
  - MIT-LICENSE
33
- - lib/optionsful.rb
33
+ - lib/baurets/optionsful.rb
34
34
  - rails/init.rb
35
+ - lib/tasks/optionsful.rake
36
+ - Rakefile
37
+ - spec/optionsful_spec.rb
38
+ - spec/spec.opts
39
+ - spec/spec_helper.rb
35
40
  has_rdoc: true
36
41
  homepage: http://optionsful.rubyforge.org
37
42
  licenses: []
data/lib/optionsful.rb DELETED
@@ -1,89 +0,0 @@
1
- class Optionsful
2
-
3
- def initialize(app)
4
- @app = app
5
- end
6
-
7
- def call(env)
8
- unless env["REQUEST_METHOD"] == "OPTIONS"
9
- @app.call(env)
10
- else
11
- extract_options_information(env)
12
- end
13
- end
14
-
15
- private
16
-
17
- def extract_options_information(env)
18
- [204, {"Allow" => extract_allowed_methods(env), "Link" => build_help_link}, ""]
19
- end
20
-
21
- def extract_allowed_methods(env)
22
- # do routing introspection:
23
- routes = do_routing_introspection
24
- # do request path investigation
25
- route_guess = guess_route(routes, env["PATH_INFO"])
26
- allows = ""
27
- # do the matches:
28
- routes.each do |route|
29
- if route.first == route_guess
30
- allows += route[1].to_s.upcase! + "|"
31
- end
32
- end
33
- allows = allows.split("|").join(", ")
34
- end
35
-
36
- def build_help_link
37
- #PENDING
38
- "<http://baurets.net/api/resources>; type=text/html; rel=help"
39
- end
40
-
41
- def guess_route(routes, path)
42
- parts = prepare_request_path(path)
43
- guess = []
44
- index = 0
45
- parts.each do |part|
46
- if is_part_static?(routes, index, part)
47
- guess << part
48
- else
49
- guess << :dynamic
50
- end
51
- index += 1
52
- end
53
- guess
54
- end
55
-
56
- def is_part_static?(routes, index, value)
57
- routes.each do |route|
58
- if route[0][index] == value
59
- return true
60
- end
61
- end
62
- return false
63
- end
64
-
65
- def do_routing_introspection
66
- routes = []
67
- ActionController::Routing::Routes.routes.each do |route|
68
- static_path = []
69
- route.segments.each do |segment|
70
- if segment.kind_of?(ActionController::Routing::StaticSegment)
71
- static_path << segment.value if (segment.respond_to?(:value) && segment.value != "/")
72
- elsif segment.kind_of?(ActionController::Routing::DynamicSegment)
73
- #TODO ignoring (.:format), think about it:
74
- static_path << :dynamic unless (segment.respond_to?(:key) && segment.key == :format)
75
- end
76
- end
77
- routes << [static_path, route.conditions[:method]] unless route.conditions[:method].nil?
78
- end
79
- routes
80
- end
81
-
82
- def prepare_request_path(path)
83
- path = path[0..(path.rindex('.')-1)] if path.include?('.') #TODO ignoring (.:format), think about it
84
- path_parts = path.split("/")
85
- path_parts.delete("")
86
- path_parts
87
- end
88
-
89
- end