padrino-core 0.12.9 → 0.13.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +5 -13
  2. data/bin/padrino +1 -2
  3. data/lib/padrino-core/application/application_setup.rb +10 -6
  4. data/lib/padrino-core/application/params_protection.rb +7 -1
  5. data/lib/padrino-core/application/routing.rb +88 -50
  6. data/lib/padrino-core/application/show_exceptions.rb +29 -0
  7. data/lib/padrino-core/application.rb +0 -19
  8. data/lib/padrino-core/caller.rb +1 -2
  9. data/lib/padrino-core/cli/base.rb +7 -11
  10. data/lib/padrino-core/cli/rake_tasks.rb +8 -21
  11. data/lib/padrino-core/loader.rb +13 -12
  12. data/lib/padrino-core/logger.rb +4 -32
  13. data/lib/padrino-core/mounter.rb +62 -21
  14. data/lib/padrino-core/path_router/compiler.rb +110 -0
  15. data/lib/padrino-core/path_router/error_handler.rb +8 -0
  16. data/lib/padrino-core/path_router/matcher.rb +123 -0
  17. data/lib/padrino-core/path_router/route.rb +169 -0
  18. data/lib/padrino-core/path_router.rb +119 -0
  19. data/lib/padrino-core/reloader/rack.rb +1 -4
  20. data/lib/padrino-core/reloader/storage.rb +3 -31
  21. data/lib/padrino-core/reloader.rb +12 -17
  22. data/lib/padrino-core/version.rb +1 -1
  23. data/lib/padrino-core.rb +0 -2
  24. data/padrino-core.gemspec +8 -2
  25. data/test/fixtures/apps/helpers/support.rb +1 -0
  26. data/test/fixtures/apps/{rack_apps.rb → mountable_apps/rack_apps.rb} +0 -4
  27. data/test/fixtures/apps/{static.html → mountable_apps/static.html} +0 -0
  28. data/test/fixtures/apps/precompiled_app.rb +19 -0
  29. data/test/fixtures/apps/system.rb +0 -2
  30. data/test/helper.rb +1 -1
  31. data/test/test_application.rb +18 -6
  32. data/test/test_csrf_protection.rb +6 -7
  33. data/test/test_filters.rb +18 -1
  34. data/test/test_logger.rb +1 -49
  35. data/test/test_mounter.rb +2 -4
  36. data/test/test_params_protection.rb +15 -15
  37. data/test/test_reloader_simple.rb +2 -2
  38. data/test/test_reloader_system.rb +0 -30
  39. data/test/test_restful_routing.rb +4 -4
  40. data/test/test_routing.rb +176 -54
  41. metadata +109 -49
  42. data/lib/padrino-core/cli/binstub.rb +0 -27
  43. data/lib/padrino-core/configuration.rb +0 -40
  44. data/lib/padrino-core/ext/http_router.rb +0 -201
  45. data/lib/padrino-core/mounter/application_extension.rb +0 -55
  46. data/test/fixtures/apps/custom_dependencies/custom_dependencies.rb +0 -11
  47. data/test/fixtures/apps/custom_dependencies/my_dependencies/my_dependency.rb +0 -0
  48. data/test/fixtures/apps/stealthy/app.rb +0 -7
  49. data/test/fixtures/apps/stealthy/helpers/stealthy_class_helpers.rb +0 -13
  50. data/test/test_configuration.rb +0 -29
  51. data/test/test_reloader_storage.rb +0 -51
@@ -18,8 +18,7 @@ module Padrino
18
18
  %r{rake_test_loader\.rb},
19
19
  %r{custom_require\.rb$},
20
20
  %r{active_support},
21
- %r{/thor},
22
- %r{/lib/bundler},
21
+ %r{/thor}
23
22
  ] unless defined?(PADRINO_IGNORE_CALLERS)
24
23
 
25
24
  ##
@@ -28,20 +28,16 @@ module Padrino
28
28
  def console(*args)
29
29
  prepare :console
30
30
  require File.expand_path("../../version", __FILE__)
31
+ ARGV.clear
32
+ require 'irb'
33
+ begin
34
+ require "irb/completion"
35
+ rescue LoadError
36
+ end
31
37
  require File.expand_path('config/boot.rb')
32
38
  puts "=> Loading #{Padrino.env} console (Padrino v.#{Padrino.version})"
33
39
  require File.expand_path('../console', __FILE__)
