padrino-core 0.12.0 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
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