padrino-core 0.12.0 → 0.12.1

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/lib/padrino-core.rb +4 -4
  3. data/lib/padrino-core/application.rb +6 -195
  4. data/lib/padrino-core/application/application_setup.rb +199 -0
  5. data/lib/padrino-core/application/routing.rb +66 -25
  6. data/lib/padrino-core/cli/base.rb +8 -5
  7. data/lib/padrino-core/cli/rake.rb +12 -9
  8. data/lib/padrino-core/loader.rb +1 -1
  9. data/lib/padrino-core/logger.rb +25 -0
  10. data/lib/padrino-core/mounter.rb +8 -3
  11. data/lib/padrino-core/reloader.rb +2 -2
  12. data/lib/padrino-core/server.rb +50 -17
  13. data/lib/padrino-core/version.rb +1 -1
  14. data/padrino-core.gemspec +2 -10
  15. data/test/fixtures/apps/demo_app.rb +7 -0
  16. data/test/fixtures/apps/demo_demo.rb +7 -0
  17. data/test/helper.rb +6 -37
  18. data/test/test_application.rb +12 -13
  19. data/test/test_core.rb +12 -13
  20. data/test/test_csrf_protection.rb +49 -23
  21. data/test/test_dependencies.rb +7 -7
  22. data/test/test_filters.rb +41 -17
  23. data/test/test_flash.rb +24 -24
  24. data/test/test_locale.rb +1 -1
  25. data/test/test_logger.rb +39 -27
  26. data/test/test_mounter.rb +34 -20
  27. data/test/test_reloader_complex.rb +5 -6
  28. data/test/test_reloader_simple.rb +23 -20
  29. data/test/test_reloader_system.rb +10 -7
  30. data/test/test_restful_routing.rb +1 -1
  31. data/test/test_router.rb +7 -7
  32. data/test/test_routing.rb +177 -141
  33. metadata +14 -53
  34. data/lib/padrino-core/application/rendering.rb +0 -325
  35. data/lib/padrino-core/application/rendering/extensions/erubis.rb +0 -68
  36. data/lib/padrino-core/application/rendering/extensions/haml.rb +0 -29
  37. data/lib/padrino-core/application/rendering/extensions/slim.rb +0 -21
  38. data/lib/padrino-core/locale/cs.yml +0 -33
  39. data/lib/padrino-core/locale/da.yml +0 -33
  40. data/lib/padrino-core/locale/de.yml +0 -33
  41. data/lib/padrino-core/locale/en.yml +0 -33
  42. data/lib/padrino-core/locale/es.yml +0 -33
  43. data/lib/padrino-core/locale/fr.yml +0 -33
  44. data/lib/padrino-core/locale/hu.yml +0 -33
  45. data/lib/padrino-core/locale/it.yml +0 -39
  46. data/lib/padrino-core/locale/ja.yml +0 -33
  47. data/lib/padrino-core/locale/lv.yml +0 -33
  48. data/lib/padrino-core/locale/nl.yml +0 -33
  49. data/lib/padrino-core/locale/no.yml +0 -33
  50. data/lib/padrino-core/locale/pl.yml +0 -33
  51. data/lib/padrino-core/locale/pt_br.yml +0 -39
  52. data/lib/padrino-core/locale/ro.yml +0 -33
  53. data/lib/padrino-core/locale/ru.yml +0 -34
  54. data/lib/padrino-core/locale/sv.yml +0 -33
  55. data/lib/padrino-core/locale/tr.yml +0 -33
  56. data/lib/padrino-core/locale/uk.yml +0 -33
  57. data/lib/padrino-core/locale/zh_cn.yml +0 -33
  58. data/lib/padrino-core/locale/zh_tw.yml +0 -33
  59. data/lib/padrino-core/support_lite.rb +0 -259
  60. data/test/fixtures/apps/.components +0 -6
  61. data/test/fixtures/apps/.gitignore +0 -7
  62. data/test/fixtures/apps/render.rb +0 -13
  63. data/test/fixtures/apps/views/blog/post.erb +0 -1
  64. data/test/fixtures/layouts/layout.erb +0 -1
  65. data/test/mini_shoulda.rb +0 -45
  66. data/test/test_rendering.rb +0 -606
  67. data/test/test_rendering_extensions.rb +0 -14
  68. data/test/test_support_lite.rb +0 -56