34
- ARGV.clear
35
- if defined? Pry
36
- Pry.start
37
- else
38
- require 'irb'
39
- begin
40
- require "irb/completion"
41
- rescue LoadError
42
- end
43
- IRB.start
44
- end
40
+ IRB.start
45
41
  end
46
42
 
47
43
  desc "generate", "Executes the Padrino generator with given options (alternatively use 'gen' or 'g')."
@@ -1,3 +1,11 @@
1
+ Dir["{lib/tasks/**,tasks/**,test,spec}/*.rake"].each do |file|
2
+ begin
3
+ load(file)
4
+ rescue LoadError => e
5
+ warn "#{file}: #{e.message}"
6
+ end
7
+ end
8
+
1
9
  # Loads the Padrino applications mounted within the project.
2
10
  # Setting up the required environment for Padrino.
3
11
  task :environment do
@@ -35,19 +43,6 @@ def list_app_routes(app, args)
35
43
  end
36
44
  end
37
45
 
38
- def env_migration_version
39
- version = ENV["MIGRATION_VERSION"]
40
- if version.nil? && ENV["VERSION"]
41
- deprecated = true
42
- warn "Environment variable VERSION is deprecated, use MIGRATION_VERSION"
43
- version = ENV["VERSION"]
44
- end
45
- version ? Integer(version) : nil
46
- rescue ArgumentError
47
- warn "Environment variable #{deprecated ? '' : 'MIGRATION_'}VERSION=#{version} should be non-existant or Integer"
48
- nil
49
- end
50
-
51
46
  desc "Displays a listing of the named routes within a project, optionally only those matched by [query]"
52
47
  task :routes, [:query] => :environment do |t, args|
53
48
  Padrino.mounted_apps.each do |app|
@@ -62,11 +57,3 @@ namespace :routes do
62
57
  list_app_routes(app, args) if app
63
58
  end
64
59
  end
65
-
66
- Dir["{lib/tasks/**,tasks/**,test,spec}/*.rake"].each do |file|
67
- begin
68
- load(File.expand_path(file))
69
- rescue LoadError => e
70
- warn "#{file}: #{e.message}"
71
- end
72
- end
@@ -58,9 +58,22 @@ module Padrino
58
58
  require_dependencies(*dependency_paths)
59
59
  after_load.each(&:call)
60
60
  logger.devel "Loaded Padrino in #{Time.now - began_at} seconds"
61
+ precompile_all_routes!
61
62
  Thread.current[:padrino_loaded] = true
62
63
  end
63
64
 
65
+ ##
66
+ # Precompiles all routes if :precompile_routes is set to true
67
+ #
68
+ def precompile_all_routes!
69
+ mounted_apps.each do |app|
70
+ app_obj = app.app_obj
71
+ next unless app_obj.respond_to?(:precompile_routes?) && app_obj.precompile_routes?
72
+ app_obj.setup_application!
73
+ logger.devel "Precompiled routes of #{app_obj} (routes size #{app_obj.compiled_router.routes.size})"
74
+ end
75
+ end
76
+
64
77
  ##
65
78
  # Clear the padrino env.
66
79
  #
@@ -170,18 +183,6 @@ module Padrino
170
183
  @_dependency_paths ||= default_dependency_paths + modules_dependency_paths
171
184
  end
172
185
 
173
- # Deprecated
174
- def set_load_paths(*)
175
- warn 'Padrino.set_load_paths is deprecated. Please, use $LOAD_PATH.concat(paths)'
176
- []
177
- end
178
-
179
- # Deprecated
180
- def load_paths
181
- warn 'Padrino.load_paths is deprecated. Please, use Padrino::Application#prerequisites'
182
- []
183
- end
184
-
185
186
  private
186
187
 
187
188
  def modules_dependency_paths
@@ -73,7 +73,7 @@ module Padrino
73
73
  bench(args[0], args[1], args[2], name)
74
74
  else
75
75
  if location = resolve_source_location(caller(1).shift)
76
- args.unshift(location)
76
+ args.prepend(location)
77
77
  end if enable_source_location?
78
78
  push(args * '', name)
79
79
  end
@@ -264,9 +264,6 @@ module Padrino
264
264
  #
265
265
  # :log_level:: Once of [:fatal, :error, :warn, :info, :debug]
266
266
  # :stream:: Once of [:to_file, :null, :stdout, :stderr] our your custom stream
