padrino-core 0.10.7 → 0.11.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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/lib/padrino-core.rb +58 -4
  3. data/lib/padrino-core/application.rb +38 -16
  4. data/lib/padrino-core/application/flash.rb +229 -0
  5. data/lib/padrino-core/application/rendering.rb +39 -11
  6. data/lib/padrino-core/application/rendering/extensions/erubis.rb +55 -0
  7. data/lib/padrino-core/application/rendering/extensions/haml.rb +26 -0
  8. data/lib/padrino-core/application/rendering/extensions/slim.rb +14 -0
  9. data/lib/padrino-core/application/routing.rb +106 -35
  10. data/lib/padrino-core/cli/base.rb +41 -38
  11. data/lib/padrino-core/cli/rake.rb +30 -9
  12. data/lib/padrino-core/cli/rake_tasks.rb +9 -14
  13. data/lib/padrino-core/loader.rb +23 -9
  14. data/lib/padrino-core/locale/fr.yml +1 -1
  15. data/lib/padrino-core/locale/ru.yml +1 -1
  16. data/lib/padrino-core/logger.rb +48 -32
  17. data/lib/padrino-core/module.rb +58 -0
  18. data/lib/padrino-core/mounter.rb +15 -5
  19. data/lib/padrino-core/reloader.rb +14 -12
  20. data/lib/padrino-core/server.rb +4 -4
  21. data/lib/padrino-core/support_lite.rb +43 -6
  22. data/lib/padrino-core/version.rb +1 -1
  23. data/padrino-core.gemspec +9 -4
  24. data/test/fixtures/app_gem/Gemfile +4 -0
  25. data/test/fixtures/app_gem/app/app.rb +3 -0
  26. data/test/fixtures/app_gem/app_gem.gemspec +17 -0
  27. data/test/fixtures/app_gem/lib/app_gem.rb +7 -0
  28. data/test/fixtures/app_gem/lib/app_gem/version.rb +3 -0
  29. data/test/mini_shoulda.rb +1 -1
  30. data/test/test_application.rb +38 -21
  31. data/test/test_csrf_protection.rb +80 -0
  32. data/test/test_filters.rb +70 -0
  33. data/test/test_flash.rb +168 -0
  34. data/test/test_logger.rb +27 -0
  35. data/test/test_mounter.rb +24 -2
  36. data/test/test_reloader_simple.rb +4 -4
  37. data/test/test_rendering.rb +75 -4
  38. data/test/test_routing.rb +164 -35
  39. data/test/test_support_lite.rb +56 -0
  40. metadata +52 -29
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9f915e954014b964f9d5afccd9999d80cd888c05
4
+ data.tar.gz: 0f64be604ae666519fdd77d32413f9bdf4c32986
5
+ SHA512:
6
+ metadata.gz: f5b45a55ece397aabf5c7e9d4c961a51edeaa882156962222a0b41d718e62c000fa301f954236fa1599d94e8f2e19109e538b775a2c651c94dfefabf6f187073
7
+ data.tar.gz: 7796c665daf7a323174e265e3fbc23d71cef98cc9ae1427cb0d5a3d18a3352fdd861fab8adb83308b01c6f4e2f7b1e3bd6ab372493b6032c43f41431dabbb15e
data/lib/padrino-core.rb CHANGED
@@ -1,8 +1,19 @@
1
1
  require 'sinatra/base'
2
- require 'padrino-core/support_lite' unless defined?(SupportLite)
2
+ require 'padrino-core/version'
3
+ require 'padrino-core/support_lite'
4
+ require 'padrino-core/application'
5
+
6
+ require 'padrino-core/caller'
7
+ require 'padrino-core/command'
8
+ require 'padrino-core/loader'
9
+ require 'padrino-core/logger'
10
+ require 'padrino-core/mounter'
11
+ require 'padrino-core/reloader'
12
+ require 'padrino-core/router'
13
+ require 'padrino-core/server'
14
+ require 'padrino-core/tasks'
15
+ require 'padrino-core/module'
3
16
 
4
- FileSet.glob_require('padrino-core/application/*.rb', __FILE__)
5
- FileSet.glob_require('padrino-core/*.rb', __FILE__)
6
17
 