@@ -1,5 +1,5 @@
1
1
  require 'http_router' unless defined?(HttpRouter)
2
- require 'padrino-core/support_lite' unless defined?(SupportLite)
2
+ require 'padrino-support'
3
3
 
4
4
  ##
5
5
  # Adds to Sinatra +controller+ informations
@@ -205,17 +205,7 @@ module Padrino
205
205
  end
206
206
 
207
207
  def apply?(request)
208
- detect = @args.any? do |arg|
209
- case arg
210
- when Symbol then request.route_obj && (request.route_obj.name == arg or request.route_obj.name == [@scoped_controller, arg].flatten.join(" ").to_sym)
211
- else arg === request.path_info
212
- end
213
- end || @options.any? do |name, val|
214
- case name
215
- when :agent then val === request.user_agent
216
- else val === request.send(name)
217
- end
218
- end
208
+ detect = match_with_arguments?(request) || match_with_options?(request)
219
209
  detect ^ !@mode
220
210
  end
221
211
 
@@ -227,6 +217,30 @@ module Padrino
227
217
  proc { instance_eval(&filter.block) if filter.apply?(request) }
228
218
  end
229
219
  end
220
+
221
+ private
222
+
223
+ def scoped_controller_name
224
+ @scoped_controller_name ||= Array(@scoped_controller).join("_")
225
+ end
226
+
227
+ def match_with_arguments?(request)
228
+ route, path = request.route_obj, request.path_info
229
+ @args.any? do |argument|
230
+ if argument.instance_of?(Symbol)
231
+ next unless route
232
+ name = route.name
233
+ argument == name || name == [scoped_controller_name, argument].join(" ").to_sym
234
+ else
235
+ argument === path
236
+ end
237
+ end
238
+ end
239
+
240
+ def match_with_options?(request)
241
+ user_agent = request.user_agent
242
+ @options.any?{|name, value| value === (name == :agent ? user_agent : request.send(name)) }
243
+ end
230
244
  end
231
245
 
232
246
  ##
@@ -371,6 +385,7 @@ module Padrino
371
385
  @_map, original_map = options.delete(:map), @_map
372
386
  @_conditions, original_conditions = options.delete(:conditions), @_conditions
373
387
  @_defaults, original_defaults = options, @_defaults
388
+ @_accepts, original_accepts = options.delete(:accepts), @_accepts
374
389
 
375
390
  # Application defaults.
376
391
  @filters, original_filters = { :before => @filters[:before].dup, :after => @filters[:after].dup }, @filters
@@ -383,9 +398,9 @@ module Padrino
383
398
  @layout = original_layout
384
399
 
385
400
  # Controller defaults.
386
- @_controller, @_parents, @_cache = original_controller, original_parent, original_cache
387
- @_defaults, @_provides, @_map = original_defaults, original_provides, original_map
388
- @_conditions, @_use_format = original_conditions, original_use_format
401
+ @_controller, @_parents, @_cache = original_controller, original_parent, original_cache
402
+ @_defaults, @_provides, @_map = original_defaults, original_provides, original_map
403
+ @_conditions, @_use_format, @_accepts = original_conditions, original_use_format, original_accepts
389
404
  else
390
405
  include(*args) if extensions.any?
391
406
  end
@@ -677,10 +692,11 @@ module Padrino
677
692
  # Do padrino parsing. We dup options so we can build HEAD request correctly.
678
693
  route_options = options.dup
679
694
  route_options[:provides] = @_provides if @_provides
695
+ route_options[:accepts] = @_accepts if @_accepts
680
696
 