267
- # :log_path:: Defines log file path or directory if :stream is :to_file
268
- # If it's a file, its location is created by mkdir_p.
269
- # If it's a directory, it must exist. In this case log name is '<env>.log'
270
267
  # :log_level::
271
268
  # The log level from, e.g. :fatal or :info. Defaults to :warn in the
272
269
  # production environment and :debug otherwise.
@@ -282,10 +279,6 @@ module Padrino
282
279
  # Padrino::Logger::Config[:development] = { :log_level => :debug, :stream => :to_file }
283
280
  # # or you can edit our defaults
284
281
  # Padrino::Logger::Config[:development][:log_level] = :error
285
- # # or change log file path
286
- # Padrino::Logger::Config[:development][:log_path] = 'logs/app-development.txt'
287
- # # or change log file directory
288
- # Padrino::Logger::Config[:development][:log_path] = '/var/logs/padrino'
289
282
  # # or you can use your stream
290
283
  # Padrino::Logger::Config[:development][:stream] = StringIO.new
291
284
  #
@@ -336,18 +329,8 @@ module Padrino
336
329
 
337
330
  stream = case config[:stream]
338
331
  when :to_file
339
- if filename = config[:log_path]
340
- filename = Padrino.root(filename) unless Pathname.new(filename).absolute?
341
- if File.directory?(filename)
342
- filename = File.join(filename, "#{Padrino.env}.log")
343
- else
344
- FileUtils.mkdir_p(File.dirname(filename))
345
- end
346
- File.new(filename, 'a+')
347
- else
348
- FileUtils.mkdir_p(Padrino.root('log')) unless File.exist?(Padrino.root('log'))
349
- File.new(Padrino.root('log', "#{Padrino.env}.log"), 'a+')
350
- end
332
+ FileUtils.mkdir_p(Padrino.root('log')) unless File.exist?(Padrino.root('log'))
333
+ File.new(Padrino.root('log', "#{Padrino.env}.log"), 'a+')
351
334
  when :null then StringIO.new
352
335
  when :stdout then $stdout
353
336
  when :stderr then $stderr
@@ -385,12 +368,6 @@ module Padrino
385
368
  # @option options [Symbol] :colorize_logging (true)
386
369
  # Whether or not to colorize log messages. Defaults to: true.
387
370
  #
388
- # @option options [Symbol] :sanitize_encoding (false)
389
- # Logger will replace undefined or broken characters with
390
- # “uFFFD” for Unicode and “?” otherwise.
391
- # Can be an encoding, false or true.
392
- # If it's true, logger sanitizes to Encoding.default_external.
393
- #
394
371
  def initialize(options={})
395
372
  @buffer = []
396
373
  @auto_flush = options.has_key?(:auto_flush) ? options[:auto_flush] : true
@@ -402,8 +379,6 @@ module Padrino
402
379
  @log_static = options.has_key?(:log_static) ? options[:log_static] : false
403
380
  @colorize_logging = options.has_key?(:colorize_logging) ? options[:colorize_logging] : true
404
381
  @source_location = options[:source_location]
405
- @sanitize_encoding = options[:sanitize_encoding] || false
406
- @sanitize_encoding = Encoding.default_external if @sanitize_encoding == true
407
382
  colorize! if @colorize_logging
408
383
  end
409
384
 
@@ -417,10 +392,7 @@ module Padrino
417
392
  def flush
418
393
  return unless @buffer.size > 0
419
394
  @@mutex.synchronize do
420
- @buffer.each do |line|
421
- line.encode!(@sanitize_encoding, :invalid => :replace, :undef => :replace) if @sanitize_encoding
422
- @log.write(line)
423
- end
395
+ @log.write(@buffer.join(''))
424
396
  @buffer.clear
425
397
  end
426
398
  end
@@ -1,4 +1,4 @@
1
- require 'padrino-core/mounter/application_extension'
1
+ require 'delegate'
2
2
 
3
3
  module Padrino
4
4
  ##
@@ -14,6 +14,55 @@ module Padrino
14
14
  class MounterException < RuntimeError
15
15
  end
16
16
 