7
18
  # The Padrino environment (falls back to the rack env or finally develop)
8
19
  PADRINO_ENV = ENV["PADRINO_ENV"] ||= ENV["RACK_ENV"] ||= "development" unless defined?(PADRINO_ENV)
@@ -80,7 +91,14 @@ module Padrino
80
91
  # end
81
92
  #
82
93
  def configure_apps(&block)
83
- @_global_configuration = block if block_given?
94
+ return unless block_given?
95
+ @@_global_configurations ||= []
96
+ @@_global_configurations << block
97
+ @_global_configuration = lambda do |app|
98
+ @@_global_configurations.each do |configuration|
99
+ app.class_eval(&configuration)
100
+ end
101
+ end
84
102
  end
85
103
 
86
104
  ##
@@ -148,5 +166,41 @@ module Padrino
148
166
  def use(m, *args, &block)
149
167
  middleware << [m, args, block]
150
168
  end
169
+
170
+ ##
171
+ # Registers a gem with padrino. This relieves the caller from setting up
172
+ # loadpaths by himself and enables Padrino to look up apps in gem folder.
173
+ #
174
+ # The name given has to be the proper gem name as given in the gemspec.
175
+ #
176
+ # @param [String] name
177
+ # The name of the gem being registered.
178
+ #
179
+ # @param [Module] main_module
180
+ # The main module of the gem.
181
+ #
182
+ # @returns The root path of the loaded gem
183
+ def gem(name, main_module)
184
+ _,spec = Gem.loaded_specs.find { |spec_name, spec| spec_name == name }
185
+ gems << spec
186
+ modules << main_module
187
+ spec.full_gem_path
188
+ end
189
+
190
+ ##
191
+ # Returns all currently known padrino gems.
192
+ #
193
+ # @returns [Gem::Specification]
194
+ def gems
195
+ @gems ||= []
196
+ end
197
+
198
+ ##
199
+ # All loaded Padrino modules.
200
+ #
201
+ # @returns [<Padrino::Module>]
202
+ def modules
203
+ @modules ||= []
204
+ end
151
205
  end # self
152
206
  end # Padrino
@@ -1,3 +1,8 @@
1
+ require 'padrino-core/application/rendering'
2
+ require 'padrino-core/application/routing'
3
+ require 'padrino-core/application/flash'
4
+ require 'padrino-core/application/showexceptions'
5
+
1
6
  module Padrino
2
7
  class ApplicationSetupError < RuntimeError # @private
3
8
  end
@@ -173,17 +178,21 @@ module Padrino
173
178
  set :method_override, true
174
179
  set :sessions, false
175
180
  set :public_folder, Proc.new { Padrino.root('public', uri_root) }
176
- set :views, Proc.new { File.join(root, "views") }
177
- set :images_path, Proc.new { File.join(public, "images") }
178
- set :protection, false
181
+ set :views, Proc.new { File.join(root, 'views') }
182
+ set :images_path, Proc.new { File.join(public_folder, 'images') }
183
+ set :protection, true
184
+ # Haml specific
185
+ set :haml, { :ugly => (Padrino.env == :production) } if defined?(Haml)
179
186
  # Padrino specific
180
187
  set :uri_root, '/'
181
188
  set :app_name, settings.to_s.underscore.to_sym
182
189
  set :default_builder, 'StandardFormBuilder'
183
- set :flash, defined?(Sinatra::Flash) || defined?(Rack::Flash)
184
190
  set :authentication, false
185
191
  # Padrino locale
186
192
  set :locale_path, Proc.new { Dir[File.join(settings.root, '/locale/**/*.{rb,yml}')] }
193
+ # Authenticity token
194
+ set :protect_from_csrf, false
195
+ set :allow_disabled_csrf, false
187
196
  # Load the Global Configurations
188
197
  class_eval(&Padrino.apps_configuration) if Padrino.apps_configuration
189
198
  end
@@ -241,27 +250,40 @@ module Padrino
241
250
  # Also initializes the application after setting up the middleware
242
251
  def setup_default_middleware(builder)
243
252
  setup_sessions builder
