padrino-core 0.12.9 → 0.13.0.beta1

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