17
+ class ApplicationWrapper < SimpleDelegator
18
+ attr_accessor :uri_root
19
+ attr_writer :public_folder
20
+
21
+ def initialize(app, options = {})
22
+ @options = options
23
+ super(app)
24
+ end
25
+
26
+ def dependencies
27
+ @__dependencies ||= Dir["#{root}/**/*.rb"]
28
+ end
29
+
30
+ def prerequisites
31
+ @__prerequisites ||= []
32
+ end
33
+
34
+ def app_file
35
+ return @__app_file if @__app_file
36
+ obj = __getobj__
37
+ @__app_file = obj.respond_to?(:app_file) ? obj.app_file : @options[:app_file]
38
+ end
39
+
40
+ def root
41
+ return @__root if @__root
42
+ obj = __getobj__
43
+ @__root = obj.respond_to?(:root) ? obj.root : File.expand_path("#{app_file}/../")
44
+ end
45
+
46
+ def public_folder
47
+ return @public_folder if @public_folder
48
+ obj = __getobj__
49
+ @public_folder = obj.respond_to?(:public_folder) ? obj.public_folder : ""
50
+ end
51
+
52
+ def app_name
53
+ @__app_name ||= @options[:app_name] || __getobj__.to_s.underscore.to_sym
54
+ end
55
+
56
+ def setup_application!
57
+ @configured ||=
58
+ begin
59
+ $LOAD_PATH.concat(prerequisites)
60
+ Padrino.require_dependencies(dependencies, :force => true) if root.start_with?(Padrino.root)
61
+ true
62
+ end
63
+ end
64
+ end
65
+
17
66
  attr_accessor :name, :uri_root, :app_file, :app_class, :app_root, :app_obj, :app_host, :cascade
18
67
 
19
68
  ##
@@ -34,10 +83,7 @@ module Padrino
34
83
  @app_file = options[:app_file] || locate_app_file
35
84
  @app_obj = options[:app_obj] || app_constant || locate_app_object
36
85
  ensure_app_file! || ensure_app_object!
37
- unless padrino_application?
38
- @app_obj.extend ApplicationExtension
39
- @app_obj.mounter_options = options
40
- end
86
+ @app_obj = ApplicationWrapper.new(@app_obj, options) unless padrino_application?
41
87
  @app_root = options[:app_root] || (@app_obj.respond_to?(:root) && @app_obj.root || File.dirname(@app_file))
42
88
  @uri_root = "/"
43
89
  @cascade = options[:cascade] ? true == options[:cascade] ? DEFAULT_CASCADE.dup : Array(options[:cascade]) : []
@@ -96,23 +142,20 @@ module Padrino
96
142
  def map_onto(router)
97
143
  app_data = self
98
144
  app_obj = @app_obj
99
-
100
- uri_root = app_data.uri_root
101
- public_folder_exists = File.exist?(app_obj.public_folder)
102
-
103
145
  if padrino_application?
104
- app_obj.set :uri_root, uri_root
105
- app_obj.set :app_name, app_obj.app_name.to_s
106
- app_obj.set :root, app_data.app_root
107
- app_obj.set :public_folder, Padrino.root('public', uri_root) unless public_folder_exists
108
- app_obj.set :static, public_folder_exists
146
+ app_obj.set :uri_root, app_data.uri_root
147
+ app_obj.set :app_name, app_data.app_obj.app_name.to_s
148
+ app_obj.set :app_file, app_data.app_file unless File.exist?(app_obj.app_file)
149
+ app_obj.set :root, app_data.app_root unless app_data.app_root.blank?
150
+ app_obj.set :public_folder, Padrino.root('public', app_data.uri_root) unless File.exist?(app_obj.public_folder)
151
+ app_obj.set :static, File.exist?(app_obj.public_folder) if app_obj.nil?
109
152
  app_obj.set :cascade, app_data.cascade
110
153
  else
111
- app_obj.uri_root = uri_root
112
- app_obj.public_folder = Padrino.root('public', uri_root) unless public_folder_exists
154
+ app_obj.uri_root = app_data.uri_root
155
+ app_obj.public_folder = Padrino.root('public', app_data.uri_root) unless File.exist?(app_obj.public_folder)
113
156
  end
114
157
  app_obj.setup_application! # Initializes the app here with above settings.
115
- router.map(:to => app_obj, :path => uri_root, :host => app_data.app_host)
158
+ router.map(:to => app_obj, :path => app_data.uri_root, :host => app_data.app_host)
116
159
  end
117
160
 
118
161
  ###
@@ -131,7 +174,7 @@ module Padrino
131
174
  def named_routes
