tennpipes-base 3.6.6
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +294 -0
- data/Rakefile +1 -0
- data/bin/tennpipes +8 -0
- data/lib/tennpipes-base.rb +196 -0
- data/lib/tennpipes-base/application.rb +175 -0
- data/lib/tennpipes-base/application/application_setup.rb +202 -0
- data/lib/tennpipes-base/application/authenticity_token.rb +25 -0
- data/lib/tennpipes-base/application/flash.rb +229 -0
- data/lib/tennpipes-base/application/params_protection.rb +129 -0
- data/lib/tennpipes-base/application/routing.rb +1002 -0
- data/lib/tennpipes-base/application/show_exceptions.rb +50 -0
- data/lib/tennpipes-base/caller.rb +53 -0
- data/lib/tennpipes-base/cli/adapter.rb +33 -0
- data/lib/tennpipes-base/cli/base.rb +105 -0
- data/lib/tennpipes-base/cli/console.rb +20 -0
- data/lib/tennpipes-base/cli/launcher.rb +103 -0
- data/lib/tennpipes-base/cli/rake.rb +50 -0
- data/lib/tennpipes-base/cli/rake_tasks.rb +72 -0
- data/lib/tennpipes-base/command.rb +38 -0
- data/lib/tennpipes-base/ext/sinatra.rb +29 -0
- data/lib/tennpipes-base/filter.rb +52 -0
- data/lib/tennpipes-base/images/404.png +0 -0
- data/lib/tennpipes-base/images/500.png +0 -0
- data/lib/tennpipes-base/loader.rb +202 -0
- data/lib/tennpipes-base/logger.rb +492 -0
- data/lib/tennpipes-base/module.rb +58 -0
- data/lib/tennpipes-base/mounter.rb +308 -0
- data/lib/tennpipes-base/path_router.rb +119 -0
- data/lib/tennpipes-base/path_router/compiler.rb +110 -0
- data/lib/tennpipes-base/path_router/error_handler.rb +8 -0
- data/lib/tennpipes-base/path_router/matcher.rb +123 -0
- data/lib/tennpipes-base/path_router/route.rb +169 -0
- data/lib/tennpipes-base/reloader.rb +309 -0
- data/lib/tennpipes-base/reloader/rack.rb +26 -0
- data/lib/tennpipes-base/reloader/storage.rb +55 -0
- data/lib/tennpipes-base/router.rb +98 -0
- data/lib/tennpipes-base/server.rb +119 -0
- data/lib/tennpipes-base/tasks.rb +21 -0
- data/lib/tennpipes-base/version.rb +20 -0
- data/lib/tennpipes-base/version.rb~ +20 -0
- data/test/fixtures/app_gem/Gemfile +4 -0
- data/test/fixtures/app_gem/app/app.rb +3 -0
- data/test/fixtures/app_gem/app_gem.gemspec +17 -0
- data/test/fixtures/app_gem/lib/app_gem.rb +7 -0
- data/test/fixtures/app_gem/lib/app_gem/version.rb +3 -0
- data/test/fixtures/apps/complex.rb +32 -0
- data/test/fixtures/apps/demo_app.rb +7 -0
- data/test/fixtures/apps/demo_demo.rb +7 -0
- data/test/fixtures/apps/demo_project/api/app.rb +7 -0
- data/test/fixtures/apps/demo_project/api/lib/api_lib.rb +3 -0
- data/test/fixtures/apps/demo_project/app.rb +7 -0
- data/test/fixtures/apps/external_apps/fake_lib.rb +1 -0
- data/test/fixtures/apps/external_apps/fake_root.rb +2 -0
- data/test/fixtures/apps/helpers/class_methods_helpers.rb +4 -0
- data/test/fixtures/apps/helpers/instance_methods_helpers.rb +4 -0
- data/test/fixtures/apps/helpers/support.rb +1 -0
- data/test/fixtures/apps/helpers/system_helpers.rb +8 -0
- data/test/fixtures/apps/kiq.rb +3 -0
- data/test/fixtures/apps/lib/myklass.rb +2 -0
- data/test/fixtures/apps/lib/myklass/mysubklass.rb +4 -0
- data/test/fixtures/apps/models/child.rb +2 -0
- data/test/fixtures/apps/models/parent.rb +5 -0
- data/test/fixtures/apps/mountable_apps/rack_apps.rb +15 -0
- data/test/fixtures/apps/mountable_apps/static.html +1 -0
- data/test/fixtures/apps/precompiled_app.rb +19 -0
- data/test/fixtures/apps/simple.rb +32 -0
- data/test/fixtures/apps/static.rb +10 -0
- data/test/fixtures/apps/system.rb +13 -0
- data/test/fixtures/apps/system_class_methods_demo.rb +7 -0
- data/test/fixtures/apps/system_instance_methods_demo.rb +7 -0
- data/test/fixtures/dependencies/a.rb +9 -0
- data/test/fixtures/dependencies/b.rb +4 -0
- data/test/fixtures/dependencies/c.rb +1 -0
- data/test/fixtures/dependencies/circular/e.rb +13 -0
- data/test/fixtures/dependencies/circular/f.rb +2 -0
- data/test/fixtures/dependencies/circular/g.rb +2 -0
- data/test/fixtures/dependencies/d.rb +4 -0
- data/test/fixtures/reloadable_apps/external/app/app.rb +6 -0
- data/test/fixtures/reloadable_apps/external/app/controllers/base.rb +6 -0
- data/test/fixtures/reloadable_apps/main/app.rb +10 -0
- data/test/helper.rb +30 -0
- data/test/test_application.rb +185 -0
- data/test/test_core.rb +93 -0
- data/test/test_csrf_protection.rb +208 -0
- data/test/test_dependencies.rb +57 -0
- data/test/test_filters.rb +389 -0
- data/test/test_flash.rb +168 -0
- data/test/test_locale.rb +21 -0
- data/test/test_logger.rb +295 -0
- data/test/test_mounter.rb +302 -0
- data/test/test_params_protection.rb +195 -0
- data/test/test_reloader_complex.rb +74 -0
- data/test/test_reloader_external.rb +21 -0
- data/test/test_reloader_simple.rb +101 -0
- data/test/test_reloader_system.rb +113 -0
- data/test/test_restful_routing.rb +33 -0
- data/test/test_router.rb +281 -0
- data/test/test_routing.rb +2328 -0
- metadata +301 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
require 'tennpipes-base/application/flash'
|
|
2
|
+
require 'tennpipes-base/application/routing'
|
|
3
|
+
require 'tennpipes-base/application/show_exceptions'
|
|
4
|
+
require 'tennpipes-base/application/authenticity_token'
|
|
5
|
+
require 'tennpipes-base/application/application_setup'
|
|
6
|
+
require 'tennpipes-base/application/params_protection'
|
|
7
|
+
|
|
8
|
+
module Tennpipes
|
|
9
|
+
##
|
|
10
|
+
# Subclasses of this become independent Tennpipes applications
|
|
11
|
+
# (stemming from Sinatra::Application).
|
|
12
|
+
# These subclassed applications can be easily mounted into other
|
|
13
|
+
# Tennpipes applications as well.
|
|
14
|
+
#
|
|
15
|
+
class Application < Sinatra::Base
|
|
16
|
+
register Tennpipes::ApplicationSetup
|
|
17
|
+
register Tennpipes::Routing
|
|
18
|
+
register Tennpipes::ParamsProtection
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Returns the logger for this application.
|
|
22
|
+
#
|
|
23
|
+
# @return [Tennpipes::Logger] Logger associated with this app.
|
|
24
|
+
#
|
|
25
|
+
def logger
|
|
26
|
+
Tennpipes.logger
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
def inherited(base)
|
|
31
|
+
begun_at = Time.now
|
|
32
|
+
CALLERS_TO_IGNORE.concat(TENNPIPES_IGNORE_CALLERS)
|
|
33
|
+
super(base)
|
|
34
|
+
base.prerequisites.replace(self.prerequisites.dup)
|
|
35
|
+
base.default_configuration!
|
|
36
|
+
logger.devel :setup, begun_at, base
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Reloads the application files from all defined load paths.
|
|
41
|
+
#
|
|
42
|
+
# This method is used from our Tennpipes Reloader during development mode
|
|
43
|
+
# in order to reload the source files.
|
|
44
|
+
#
|
|
45
|
+
# @return [TrueClass]
|
|
46
|
+
#
|
|
47
|
+
# @example
|
|
48
|
+
# MyApp.reload!
|
|
49
|
+
#
|
|
50
|
+
def reload!
|
|
51
|
+
logger.devel "Reloading application #{settings}"
|
|
52
|
+
reset!
|
|
53
|
+
reset_router!
|
|
54
|
+
Tennpipes.require_dependencies(settings.app_file, :force => true)
|
|
55
|
+
require_dependencies
|
|
56
|
+
default_routes
|
|
57
|
+
default_errors
|
|
58
|
+
I18n.reload! if defined?(I18n)
|
|
59
|
+
true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# Resets application routes to only routes not defined by the user.
|
|
64
|
+
#
|
|
65
|
+
# @return [TrueClass]
|
|
66
|
+
#
|
|
67
|
+
# @example
|
|
68
|
+
# MyApp.reset_routes!
|
|
69
|
+
#
|
|
70
|
+
def reset_routes!
|
|
71
|
+
reset_router!
|
|
72
|
+
default_routes
|
|
73
|
+
true
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Returns the routes of our app.
|
|
78
|
+
#
|
|
79
|
+
# @example
|
|
80
|
+
# MyApp.routes
|
|
81
|
+
#
|
|
82
|
+
def routes
|
|
83
|
+
router.routes
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
# Returns an absolute path of view in application views folder.
|
|
88
|
+
#
|
|
89
|
+
# @example
|
|
90
|
+
# Admin.view_path 'users/index' #=> "/home/user/test/admin/views/users/index"
|
|
91
|
+
#
|
|
92
|
+
def view_path(view)
|
|
93
|
+
File.expand_path(view, views)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
##
|
|
97
|
+
# Returns an absolute path of application layout.
|
|
98
|
+
#
|
|
99
|
+
# @example
|
|
100
|
+
# Admin.layout_path :application #=> "/home/user/test/admin/views/layouts/application"
|
|
101
|
+
#
|
|
102
|
+
def layout_path(layout)
|
|
103
|
+
view_path("layouts/#{layout}")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
# Run the Tennpipes app as a self-hosted server using
|
|
108
|
+
# Thin, Mongrel or WEBrick (in that order).
|
|
109
|
+
#
|
|
110
|
+
# @see Tennpipes::Server#start
|
|
111
|
+
#
|
|
112
|
+
def run!(options={})
|
|
113
|
+
return unless Tennpipes.load!
|
|
114
|
+
Tennpipes.mount(settings.to_s).to('/')
|
|
115
|
+
Tennpipes.run!(options)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
##
|
|
119
|
+
# Returns default list of path globs to load as dependencies.
|
|
120
|
+
# Appends custom dependency patterns to the be loaded for your Application.
|
|
121
|
+
#
|
|
122
|
+
# @return [Array]
|
|
123
|
+
# list of path globs to load as dependencies
|
|
124
|
+
#
|
|
125
|
+
# @example
|
|
126
|
+
# MyApp.dependencies << "#{Tennpipes.root}/uploaders/**/*.rb"
|
|
127
|
+
# MyApp.dependencies << Tennpipes.root('other_app', 'controllers.rb')
|
|
128
|
+
#
|
|
129
|
+
def dependencies
|
|
130
|
+
[
|
|
131
|
+
'urls.rb',
|
|
132
|
+
'config/urls.rb',
|
|
133
|
+
'mailers/*.rb',
|
|
134
|
+
'mailers.rb',
|
|
135
|
+
'controllers/**/*.rb',
|
|
136
|
+
'controllers.rb',
|
|
137
|
+
'helpers/**/*.rb',
|
|
138
|
+
'helpers.rb',
|
|
139
|
+
].flat_map{ |file| Dir.glob(File.join(settings.root, file)) }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
##
|
|
143
|
+
# An array of file to load before your app.rb, basically are files
|
|
144
|
+
# which our app depends on.
|
|
145
|
+
#
|
|
146
|
+
# By default we look for files:
|
|
147
|
+
#
|
|
148
|
+
# # List of default files that we are looking for:
|
|
149
|
+
# yourapp/models.rb
|
|
150
|
+
# yourapp/models/**/*.rb
|
|
151
|
+
# yourapp/lib.rb
|
|
152
|
+
# yourapp/lib/**/*.rb
|
|
153
|
+
#
|
|
154
|
+
# @example Adding a custom prerequisite
|
|
155
|
+
# MyApp.prerequisites << Tennpipes.root('my_app', 'custom_model.rb')
|
|
156
|
+
#
|
|
157
|
+
def prerequisites
|
|
158
|
+
@_prerequisites ||= []
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def default(option, *args, &block)
|
|
162
|
+
set(option, *args, &block) unless respond_to?(option)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
protected
|
|
166
|
+
|
|
167
|
+
##
|
|
168
|
+
# Requires all files within the application load paths.
|
|
169
|
+
#
|
|
170
|
+
def require_dependencies
|
|
171
|
+
Tennpipes.require_dependencies(dependencies, :force => true)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
module Tennpipes
|
|
2
|
+
##
|
|
3
|
+
# Holds setup-oriented methods for Tennpipes::Application.
|
|
4
|
+
#
|
|
5
|
+
module ApplicationSetup
|
|
6
|
+
def self.registered(app)
|
|
7
|
+
app.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
##
|
|
12
|
+
# Defines default settings for Tennpipes application.
|
|
13
|
+
#
|
|
14
|
+
def default_configuration!
|
|
15
|
+
set :app_file, File.expand_path(caller_files.first || $0)
|
|
16
|
+
set :app_name, settings.to_s.underscore.to_sym
|
|
17
|
+
|
|
18
|
+
set :environment, Tennpipes.env
|
|
19
|
+
set :reload, proc { development? }
|
|
20
|
+
set :logging, proc { development? }
|
|
21
|
+
|
|
22
|
+
set :method_override, true
|
|
23
|
+
set :default_builder, 'StandardFormBuilder'
|
|
24
|
+
|
|
25
|
+
default_paths
|
|
26
|
+
default_security
|
|
27
|
+
global_configuration
|
|
28
|
+
setup_prerequisites
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Setup the application by registering initializers, load paths and logger.
|
|
33
|
+
# Invoked automatically when an application is first instantiated.
|
|
34
|
+
#
|
|
35
|
+
# @return [TrueClass]
|
|
36
|
+
#
|
|
37
|
+
def setup_application!
|
|
38
|
+
return if @_configured
|
|
39
|
+
require_dependencies
|
|
40
|
+
default_routes
|
|
41
|
+
default_errors
|
|
42
|
+
setup_locale
|
|
43
|
+
precompile_routes!
|
|
44
|
+
@_configured = true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def precompile_routes?
|
|
48
|
+
settings.respond_to?(:precompile_routes) && settings.precompile_routes?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def precompile_routes!
|
|
52
|
+
compiled_router.prepare!
|
|
53
|
+
compiled_router.engine.compile!
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def default_paths
|
|
59
|
+
set :locale_path, proc { Dir.glob File.join(root, 'locale/**/*.{rb,yml}') }
|
|
60
|
+
set :views, proc { File.join(root, 'views') }
|
|
61
|
+
|
|
62
|
+
set :uri_root, '/'
|
|
63
|
+
set :public_folder, proc { Tennpipes.root('public', uri_root) }
|
|
64
|
+
set :images_path, proc { File.join(public_folder, 'images') }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def default_security
|
|
68
|
+
set :protection, :except => :path_traversal
|
|
69
|
+
set :sessions, false
|
|
70
|
+
set :protect_from_csrf, false
|
|
71
|
+
set :report_csrf_failure, false
|
|
72
|
+
set :allow_disabled_csrf, false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
##
|
|
76
|
+
# Applies global tennpipes configuration blocks to current application.
|
|
77
|
+
#
|
|
78
|
+
def global_configuration
|
|
79
|
+
Tennpipes.global_configurations.each do |configuration|
|
|
80
|
+
class_eval(&configuration)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def setup_prerequisites
|
|
85
|
+
prerequisites.concat(default_prerequisites).uniq!
|
|
86
|
+
Tennpipes.require_dependencies(prerequisites)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# Returns globs of default paths of application prerequisites.
|
|
91
|
+
#
|
|
92
|
+
def default_prerequisites
|
|
93
|
+
[
|
|
94
|
+
'/models.rb',
|
|
95
|
+
'/models/**/*.rb',
|
|
96
|
+
'/lib.rb',
|
|
97
|
+
'/lib/**/*.rb',
|
|
98
|
+
].map{ |glob| File.join(settings.root, glob) }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Overrides the default middleware for Sinatra based on Tennpipes conventions.
|
|
102
|
+
# Also initializes the application after setting up the middleware.
|
|
103
|
+
def setup_default_middleware(builder)
|
|
104
|
+
setup_sessions builder
|
|
105
|
+
builder.use Sinatra::ExtendedRack if defined?(EventMachine)
|
|
106
|
+
builder.use Tennpipes::ShowExceptions if show_exceptions?
|
|
107
|
+
builder.use Tennpipes::Logger::Rack, uri_root if Tennpipes.logger && logging?
|
|
108
|
+
builder.use Tennpipes::Reloader::Rack if reload?
|
|
109
|
+
builder.use Rack::MethodOverride if method_override?
|
|
110
|
+
builder.use Rack::Head
|
|
111
|
+
register Tennpipes::Flash
|
|
112
|
+
setup_protection builder
|
|
113
|
+
setup_csrf_protection builder
|
|
114
|
+
setup_application!
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
##
|
|
118
|
+
# We need to add almost __sinatra__ images.
|
|
119
|
+
#
|
|
120
|
+
def default_routes
|
|
121
|
+
configure :development do
|
|
122
|
+
get '*__sinatra__/:image.png' do
|
|
123
|
+
content_type :png
|
|
124
|
+
send_file(File.dirname(__FILE__) + "/../images/#{params[:image]}.png")
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
##
|
|
130
|
+
# This log errors for production environments.
|
|
131
|
+
#
|
|
132
|
+
def default_errors
|
|
133
|
+
configure :production do
|
|
134
|
+
error ::Exception do
|
|
135
|
+
logger.exception env['sinatra.error']
|
|
136
|
+
halt(500, { 'Content-Type' => 'text/html' }, ['<h1>Internal Server Error</h1>'])
|
|
137
|
+
end unless errors.has_key?(::Exception)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def setup_locale
|
|
142
|
+
return unless defined? I18n
|
|
143
|
+
Reloader.special_files += locale_path
|
|
144
|
+
I18n.load_path << locale_path
|
|
145
|
+
I18n.reload!
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# allow custome session management
|
|
149
|
+
def setup_sessions(builder)
|
|
150
|
+
if sessions.kind_of?(Hash) && sessions[:use]
|
|
151
|
+
builder.use sessions[:use], sessions[:config] || {}
|
|
152
|
+
else
|
|
153
|
+
super
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# sets up csrf protection for the app
|
|
158
|
+
def setup_csrf_protection(builder)
|
|
159
|
+
check_csrf_protection_dependency
|
|
160
|
+
|
|
161
|
+
if protect_from_csrf?
|
|
162
|
+
options = options_for_csrf_protection_setup
|
|
163
|
+
options.merge!(protect_from_csrf) if protect_from_csrf.kind_of?(Hash)
|
|
164
|
+
builder.use(options[:except] ? Tennpipes::AuthenticityToken : Rack::Protection::AuthenticityToken, options)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# returns the options used in the builder for csrf protection setup
|
|
169
|
+
def options_for_csrf_protection_setup
|
|
170
|
+
options = { :logger => logger }
|
|
171
|
+
if report_csrf_failure? || allow_disabled_csrf?
|
|
172
|
+
options.merge!(
|
|
173
|
+
:reaction => :report,
|
|
174
|
+
:report_key => 'protection.csrf.failed'
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
options
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# warn if the protect_from_csrf is active but sessions are not
|
|
181
|
+
def check_csrf_protection_dependency
|
|
182
|
+
if (protect_from_csrf? && !sessions?) && !defined?(Tennpipes::IGNORE_CSRF_SETUP_WARNING)
|
|
183
|
+
warn(<<-ERROR)
|
|
184
|
+
`protect_from_csrf` is activated, but `sessions` seem to be off. To enable csrf
|
|
185
|
+
protection, use:
|
|
186
|
+
|
|
187
|
+
enable :sessions
|
|
188
|
+
|
|
189
|
+
or deactivate protect_from_csrf:
|
|
190
|
+
|
|
191
|
+
disable :protect_from_csrf
|
|
192
|
+
|
|
193
|
+
If you use a different session store, ignore this warning using:
|
|
194
|
+
|
|
195
|
+
# in boot.rb:
|
|
196
|
+
Tennpipes::IGNORE_CSRF_SETUP_WARNING = true
|
|
197
|
+
ERROR
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Tennpipes
|
|
2
|
+
class AuthenticityToken < Rack::Protection::AuthenticityToken
|
|
3
|
+
def initialize(app, options = {})
|
|
4
|
+
@app = app
|
|
5
|
+
@except = options[:except]
|
|
6
|
+
@except = Array(@except) unless @except.is_a?(Proc)
|
|
7
|
+
super
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call(env)
|
|
11
|
+
if except?(env)
|
|
12
|
+
@app.call(env)
|
|
13
|
+
else
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def except?(env)
|
|
19
|
+
return false unless @except
|
|
20
|
+
path_info = env['PATH_INFO']
|
|
21
|
+
@except.is_a?(Proc) ? @except.call(env) : @except.any?{|path|
|
|
22
|
+
path.is_a?(Regexp) ? path.match(path_info) : path == path_info }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
module Tennpipes
|
|
2
|
+
module Flash
|
|
3
|
+
|
|
4
|
+
class << self
|
|
5
|
+
def registered(app)
|
|
6
|
+
app.helpers Helpers
|
|
7
|
+
app.after do
|
|
8
|
+
session[:_flash] = @_flash.next if @_flash
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class Storage
|
|
14
|
+
include Enumerable
|
|
15
|
+
|
|
16
|
+
# @private
|
|
17
|
+
def initialize(session=nil)
|
|
18
|
+
@_now = session || {}
|
|
19
|
+
@_next = {}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def now
|
|
23
|
+
@_now
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def next
|
|
27
|
+
@_next
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @since 0.10.8
|
|
31
|
+
# @api public
|
|
32
|
+
def [](type)
|
|
33
|
+
@_now[type]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @since 0.10.8
|
|
37
|
+
# @api public
|
|
38
|
+
def []=(type, message)
|
|
39
|
+
@_next[type] = message
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @since 0.10.8
|
|
43
|
+
# @api public
|
|
44
|
+
def delete(type)
|
|
45
|
+
@_now.delete(type)
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @since 0.10.8
|
|
50
|
+
# @api public
|
|
51
|
+
def keys
|
|
52
|
+
@_now.keys
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @since 0.10.8
|
|
56
|
+
# @api public
|
|
57
|
+
def key?(type)
|
|
58
|
+
@_now.key?(type)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @since 0.10.8
|
|
62
|
+
# @api public
|
|
63
|
+
def each(&block)
|
|
64
|
+
@_now.each(&block)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @since 0.10.8
|
|
68
|
+
# @api public
|
|
69
|
+
def replace(hash)
|
|
70
|
+
@_now.replace(hash)
|
|
71
|
+
self
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @since 0.10.8
|
|
75
|
+
# @api public
|
|
76
|
+
def update(hash)
|
|
77
|
+
@_now.update(hash)
|
|
78
|
+
self
|
|
79
|
+
end
|
|
80
|
+
alias_method :merge!, :update
|
|
81
|
+
|
|
82
|
+
# @since 0.10.8
|
|
83
|
+
# @api public
|
|
84
|
+
def sweep
|
|
85
|
+
@_now.replace(@_next)
|
|
86
|
+
@_next = {}
|
|
87
|
+
self
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @since 0.10.8
|
|
91
|
+
# @api public
|
|
92
|
+
def keep(key = nil)
|
|
93
|
+
if key
|
|
94
|
+
@_next[key] = @_now[key]
|
|
95
|
+
else
|
|
96
|
+
@_next.merge!(@_now)
|
|
97
|
+
end
|
|
98
|
+
self
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @since 0.10.8
|
|
102
|
+
# @api public
|
|
103
|
+
def discard(key = nil)
|
|
104
|
+
if key
|
|
105
|
+
@_next.delete(key)
|
|
106
|
+
else
|
|
107
|
+
@_next = {}
|
|
108
|
+
end
|
|
109
|
+
self
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @since 0.10.8
|
|
113
|
+
# @api public
|
|
114
|
+
def clear
|
|
115
|
+
@_now.clear
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @since 0.10.8
|
|
119
|
+
# @api public
|
|
120
|
+
def empty?
|
|
121
|
+
@_now.empty?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @since 0.10.8
|
|
125
|
+
# @api public
|
|
126
|
+
def to_hash
|
|
127
|
+
@_now.dup
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def length
|
|
131
|
+
@_now.length
|
|
132
|
+
end
|
|
133
|
+
alias_method :size, :length
|
|
134
|
+
|
|
135
|
+
# @since 0.10.8
|
|
136
|
+
# @api public
|
|
137
|
+
def to_s
|
|
138
|
+
@_now.to_s
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @since 0.10.8
|
|
142
|
+
# @api public
|
|
143
|
+
def error=(message)
|
|
144
|
+
self[:error] = message
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @since 0.10.8
|
|
148
|
+
# @api public
|
|
149
|
+
def error
|
|
150
|
+
self[:error]
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @since 0.10.8
|
|
154
|
+
# @api public
|
|
155
|
+
def notice=(message)
|
|
156
|
+
self[:notice] = message
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @since 0.10.8
|
|
160
|
+
# @api public
|
|
161
|
+
def notice
|
|
162
|
+
self[:notice]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @since 0.10.8
|
|
166
|
+
# @api public
|
|
167
|
+
def success=(message)
|
|
168
|
+
self[:success] = message
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @since 0.10.8
|
|
172
|
+
# @api public
|
|
173
|
+
def success
|
|
174
|
+
self[:success]
|
|
175
|
+
end
|
|
176
|
+
end # Storage
|
|
177
|
+
|
|
178
|
+
module Helpers
|
|
179
|
+
###
|
|
180
|
+
# Overloads the existing redirect helper in-order to provide support for
|
|
181
|
+
# flash messages.
|
|
182
|
+
#
|
|
183
|
+
# @overload redirect(url)
|
|
184
|
+
# @param [String] url
|
|
185
|
+
#
|
|
186
|
+
# @overload redirect(url, status_code)
|
|
187
|
+
# @param [String] url
|
|
188
|
+
# @param [Fixnum] status_code
|
|
189
|
+
#
|
|
190
|
+
# @overload redirect(url, status_code, flash_messages)
|
|
191
|
+
# @param [String] url
|
|
192
|
+
# @param [Fixnum] status_code
|
|
193
|
+
# @param [Hash] flash_messages
|
|
194
|
+
#
|
|
195
|
+
# @overload redirect(url, flash_messages)
|
|
196
|
+
# @param [String] url
|
|
197
|
+
# @param [Hash] flash_messages
|
|
198
|
+
#
|
|
199
|
+
# @example
|
|
200
|
+
# redirect(dashboard, success: :user_created)
|
|
201
|
+
# redirect(new_location, 301, notice: 'This page has moved. Please update your bookmarks!!')
|
|
202
|
+
#
|
|
203
|
+
# @since 0.10.8
|
|
204
|
+
# @api public
|
|
205
|
+
def redirect(url, *args)
|
|
206
|
+
flashes = args.extract_options!
|
|
207
|
+
|
|
208
|
+
flashes.each do |type, message|
|
|
209
|
+
message = I18n.translate(message) if message.is_a?(Symbol) && defined?(I18n)
|
|
210
|
+
flash[type] = message
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
super(url, args)
|
|
214
|
+
end
|
|
215
|
+
alias_method :redirect_to, :redirect
|
|
216
|
+
|
|
217
|
+
###
|
|
218
|
+
# Returns the flash storage object.
|
|
219
|
+
#
|
|
220
|
+
# @return [Storage]
|
|
221
|
+
#
|
|
222
|
+
# @since 0.10.8
|
|
223
|
+
# @api public
|
|
224
|
+
def flash
|
|
225
|
+
@_flash ||= Storage.new(env['rack.session'] ? session[:_flash] : {})
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|