padrino-core 0.16.2 → 0.18.0
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 +4 -4
- data/lib/padrino-core/application/application_setup.rb +19 -1
- data/lib/padrino-core/application/routing.rb +31 -10
- data/lib/padrino-core/application.rb +13 -6
- data/lib/padrino-core/cli/base.rb +2 -1
- data/lib/padrino-core/cli/binstub.rb +2 -1
- data/lib/padrino-core/cli/console.rb +1 -1
- data/lib/padrino-core/cli/launcher.rb +3 -3
- data/lib/padrino-core/cli/rake.rb +0 -2
- data/lib/padrino-core/cli/rake_tasks.rb +14 -4
- data/lib/padrino-core/loader.rb +2 -2
- data/lib/padrino-core/logger.rb +63 -14
- data/lib/padrino-core/module.rb +7 -4
- data/lib/padrino-core/mounter/application_extension.rb +1 -1
- data/lib/padrino-core/mounter.rb +22 -10
- data/lib/padrino-core/path_router/compiler.rb +9 -3
- data/lib/padrino-core/reloader/storage.rb +19 -0
- data/lib/padrino-core/reloader.rb +103 -3
- data/lib/padrino-core/server.rb +5 -3
- data/lib/padrino-core/version.rb +1 -1
- data/test/fixtures/apps/concerned/models/catalog_item.rb +7 -0
- data/test/fixtures/apps/concerned/models/filtered_item.rb +5 -0
- data/test/fixtures/apps/concerned/models/mixins/filterable.rb +13 -0
- data/test/fixtures/apps/concerned/models/mixins/sortable.rb +13 -0
- data/test/fixtures/apps/external_constants/app.rb +7 -0
- data/test/fixtures/apps/external_constants/helpers/external_constants_helpers.rb +4 -0
- data/test/fixtures/apps/helpers/class_methods_helpers.rb +1 -1
- data/test/fixtures/apps/helpers/instance_methods_helpers.rb +1 -1
- data/test/fixtures/dependencies/autoload/a.rb +5 -0
- data/test/fixtures/dependencies/autoload/b.rb +2 -0
- data/test/fixtures/dependencies/autoload/lazy.rb +2 -0
- data/test/fixtures/dependencies/gc/t.rb +5 -0
- data/test/fixtures/dependencies/gc/u.rb +3 -0
- data/test/fixtures/dependencies/gc/v.rb +10 -0
- data/test/fixtures/dependencies/gc/w.rb +2 -0
- data/test/fixtures/dependencies/gc/x.rb +2 -0
- data/test/fixtures/dependencies/gc/y.rb +2 -0
- data/test/fixtures/dependencies/parent/admin.rb +5 -0
- data/test/fixtures/dependencies/parent/trackable.rb +2 -0
- data/test/fixtures/dependencies/parent/user.rb +2 -0
- data/test/fixtures/dependencies/partial/a.rb +3 -0
- data/test/fixtures/dependencies/partial/b.rb +2 -0
- data/test/fixtures/dependencies/reload/forced.rb +1 -0
- data/test/fixtures/dependencies/reload/untracked.rb +3 -0
- data/test/fixtures/dependencies/reload/untracked_forced.rb +3 -0
- data/test/fixtures/dependencies/untracked/a.rb +2 -0
- data/test/fixtures/dependencies/untracked/b.rb +2 -0
- data/test/helper.rb +21 -0
- data/test/test_binstub.rb +47 -0
- data/test/test_cli.rb +52 -4
- data/test/test_dependencies.rb +163 -0
- data/test/test_host_authorization.rb +117 -0
- data/test/test_launcher.rb +51 -0
- data/test/test_logger.rb +136 -5
- data/test/test_mounter.rb +104 -0
- data/test/test_rake_tasks.rb +37 -0
- data/test/test_reloader_complex.rb +3 -0
- data/test/test_reloader_external.rb +3 -0
- data/test/test_reloader_simple.rb +67 -0
- data/test/test_reloader_storage.rb +3 -4
- data/test/test_reloader_system.rb +131 -6
- data/test/test_routing.rb +160 -1
- data/test/test_server.rb +90 -0
- metadata +36 -84
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 60c8ed53139a3e9558b1e665205eeb798960a6049ac0788e3454f8f6f4280de0
|
|
4
|
+
data.tar.gz: '08dc99355571157c9113a0083c8acacd9970c7f64e407008265fdc177e590572'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 50d10641e73dd6b858b2a6490cdc77372055ace5232683d7727e44b45a85267d8bd56fa2c5ce49852c51e5c017169a7449ecb0d297b6b5d67a6896b8f7396b93
|
|
7
|
+
data.tar.gz: 79af9aed08ab7c2189d162b75772e9d40f37ca45189abf26d18c9c42f0ca62d149d30756c77088fdaa119683192c76c94b8e9acf07b6b2abb8d0f72cd214155e
|
|
@@ -60,7 +60,10 @@ module Padrino
|
|
|
60
60
|
set :views, proc { File.join(root, 'views') }
|
|
61
61
|
|
|
62
62
|
set :uri_root, '/'
|
|
63
|
-
set :public_folder, proc {
|
|
63
|
+
set :public_folder, proc {
|
|
64
|
+
app_public = Padrino.root('public', uri_root)
|
|
65
|
+
File.exist?(app_public) ? app_public : Padrino.root('public')
|
|
66
|
+
}
|
|
64
67
|
set :images_path, proc { File.join(public_folder, 'images') }
|
|
65
68
|
set :base_url, 'http://localhost'
|
|
66
69
|
end
|
|
@@ -111,16 +114,31 @@ module Padrino
|
|
|
111
114
|
builder.use Rack::Head
|
|
112
115
|
register Padrino::Flash
|
|
113
116
|
setup_protection builder
|
|
117
|
+
setup_host_authorization builder if host_authorization_set?
|
|
114
118
|
setup_csrf_protection builder
|
|
115
119
|
setup_application!
|
|
116
120
|
end
|
|
117
121
|
|
|
122
|
+
##
|
|
123
|
+
# Sinatra 4.1+ checks the Host header against its host_authorization
|
|
124
|
+
# setting. Its default permits only local hosts in development, so
|
|
125
|
+
# Padrino applies the setting only when it is set to a Hash on the app,
|
|
126
|
+
# a Padrino application it inherits from or in Padrino.configure_apps,
|
|
127
|
+
# and apps that don't set it keep answering any host.
|
|
128
|
+
#
|
|
129
|
+
def host_authorization_set?
|
|
130
|
+
respond_to?(:setup_host_authorization, true) &&
|
|
131
|
+
method(:host_authorization).owner != Sinatra::Base.singleton_class &&
|
|
132
|
+
host_authorization.is_a?(Hash)
|
|
133
|
+
end
|
|
134
|
+
|
|
118
135
|
##
|
|
119
136
|
# We need to add almost __sinatra__ images.
|
|
120
137
|
#
|
|
121
138
|
def default_routes
|
|
122
139
|
configure :development do
|
|
123
140
|
get '*__sinatra__/:image.png' do
|
|
141
|
+
halt 404 unless %w[404 500].include?(params[:image])
|
|
124
142
|
content_type :png
|
|
125
143
|
send_file("#{__dir__}/../images/#{params[:image]}.png")
|
|
126
144
|
end
|
|
@@ -341,7 +341,7 @@ module Padrino
|
|
|
341
341
|
params = args.last.is_a?(Hash) ? args.pop : {}
|
|
342
342
|
fragment = params.delete(:fragment) || params.delete(:anchor)
|
|
343
343
|
path = make_path_with_params(args, value_to_param(params))
|
|
344
|
-
rebase_url(fragment ? path
|
|
344
|
+
rebase_url(fragment ? "#{path}##{fragment}" : path)
|
|
345
345
|
end
|
|
346
346
|
alias url_for url
|
|
347
347
|
|
|
@@ -372,7 +372,7 @@ module Padrino
|
|
|
372
372
|
|
|
373
373
|
def rebase_url(url)
|
|
374
374
|
if url.start_with?('/')
|
|
375
|
-
new_url =
|
|
375
|
+
new_url = String.new
|
|
376
376
|
new_url << conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
|
|
377
377
|
new_url << conform_uri(uri_root) if defined?(uri_root)
|
|
378
378
|
new_url << url
|
|
@@ -381,6 +381,20 @@ module Padrino
|
|
|
381
381
|
end
|
|
382
382
|
end
|
|
383
383
|
|
|
384
|
+
##
|
|
385
|
+
# The project's shared public/ for an app mounted under a sub-path whose
|
|
386
|
+
# public folder is the default public/<uri_root>. Static files and asset
|
|
387
|
+
# stamps fall back to it for files public/<uri_root> doesn't have. Nil for
|
|
388
|
+
# standalone Sinatra apps that only register Padrino::Routing.
|
|
389
|
+
#
|
|
390
|
+
# @api private
|
|
391
|
+
def shared_public_folder
|
|
392
|
+
return unless respond_to?(:uri_root) && Padrino.respond_to?(:root)
|
|
393
|
+
return if uri_root.nil? || uri_root == '/' || !public_folder
|
|
394
|
+
|
|
395
|
+
Padrino.root('public') if File.expand_path(public_folder) == Padrino.root('public', uri_root)
|
|
396
|
+
end
|
|
397
|
+
|
|
384
398
|
##
|
|
385
399
|
# Processes the existing path and prepends the 'parent' parameters onto the route
|
|
386
400
|
# Used for calculating path in route method.
|
|
@@ -599,12 +613,14 @@ module Padrino
|
|
|
599
613
|
# path i.e :index or :show
|
|
600
614
|
if path.is_a?(Symbol)
|
|
601
615
|
name = path
|
|
602
|
-
path = map&.dup || (path == :index ? '/' : path.to_s)
|
|
616
|
+
path = map&.dup || (path == :index ? '/' : path.to_s.dup)
|
|
603
617
|
end
|
|
604
618
|
|
|
605
619
|
# Build our controller
|
|
606
620
|
controller = Array(@_controller).map(&:to_s)
|
|
607
621
|
|
|
622
|
+
path = path.dup if path.is_a?(String)
|
|
623
|
+
|
|
608
624
|
case path
|
|
609
625
|
when String # path i.e "/index" or "/show"
|
|
610
626
|
# Now we need to parse our 'with' params
|
|
@@ -855,15 +871,20 @@ module Padrino
|
|
|
855
871
|
|
|
856
872
|
##
|
|
857
873
|
# This is mostly just a helper so request.path_info isn't changed when
|
|
858
|
-
# serving files from the public directory.
|
|
874
|
+
# serving files from the public directory. An app mounted under a sub-path
|
|
875
|
+
# falls back to the shared public/ for files missing from public/<uri_root>.
|
|
859
876
|
#
|
|
860
877
|
def static_file?(path_info)
|
|
861
878
|
return unless (public_dir = settings.public_folder)
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
879
|
+
# Decode the path the way Sinatra's static! and the router do: %XX only, so '+' stays a plus.
|
|
880
|
+
file = Rack::Utils.unescape_path(path_info.b).force_encoding(Encoding::UTF_8)
|
|
881
|
+
[File.expand_path(public_dir), settings.shared_public_folder].compact.each do |dir|
|
|
882
|
+
path = "#{dir}#{file}"
|
|
883
|
+
next unless Rack::Utils.valid_path?(path)
|
|
884
|
+
path = File.expand_path(path)
|
|
885
|
+
return path if path.start_with?("#{dir}/") && File.file?(path)
|
|
886
|
+
end
|
|
887
|
+
nil
|
|
867
888
|
end
|
|
868
889
|
|
|
869
890
|
#
|
|
@@ -963,7 +984,7 @@ module Padrino
|
|
|
963
984
|
verb = request.request_method
|
|
964
985
|
candidacies, allows = routes.partition { |route| route.verb == verb }
|
|
965
986
|
if candidacies.empty?
|
|
966
|
-
response['
|
|
987
|
+
response['Allow'] = allows.map(&:verb).uniq.join(', ')
|
|
967
988
|
halt 405
|
|
968
989
|
end
|
|
969
990
|
end
|
|
@@ -119,15 +119,22 @@ module Padrino
|
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
##
|
|
122
|
-
# Returns
|
|
123
|
-
#
|
|
122
|
+
# Returns the files to load as dependencies of your Application: those matching
|
|
123
|
+
# the default globs below, under the application's root. The list is built again
|
|
124
|
+
# on each call, so appending to it has no effect; to load more files, override
|
|
125
|
+
# the method and add them to +super+. Add file paths (expand globs with Dir.glob)
|
|
126
|
+
# under Padrino.root: the reloader watches these files and reloads the application
|
|
127
|
+
# when one changes.
|
|
124
128
|
#
|
|
125
|
-
# @return [Array]
|
|
126
|
-
#
|
|
129
|
+
# @return [Array<String>]
|
|
130
|
+
# paths of the files to load as dependencies
|
|
127
131
|
#
|
|
128
132
|
# @example
|
|
129
|
-
# MyApp
|
|
130
|
-
#
|
|
133
|
+
# class MyApp < Padrino::Application
|
|
134
|
+
# def self.dependencies
|
|
135
|
+
# super + Dir.glob(Padrino.root('uploaders', '**', '*.rb'))
|
|
136
|
+
# end
|
|
137
|
+
# end
|
|
131
138
|
#
|
|
132
139
|
def dependencies
|
|
133
140
|
[
|
|
@@ -61,7 +61,7 @@ module Padrino
|
|
|
61
61
|
require 'padrino-gen/command'
|
|
62
62
|
ARGV.shift
|
|
63
63
|
ARGV << 'help' if ARGV.empty?
|
|
64
|
-
Padrino.bin_gen(*ARGV)
|
|
64
|
+
exit 1 unless Padrino.bin_gen(*ARGV)
|
|
65
65
|
rescue StandardError
|
|
66
66
|
puts '<= You need padrino-gen! Run: gem install padrino-gen'
|
|
67
67
|
end
|
|
@@ -82,6 +82,7 @@ module Padrino
|
|
|
82
82
|
abort 'Please specify code or file' if code_or_file.nil?
|
|
83
83
|
|
|
84
84
|
require File.expand_path('config/boot.rb')
|
|
85
|
+
Padrino.mounted_apps.each(&:setup_application!)
|
|
85
86
|
|
|
86
87
|
if File.exist?(code_or_file)
|
|
87
88
|
eval(File.read(code_or_file), nil, code_or_file)
|
|
@@ -21,7 +21,8 @@ module Padrino
|
|
|
21
21
|
if File.file?(binstub)
|
|
22
22
|
exec Gem.ruby, binstub, *ARGV
|
|
23
23
|
else
|
|
24
|
-
|
|
24
|
+
# exit! skips the flush of buffered output, so write to the unbuffered stderr. Not warn: -W0 silences it.
|
|
25
|
+
$stderr.puts 'Please run `bundle install && bundle binstubs --all` from your project root to generate bundle-specific executables'
|
|
25
26
|
exit!
|
|
26
27
|
end
|
|
27
28
|
end
|
|
@@ -18,7 +18,7 @@ module Padrino
|
|
|
18
18
|
method_option :pid, type: :string, aliases: '-i', desc: 'File to store pid.'
|
|
19
19
|
method_option :debug, type: :boolean, desc: 'Set debugging flags.'
|
|
20
20
|
method_option :options, type: :array, aliases: '-O', desc: <<~DESC.chomp
|
|
21
|
-
--options NAME=VALUE NAME2=VALUE2
|
|
21
|
+
--options NAME=VALUE NAME2=VALUE2. pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$PROGRAM_NAME} start --server_options'
|
|
22
22
|
DESC
|
|
23
23
|
method_option :server_options, type: :boolean, desc: "Tells the current server handler's options that can be used with --options"
|
|
24
24
|
|
|
@@ -48,7 +48,7 @@ module Padrino
|
|
|
48
48
|
# https://github.com/rack/rack/blob/master/lib/rack/server.rb\#L100
|
|
49
49
|
def server_options(options)
|
|
50
50
|
info = []
|
|
51
|
-
server =
|
|
51
|
+
server = Rackup::Handler.get(options[:server]) || Rackup::Handler.default
|
|
52
52
|
if server.respond_to?(:valid_options)
|
|
53
53
|
info << ''
|
|
54
54
|
info << "Server-specific options for #{server.name}:"
|
|
@@ -62,7 +62,7 @@ module Padrino
|
|
|
62
62
|
return '' unless has_options
|
|
63
63
|
end
|
|
64
64
|
info.join("\n")
|
|
65
|
-
rescue NameError
|
|
65
|
+
rescue NameError, LoadError
|
|
66
66
|
"Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options"
|
|
67
67
|
end
|
|
68
68
|
|
|
@@ -13,8 +13,6 @@ module PadrinoTasks
|
|
|
13
13
|
def self.init(init = false)
|
|
14
14
|
Padrino::Tasks.files.flatten.uniq.each do |rakefile|
|
|
15
15
|
Rake.application.add_import(rakefile)
|
|
16
|
-
rescue StandardError
|
|
17
|
-
puts "<= Failed load #{ext}"
|
|
18
16
|
end
|
|
19
17
|
|
|
20
18
|
load(File.expand_path('rake_tasks.rb', __dir__))
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
# Model paths that :skeleton left out, loaded by a later :environment in the same run
|
|
2
|
+
# (e.g. `rake ar:migrate db:seed`).
|
|
3
|
+
# ceiling: they load after config/apps.rb and the after_load hooks, so a hook that walks the models
|
|
4
|
+
# doesn't see them in that case; loading them before the hooks would mean re-running Padrino.load!.
|
|
5
|
+
skipped_model_paths = []
|
|
6
|
+
|
|
1
7
|
# Loads the Padrino applications mounted within the project.
|
|
2
8
|
# Setting up the required environment for Padrino.
|
|
3
9
|
task :environment do
|
|
4
10
|
require File.expand_path('config/boot.rb', Rake.application.original_dir)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
unless skipped_model_paths.empty?
|
|
12
|
+
Padrino.dependency_paths.concat(skipped_model_paths)
|
|
13
|
+
Padrino.require_dependencies(*skipped_model_paths)
|
|
14
|
+
skipped_model_paths.clear
|
|
8
15
|
end
|
|
16
|
+
|
|
17
|
+
Padrino.mounted_apps.each(&:setup_application!)
|
|
9
18
|
end
|
|
10
19
|
|
|
11
20
|
task :skeleton do
|
|
12
21
|
PADRINO_ROOT ||= Rake.application.original_dir
|
|
13
22
|
require 'padrino-core'
|
|
14
|
-
Padrino.
|
|
23
|
+
skipped_model_paths.concat(Padrino.dependency_paths.select { |path| path.include?('/models/') })
|
|
24
|
+
Padrino.dependency_paths.reject! { |path| path.include?('/models/') }
|
|
15
25
|
require File.expand_path('config/boot.rb', Rake.application.original_dir)
|
|
16
26
|
end
|
|
17
27
|
|
data/lib/padrino-core/loader.rb
CHANGED
|
@@ -31,7 +31,7 @@ module Padrino
|
|
|
31
31
|
#
|
|
32
32
|
# @example
|
|
33
33
|
# after_load do
|
|
34
|
-
#
|
|
34
|
+
# SomeORM.finalize
|
|
35
35
|
# end
|
|
36
36
|
#
|
|
37
37
|
def after_load(&block)
|
|
@@ -150,7 +150,7 @@ module Padrino
|
|
|
150
150
|
error = fatal = loaded = nil
|
|
151
151
|
|
|
152
152
|
files.dup.each do |file|
|
|
153
|
-
Reloader.safe_load(file, options)
|
|
153
|
+
Reloader.enabled? || options[:force] ? Reloader.safe_load(file, options) : Reloader.untracked_load(file)
|
|
154
154
|
files.delete(file)
|
|
155
155
|
loaded = true
|
|
156
156
|
rescue NameError, LoadError => error
|
data/lib/padrino-core/logger.rb
CHANGED
|
@@ -30,6 +30,10 @@ module Padrino
|
|
|
30
30
|
#
|
|
31
31
|
# @example using ruby default logger
|
|
32
32
|
# require 'logger'
|
|
33
|
+
# Padrino.logger = ::Logger.new(STDOUT)
|
|
34
|
+
#
|
|
35
|
+
# @example using ruby default logger with Padrino formatting and #colorize!
|
|
36
|
+
# require 'logger'
|
|
33
37
|
# new_logger = ::Logger.new(STDOUT)
|
|
34
38
|
# new_logger.extend(Padrino::Logger::Extensions)
|
|
35
39
|
# Padrino.logger = new_logger
|
|
@@ -85,8 +89,8 @@ module Padrino
|
|
|
85
89
|
if args.size > 1
|
|
86
90
|
bench(args[0], args[1], args[2], name)
|
|
87
91
|
else
|
|
88
|
-
location = resolve_source_location(caller(1).shift)
|
|
89
|
-
args.unshift(location) if location
|
|
92
|
+
location = resolve_source_location(caller(1).shift) if enable_source_location?
|
|
93
|
+
args.unshift(location) if location
|
|
90
94
|
push(args * '', name)
|
|
91
95
|
end
|
|
92
96
|
end
|
|
@@ -94,7 +98,7 @@ module Padrino
|
|
|
94
98
|
define_method(:"#{name}?") { number >= level }
|
|
95
99
|
end
|
|
96
100
|
|
|
97
|
-
SOURCE_LOCATION_REGEXP = /^(.*?):(\d+?)(?::in
|
|
101
|
+
SOURCE_LOCATION_REGEXP = /^(.*?):(\d+?)(?::in [`'].+?')?$/
|
|
98
102
|
|
|
99
103
|
##
|
|
100
104
|
# Returns true if :source_location is set to true.
|
|
@@ -111,7 +115,11 @@ module Padrino
|
|
|
111
115
|
return unless path && line
|
|
112
116
|
|
|
113
117
|
root = Padrino.root
|
|
114
|
-
|
|
118
|
+
if Pathname.new(path).relative?
|
|
119
|
+
return unless File.exist?(path) # code from irb, eval or ruby -e has no file
|
|
120
|
+
|
|
121
|
+
path = File.realpath(path)
|
|
122
|
+
end
|
|
115
123
|
return unless path.start_with?(root) && !path.start_with?(Padrino.root('vendor'))
|
|
116
124
|
|
|
117
125
|
"[#{path.gsub("#{root}/", '')}:#{line}] "
|
|
@@ -240,6 +248,33 @@ module Padrino
|
|
|
240
248
|
end
|
|
241
249
|
end
|
|
242
250
|
|
|
251
|
+
##
|
|
252
|
+
# Plain versions of the Padrino-specific methods of {Extensions}. A logger assigned
|
|
253
|
+
# without {Extensions} gets the ones it lacks, so Padrino can log to it while its
|
|
254
|
+
# standard logging methods stay untouched.
|
|
255
|
+
#
|
|
256
|
+
module Fallbacks
|
|
257
|
+
def devel(*); end
|
|
258
|
+
|
|
259
|
+
def devel?
|
|
260
|
+
false
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def bench(action, began_at, message, level = :debug, _color = :yellow)
|
|
264
|
+
return unless Levels.key?(level)
|
|
265
|
+
|
|
266
|
+
public_send level, "#{action.to_s.upcase} (#{Kernel.format('%0.4fs', Time.now - began_at)}) #{message}"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def exception(boom, verbosity = :long, level = :error)
|
|
270
|
+
Extensions.instance_method(:exception).bind(self).call(boom, verbosity, level)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def colorize(string, *_colors)
|
|
274
|
+
string
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
243
278
|
module Colorize
|
|
244
279
|
# Colors for levels
|
|
245
280
|
unless defined?(ColoredLevels)
|
|
@@ -332,16 +367,25 @@ module Padrino
|
|
|
332
367
|
end
|
|
333
368
|
|
|
334
369
|
def self.logger=(logger)
|
|
335
|
-
unless logger.
|
|
336
|
-
warn <<~MESSAGE
|
|
337
|
-
WARNING! `Padrino.logger = new_logger` no longer extends it with #colorize! and other features.
|
|
338
|
-
To do it with a custom logger you have to manually `new_logger.extend(Padrino::Logger::Extensions)`
|
|
339
|
-
before passing to `Padrino.logger = new_logger`.
|
|
340
|
-
MESSAGE
|
|
341
|
-
end
|
|
370
|
+
add_fallbacks(logger) unless logger.is_a?(Padrino::Logger::Extensions)
|
|
342
371
|
@_logger = logger
|
|
343
372
|
end
|
|
344
373
|
|
|
374
|
+
##
|
|
375
|
+
# Defines the {Fallbacks} methods a logger does not have yet.
|
|
376
|
+
#
|
|
377
|
+
def self.add_fallbacks(logger)
|
|
378
|
+
return if logger.nil?
|
|
379
|
+
|
|
380
|
+
missing = Fallbacks.instance_methods.reject { |name| logger.respond_to?(name) }
|
|
381
|
+
return if missing.empty?
|
|
382
|
+
return warn("WARNING! Padrino.logger is frozen and lacks #{missing.join(', ')}, logging from Padrino will fail.") if logger.frozen?
|
|
383
|
+
|
|
384
|
+
fallbacks = ::Module.new
|
|
385
|
+
missing.each { |name| fallbacks.send(:define_method, name, Fallbacks.instance_method(name)) }
|
|
386
|
+
logger.extend(fallbacks)
|
|
387
|
+
end
|
|
388
|
+
|
|
345
389
|
##
|
|
346
390
|
# Setup a new logger.
|
|
347
391
|
#
|
|
@@ -443,7 +487,11 @@ module Padrino
|
|
|
443
487
|
return unless @buffer.size.positive?
|
|
444
488
|
self.class.mutex.synchronize do
|
|
445
489
|
@buffer.each do |line|
|
|
446
|
-
|
|
490
|
+
if @sanitize_encoding
|
|
491
|
+
line = line.encode(@sanitize_encoding, invalid: :replace, undef: :replace)
|
|
492
|
+
elsif line.encoding != Encoding::UTF_8
|
|
493
|
+
line = line.encode(@log.external_encoding || Encoding::UTF_8, invalid: :replace, undef: :replace)
|
|
494
|
+
end
|
|
447
495
|
@log.write(line)
|
|
448
496
|
end
|
|
449
497
|
@buffer.clear
|
|
@@ -475,7 +523,7 @@ module Padrino
|
|
|
475
523
|
# The message
|
|
476
524
|
#
|
|
477
525
|
def <<(message = nil)
|
|
478
|
-
message
|
|
526
|
+
message += "\n" unless message[-1] == "\n"
|
|
479
527
|
self.class.mutex.synchronize { @buffer << message }
|
|
480
528
|
flush if @auto_flush
|
|
481
529
|
message
|
|
@@ -483,7 +531,8 @@ module Padrino
|
|
|
483
531
|
alias write <<
|
|
484
532
|
|
|
485
533
|
def format(message, level)
|
|
486
|
-
|
|
534
|
+
datetime = @format_datetime.empty? ? '' : Time.now.strftime(@format_datetime)
|
|
535
|
+
Kernel.format(@format_message, stylized_level(level), colorize(datetime, :yellow), message.to_s.strip)
|
|
487
536
|
end
|
|
488
537
|
|
|
489
538
|
##
|
data/lib/padrino-core/module.rb
CHANGED
|
@@ -34,8 +34,9 @@ module Padrino
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
##
|
|
37
|
-
# Returns the
|
|
38
|
-
#
|
|
37
|
+
# Returns the path globs of the module's files to load as dependencies. The list
|
|
38
|
+
# is built again on each call, so appending to it has no effect; to load more
|
|
39
|
+
# files, override the method and add globs to +super+.
|
|
39
40
|
#
|
|
40
41
|
# @return [Array<String>]
|
|
41
42
|
# The dependency paths.
|
|
@@ -44,9 +45,11 @@ module Padrino
|
|
|
44
45
|
# module MyModule
|
|
45
46
|
# extend Padrino::Module
|
|
46
47
|
# gem! 'my_gem'
|
|
47
|
-
# end
|
|
48
48
|
#
|
|
49
|
-
#
|
|
49
|
+
# def self.dependency_paths
|
|
50
|
+
# super + ["#{root}/uploaders/*.rb"]
|
|
51
|
+
# end
|
|
52
|
+
# end
|
|
50
53
|
#
|
|
51
54
|
def dependency_paths
|
|
52
55
|
[
|
data/lib/padrino-core/mounter.rb
CHANGED
|
@@ -87,17 +87,13 @@ module Padrino
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
##
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
# @param [Padrino::Router]
|
|
94
|
-
#
|
|
95
|
-
# @return [Padrino::Router]
|
|
90
|
+
# Applies the mount settings (uri_root, root, public folder, cascade) to the
|
|
91
|
+
# application and sets it up, so its routes, controllers and mailers are loaded.
|
|
96
92
|
#
|
|
97
93
|
# @example
|
|
98
|
-
# @app.
|
|
94
|
+
# @app.setup_application!
|
|
99
95
|
#
|
|
100
|
-
def
|
|
96
|
+
def setup_application!
|
|
101
97
|
app_data = self
|
|
102
98
|
app_obj = @app_obj
|
|
103
99
|
|
|
@@ -117,7 +113,22 @@ module Padrino
|
|
|
117
113
|
app_obj.public_folder = Padrino.root('public', uri_root) unless public_folder_exists
|
|
118
114
|
end
|
|
119
115
|
app_obj.setup_application! # Initializes the app here with above settings.
|
|
120
|
-
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
##
|
|
119
|
+
# Maps Padrino application onto a Padrino::Router.
|
|
120
|
+
# For use in constructing a Rack application.
|
|
121
|
+
#
|
|
122
|
+
# @param [Padrino::Router]
|
|
123
|
+
#
|
|
124
|
+
# @return [Padrino::Router]
|
|
125
|
+
#
|
|
126
|
+
# @example
|
|
127
|
+
# @app.map_onto(router)
|
|
128
|
+
#
|
|
129
|
+
def map_onto(router)
|
|
130
|
+
setup_application!
|
|
131
|
+
router.map(to: app_obj, path: uri_root, host: app_host)
|
|
121
132
|
end
|
|
122
133
|
|
|
123
134
|
###
|
|
@@ -183,7 +194,8 @@ module Padrino
|
|
|
183
194
|
def locate_app_object
|
|
184
195
|
@_app_object ||= begin
|
|
185
196
|
ensure_app_file!
|
|
186
|
-
|
|
197
|
+
# Always tracked, since Application#reload! must re-run the app file.
|
|
198
|
+
Reloader.safe_load(app_file) if File.file?(app_file)
|
|
187
199
|
app_constant
|
|
188
200
|
end
|
|
189
201
|
end
|
|
@@ -70,6 +70,8 @@ module Padrino
|
|
|
70
70
|
# Returns a instance of PathRouter::Route if path is matched with current regexp
|
|
71
71
|
#
|
|
72
72
|
def match?(offset, path)
|
|
73
|
+
return unless path
|
|
74
|
+
|
|
73
75
|
@routes[offset..].find do |route|
|
|
74
76
|
route.regexp === path || (path.end_with?('/') && route.regexp === path[0..-2])
|
|
75
77
|
end
|
|
@@ -88,10 +90,14 @@ module Padrino
|
|
|
88
90
|
end
|
|
89
91
|
|
|
90
92
|
##
|
|
91
|
-
# Decode env["PATH_INFO"]
|
|
93
|
+
# Decode env["PATH_INFO"]. Returns nil when the path doesn't decode to valid text
|
|
94
|
+
# (a malformed or non-UTF-8 escape such as "/%ff"), so it matches no route.
|
|
92
95
|
#
|
|
93
96
|
def decode_pattern(pattern)
|
|
94
|
-
decode_uri(encode_default_external(pattern))
|
|
97
|
+
decoded = decode_uri(encode_default_external(pattern))
|
|
98
|
+
decoded if decoded.valid_encoding?
|
|
99
|
+
rescue ArgumentError, EncodingError
|
|
100
|
+
nil
|
|
95
101
|
end
|
|
96
102
|
|
|
97
103
|
##
|
|
@@ -105,7 +111,7 @@ module Padrino
|
|
|
105
111
|
# Decode uri escape sequences
|
|
106
112
|
#
|
|
107
113
|
def decode_uri(string)
|
|
108
|
-
string.split(/%2F|%2f/, -1).map { |part| Rack::Utils.unescape(part) }.join('%2F')
|
|
114
|
+
string.split(/%2F|%2f/, -1).map { |part| Rack::Utils.unescape(part.gsub('+', '%2B')) }.join('%2F')
|
|
109
115
|
end
|
|
110
116
|
end
|
|
111
117
|
end
|
|
@@ -20,6 +20,7 @@ module Padrino
|
|
|
20
20
|
|
|
21
21
|
def prepare(name)
|
|
22
22
|
file = remove(name)
|
|
23
|
+
reset_concerns(name)
|
|
23
24
|
@old_entries ||= {}
|
|
24
25
|
@old_entries[name] = {
|
|
25
26
|
constants: object_classes,
|
|
@@ -57,6 +58,24 @@ module Padrino
|
|
|
57
58
|
@files ||= {}
|
|
58
59
|
end
|
|
59
60
|
|
|
61
|
+
##
|
|
62
|
+
# Resets the ActiveSupport::Concern modules first defined in the file. Unlike classes
|
|
63
|
+
# they are kept on reload, so that classes including them keep working and namespaces
|
|
64
|
+
# keep their constants, but their state is reset so the file can define them again.
|
|
65
|
+
#
|
|
66
|
+
def reset_concerns(file)
|
|
67
|
+
return unless defined?(::ActiveSupport::Concern)
|
|
68
|
+
|
|
69
|
+
ObjectSpace.each_object(::Module) do |mod|
|
|
70
|
+
# Module#=== doesn't call mod, which can be a DeprecatedConstantProxy that warns on any call.
|
|
71
|
+
next unless ::ActiveSupport::Concern === mod && mod.name
|
|
72
|
+
next unless Object.const_source_location(mod.name)&.first == file
|
|
73
|
+
Reloader.reset_concern(mod) if Object.const_get(mod.name).equal?(mod)
|
|
74
|
+
rescue NameError
|
|
75
|
+
next
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
60
79
|
##
|
|
61
80
|
# Returns all the classes in the object space.
|
|
62
81
|
#
|