132
175
  app_obj.routes.map { |route|
133
176
  route_name = route.name.to_s
134
- route_name =
177
+ route_name =
135
178
  if route.controller
136
179
  route_name.split(" ", 2).map{|name| ":#{name}" }.join(", ")
137
180
  else
@@ -188,10 +231,8 @@ module Padrino
188
231
  # Returns the determined location of the mounted application main file.
189
232
  #
190
233
  def locate_app_file
191
- app_const = app_constant
192
-
193
234
  candidates = []
194
- candidates << app_const.app_file if app_const.respond_to?(:app_file)
235
+ candidates << app_constant.app_file if app_constant.respond_to?(:app_file) && File.exist?(app_constant.app_file.to_s)
195
236
  candidates << Padrino.first_caller if File.identical?(Padrino.first_caller.to_s, Padrino.called_from.to_s)
196
237
  candidates << Padrino.mounted_root(name.downcase, "app.rb")
197
238
  simple_name = name.split("::").last.downcase
@@ -0,0 +1,110 @@
1
+ module Padrino
2
+ module PathRouter
3
+ #
4
+ # High performance engine for finding all routes which are matched with pattern
5
+ #
6
+ class Compiler
7
+ # All regexps generated by recursive compiler
8
+ attr_reader :regexps
9
+
10
+ ##
11
+ # Constructs an instance of Padrino::PathRouter::Compiler
12
+ #
13
+ def initialize(routes)
14
+ @routes = routes
15
+ end
16
+
17
+ ##
18
+ # Compiles all routes into regexps.
19
+ #
20
+ def compile!
21
+ return if compiled?
22
+ @regexps = @routes.map.with_index do |route, index|
23
+ route.index = index
24
+ /(?<_#{index}>#{route.matcher.to_regexp})/
25
+ end
26
+ @regexps = recursive_compile(@regexps)
27
+ @compiled = true
28
+ end
29
+
30
+ ##
31
+ # Returns true if all routes has been compiled.
32
+ #
33
+ def compiled?
34
+ !!@compiled
35
+ end
36
+
37
+ ##
38
+ # Finds routes by using request or env.
39
+ #
40
+ def find_by(request_or_env)
41
+ request = request_or_env.is_a?(Hash) ? Sinatra::Request.new(request_or_env) : request_or_env
42
+ pattern = encode_default_external(request.path_info)
43
+ verb = request.request_method
44
+ rotation { |offset| match?(offset, pattern) }.select { |route| route.verb == verb }
45
+ end
46
+
47
+ ##
48
+ # Calls routes by using request.
49
+ #
50
+ def call_by_request(request)
51
+ rotation do |offset|
52
+ pattern = encode_default_external(request.path_info)
53
+ if route = match?(offset, pattern)
54
+ params = route.params_for(pattern, request.params)
55
+ yield(route, params) if route.verb == request.request_method
56
+ route
57
+ end
58
+ end
59
+ end
60
+
61
+ ##
62
+ # Finds routes by using PATH_INFO.
63
+ #
64
+ def find_by_pattern(pattern)
65
+ pattern = pattern.encode(Encoding.default_external)
66
+ rotation { |offset| match?(offset, pattern) }
67
+ end
68
+
69
+ private
70
+
71
+ ##
72
+ # Returns a instance of PathRouter::Route if path is matched with current regexp
73
+ #
74
+ def match?(offset, path)
75
+ current_regexp = @regexps[offset]
76
+ return unless current_regexp === path || current_regexp === path[0..-2]
77
+ @routes[offset..-1].detect{ |route| Regexp.last_match["_#{route.index}"] }
78
+ end
79
+
80
+ ##
81
+ # Runs through all regexps to find routes.
82
+ #
83
+ def rotation(offset = 0)
84
+ compile! unless compiled?
85
+ loop.with_object([]) do |_, candidacies|
86
+ return candidacies unless route = yield(offset)
87
+ candidacies << route
88
+ offset = route.index.next
89
+ end
90
+ end
91
+
92
+ ##
93
+ # Compiles routes into regexp recursively.
94
+ #
95
+ def recursive_compile(regexps, paths = [])
96
+ return paths if regexps.length.zero?
97
+ paths << Regexp.union(regexps)
98
+ regexps.shift
99
+ recursive_compile(regexps, paths)
100
+ end
101
+
102
+ ##
103
+ # Encode string with Encoding.default_external
104
+ #
105
+ def encode_default_external(string)
106
+ string.encode(Encoding.default_external)
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,8 @@
1
+ module Padrino
2
+ module PathRouter
3
+ ##
4
+ # @see PathRouter::Router#path
5
+ #
6
+ InvalidRouteException = Class.new(ArgumentError)
7
+ end
8
+ end