681
- # CSRF protection is always active except when explicitly switched off.
682
- if allow_disabled_csrf
683
- unless route_options[:csrf_protection] == false
697
+ # Add Sinatra condition to check rack-protection failure.
698
+ if protect_from_csrf && (report_csrf_failure || allow_disabled_csrf)
699
+ unless route_options.has_key?(:csrf_protection)
684
700
  route_options[:csrf_protection] = true
685
701
  end
686
702
  end
@@ -734,7 +750,7 @@ module Padrino
734
750
  route.after_filters << @filters[:after]
735
751
  if @_controller
736
752
  route.use_layout = @layout
737
- route.controller = Array(@_controller)[0].to_s
753
+ route.controller = Array(@_controller).join('/')
738
754
  end
739
755
 
740
756
  deferred_routes[priority] << [route, block]
@@ -772,6 +788,8 @@ module Padrino
772
788
 
773
789
  # Now we need to parse our provides
774
790
  options.delete(:provides) if options[:provides].nil?
791
+
792
+ options.delete(:accepts) if options[:accepts].nil?
775
793
 
776
794
  if @_use_format or format_params = options[:provides]
777
795
  process_path_for_provides(path, format_params)
@@ -932,17 +950,40 @@ module Padrino
932
950
  end
933
951
 
934
952
  ##
935
- # Implements CSRF checking when `allow_disabled_csrf` is set to true.
953
+ # Allows routing by Media type.
954
+ #
955
+ # @example
956
+ # get "/a", :accepts => [:html, :js]
957
+ # # => GET /a CONTENT_TYPE text/html => :html
958
+ # # => GET /a CONTENT_TYPE application/javascript => :js
959
+ # # => GET /a CONTENT_TYPE application/xml => 406
936
960
  #
937
- # This condition is always on, except when it is explicitly switched
938
- # off.
961
+ def accepts(*types)
962
+ mime_types = types.map { |type| mime_type(CONTENT_TYPE_ALIASES[type] || type) }.compact
963
+ condition do
964
+ halt 406 unless media_type = mime_types.detect{|mime_type| mime_type == request.media_type }
965
+ if media_type != 'application/json'
966
+ content_type(media_type, :charset => 'utf-8')
967
+ else
968
+ content_type(media_type)
969
+ end
970
+ end
971
+ end
972
+
973
+ ##
974
+ # Implements checking for rack-protection failure flag when
975
+ # `report_csrf_failure` is enabled.
939
976
  #
940
977
  # @example
941
978
  # post("/", :csrf_protection => false)
942
979
  #
943
- def csrf_protection(on = true)
944
- if on
945
- condition { halt 403 if request.env['protection.csrf.failed'] }
980
+ def csrf_protection(enabled)
981
+ return unless enabled
982
+ condition do
983
+ if request.env['protection.csrf.failed']
984
+ message = settings.protect_from_csrf.kind_of?(Hash) && settings.protect_from_csrf[:message] || 'Forbidden'
985
+ halt(403, message)
986
+ end
946
987
  end
947
988
  end
948
989
  end
@@ -13,15 +13,15 @@ module Padrino
13
13
  desc "start", "Starts the Padrino application (alternatively use 's')."
14
14
  map "s" => :start
15
15
  method_option :server, :type => :string, :aliases => "-a", :desc => "Rack Handler (default: autodetect)"
16
- method_option :host, :type => :string, :aliases => "-h", :required => true, :default => '127.0.0.1', :desc => "Bind to HOST address."
17
- method_option :port, :type => :numeric, :aliases => "-p", :required => true, :default => 3000, :desc => "Use PORT."
16
+ method_option :host, :type => :string, :aliases => "-h", :desc => "Bind to HOST address (default: 127.0.0.1)"
17
+ method_option :port, :type => :numeric, :aliases => "-p", :desc => "Use PORT (default: 3000)"
18
18
  method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background."
19
19
  method_option :pid, :type => :string, :aliases => "-i", :desc => "File to store pid."
20
20
  method_option :debug, :type => :boolean, :desc => "Set debugging flags."
21
21
  method_option :options, :type => :array, :aliases => "-O", :desc => "--options NAME=VALUE NAME2=VALUE2'. pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$0} --server_options"