244
- setup_flash builder
245
253
  builder.use Padrino::ShowExceptions if show_exceptions?
246
254
  builder.use Padrino::Logger::Rack, uri_root if Padrino.logger && logging?
247
255
  builder.use Padrino::Reloader::Rack if reload?
248
256
  builder.use Rack::MethodOverride if method_override?
249
257
  builder.use Rack::Head
258
+ register Padrino::Flash
250
259
  setup_protection builder
260
+ setup_csrf_protection builder
251
261
  setup_application!
252
262
  end
253
263
 
254
- # TODO Remove this in a few versions (rack-flash deprecation)
255
- # Move register Sinatra::Flash into setup_default_middleware
256
- # Initializes flash using sinatra-flash or rack-flash
257
- def setup_flash(builder)
258
- register Sinatra::Flash if flash? && defined?(Sinatra::Flash)
259
- if defined?(Rack::Flash) && !defined?(Sinatra::Flash)
260
- logger.warn %Q{
261
- [Deprecation] In Gemfile, 'rack-flash' should be replaced with 'sinatra-flash'!
262
- Rack-Flash is not compatible with later versions of Rack and should be replaced.
263
- }
264
- builder.use Rack::Flash, :sweep => true if flash?
264
+ # sets up csrf protection for the app
265
+ def setup_csrf_protection(builder)
266
+ if protect_from_csrf? && !sessions?
267
+ raise(<<-ERROR)
268
+ `protect_from_csrf` is activated, but `sessions` are not. To enable csrf
269
+ protection, use:
270
+
271
+ enable :sessions
272
+
273
+ or deactivate protect_from_csrf:
274
+
275
+ disable :protect_from_csrf
276
+ ERROR
277
+ end
278
+
279
+ if protect_from_csrf?
280
+ if allow_disabled_csrf?
281
+ builder.use Rack::Protection::AuthenticityToken,
282
+ :reaction => :report,
283
+ :report_key => 'protection.csrf.failed'
284
+ else
285
+ builder.use Rack::Protection::AuthenticityToken
286
+ end
265
287
  end
266
288
  end
267
289
  end # self
