optionsful 0.1.0 → 0.1.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/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