22
22
  method_option :server_options, :type => :boolean, :desc => "Tells the current server handler's options that can be used with --options"
23
23
 
24
- def start
24
+ def start(*args)
25
25
  prepare :start
26
26
  require File.expand_path("../adapter", __FILE__)
27
27
  require File.expand_path('config/boot.rb')
@@ -29,7 +29,7 @@ module Padrino
29
29
  if options[:server_options]
30
30
  puts server_options(options)
31
31
  else
32
- Padrino::Cli::Adapter.start(options)
32
+ Padrino::Cli::Adapter.start(args.last ? options.merge(:config => args.last).freeze : options)
33
33
  end
34
34
  end
35
35
 
@@ -69,7 +69,10 @@ module Padrino
69
69
  require File.expand_path("../../version", __FILE__)
70
70
  ARGV.clear
71
71
  require 'irb'
72
- require "irb/completion"
72
+ begin
73
+ require "irb/completion"
74
+ rescue LoadError
75
+ end
73
76
  require File.expand_path('config/boot.rb')
74
77
  puts "=> Loading #{Padrino.env} console (Padrino v.#{Padrino.version})"
75
78
  require File.expand_path('../console', __FILE__)
@@ -3,7 +3,10 @@ require 'rake'
3
3
  require 'rake/dsl_definition'
4
4
  require 'thor'
5
5
  require 'securerandom' unless defined?(SecureRandom)
6
- require 'padrino-gen'
6
+ begin
7
+ require 'padrino-gen'
8
+ rescue LoadError
9
+ end
7
10
 
8
11
  module PadrinoTasks
9
12
  def self.init(init=false)
@@ -23,18 +26,18 @@ module PadrinoTasks
23
26
 
24
27
  def self.load?(task, constant_present)
25
28
  if constant_present && !PadrinoTasks.tasks.include?(task)
26
- warn <<-WARNING.undent
27
- Loading #{task} tasks automatically.
28
- This functionality will be disabled in future versions. Please put
29
+ warn <<-WARNING
30
+ Loading #{task} tasks automatically.
31
+ This functionality will be disabled in future versions. Please put
29
32
 