@@ -0,0 +1,229 @@
1
+ module Padrino
2
+ module Flash
3
+
4
+ class << self
5
+ # @private
6
+ def registered(app)
7
+ app.helpers Helpers
8
+ app.after do
9
+ session[:_flash] = @_flash.next if @_flash
10
+ end
11
+ end
12
+ end # self
13
+
14
+ class Storage
15
+ include Enumerable
16
+
17
+ # @private
18
+ def initialize(session=nil)
19
+ @_now = session || {}
20
+ @_next = {}
21
+ end
22
+
23
+ def now
24
+ @_now
25
+ end
26
+
27
+ def next
28
+ @_next
29
+ end
30
+
31
+ # @since 0.10.8
32
+ # @api public
33
+ def [](type)
34
+ @_now[type]
35
+ end
36
+
37
+ # @since 0.10.8
38
+ # @api public
39
+ def []=(type, message)
40
+ @_next[type] = message
41
+ end
42
+
43
+ # @since 0.10.8
44
+ # @api public
45
+ def delete(type)
46
+ @_now.delete(type)
47
+ self
48
+ end
49
+
50
+ # @since 0.10.8
51
+ # @api public
52
+ def keys
53
+ @_now.keys
54
+ end
55
+
56
+ # @since 0.10.8
57
+ # @api public
58
+ def key?(type)
59
+ @_now.key?(type)
60
+ end
61
+
62
+ # @since 0.10.8
63
+ # @api public
64
+ def each(&block)
65
+ @_now.each(&block)
66
+ end
67
+
68
+ # @since 0.10.8
69
+ # @api public
70
+ def replace(hash)
71
+ @_now.replace(hash)
72
+ self
73
+ end
74
+
75
+ # @since 0.10.8
76
+ # @api public
77
+ def update(hash)
78
+ @_now.update(hash)
79
+ self
80
+ end
81
+ alias_method :merge!, :update
82
+
83
+ # @since 0.10.8
84
+ # @api public
85
+ def sweep
86
+ @_now.replace(@_next)
87
+ @_next = {}
88
+ self
89
+ end
90
+
91
+ # @since 0.10.8
92
+ # @api public
93
+ def keep(key = nil)
94
+ if key
95
+ @_next[key] = @_now[key]
96
+ else
97
+ @_next.merge!(@_now)
98
+ end
99
+ self
100
+ end
101
+
102
+ # @since 0.10.8
103
+ # @api public
104
+ def discard(key = nil)
105
+ if key
106
+ @_next.delete(key)
107
+ else
108
+ @_next = {}
109
+ end
110
+ self
111
+ end
112
+
113
+ # @since 0.10.8
114
+ # @api public
115
+ def clear
116
+ @_now.clear
117
+ end
118
+
119
+ # @since 0.10.8
120
+ # @api public
121
+ def empty?
122
+ @_now.empty?
123
+ end
124
+
125
+ # @since 0.10.8
126
+ # @api public
127
+ def to_hash
128
+ @_now.dup
129
+ end
130
+
131
+ def length
132
+ @_now.length
133
+ end
134
+ alias_method :size, :length
135
+
136
+ # @since 0.10.8
137
+ # @api public
138
+ def to_s
139
+ @_now.to_s
140
+ end
141
+
142
+ # @since 0.10.8
143
+ # @api public
144
+ def error=(message)
145
+ self[:error] = message
146
+ end
147
+
148
+ # @since 0.10.8
149
+ # @api public
150
+ def error
151
+ self[:error]
152
+ end
153
+
154
+ # @since 0.10.8
155
+ # @api public
156
+ def notice=(message)
157
+ self[:notice] = message
158
+ end
159
+
160
+ # @since 0.10.8
161
+ # @api public
162
+ def notice
163
+ self[:notice]
164
+ end
165
+
166
+ # @since 0.10.8
167
+ # @api public
168
+ def success=(message)
169
+ self[:success] = message
170
+ end
171
+
172
+ # @since 0.10.8
173
+ # @api public
174
+ def success
175
+ self[:success]
176
+ end
177
+ end # Storage
178
+
179
+ module Helpers
180
+ ###
181
+ # Overloads the existing redirect helper in-order to provide support for flash messages
182
+ #
183
+ # @overload redirect(url)
184
+ # @param [String] url
185
+ #
186
+ # @overload redirect(url, status_code)
187
+ # @param [String] url
188
+ # @param [Fixnum] status_code
189
+ #
190
+ # @overload redirect(url, status_code, flash_messages)
191
+ # @param [String] url
192
+ # @param [Fixnum] status_code
193
+ # @param [Hash] flash_messages
194
+ #
195
+ # @overload redirect(url, flash_messages)
196
+ # @param [String] url
197
+ # @param [Hash] flash_messages
198
+ #
199
+ # @example
200
+ # redirect(dashboard, success: :user_created)
201
+ # redirect(new_location, 301, notice: 'This page has moved. Please update your bookmarks!!')
202
+ #
203
+ # @since 0.10.8
204
+ # @api public
205
+ def redirect(url, *args)
206
+ flashes = args.extract_options!
207
+
208
+ flashes.each do |type, message|
209
+ message = I18n.translate(message) if message.is_a?(Symbol) && defined?(I18n)
210
+ flash[type] = message
211
+ end
212
+
213
+ super(url, args)
214
+ end
215
+ alias_method :redirect_to, :redirect
216
+
217
+ ###
218
+ # Returns the flash storage object
219
+ #
220
+ # @return [Storage]
221
+ #
222
+ # @since 0.10.8
223
+ # @api public
224
+ def flash
225
+ @_flash ||= Storage.new(env['rack.session'] ? session[:_flash] : {})
226
+ end
227
+ end # Helpers
228
+ end # Flash
229
+ end # Padrino
@@ -7,6 +7,16 @@ module Padrino
7
7
  # locale enabled rendering, among other features.
8
8
  #
9
9
  module Rendering
10
+ ##
11
+ # A SafeTemplate assumes that its output is safe.
12
+ #
13
+ # @api private
14
+ module SafeTemplate
15
+ def render(*)
16
+ super.html_safe
17
+ end
18
+ end
19
+
10
20
  ##
