sinatra-advanced-routes 0.4.0.a

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ Sinatra::AdvancedRoutes
2
+ =======================
3
+
4
+ Makes routes first class objects in [Sinatra](http://sinatrarb.com).
5
+
6
+ BigBand
7
+ -------
8
+
9
+ Sinatra::AdvancedRoutes is part of the [BigBand](http://github.com/rkh/big_band) stack.
10
+ Check it out if you are looking for other fancy Sinatra extensions.
11
+
12
+ Example
13
+ -------
14
+
15
+ require "sinatra"
16
+ require "sinatra/advanced_routes"
17
+
18
+ admin_route = get "/admin" do
19
+ administrate_stuff
20
+ end
21
+
22
+ before do
23
+ # Let's deactivate the route if we have no password file.
24
+ if File.exists? "admin_password" then admin_route.activate
25
+ else admin_route.deactivate
26
+ end
27
+ end
28
+
29
+ first_route = get "/:name" do
30
+ # stuff
31
+ end
32
+
33
+ other_route = get "/foo_:name" do
34
+ # other stuff
35
+ end
36
+
37
+ # Unfortunatly first_route will catch all the requests other_route would
38
+ # have gotten, since it has been defined first. But wait, we can fix this!
39
+ other_route.promote
40
+
41
+ Usage with Sinatra::Base
42
+ ------------------------
43
+
44
+ require "sinatra/base"
45
+ require "sinatra/advanced_routes"
46
+
47
+ class Foo < Sinatra::Base
48
+ register Sinatra::AdvancedRoutes
49
+ end
@@ -0,0 +1,164 @@
1
+ require "sinatra/base"
2
+ require "sinatra/sugar"
3
+ require "monkey"
4
+
5
+ module Sinatra
6
+ Base.ignore_caller
7
+
8
+ module AdvancedRoutes
9
+
10
+ module ArrayMethods
11
+ ::Array.send :include, self
12
+
13
+ def to_route(verb, args = {})
14
+ dup.to_route! verb, args
15
+ end
16
+
17
+ def to_route!(verb, args = {})
18
+ extend Sinatra::AdvancedRoutes::Route
19
+ self.verb = verb
20
+ args.each do |key, value|
21
+ send "#{key}=", value
22
+ end
23
+ self
24
+ end
25
+
26
+ def signature
27
+ self
28
+ end
29
+
30
+ end
31
+
32
+ module Route
33
+
34
+ def self.new(verb, args = {})
35
+ [].to_route! verb, args
36
+ end
37
+
38
+ attr_accessor :app, :verb, :file, :line, :path, :docstring
39
+
40
+ def pattern; self[0]; end
41
+ def keys; self[1]; end
42
+ def conditions; self[2]; end
43
+ def block; self[3]; end
44
+ alias to_proc block
45
+
46
+ def pattern=(value); self[0] = value; end
47
+ def keys=(value); self[1] = value; end
48
+ def conditions=(value); self[2] = value; end
49
+ def block=(value); self[3] = value; end
50
+
51
+ def signature
52
+ [pattern, keys, conditions, block]
53
+ end
54
+
55
+ def active?
56
+ app.routes[verb].include? self
57
+ end
58
+
59
+ def activate(at_top = false)
60
+ also_change.each { |r| r.activate }
61
+ return if active?
62
+ meth = at_top ? :unshift : :push
63
+ (app.routes[verb] ||= []).send(meth, self)
64
+ invoke_hook :route_added, verb, path, block
65
+ invoke_hook :advanced_route_activated, self
66
+ self
67
+ end
68
+
69
+ def deactivate
70
+ also_change.each { |r| r.deactivate }
71
+ return unless active?
72
+ (app.routes[verb] ||= []).delete(signature)
73
+ invoke_hook :route_removed, verb, path, block
74
+ invoke_hook :advanced_route_deactivated, self
75
+ self
76
+ end
77
+
78
+ def promote(upwards = true)
79
+ also_change.each { |r| r.promote(upwards) }
80
+ deactivate
81
+ activate(upwards)
82
+ end
83
+
84
+ def file?
85
+ !!@file
86
+ end
87
+
88
+ def inspect
89
+ "#<Sinatra::AdvancedRoutes::Route #{ivar_inspect.join ", "}>"
90
+ end
91
+
92
+ def to_route(verb, args = {})
93
+ args = args.dup
94
+ [:app, :verb, :file, :line, :path].each { |key| args[key] ||= send(key) }
95
+ super(verb, args)
96
+ end
97
+
98
+ def also_change(*other_routes)
99
+ (@also_change ||= []).push(*other_routes)
100
+ end
101
+
102
+ private
103
+
104
+ def ivar_inspect
105
+ [:signature, :verb, :app, :file, :line].map do |var|
106
+ value = send(var)
107
+ "@#{var}=#{value.inspect}" unless value.nil?
108
+ end.compact
109
+ end
110
+
111
+ def invoke_hook(*args)
112
+ app.send(:invoke_hook, *args)
113
+ end
114
+
115
+ end
116
+
117
+ module ClassMethods
118
+
119
+ def get(path, opts={}, &block)
120
+ first_route, *other_routes = capture_routes { super }
121
+ first_route.also_change(*other_routes)
122
+ first_route
123
+ end
124
+
125
+ def route(verb, path, options={}, &block)
126
+ file, line = block.source_location if block.respond_to? :source_location
127
+ file ||= caller_files.first
128
+ route = super(verb, path, options, &block)
129
+ route.to_route! verb, :app => self, :file => file.expand_path, :line => line, :path => path
130
+ invoke_hook :advanced_route_added, route
131
+ @capture_routes << route if @capture_routes
132
+ route
133
+ end
134
+
135
+ def each_route(&block)
136
+ return enum_for(:each_route) if respond_to? :enum_for and not block
137
+ routes.inject([]) { |result, (verb, list)| result.push *list.each(&block) }
138
+ end
139
+
140
+ private
141
+
142
+ def capture_routes
143
+ capture_routes_was, @capture_routes = @capture_routes, []
144
+ yield
145
+ captured, @capture_routes = @capture_routes, capture_routes_was
146
+ captured
147
+ end
148
+
149
+ end
150
+
151
+ def self.registered(klass)
152
+ klass.extend ClassMethods
153
+ klass.routes.each do |verb, routes|
154
+ routes.each do |route|
155
+ route.to_route! verb, :app => klass
156
+ klass.send :invoke_hook, :advanced_root_added, route
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ register AdvancedRoutes
163
+
164
+ end
@@ -0,0 +1,92 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe Sinatra::AdvancedRoutes do
4
+ before { app :AdvancedRoutes }
5
+ [:get, :head, :post, :put, :delete].each do |verb|
6
+ describe "HTTP #{verb.to_s.upcase}" do
7
+
8
+ describe "activation" do
9
+
10
+ it "is able to deactivate routes from the outside" do
11
+ route = define_route(verb, "/foo") { "bar" }
12
+ route.should be_active
13
+ browse_route(verb, "/foo").should be_ok
14
+ route.deactivate
15
+ route.should_not be_active
16
+ browse_route(verb, "/foo").should_not be_ok
17
+ end
18
+
19
+ it "is able to deacitvate routes from a before filter" do
20
+ route = define_route(verb, "/foo") { "bar" }
21
+ app.before { route.deactivate }
22
+ route.should be_active
23
+ browse_route(verb, "/foo").should_not be_ok
24
+ route.should_not be_active
25
+ end
26
+
27
+ it "is able to reactivate deactivated routes" do
28
+ route = define_route(verb, "/foo") { "bar" }
29
+ route.deactivate
30
+ route.activate
31
+ route.should be_active
32
+ browse_route(verb, "/foo").should be_ok
33
+ end
34
+
35
+ end
36
+
37
+ describe "inspection" do
38
+ before { @route = define_route(verb, "/foo") { } }
39
+ it("exposes app") { @route.app.should == app }
40
+ it("exposes path") { @route.path.should == "/foo" }
41
+ it("exposes file") { @route.file.should == __FILE__.expand_path }
42
+ it("exposes verb") { @route.verb.should == verb.to_s.upcase }
43
+ it("exposes pattern") { @route.pattern.should == @route[0] }
44
+ it("exposes keys") { @route.keys.should == @route[1] }
45
+ it("exposes conditions") { @route.conditions.should == @route[2] }
46
+ it("exposes block") { @route.block.should == @route[3] }
47
+ end
48
+
49
+ describe "promotion" do
50
+ it "preffers promoted routes over earlier defined routes" do
51
+ next if verb == :head # cannot check body for head
52
+ bar = define_route(verb, "/foo") { "bar" }
53
+ baz = define_route(verb, "/foo") { "baz" }
54
+ browse_route(verb, "/foo").body.should == "bar"
55
+ baz.promote
56
+ browse_route(verb, "/foo").body.should == "baz"
57
+ bar.promote
58
+ browse_route(verb, "/foo").body.should == "bar"
59
+ end
60
+ end
61
+
62
+ describe "hooks" do
63
+ before do
64
+ @extension = Module.new
65
+ app.register @extension
66
+ end
67
+
68
+ it "triggers advanced_root_added hook" do
69
+ meth = @extension.should_receive(:advanced_route_added)
70
+ verb == :get ? meth.twice : meth.once
71
+ define_route(verb, "/foo") { }
72
+ end
73
+
74
+ it "triggers advanced_root_activated hook" do
75
+ route = define_route(verb, "/foo") { }
76
+ route.deactivate
77
+ meth = @extension.should_receive(:advanced_route_activated)
78
+ verb == :get ? meth.twice : meth.once
79
+ route.activate
80
+ end
81
+
82
+ it "triggers advanced_root_deactivated hook" do
83
+ route = define_route(verb, "/foo") { }
84
+ meth = @extension.should_receive(:advanced_route_deactivated)
85
+ verb == :get ? meth.twice : meth.once
86
+ route.deactivate
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,4 @@
1
+ require "sinatra/rspec"
2
+ require "sinatra/advanced_routes"
3
+ require "monkey"
4
+ Sinatra::Base.set :environment, :test
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-advanced-routes
3
+ version: &id001 !ruby/object:Gem::Version
4
+ version: 0.4.0.a
5
+ platform: ruby
6
+ authors:
7
+ - Konstantin Haase
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-17 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: monkey-lib
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - *id001
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: sinatra-sugar
26
+ type: :runtime
27
+ version_requirement:
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "="
31
+ - *id001
32
+ version:
33
+ - !ruby/object:Gem::Dependency
34
+ name: sinatra-test-helper
35
+ type: :development
36
+ version_requirement:
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "="
40
+ - *id001
41
+ version:
42
+ - !ruby/object:Gem::Dependency
43
+ name: sinatra
44
+ type: :runtime
45
+ version_requirement:
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 0.9.4
51
+ version:
52
+ - !ruby/object:Gem::Dependency
53
+ name: rspec
54
+ type: :development
55
+ version_requirement:
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.3.0
61
+ version:
62
+ description: Make Sinatra routes first class objects (part of BigBand).
63
+ email: konstantin.mailinglists@googlemail.com
64
+ executables: []
65
+
66
+ extensions: []
67
+
68
+ extra_rdoc_files: []
69
+
70
+ files:
71
+ - lib/sinatra/advanced_routes.rb
72
+ - spec/sinatra/advanced_routes_spec.rb
73
+ - spec/spec_helper.rb
74
+ - README.md
75
+ has_rdoc: yard
76
+ homepage: http://github.com/rkh/sinatra-advanced-routes
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options: []
81
+
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ version:
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">"
93
+ - !ruby/object:Gem::Version
94
+ version: 1.3.1
95
+ version:
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.5
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Make Sinatra routes first class objects (part of BigBand).
103
+ test_files: []
104
+