30
- PadrinoTasks.use(#{task.inspect})
31
- PadrinoTasks.init
33
+ PadrinoTasks.use(#{task.inspect})
34
+ PadrinoTasks.init
32
35
 
33
- and remove
36
+ and remove
34
37
 
35
- require File.expand_path('../config/boot.rb', __FILE__)
38
+ require File.expand_path('../config/boot.rb', __FILE__)
36
39
 
37
- in you Rakefile instead.
40
+ in you Rakefile instead.
38
41
  WARNING
39
42
  end
40
43
 
@@ -155,7 +155,7 @@ module Padrino
155
155
 
156
156
  if fatal || !loaded
157
157
  e = fatal || error
158
- logger.error "#{e.class}: #{e.message}; #{e.backtrace.first}"
158
+ logger.exception e, :short
159
159
  raise e
160
160
  end
161
161
  end
@@ -172,6 +172,31 @@ module Padrino
172
172
  def colorize!
173
173
  self.extend(Colorize)
174
174
  end
175
+
176
+ ##
177
+ # Logs an exception.
178
+ #
179
+ # @param [Exception] exception
180
+ # The exception to log
181
+ #
182
+ # @param [Symbol] verbosity
183
+ # :short or :long, default is :long
184
+ #
185
+ # @example
186
+ # Padrino.logger.exception e
187
+ # Padrino.logger.exception(e, :short)
188
+ def exception(boom, verbosity = :long, level = :error)
189
+ return unless Levels.has_key?(level)
190
+ text = ["#{boom.class} - #{boom.message}:"]
191
+ trace = boom.backtrace
192
+ case verbosity
193
+ when :long
194
+ text += trace
195
+ when :short
196
+ text << trace.first
197
+ end if trace.kind_of?(Array)
198
+ send level, text.join("\n ")
199
+ end
175
200
  end
176
201
 
177
202
  module Colorize
@@ -110,8 +110,13 @@ module Padrino
110
110
  def named_routes
111
111
  app_obj.routes.map { |route|
112
112
  route_name = route.name.to_s
113
- route_name.sub!(/^#{route.controller} /, "") if route.controller
114
- name_array = "(#{route.controller ? %Q[:#{route.controller}] + ", " : ""}:#{route_name})"
113
+ route_name =
114
+ if route.controller
115
+ route_name.split(" ", 2).map{|name| ":#{name}" }.join(", ")
116
+ else
117
+ ":#{route_name}"
118
+ end
119
+ name_array = "(#{route_name})"
115
120
  request_method = route.request_methods.first
116
121
  next if route.name.blank? || request_method == 'HEAD'
117
122
  original_path = route.original_path.is_a?(Regexp) ? route.original_path.inspect : route.original_path
@@ -137,7 +142,7 @@ module Padrino
137
142
  klass = Object
138
143
  for piece in app_class.split("::")
139
144
  piece = piece.to_sym
140
- if klass.const_defined?(piece)
145
+ if klass.const_defined?(piece, false)
141
146
  klass = klass.const_get(piece)
142
147
  else
143
148
  return
@@ -96,7 +96,7 @@ module Padrino
96
96
  update_modification_time(file)
97
97
  rescue Exception => e
98
98
  unless options[:cyclic]
99
- logger.error "#{e.class}: #{e.message}; #{e.backtrace.first}"
99
+ logger.exception e, :short
100
100
  logger.error "Failed to load #{file}; removing partially defined constants"
101
101
  end
102
102
  Storage.rollback(file)
@@ -167,10 +167,10 @@ module Padrino
167
167
  apps.each { |app| app.app_obj.reload! }
168
168
  update_modification_time(file)
169
169
  else
170
- safe_load(file)
171
170
  reloadable_apps.each do |app|
172
171
  app.app_obj.reload! if app.app_obj.dependencies.include?(file)
173
172
  end
173
+ safe_load(file)
174
174
  end
175
175
  end
176
176
 
@@ -9,33 +9,41 @@ module Padrino
9
9
  #
10
10
  def self.run!(options={})
11
11
  Padrino.load!
12
- Server.start(Padrino.application, options)
12
+ Server.start(*detect_application(options))
13
+ end
14
+
15
+ private
16
+
17
+ #
18
+ #
19
+ def self.detect_application(options)
20
+ default_config_file = 'config.ru'
21
+ if (config_file = options.delete(:config)) || File.file?(default_config_file)
22
+ config_file ||= default_config_file
23
+ fail "Rack config file `#{config_file}` must have `.ru` extension" unless config_file =~ /\.ru$/
24
+ rack_app, rack_options = Rack::Builder.parse_file(config_file)
25
+ [rack_app, rack_options.merge(options)]
26
+ else
27
+ [Padrino.application, options]
28
+ end
13
29
  end
14
30
 
15
31
  ##
16
32
  # This module builds a Padrino server to run the project based on available handlers.
17
33
  #
18
34
  class Server < Rack::Server
35
+ DEFAULT_ADDRESS = { :Host => '127.0.0.1', :Port => 3000 }
36
+
19
37
  # Server Handlers
20
- Handlers = [:thin, :puma, :mongrel, :trinidad, :webrick]
38
+ Handlers = [:thin, :puma, :'spider-gazelle', :mongrel, :trinidad, :webrick]
21
39
 
22
40
  # Starts the application on the available server with specified options.
23
- def self.start(app, opts={})
24
- options = {}.merge(opts) # We use a standard hash instead of Thor::CoreExt::HashWithIndifferentAccess
25
- options.symbolize_keys!
26
- options[:Host] = options.delete(:host) || '127.0.0.1'
27
- options[:Port] = options.delete(:port) || 3000
28
- options[:AccessLog] = []
29
- if options[:daemonize]
30
- options[:pid] = File.expand_path(options[:pid].blank? ? 'tmp/pids/server.pid' : opts[:pid])
31
- FileUtils.mkdir_p(File.dirname(options[:pid]))
32
- end
41
+ def self.start(app, options={})
42
+ options = options.to_hash.symbolize_keys
43
+ options.update(parse_server_options(options.delete(:options)))
44
+ options.update(detect_address(options))
45
+ options[:pid] = prepare_pid(options[:pid]) if options[:daemonize]
33
46
  options[:server] = detect_rack_handler if options[:server].blank?
34
- if options[:options].is_a?(Array)
35
- parsed_server_options = options.delete(:options).map { |opt| opt.split('=', 2) }.flatten
36
- server_options = Hash[*parsed_server_options].symbolize_keys!
37
- options.merge!(server_options)
38
- end
39
47
  new(options, app).start
40
48
  end
41
49
 
@@ -63,6 +71,7 @@ module Padrino
63
71
  end
64
72
 
65
73
  private
74
+
66
75
  # Detects the supported handler to use.
67
76
  #
68
77
  # @example
@@ -78,5 +87,29 @@ module Padrino
78
87
  end
79
88
  fail "Server handler (#{Handlers.join(', ')}) not found."
80
89
  end
90
+
91
+ # Prepares a directory for pid file.
92
+ #
93
+ def self.prepare_pid(pid)
94
+ pid = 'tmp/pids/server.pid' if pid.blank?
95
+ FileUtils.mkdir_p(File.dirname(pid))
96
+ File.expand_path(pid)
97
+ end
98
+
99
+ # Parses an array of server options.
100
+ #
101
+ def self.parse_server_options(options)
102
+ parsed_server_options = Array(options).map{ |option| option.split('=', 2) }.flatten
103
+ Hash[*parsed_server_options].symbolize_keys
104
+ end
105
+
106
+ # Detects Host and Port for Rack server.
107
+ #
108
+ def self.detect_address(options)
109
+ address = DEFAULT_ADDRESS.merge options.slice(:Host, :Port)
110
+ address[:Host] = options[:host] if options[:host].present?
111
+ address[:Port] = options[:port] if options[:port].present?
112
+ address
113
+ end
81
114
  end
82
115
  end
@@ -6,7 +6,7 @@
6
6
  #
7
7
  module Padrino
8
8
  # The version constant for the current version of Padrino.
9
- VERSION = '0.12.0' unless defined?(Padrino::VERSION)
9
+ VERSION = '0.12.1' unless defined?(Padrino::VERSION)
10
10
 
11
11
  #
12
12
  # The current Padrino version.
data/padrino-core.gemspec CHANGED
@@ -23,22 +23,14 @@ Gem::Specification.new do |s|
23
23
  s.require_paths = ["lib"]
24
24
  s.rdoc_options = ["--charset=UTF-8"]
25
25
 
26
- # TODO remove after a couple versions
27
- # s.post_install_message = "\e[32m" + ("*" * 20)
28
- # s.post_install_message << "\n UPGRADE NOTES\n\n\e[31m When upgrading, please 'enable :sessions' for each application"
29
- # s.post_install_message << " as shown here:\e[0m http://bit.ly/kODKMx\n"
30
- # s.post_install_message << "\e[31m When upgrading, please 'register Padrino::Rendering' for each application"
31
- # s.post_install_message << " as shown here:\e[0m https://gist.github.com/1d36a35794dbbd664ea4"
32
- # s.post_install_message << "\n\e[32m" + ("*" * 20) + "\n\e[0m"
33
-
34
- s.add_dependency("tilt", "~> 1.4.1")
26
+ s.add_dependency("padrino-support", Padrino.version)
35
27
  if ENV["SINATRA_EDGE"]
36
28
  s.add_dependency("sinatra")
37
29
  else
38
30
  s.add_dependency("sinatra", "~> 1.4.2")
39
31
  end
40
32
  s.add_dependency("http_router", "~> 0.11.0")
41
- s.add_dependency("thor", "~> 0.17.0")
33
+ s.add_dependency("thor", "~> 0.18.0")
42
34
  s.add_dependency("activesupport", ">= 3.1")
43
35
  s.add_dependency("rack-protection", ">= 1.5.0")
44
36
  end