11
21
  # Exception responsible for when an expected template did not exist.
12
22
  #
@@ -25,19 +35,34 @@ module Padrino
25
35
  ] unless defined?(IGNORE_FILE_PATTERN)
26
36
 
27
37
  ##
28
- # Default rendering options used in the #render-method.
38
+ # Default options used in the #resolve_template-method.
29
39
  #
30
40
  DEFAULT_RENDERING_OPTIONS = { :strict_format => false, :raise_exceptions => true } unless defined?(DEFAULT_RENDERING_OPTIONS)
31
41
 
32
42
  class << self
43
+ ##
44
+ # Default engine configurations for Padrino::Rendering
45
+ #
46
+ # @return {Hash<Symbol,Hash>}
47
+ # The configurations, keyed by engine.
48
+ def engine_configurations
49
+ @engine_configurations ||= {}
50
+ end
51
+
33
52
  ##
34
53
  # Main class that register this extension.
35
54
  #
36
55
  def registered(app)
37
- app.send(:include, InstanceMethods)
38
- app.extend(ClassMethods)
56
+ included(app)
57
+ engine_configurations.each do |engine, configs|
58
+ app.set engine, configs
59
+ end
60
+ end
61
+
62
+ def included(base)
63
+ base.send(:include, InstanceMethods)
64
+ base.extend(ClassMethods)
39
65
  end
40
- alias :included :registered
41
66
  end
42
67
 
43
68
  ##
@@ -152,11 +177,8 @@ module Padrino
152
177
  # * Use render 'path/to/template.haml' (with explicit engine lookup)
153
178
  # * Use render 'path/to/template', :layout => false
154
179
  # * Use render 'path/to/template', :layout => false, :engine => 'haml'
155
- # * Use render { :a => 1, :b => 2, :c => 3 } # => return a json string
156
180
  #
157
181
  def render(engine, data=nil, options={}, locals={}, &block)
158
- # If engine is a hash then render data converted to json
159
- content_type(:json, :charset => 'utf-8') and return engine.to_json if engine.is_a?(Hash)
160
182
 
161
183
  # If engine is nil, ignore engine parameter and shift up all arguments
162
184
  # render nil, "index", { :layout => true }, { :localvar => "foo" }
@@ -175,10 +197,10 @@ module Padrino
175
197
  root = settings.respond_to?(:root) ? settings.root : ""
176
198
 
177
199
  # Use @layout if it exists
178
- options[:layout] = @layout if options[:layout].nil?
179
-
200
+ layout_was = options[:layout]
201
+ options[:layout] = @layout if options[:layout].nil? || options[:layout] == true
180
202
  # Resolve layouts similar to in Rails
181
- if (options[:layout].nil? || options[:layout] == true) && !settings.templates.has_key?(:layout)
203
+ if options[:layout].nil? && !settings.templates.has_key?(:layout)
182
204
  layout_path, layout_engine = *resolved_layout
183
205
  options[:layout] = layout_path || false # We need to force layout false so sinatra don't try to render it
184
206
  options[:layout] = false unless layout_engine == engine # TODO allow different layout engine
@@ -186,10 +208,12 @@ module Padrino
186
208
  elsif options[:layout].present?
187
209
  options[:layout] = settings.fetch_layout_path(options[:layout] || @layout)
188
210
  end
211
+ # Default to original layout value if none found
212
+ options[:layout] ||= layout_was
189
213
 
190
214
  # Cleanup the template
191
215
  @current_engine, engine_was = engine, @current_engine
192
- @_out_buf, _buf_was = "", @_out_buf
216
+ @_out_buf, _buf_was = ActiveSupport::SafeBuffer.new, @_out_buf
193
217
 
194
218
  # Pass arguments to Sinatra render method
195
219
  super(engine, data, options.dup, locals, &block)
@@ -290,3 +314,7 @@ module Padrino
290
314
  end # InstanceMethods
291
315
  end # Rendering
292
316
  end # Padrino
317
+
318
+ require 'padrino-core/application/rendering/extensions/haml'
319
+ require 'padrino-core/application/rendering/extensions/erubis'
320
+ require 'padrino-core/application/rendering/extensions/slim'