sinatra-advanced-routes 0.4.0.a

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.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
+