use latest padrino
This commit is contained in:
parent
39d3fa01ad
commit
69c36e691f
209 changed files with 2754 additions and 719 deletions
|
@ -413,8 +413,7 @@ module Middleman
|
|||
@_out_buf = _buf_was
|
||||
end
|
||||
|
||||
# concat_safe_content
|
||||
concat_content render_individual_file(layout_path, @current_locs || {}, @current_opts || {}, self) { content }
|
||||
concat_safe_content render_individual_file(layout_path, @current_locs || {}, @current_opts || {}, self) { content }
|
||||
ensure
|
||||
@current_engine = engine_was
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
if defined?(::Padrino::Helpers)
|
||||
require 'vendored-middleman-deps/padrino-core-0.10.7/lib/padrino-core/support_lite'
|
||||
require 'vendored-middleman-deps/padrino-helpers-0.10.7/lib/padrino-helpers'
|
||||
if !defined?(::Padrino::Helpers)
|
||||
require 'vendored-middleman-deps/padrino-core-0.11.2/lib/padrino-core/support_lite'
|
||||
require 'vendored-middleman-deps/padrino-helpers-0.11.2/lib/padrino-helpers'
|
||||
end
|
||||
|
||||
module Middleman
|
||||
|
|
|
@ -5,9 +5,9 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
|||
|
||||
require 'active_support/core_ext/object/to_query'
|
||||
|
||||
if defined?(::Padrino::Helpers)
|
||||
require 'vendored-middleman-deps/padrino-core-0.10.7/lib/padrino-core/support_lite'
|
||||
require 'vendored-middleman-deps/padrino-helpers-0.10.7/lib/padrino-helpers'
|
||||
if !defined?(::Padrino::Helpers)
|
||||
require 'vendored-middleman-deps/padrino-core-0.11.2/lib/padrino-core/support_lite'
|
||||
require 'vendored-middleman-deps/padrino-helpers-0.11.2/lib/padrino-helpers'
|
||||
end
|
||||
|
||||
app.helpers ::Padrino::Helpers::OutputHelpers
|
||||
|
@ -18,7 +18,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
|||
app.helpers ::Padrino::Helpers::RenderHelpers
|
||||
app.helpers ::Padrino::Helpers::NumberHelpers
|
||||
# app.helpers ::Padrino::Helpers::TranslationHelpers
|
||||
# app.helpers ::Padrino::Helpers::Breadcrumbs
|
||||
app.helpers ::Padrino::Helpers::Breadcrumbs
|
||||
|
||||
app.config.define_setting :relative_links, false, 'Whether to generate relative links instead of absolute ones'
|
||||
end
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
require File.expand_path('../../tasks', __FILE__)
|
||||
require 'rake'
|
||||
require 'rake/dsl_definition'
|
||||
require 'thor'
|
||||
require 'securerandom' unless defined?(SecureRandom)
|
||||
|
||||
module PadrinoTasks
|
||||
def self.init(init=false)
|
||||
Padrino::Tasks.files.flatten.uniq.each { |rakefile| Rake.application.add_import(rakefile) rescue puts "<= Failed load #{ext}" }
|
||||
if init
|
||||
Rake.application.init
|
||||
Rake.application.instance_variable_set(:@rakefile, __FILE__)
|
||||
load(File.expand_path('../rake_tasks.rb', __FILE__))
|
||||
Rake.application.load_imports
|
||||
Rake.application.top_level
|
||||
else
|
||||
load(File.expand_path('../rake_tasks.rb', __FILE__))
|
||||
Rake.application.load_imports
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def shell
|
||||
@_shell ||= Thor::Base.shell.new
|
||||
end
|
|
@ -1,8 +1,19 @@
|
|||
require 'sinatra/base'
|
||||
require 'padrino-core/support_lite' unless defined?(SupportLite)
|
||||
require 'padrino-core/version'
|
||||
require 'padrino-core/support_lite'
|
||||
require 'padrino-core/application'
|
||||
|
||||
require 'padrino-core/caller'
|
||||
require 'padrino-core/command'
|
||||
require 'padrino-core/loader'
|
||||
require 'padrino-core/logger'
|
||||
require 'padrino-core/mounter'
|
||||
require 'padrino-core/reloader'
|
||||
require 'padrino-core/router'
|
||||
require 'padrino-core/server'
|
||||
require 'padrino-core/tasks'
|
||||
require 'padrino-core/module'
|
||||
|
||||
FileSet.glob_require('padrino-core/application/*.rb', __FILE__)
|
||||
FileSet.glob_require('padrino-core/*.rb', __FILE__)
|
||||
|
||||
# The Padrino environment (falls back to the rack env or finally develop)
|
||||
PADRINO_ENV = ENV["PADRINO_ENV"] ||= ENV["RACK_ENV"] ||= "development" unless defined?(PADRINO_ENV)
|
||||
|
@ -80,7 +91,14 @@ module Padrino
|
|||
# end
|
||||
#
|
||||
def configure_apps(&block)
|
||||
@_global_configuration = block if block_given?
|
||||
return unless block_given?
|
||||
@@_global_configurations ||= []
|
||||
@@_global_configurations << block
|
||||
@_global_configuration = lambda do |app|
|
||||
@@_global_configurations.each do |configuration|
|
||||
app.class_eval(&configuration)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -148,5 +166,41 @@ module Padrino
|
|||
def use(m, *args, &block)
|
||||
middleware << [m, args, block]
|
||||
end
|
||||
|
||||
##
|
||||
# Registers a gem with padrino. This relieves the caller from setting up
|
||||
# loadpaths by himself and enables Padrino to look up apps in gem folder.
|
||||
#
|
||||
# The name given has to be the proper gem name as given in the gemspec.
|
||||
#
|
||||
# @param [String] name
|
||||
# The name of the gem being registered.
|
||||
#
|
||||
# @param [Module] main_module
|
||||
# The main module of the gem.
|
||||
#
|
||||
# @returns The root path of the loaded gem
|
||||
def gem(name, main_module)
|
||||
_,spec = Gem.loaded_specs.find { |spec_name, spec| spec_name == name }
|
||||
gems << spec
|
||||
modules << main_module
|
||||
spec.full_gem_path
|
||||
end
|
||||
|
||||
##
|
||||
# Returns all currently known padrino gems.
|
||||
#
|
||||
# @returns [Gem::Specification]
|
||||
def gems
|
||||
@gems ||= []
|
||||
end
|
||||
|
||||
##
|
||||
# All loaded Padrino modules.
|
||||
#
|
||||
# @returns [<Padrino::Module>]
|
||||
def modules
|
||||
@modules ||= []
|
||||
end
|
||||
end # self
|
||||
end # Padrino
|
|
@ -1,3 +1,8 @@
|
|||
require 'padrino-core/application/rendering'
|
||||
require 'padrino-core/application/routing'
|
||||
require 'padrino-core/application/flash'
|
||||
require 'padrino-core/application/showexceptions'
|
||||
|
||||
module Padrino
|
||||
class ApplicationSetupError < RuntimeError # @private
|
||||
end
|
||||
|
@ -173,17 +178,21 @@ module Padrino
|
|||
set :method_override, true
|
||||
set :sessions, false
|
||||
set :public_folder, Proc.new { Padrino.root('public', uri_root) }
|
||||
set :views, Proc.new { File.join(root, "views") }
|
||||
set :images_path, Proc.new { File.join(public, "images") }
|
||||
set :protection, false
|
||||
set :views, Proc.new { File.join(root, 'views') }
|
||||
set :images_path, Proc.new { File.join(public_folder, 'images') }
|
||||
set :protection, true
|
||||
# Haml specific
|
||||
set :haml, { :ugly => (Padrino.env == :production) } if defined?(Haml)
|
||||
# Padrino specific
|
||||
set :uri_root, '/'
|
||||
set :app_name, settings.to_s.underscore.to_sym
|
||||
set :default_builder, 'StandardFormBuilder'
|
||||
set :flash, defined?(Sinatra::Flash) || defined?(Rack::Flash)
|
||||
set :authentication, false
|
||||
# Padrino locale
|
||||
set :locale_path, Proc.new { Dir[File.join(settings.root, '/locale/**/*.{rb,yml}')] }
|
||||
# Authenticity token
|
||||
set :protect_from_csrf, false
|
||||
set :allow_disabled_csrf, false
|
||||
# Load the Global Configurations
|
||||
class_eval(&Padrino.apps_configuration) if Padrino.apps_configuration
|
||||
end
|
||||
|
@ -241,27 +250,42 @@ module Padrino
|
|||
# Also initializes the application after setting up the middleware
|
||||
def setup_default_middleware(builder)
|
||||
setup_sessions builder
|
||||
setup_flash builder
|
||||
builder.use Padrino::ShowExceptions if show_exceptions?
|
||||
builder.use Padrino::Logger::Rack, uri_root if Padrino.logger && logging?
|
||||
builder.use Padrino::Reloader::Rack if reload?
|
||||
builder.use Rack::MethodOverride if method_override?
|
||||
builder.use Rack::Head
|
||||
register Padrino::Flash
|
||||
setup_protection builder
|
||||
setup_csrf_protection builder
|
||||
setup_application!
|
||||
end
|
||||
|
||||
# TODO Remove this in a few versions (rack-flash deprecation)
|
||||
# Move register Sinatra::Flash into setup_default_middleware
|
||||
# Initializes flash using sinatra-flash or rack-flash
|
||||
def setup_flash(builder)
|
||||
register Sinatra::Flash if flash? && defined?(Sinatra::Flash)
|
||||
if defined?(Rack::Flash) && !defined?(Sinatra::Flash)
|
||||
logger.warn %Q{
|
||||
[Deprecation] In Gemfile, 'rack-flash' should be replaced with 'sinatra-flash'!
|
||||
Rack-Flash is not compatible with later versions of Rack and should be replaced.
|
||||
}
|
||||
builder.use Rack::Flash, :sweep => true if flash?
|
||||
# sets up csrf protection for the app
|
||||
def setup_csrf_protection(builder)
|
||||
if protect_from_csrf? && !sessions?
|
||||
raise(<<-ERROR)
|
||||
`protect_from_csrf` is activated, but `sessions` are not. To enable csrf
|
||||
protection, use:
|
||||
|
||||
enable :sessions
|
||||
|
||||
or deactivate protect_from_csrf:
|
||||
|
||||
disable :protect_from_csrf
|
||||
ERROR
|
||||
end
|
||||
|
||||
if protect_from_csrf?
|
||||
if allow_disabled_csrf?
|
||||
builder.use Rack::Protection::AuthenticityToken,
|
||||
:reaction => :report,
|
||||
:report_key => 'protection.csrf.failed',
|
||||
:logger => logger
|
||||
else
|
||||
builder.use Rack::Protection::AuthenticityToken,
|
||||
:logger => logger
|
||||
end
|
||||
end
|
||||
end
|
||||
end # self
|
|
@ -0,0 +1,229 @@
|
|||
module Padrino
|
||||
module Flash
|
||||
|
||||
class << self
|
||||
# @private
|
||||
def registered(app)
|
||||
app.helpers Helpers
|
||||
app.after do
|
||||
session[:_flash] = @_flash.next if @_flash
|
||||
end
|
||||
end
|
||||
end # self
|
||||
|
||||
class Storage
|
||||
include Enumerable
|
||||
|
||||
# @private
|
||||
def initialize(session=nil)
|
||||
@_now = session || {}
|
||||
@_next = {}
|
||||
end
|
||||
|
||||
def now
|
||||
@_now
|
||||
end
|
||||
|
||||
def next
|
||||
@_next
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def [](type)
|
||||
@_now[type]
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def []=(type, message)
|
||||
@_next[type] = message
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def delete(type)
|
||||
@_now.delete(type)
|
||||
self
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def keys
|
||||
@_now.keys
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def key?(type)
|
||||
@_now.key?(type)
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def each(&block)
|
||||
@_now.each(&block)
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def replace(hash)
|
||||
@_now.replace(hash)
|
||||
self
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def update(hash)
|
||||
@_now.update(hash)
|
||||
self
|
||||
end
|
||||
alias_method :merge!, :update
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def sweep
|
||||
@_now.replace(@_next)
|
||||
@_next = {}
|
||||
self
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def keep(key = nil)
|
||||
if key
|
||||
@_next[key] = @_now[key]
|
||||
else
|
||||
@_next.merge!(@_now)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def discard(key = nil)
|
||||
if key
|
||||
@_next.delete(key)
|
||||
else
|
||||
@_next = {}
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def clear
|
||||
@_now.clear
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def empty?
|
||||
@_now.empty?
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def to_hash
|
||||
@_now.dup
|
||||
end
|
||||
|
||||
def length
|
||||
@_now.length
|
||||
end
|
||||
alias_method :size, :length
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def to_s
|
||||
@_now.to_s
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def error=(message)
|
||||
self[:error] = message
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def error
|
||||
self[:error]
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def notice=(message)
|
||||
self[:notice] = message
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def notice
|
||||
self[:notice]
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def success=(message)
|
||||
self[:success] = message
|
||||
end
|
||||
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def success
|
||||
self[:success]
|
||||
end
|
||||
end # Storage
|
||||
|
||||
module Helpers
|
||||
###
|
||||
# Overloads the existing redirect helper in-order to provide support for flash messages
|
||||
#
|
||||
# @overload redirect(url)
|
||||
# @param [String] url
|
||||
#
|
||||
# @overload redirect(url, status_code)
|
||||
# @param [String] url
|
||||
# @param [Fixnum] status_code
|
||||
#
|
||||
# @overload redirect(url, status_code, flash_messages)
|
||||
# @param [String] url
|
||||
# @param [Fixnum] status_code
|
||||
# @param [Hash] flash_messages
|
||||
#
|
||||
# @overload redirect(url, flash_messages)
|
||||
# @param [String] url
|
||||
# @param [Hash] flash_messages
|
||||
#
|
||||
# @example
|
||||
# redirect(dashboard, success: :user_created)
|
||||
# redirect(new_location, 301, notice: 'This page has moved. Please update your bookmarks!!')
|
||||
#
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def redirect(url, *args)
|
||||
flashes = args.extract_options!
|
||||
|
||||
flashes.each do |type, message|
|
||||
message = I18n.translate(message) if message.is_a?(Symbol) && defined?(I18n)
|
||||
flash[type] = message
|
||||
end
|
||||
|
||||
super(url, args)
|
||||
end
|
||||
alias_method :redirect_to, :redirect
|
||||
|
||||
###
|
||||
# Returns the flash storage object
|
||||
#
|
||||
# @return [Storage]
|
||||
#
|
||||
# @since 0.10.8
|
||||
# @api public
|
||||
def flash
|
||||
@_flash ||= Storage.new(env['rack.session'] ? session[:_flash] : {})
|
||||
end
|
||||
end # Helpers
|
||||
end # Flash
|
||||
end # Padrino
|
|
@ -7,6 +7,16 @@ module Padrino
|
|||
# locale enabled rendering, among other features.
|
||||
#
|
||||
module Rendering
|
||||
##
|
||||
# A SafeTemplate assumes that its output is safe.
|
||||
#
|
||||
# @api private
|
||||
module SafeTemplate
|
||||
def render(*)
|
||||
super.html_safe
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Exception responsible for when an expected template did not exist.
|
||||
#
|
||||
|
@ -25,19 +35,34 @@ module Padrino
|
|||
] unless defined?(IGNORE_FILE_PATTERN)
|
||||
|
||||
##
|
||||
# Default rendering options used in the #render-method.
|
||||
# Default options used in the #resolve_template-method.
|
||||
#
|
||||
DEFAULT_RENDERING_OPTIONS = { :strict_format => false, :raise_exceptions => true } unless defined?(DEFAULT_RENDERING_OPTIONS)
|
||||
|
||||
class << self
|
||||
##
|
||||
# Default engine configurations for Padrino::Rendering
|
||||
#
|
||||
# @return {Hash<Symbol,Hash>}
|
||||
# The configurations, keyed by engine.
|
||||
def engine_configurations
|
||||
@engine_configurations ||= {}
|
||||
end
|
||||
|
||||
##
|
||||
# Main class that register this extension.
|
||||
#
|
||||
def registered(app)
|
||||
app.send(:include, InstanceMethods)
|
||||
app.extend(ClassMethods)
|
||||
included(app)
|
||||
engine_configurations.each do |engine, configs|
|
||||
app.set engine, configs
|
||||
end
|
||||
end
|
||||
|
||||
def included(base)
|
||||
base.send(:include, InstanceMethods)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
alias :included :registered
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -152,11 +177,8 @@ module Padrino
|
|||
# * Use render 'path/to/template.haml' (with explicit engine lookup)
|
||||
# * Use render 'path/to/template', :layout => false
|
||||
# * Use render 'path/to/template', :layout => false, :engine => 'haml'
|
||||
# * Use render { :a => 1, :b => 2, :c => 3 } # => return a json string
|
||||
#
|
||||
def render(engine, data=nil, options={}, locals={}, &block)
|
||||
# If engine is a hash then render data converted to json
|
||||
content_type(:json, :charset => 'utf-8') and return engine.to_json if engine.is_a?(Hash)
|
||||
|
||||
# If engine is nil, ignore engine parameter and shift up all arguments
|
||||
# render nil, "index", { :layout => true }, { :localvar => "foo" }
|
||||
|
@ -175,10 +197,10 @@ module Padrino
|
|||
root = settings.respond_to?(:root) ? settings.root : ""
|
||||
|
||||
# Use @layout if it exists
|
||||
options[:layout] = @layout if options[:layout].nil?
|
||||
|
||||
layout_was = options[:layout]
|
||||
options[:layout] = @layout if options[:layout].nil? || options[:layout] == true
|
||||
# Resolve layouts similar to in Rails
|
||||
if (options[:layout].nil? || options[:layout] == true) && !settings.templates.has_key?(:layout)
|
||||
if options[:layout].nil? && !settings.templates.has_key?(:layout)
|
||||
layout_path, layout_engine = *resolved_layout
|
||||
options[:layout] = layout_path || false # We need to force layout false so sinatra don't try to render it
|
||||
options[:layout] = false unless layout_engine == engine # TODO allow different layout engine
|
||||
|
@ -186,10 +208,12 @@ module Padrino
|
|||
elsif options[:layout].present?
|
||||
options[:layout] = settings.fetch_layout_path(options[:layout] || @layout)
|
||||
end
|
||||
# Default to original layout value if none found
|
||||
options[:layout] ||= layout_was
|
||||
|
||||
# Cleanup the template
|
||||
@current_engine, engine_was = engine, @current_engine
|
||||
@_out_buf, _buf_was = "", @_out_buf
|
||||
@_out_buf, _buf_was = ActiveSupport::SafeBuffer.new, @_out_buf
|
||||
|
||||
# Pass arguments to Sinatra render method
|
||||
super(engine, data, options.dup, locals, &block)
|
||||
|
@ -290,3 +314,7 @@ module Padrino
|
|||
end # InstanceMethods
|
||||
end # Rendering
|
||||
end # Padrino
|
||||
|
||||
require 'padrino-core/application/rendering/extensions/haml'
|
||||
require 'padrino-core/application/rendering/extensions/erubis'
|
||||
require 'padrino-core/application/rendering/extensions/slim'
|
|
@ -0,0 +1,55 @@
|
|||
begin
|
||||
require 'erubis'
|
||||
|
||||
module Padrino
|
||||
module Erubis
|
||||
##
|
||||
# SafeBufferEnhancer is an Erubis Enhancer that compiles templates that
|
||||
# are fit for using ActiveSupport::SafeBuffer as a Buffer.
|
||||
#
|
||||
# @api private
|
||||
module SafeBufferEnhancer
|
||||
def add_expr_literal(src, code)
|
||||
src << " #{@bufvar}.concat((" << code << ').to_s);'
|
||||
end
|
||||
|
||||
def add_expr_escaped(src, code)
|
||||
src << " #{@bufvar}.safe_concat " << code << ';'
|
||||
end
|
||||
|
||||
def add_text(src, text)
|
||||
src << " #{@bufvar}.safe_concat '" << escape_text(text) << "';" unless text.empty?
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# SafeBufferTemplate is the classic Erubis template, augmented with
|
||||
# SafeBufferEnhancer.
|
||||
#
|
||||
# @api private
|
||||
class SafeBufferTemplate < ::Erubis::Eruby
|
||||
include SafeBufferEnhancer
|
||||
end
|
||||
|
||||
##
|
||||
# Modded ErubisTemplate that doesn't insist in an String as output
|
||||
# buffer.
|
||||
#
|
||||
# @api private
|
||||
class Template < Tilt::ErubisTemplate
|
||||
def precompiled_preamble(locals)
|
||||
old_postamble = super.split("\n")[0..-2]
|
||||
[old_postamble, "#{@outvar} = _buf = (#{@outvar} || ActiveSupport::SafeBuffer.new)"].join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Tilt.prefer Padrino::Erubis::Template, :erb
|
||||
|
||||
if defined? Padrino::Rendering
|
||||
Padrino::Rendering.engine_configurations[:erb] =
|
||||
{:engine_class => Padrino::Erubis::SafeBufferTemplate}
|
||||
end
|
||||
rescue LoadError
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
begin
|
||||
require 'haml'
|
||||
require 'haml/helpers/xss_mods'
|
||||
|
||||
module Haml
|
||||
module Helpers
|
||||
include XssMods
|
||||
end
|
||||
|
||||
module Util
|
||||
def self.rails_xss_safe?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if defined? Padrino::Rendering
|
||||
Padrino::Rendering.engine_configurations[:haml] =
|
||||
{:escape_html => true}
|
||||
|
||||
class Tilt::HamlTemplate
|
||||
include Padrino::Rendering::SafeTemplate
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
begin
|
||||
require 'slim'
|
||||
|
||||
if defined? Padrino::Rendering
|
||||
Padrino::Rendering.engine_configurations[:slim] =
|
||||
{:generator => Temple::Generators::RailsOutputBuffer,
|
||||
:buffer => "@_out_buf", :use_html_safe => true}
|
||||
|
||||
class Slim::Template
|
||||
include Padrino::Rendering::SafeTemplate
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
end
|
|
@ -11,6 +11,9 @@ class Sinatra::Request
|
|||
def controller
|
||||
route_obj && route_obj.controller
|
||||
end
|
||||
def action
|
||||
route_obj && route_obj.action
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -28,8 +31,8 @@ class HttpRouter
|
|||
@route = path.route
|
||||
@params ||= {}
|
||||
@params.update(env['router.params'])
|
||||
@block_params = if path.route.is_a?(HttpRouter::RegexRoute)
|
||||
params_list = env['router.request'].extra_env['router.regex_match'].to_a
|
||||
@block_params = if match_data = env['router.request'].extra_env['router.regex_match']
|
||||
params_list = match_data.to_a
|
||||
params_list.shift
|
||||
@params[:captures] = params_list
|
||||
params_list
|
||||
|
@ -47,7 +50,6 @@ class HttpRouter
|
|||
(@route.before_filters - settings.filters[:before]).each { |block| instance_eval(&block) }
|
||||
@layout = path.route.use_layout if path.route.use_layout
|
||||
@route.custom_conditions.each { |block| pass if block.bind(self).call == false } if @route.custom_conditions
|
||||
@block_params = @block_params[0, @route.dest.arity] if @route.dest.arity > 0
|
||||
halt_response = catch(:halt) { route_eval { @route.dest[self, @block_params] } }
|
||||
@_response_buffer = halt_response.is_a?(Array) ? halt_response.last : halt_response
|
||||
successful = true
|
||||
|
@ -62,7 +64,9 @@ class HttpRouter
|
|||
|
||||
# @private
|
||||
class Route
|
||||
attr_accessor :use_layout, :controller, :cache, :cache_key, :cache_expires_in
|
||||
VALID_HTTP_VERBS.replace %w[GET POST PUT PATCH DELETE HEAD OPTIONS LINK UNLINK]
|
||||
|
||||
attr_accessor :use_layout, :controller, :action, :cache, :cache_key, :cache_expires_in, :parent
|
||||
|
||||
def before_filters(&block)
|
||||
@_before_filters ||= []
|
||||
|
@ -84,6 +88,60 @@ class HttpRouter
|
|||
|
||||
@_custom_conditions
|
||||
end
|
||||
|
||||
def significant_variable_names
|
||||
@significant_variable_names ||= if @original_path.is_a?(String)
|
||||
@original_path.scan(/(^|[^\\])[:\*]([a-zA-Z0-9_]+)/).map{|p| p.last.to_sym}
|
||||
elsif @original_path.is_a?(Regexp) and @original_path.respond_to?(:named_captures)
|
||||
@original_path.named_captures.keys.map(&:to_sym)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#Monkey patching the Request class. Using Rack::Utils.unescape rather than
|
||||
#URI.unescape which can't handle utf-8 chars
|
||||
class Request
|
||||
def initialize(path, rack_request)
|
||||
@rack_request = rack_request
|
||||
@path = Rack::Utils.unescape(path).split(/\//)
|
||||
@path.shift if @path.first == ''
|
||||
@path.push('') if path[-1] == ?/
|
||||
@extra_env = {}
|
||||
@params = []
|
||||
@acceptable_methods = Set.new
|
||||
end
|
||||
end
|
||||
|
||||
class Node::Path
|
||||
def to_code
|
||||
path_ivar = inject_root_ivar(self)
|
||||
"#{"if !callback && request.path.size == 1 && request.path.first == '' && (request.rack_request.head? || request.rack_request.get?) && request.rack_request.path_info[-1] == ?/
|
||||
catch(:pass) do
|
||||
response = ::Rack::Response.new
|
||||
response.redirect(request.rack_request.path_info[0, request.rack_request.path_info.size - 1], 302)
|
||||
return response.finish
|
||||
end
|
||||
end" if router.redirect_trailing_slash?}
|
||||
|
||||
#{"if request.#{router.ignore_trailing_slash? ? 'path_finished?' : 'path.empty?'}" unless route.match_partially}
|
||||
catch(:pass) do
|
||||
if callback
|
||||
request.called = true
|
||||
callback.call(Response.new(request, #{path_ivar}))
|
||||
else
|
||||
env = request.rack_request.dup.env
|
||||
env['router.request'] = request
|
||||
env['router.params'] ||= {}
|
||||
#{"env['router.params'].merge!(Hash[#{param_names.inspect}.zip(request.params)])" if dynamic?}
|
||||
@router.rewrite#{"_partial" if route.match_partially}_path_info(env, request)
|
||||
response = @router.process_destination_path(#{path_ivar}, env)
|
||||
return response unless router.pass_on_response(response)
|
||||
end
|
||||
end
|
||||
#{"end" unless route.match_partially}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,7 +156,7 @@ module Padrino
|
|||
def apply?(request)
|
||||
detect = @args.any? do |arg|
|
||||
case arg
|
||||
when Symbol then request.route_obj && (request.route_obj.named == arg or request.route_obj.named == [@scoped_controller, arg].flatten.join("_").to_sym)
|
||||
when Symbol then request.route_obj && (request.route_obj.name == arg or request.route_obj.name == [@scoped_controller, arg].flatten.join("_").to_sym)
|
||||
else arg === request.path_info
|
||||
end
|
||||
end || @options.any? do |name, val|
|
||||
|
@ -166,7 +224,7 @@ module Padrino
|
|||
# Class methods responsible for enhanced routing for controllers.
|
||||
module ClassMethods
|
||||
##
|
||||
# Method for organize in a better way our routes.
|
||||
# Method to organize our routes in a better way.
|
||||
#
|
||||
# @param [Array] args
|
||||
# Controller arguments.
|
||||
|
@ -237,8 +295,8 @@ module Padrino
|
|||
# get :index, :map => "/:lang" do; "params[:lang] == :de"; end
|
||||
# end
|
||||
#
|
||||
# In a controller before and after filters are scoped and didn't affect other controllers or main app.
|
||||
# In a controller layout are scoped and didn't affect others controllers and main app.
|
||||
# In a controller, before and after filters are scoped and don't affect other controllers or the main app.
|
||||
# In a controller, layouts are scoped and don't affect other controllers or the main app.
|
||||
#
|
||||
# @example
|
||||
# controller :posts do
|
||||
|
@ -449,7 +507,8 @@ module Padrino
|
|||
#
|
||||
def recognize_path(path)
|
||||
responses = @router.recognize(Rack::MockRequest.env_for(path))
|
||||
[responses[0].path.route.named, responses[0].params]
|
||||
responses = responses[0] if responses[0].is_a?(Array)
|
||||
[responses[0].path.route.name, responses[0].params]
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -470,11 +529,12 @@ module Padrino
|
|||
params[:format] = params[:format].to_s unless params[:format].nil?
|
||||
params = value_to_param(params)
|
||||
end
|
||||
url = if params_array.empty?
|
||||
compiled_router.url(name, params)
|
||||
else
|
||||
compiled_router.url(name, *(params_array << params))
|
||||
end
|
||||
url =
|
||||
if params_array.empty?
|
||||
compiled_router.path(name, params)
|
||||
else
|
||||
compiled_router.path(name, *(params_array << params))
|
||||
end
|
||||
url[0,0] = conform_uri(uri_root) if defined?(uri_root)
|
||||
url[0,0] = conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
|
||||
url = "/" if url.blank?
|
||||
|
@ -556,8 +616,17 @@ module Padrino
|
|||
# Do padrino parsing. We dup options so we can build HEAD request correctly
|
||||
route_options = options.dup
|
||||
route_options[:provides] = @_provides if @_provides
|
||||
|
||||
# CSRF protection is always active except when explicitly switched off
|
||||
if allow_disabled_csrf
|
||||
unless route_options[:csrf_protection] == false
|
||||
route_options[:csrf_protection] = true
|
||||
end
|
||||
end
|
||||
|
||||
path, *route_options[:with] = path if path.is_a?(Array)
|
||||
path, name, options, route_options = *parse_route(path, route_options, verb)
|
||||
action = path
|
||||
path, name, route_parents, options, route_options = *parse_route(path, route_options, verb)
|
||||
options.reverse_merge!(@_conditions) if @_conditions
|
||||
|
||||
# Sinatra defaults
|
||||
|
@ -572,20 +641,22 @@ module Padrino
|
|||
|
||||
# HTTPRouter route construction
|
||||
route = router.add(path, route_options)
|
||||
route.name(name) if name
|
||||
route.name = name if name
|
||||
route.action = action
|
||||
priority_name = options.delete(:priority) || :normal
|
||||
priority = ROUTE_PRIORITY[priority_name] or raise("Priority #{priority_name} not recognized, try #{ROUTE_PRIORITY.keys.join(', ')}")
|
||||
route.cache = options.key?(:cache) ? options.delete(:cache) : @_cache
|
||||
route.send(verb.downcase.to_sym)
|
||||
route.host(options.delete(:host)) if options.key?(:host)
|
||||
route.user_agent(options.delete(:agent)) if options.key?(:agent)
|
||||
route.parent = route_parents ? (route_parents.count == 1 ? route_parents.first : route_parents) : route_parents
|
||||
route.add_request_method(verb.downcase.to_sym)
|
||||
route.host = options.delete(:host) if options.key?(:host)
|
||||
route.user_agent = options.delete(:agent) if options.key?(:agent)
|
||||
if options.key?(:default_values)
|
||||
defaults = options.delete(:default_values)
|
||||
route.default(defaults) if defaults
|
||||
route.add_default_values(defaults) if defaults
|
||||
end
|
||||
options.delete_if do |option, args|
|
||||
if route.send(:significant_variable_names).include?(option)
|
||||
route.matching(option => Array(args).first)
|
||||
if route.significant_variable_names.include?(option)
|
||||
route.add_match_with(option => Array(args).first)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -646,8 +717,8 @@ module Padrino
|
|||
|
||||
if @_use_format or format_params = options[:provides]
|
||||
process_path_for_provides(path, format_params)
|
||||
options[:matching] ||= {}
|
||||
options[:matching][:format] = /[^\.]+/
|
||||
# options[:add_match_with] ||= {}
|
||||
# options[:add_match_with][:format] = /[^\.]+/
|
||||
end
|
||||
|
||||
absolute_map = map && map[0] == ?/
|
||||
|
@ -657,14 +728,14 @@ module Padrino
|
|||
if map.blank? and !absolute_map
|
||||
controller_path = controller.join("/")
|
||||
path.gsub!(%r{^\(/\)|/\?}, "")
|
||||
path = File.join(controller_path, path)
|
||||
path = File.join(controller_path, path) unless @_map
|
||||
end
|
||||
# Here we build the correct name route
|
||||
end
|
||||
|
||||
# Now we need to parse our 'parent' params and parent scope
|
||||
if !absolute_map and parent_params = options.delete(:parent) || @_parents
|
||||
parent_params = Array(@_parents) + Array(parent_params)
|
||||
parent_params = (Array(@_parents) + Array(parent_params)).uniq
|
||||
path = process_path_for_parent_params(path, parent_params)
|
||||
end
|
||||
|
||||
|
@ -692,7 +763,7 @@ module Padrino
|
|||
# Merge in option defaults
|
||||
options.reverse_merge!(:default_values => @_defaults)
|
||||
|
||||
[path, name, options, route_options]
|
||||
[path, name, parent_params, options, route_options]
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -756,19 +827,22 @@ module Padrino
|
|||
def provides(*types)
|
||||
@_use_format = true
|
||||
condition do
|
||||
mime_types = types.map { |t| mime_type(t) }
|
||||
mime_types = types.map { |t| mime_type(t) }.compact
|
||||
url_format = params[:format].to_sym if params[:format]
|
||||
accepts = request.accept.map { |a| a.split(";")[0].strip }
|
||||
accepts = request.accept.map { |a| a.to_str }
|
||||
|
||||
# per rfc2616-sec14:
|
||||
# Assume */* if no ACCEPT header is given.
|
||||
catch_all = (accepts.delete "*/*" || accepts.empty?)
|
||||
matching_types = accepts.empty? ? mime_types.slice(0,1) : (accepts & mime_types)
|
||||
if matching_types.empty? && types.include?(:any)
|
||||
matching_types = accepts
|
||||
end
|
||||
|
||||
if !url_format && matching_types.first
|
||||
type = ::Rack::Mime::MIME_TYPES.find { |k, v| v == matching_types.first }[0].sub(/\./,'').to_sym
|
||||
accept_format = CONTENT_TYPE_ALIASES[type] || type
|
||||
elsif catch_all
|
||||
elsif catch_all && !types.include?(:any)
|
||||
type = types.first
|
||||
accept_format = CONTENT_TYPE_ALIASES[type] || type
|
||||
end
|
||||
|
@ -793,6 +867,21 @@ module Padrino
|
|||
matched_format
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Implements CSRF checking when `allow_disabled_csrf` is set to true.
|
||||
#
|
||||
# This condition is always on, except when it is explicitly switched
|
||||
# off.
|
||||
#
|
||||
# @example
|
||||
# post("/", :csrf_protection => false)
|
||||
#
|
||||
def csrf_protection(on = true)
|
||||
if on
|
||||
condition { halt 403 if request.env['protection.csrf.failed'] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -836,7 +925,7 @@ module Padrino
|
|||
else
|
||||
path_params << params
|
||||
end
|
||||
@route.url(*path_params)
|
||||
@route.path(*path_params)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -905,13 +994,19 @@ module Padrino
|
|||
end
|
||||
|
||||
def dispatch!
|
||||
static! if settings.static? && (request.get? || request.head?)
|
||||
route!
|
||||
invoke do
|
||||
static! if settings.static? && (request.get? || request.head?)
|
||||
route!
|
||||
end
|
||||
rescue ::Exception => boom
|
||||
filter! :before
|
||||
handle_exception!(boom)
|
||||
filter! :before if boom.kind_of? ::Sinatra::NotFound
|
||||
invoke { @boom_handled = handle_exception!(boom) }
|
||||
ensure
|
||||
filter! :after unless env['sinatra.static_file']
|
||||
@boom_handled or begin
|
||||
filter! :after unless env['sinatra.static_file']
|
||||
rescue ::Exception => boom
|
||||
invoke { handle_exception!(boom) } unless @env['sinatra.error']
|
||||
end
|
||||
end
|
||||
|
||||
def route!(base=settings, pass_block=nil)
|
||||
|
@ -919,9 +1014,10 @@ module Padrino
|
|||
if base.compiled_router and match = base.compiled_router.call(@request.env)
|
||||
if match.respond_to?(:each)
|
||||
route_eval do
|
||||
match[1].each {|k,v| response[k] = v}
|
||||
match[1].each { |k,v| response[k] = v }
|
||||
status match[0]
|
||||
route_missing if match[0] == 404
|
||||
route_missing if allow = response['Allow'] and allow.include?(request.env['REQUEST_METHOD'])
|
||||
end
|
||||
end
|
||||
else
|
|
@ -6,17 +6,18 @@ module Padrino
|
|||
class Base < Thor
|
||||
include Thor::Actions
|
||||
|
||||
class_option :chdir, :type => :string, :aliases => "-c", :desc => "Change to dir before starting"
|
||||
class_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development, :desc => "Padrino Environment"
|
||||
class_option :chdir, :type => :string, :aliases => "-c", :desc => "Change to dir before starting."
|
||||
class_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development, :desc => "Padrino Environment."
|
||||
class_option :help, :type => :boolean, :desc => "Show help usage"
|
||||
|
||||
desc "start", "Starts the Padrino application"
|
||||
method_option :server, :type => :string, :aliases => "-a", :desc => "Rack Handler (default: autodetect)"
|
||||
method_option :host, :type => :string, :aliases => "-h", :required => true, :default => "0.0.0.0", :desc => "Bind to HOST address"
|
||||
method_option :port, :type => :numeric, :aliases => "-p", :required => true, :default => 3000, :desc => "Use PORT"
|
||||
method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background"
|
||||
method_option :pid, :type => :string, :aliases => "-i", :desc => "File to store pid"
|
||||
method_option :debug, :type => :boolean, :desc => "Set debugging flags"
|
||||
desc "start", "Starts the Padrino application (alternatively use 's')."
|
||||
map "s" => :start
|
||||
method_option :server, :type => :string, :aliases => "-a", :desc => "Rack Handler (default: autodetect)"
|
||||
method_option :host, :type => :string, :aliases => "-h", :required => true, :default => '127.0.0.1', :desc => "Bind to HOST address."
|
||||
method_option :port, :type => :numeric, :aliases => "-p", :required => true, :default => 3000, :desc => "Use PORT."
|
||||
method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background."
|
||||
method_option :pid, :type => :string, :aliases => "-i", :desc => "File to store pid."
|
||||
method_option :debug, :type => :boolean, :desc => "Set debugging flags."
|
||||
def start
|
||||
prepare :start
|
||||
require File.expand_path("../adapter", __FILE__)
|
||||
|
@ -24,12 +25,8 @@ module Padrino
|
|||
Padrino::Cli::Adapter.start(options)
|
||||
end
|
||||
|
||||
desc "s", "Starts the Padrino application"
|
||||
def s
|
||||
invoke :start
|
||||
end
|
||||
|
||||
desc "stop", "Stops the Padrino application"
|
||||
desc "stop", "Stops the Padrino application (alternatively use 'st')."
|
||||
map "st" => :stop
|
||||
method_option :pid, :type => :string, :aliases => "-p", :desc => "File to store pid", :default => 'tmp/pids/server.pid'
|
||||
def stop
|
||||
prepare :stop
|
||||
|
@ -37,7 +34,7 @@ module Padrino
|
|||
Padrino::Cli::Adapter.stop(options)
|
||||
end
|
||||
|
||||
desc "rake", "Execute rake tasks"
|
||||
desc "rake", "Execute rake tasks."
|
||||
method_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development
|
||||
method_option :list, :type => :string, :aliases => "-T", :desc => "Display the tasks (matching optional PATTERN) with descriptions, then exit."
|
||||
method_option :trace, :type => :boolean, :aliases => "-t", :desc => "Turn on invoke/execute tracing, enable full backtrace."
|
||||
|
@ -51,12 +48,15 @@ module Padrino
|
|||
ARGV.concat(args)
|
||||
puts "=> Executing Rake #{ARGV.join(' ')} ..."
|
||||
load File.expand_path('../rake.rb', __FILE__)
|
||||
require File.expand_path('config/boot.rb')
|
||||
PadrinoTasks.init(true)
|
||||
Rake.application.init
|
||||
Rake.application.instance_variable_set(:@rakefile, __FILE__)
|
||||
load File.expand_path('Rakefile')
|
||||
Rake.application.top_level
|
||||
end
|
||||
|
||||
desc "console", "Boots up the Padrino application irb console"
|
||||
def console
|
||||
desc "console", "Boots up the Padrino application irb console (alternatively use 'c')."
|
||||
map "c" => :console
|
||||
def console(*args)
|
||||
prepare :console
|
||||
require File.expand_path("../../version", __FILE__)
|
||||
ARGV.clear
|
||||
|
@ -68,12 +68,8 @@ module Padrino
|
|||
IRB.start
|
||||
end
|
||||
|
||||
desc "c", "Boots up the Padrino application irb console"
|
||||
def c(*args)
|
||||
invoke(:console, args)
|
||||
end
|
||||
|
||||
desc "generate", "Executes the Padrino generator with given options."
|
||||
desc "generate", "Executes the Padrino generator with given options (alternatively use 'gen' or 'g')."
|
||||
map ["gen", "g"] => :generate
|
||||
def generate(*args)
|
||||
# Build Padrino g as an alias of padrino-gen
|
||||
begin
|
||||
|
@ -90,23 +86,30 @@ module Padrino
|
|||
end
|
||||
end
|
||||
|
||||
desc "g", "Executes the Padrino generator with given options."
|
||||
def g(*args)
|
||||
invoke(:generate, args)
|
||||
end
|
||||
|
||||
desc "gen", "Executes the Padrino generator with given options."
|
||||
def gen(*args)
|
||||
invoke(:generate, args)
|
||||
end
|
||||
|
||||
desc "version", "Show current Padrino Version"
|
||||
map "-v" => :version, "--version" => :version
|
||||
desc "version", "Show current Padrino version."
|
||||
map ["-v", "--version"] => :version
|
||||
def version
|
||||
require 'padrino-core/version'
|
||||
puts "Padrino v. #{Padrino.version}"
|
||||
end
|
||||
|
||||
desc "runner", "Run a piece of code in the Padrino application environment (alternatively use 'run' or 'r')."
|
||||
map ["run", "r"] => :runner
|
||||
def runner(*args)
|
||||
prepare :runner
|
||||
|
||||
code_or_file = args.shift
|
||||
abort "Please specify code or file" if code_or_file.nil?
|
||||
|
||||
require File.expand_path('config/boot.rb')
|
||||
|
||||
if File.exist?(code_or_file)
|
||||
eval(File.read(code_or_file), nil, code_or_file)
|
||||
else
|
||||
eval(code_or_file)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def prepare(task)
|
||||
if options.help?
|
|
@ -0,0 +1,47 @@
|
|||
require File.expand_path('../../tasks', __FILE__)
|
||||
require 'rake'
|
||||
require 'rake/dsl_definition'
|
||||
require 'thor'
|
||||
require 'securerandom' unless defined?(SecureRandom)
|
||||
require 'padrino-gen'
|
||||
|
||||
module PadrinoTasks
|
||||
def self.init(init=false)
|
||||
$LOAD_PATH.unshift(File.expand_path("lib")) # Adds "lib" to the load path
|
||||
Padrino::Tasks.files.flatten.uniq.each { |rakefile| Rake.application.add_import(rakefile) rescue puts "<= Failed load #{ext}" }
|
||||
load(File.expand_path('../rake_tasks.rb', __FILE__)) # Load default rake tasks
|
||||
Rake.application.load_imports
|
||||
end
|
||||
|
||||
def self.use(task)
|
||||
tasks << task
|
||||
end
|
||||
|
||||
def self.tasks
|
||||
@tasks ||= []
|
||||
end
|
||||
|
||||
def self.load?(task, constant_present)
|
||||
if constant_present && !PadrinoTasks.tasks.include?(task)
|
||||
warn <<-WARNING.undent
|
||||
Loading #{task} tasks automatically.
|
||||
This functionality will be disabled in future versions. Please put
|
||||
|
||||
PadrinoTasks.use(#{task.inspect})
|
||||
PadrinoTasks.init
|
||||
|
||||
and remove
|
||||
|
||||
require File.expand_path('../config/boot.rb', __FILE__)
|
||||
|
||||
in you Rakefile instead.
|
||||
WARNING
|
||||
end
|
||||
|
||||
constant_present || PadrinoTasks.tasks.include?(task)
|
||||
end
|
||||
end
|
||||
|
||||
def shell
|
||||
@_shell ||= Thor::Base.shell.new
|
||||
end
|
|
@ -1,11 +1,17 @@
|
|||
# Load rake tasks from common rake task definition locations
|
||||
Dir["lib/tasks/**/*.rake"].
|
||||
concat(Dir["tasks/**/*.rake"]).
|
||||
concat(Dir["{test,spec}/*.rake"]).each { |rake| load(rake) }
|
||||
Dir["{lib/tasks/**,tasks/**,test,spec}/*.rake"].each do |file|
|
||||
begin
|
||||
load(file)
|
||||
rescue LoadError => e
|
||||
warn "#{file}: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
# Loads the Padrino applications mounted within the project
|
||||
# setting up the required environment for Padrino
|
||||
task :environment do
|
||||
require File.expand_path('config/boot.rb', Rake.application.original_dir)
|
||||
|
||||
Padrino.mounted_apps.each do |app|
|
||||
app.app_obj.setup_application!
|
||||
end
|
||||
|
@ -46,14 +52,3 @@ namespace :routes do
|
|||
list_app_routes(app, args) if app
|
||||
end
|
||||
end
|
||||
|
||||
desc "Generate the Rakefile"
|
||||
task :gen do
|
||||
File.open(Padrino.root("Rakefile"), "w") do |file|
|
||||
file.puts <<-RUBY.gsub(/^ {6}/, '')
|
||||
require File.expand_path('../config/boot.rb', __FILE__)
|
||||
require 'padrino-core/cli/rake'
|
||||
PadrinoTasks.init
|
||||
RUBY
|
||||
end
|
||||
end
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
@ -60,6 +60,8 @@ module Padrino
|
|||
#
|
||||
def load!
|
||||
return false if loaded?
|
||||
t = Time.now
|
||||
|
||||
@_called_from = first_caller
|
||||
Padrino.set_encoding
|
||||
Padrino.set_load_paths(*load_paths) # We set the padrino load paths
|
||||
|
@ -71,6 +73,8 @@ module Padrino
|
|||
Padrino.after_load.each(&:call) # Run after hooks
|
||||
Padrino::Reloader.run!
|
||||
Thread.current[:padrino_loaded] = true
|
||||
|
||||
Padrino.logger.devel "Loaded Padrino in #{Time.now - t} seconds"
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -162,10 +166,8 @@ module Padrino
|
|||
begin
|
||||
Padrino::Reloader.safe_load(file, options.dup)
|
||||
files.delete(file)
|
||||
rescue LoadError => e
|
||||
errors << e
|
||||
failed << file
|
||||
rescue NameError => e
|
||||
rescue NameError, LoadError => e
|
||||
Padrino.logger.devel "Problem while loading #{file}: #{e.to_s}"
|
||||
errors << e
|
||||
failed << file
|
||||
rescue Exception => e
|
||||
|
@ -190,11 +192,7 @@ module Padrino
|
|||
# Padrino.dependency_paths << "#{Padrino.root}/uploaders/*.rb"
|
||||
#
|
||||
def dependency_paths
|
||||
@_dependency_paths_was = [
|
||||
"#{root}/config/database.rb", "#{root}/lib/**/*.rb", "#{root}/shared/lib/**/*.rb",
|
||||
"#{root}/models/**/*.rb", "#{root}/shared/models/**/*.rb", "#{root}/config/apps.rb"
|
||||
]
|
||||
@_dependency_paths ||= @_dependency_paths_was
|
||||
@_dependency_paths ||= (dependency_paths_was + Array(module_paths))
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -207,5 +205,21 @@ module Padrino
|
|||
$:.concat(paths); load_paths.concat(paths)
|
||||
$:.uniq!; load_paths.uniq!
|
||||
end
|
||||
|
||||
private
|
||||
def module_paths
|
||||
Padrino.modules.map(&:dependency_paths).flatten!
|
||||
end
|
||||
|
||||
def dependency_paths_was
|
||||
[
|
||||
"#{root}/config/database.rb",
|
||||
"#{root}/lib/**/*.rb",
|
||||
"#{root}/shared/lib/**/*.rb",
|
||||
"#{root}/models/**/*.rb",
|
||||
"#{root}/shared/models/**/*.rb",
|
||||
"#{root}/config/apps.rb"
|
||||
]
|
||||
end
|
||||
end # self
|
||||
end # Padrino
|
|
@ -5,8 +5,8 @@ de:
|
|||
# Wenn keine Formate angegeben werden, wird "default" benutzt.
|
||||
# Du kannst auch weitere Formate hinzufügen, wenn Du möchtest.
|
||||
default: "&d.&m.%Y"
|
||||
short: "%b %d"
|
||||
long: "%B %d, %Y"
|
||||
short: "%d. %b"
|
||||
long: "%d. %B %Y"
|
||||
only_day: "%e"
|
||||
|
||||
day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag]
|
||||
|
@ -20,9 +20,9 @@ de:
|
|||
|
||||
time:
|
||||
formats:
|
||||
default: "%a, %d %b %Y %H:%M:%S %z"
|
||||
short: "%d %b %H:%M"
|
||||
long: "%B %d, %Y %H:%M"
|
||||
default: "%a, %d. %b %Y %H:%M:%S %z"
|
||||
short: "%d. %b %H:%M"
|
||||
long: "%d. %B %Y %H:%M"
|
||||
am: "am"
|
||||
pm: "pm"
|
||||
|
||||
|
@ -31,4 +31,4 @@ de:
|
|||
array:
|
||||
words_connector: ", "
|
||||
two_words_connector: " und "
|
||||
last_word_connector: ", und "
|
||||
last_word_connector: " und "
|
|
@ -12,7 +12,7 @@ fr:
|
|||
day_names: [Dimanche, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi]
|
||||
abbr_day_names: [Lun, Mar, Mer, Jeu, Ven, Sam, Dim]
|
||||
month_names: [~, Janvier, Février, Mars, Avril, Mai, Juin, Juillet, Août, Septembre, Octobre, Novembre, Décembre]
|
||||
abbr_month_names: [~, Jan, Fev, Mar, Avr, Mai, Jui, Jui, Aou, Sep, Oct, Nov, Dec]
|
||||
abbr_month_names: [~, Jan, Fev, Mar, Avr, Mai, Jun, Jul, Aou, Sep, Oct, Nov, Dec]
|
||||
order:
|
||||
- day
|
||||
- month
|
|
@ -12,7 +12,7 @@ ru:
|
|||
day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота]
|
||||
abbr_day_names: [Вс, Пн, Вт, Ср, Чт, Пт, Сб]
|
||||
month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь]
|
||||
abbr_month_names: [~, Янв, Феб, Мар, Апр, Май, Июн, Июл, Авг, Сен, Окт, Ноя, Дек]
|
||||
abbr_month_names: [~, Янв, Фев, Мар, Апр, Май, Июн, Июл, Авг, Сен, Окт, Ноя, Дек]
|
||||
order:
|
||||
- year
|
||||
- month
|
|
@ -4,15 +4,15 @@ zh_cn:
|
|||
# Use the strftime parameters for formats.
|
||||
# When no format has been given, it uses default.
|
||||
# You can provide other formats here if you like!
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b%d日"
|
||||
long: "%Y年%b%d日"
|
||||
default: "%Y 年 %m 月 %d 日"
|
||||
short: "%b 月 %d 日"
|
||||
long: "公元 %Y 年 %B 月 %d 日"
|
||||
only_day: "%e"
|
||||
|
||||
day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
|
||||
abbr_day_names: [日, 一, 二, 三, 四, 五, 六]
|
||||
month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]
|
||||
abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
|
||||
month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
|
||||
abbr_month_names: [~, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
|
||||
order:
|
||||
- year
|
||||
- month
|
||||
|
@ -20,15 +20,15 @@ zh_cn:
|
|||
|
||||
time:
|
||||
formats:
|
||||
default: "%Y年%b%d日 %A %H:%M:%S %Z"
|
||||
short: "%b%d日 %H:%M"
|
||||
long: "%Y年%b%d日 %H:%M"
|
||||
default: "%Y 年 %b 月 %d 日 %H:%M:%S %z"
|
||||
short: "%d 月 %b 日 %H:%M"
|
||||
long: "%Y 年 %B 月 %d 日 %H 时 %M 分"
|
||||
am: "上午"
|
||||
pm: "下午"
|
||||
|
||||
# Used in array.to_sentence.
|
||||
support:
|
||||
array:
|
||||
words_connector: ", "
|
||||
two_words_connector: " 和 "
|
||||
last_word_connector: ", 和 "
|
||||
words_connector: ","
|
||||
two_words_connector: "和"
|
||||
last_word_connector: ",还有"
|
|
@ -13,8 +13,7 @@ module Padrino
|
|||
# logger.warn "bar"
|
||||
#
|
||||
def self.logger
|
||||
Padrino::Logger.setup! if Thread.current[:padrino_logger].nil?
|
||||
Thread.current[:padrino_logger]
|
||||
Padrino::Logger.logger
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -35,8 +34,7 @@ module Padrino
|
|||
# Padrino.logger = Buffered.new(STDOUT)
|
||||
#
|
||||
def self.logger=(value)
|
||||
value.extend(Padrino::Logger::Extensions) unless (Padrino::Logger::Extensions === value)
|
||||
Thread.current[:padrino_logger] = value
|
||||
Padrino::Logger.logger = value
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -95,7 +93,7 @@ module Padrino
|
|||
#
|
||||
# @example
|
||||
# logger.bench 'GET', started_at, '/blog/categories'
|
||||
# # => DEBUG - GET (0.056ms) - /blog/categories
|
||||
# # => DEBUG - GET (0.0056s) - /blog/categories
|
||||
#
|
||||
def bench(action, began_at, message, level=:debug, color=:yellow)
|
||||
@_pad ||= 8
|
||||
|
@ -103,7 +101,7 @@ module Padrino
|
|||
duration = Time.now - began_at
|
||||
color = :red if duration > 1
|
||||
action = colorize(action.to_s.upcase.rjust(@_pad), color)
|
||||
duration = colorize('%0.4fms' % duration, :bold, color)
|
||||
duration = colorize('%0.4fs' % duration, :bold, color)
|
||||
push "#{action} (#{duration}) #{message}", level
|
||||
end
|
||||
|
||||
|
@ -208,7 +206,6 @@ module Padrino
|
|||
end
|
||||
|
||||
include Extensions
|
||||
include Colorize
|
||||
|
||||
attr_accessor :level
|
||||
attr_accessor :auto_flush
|
||||
|
@ -216,8 +213,7 @@ module Padrino
|
|||
attr_reader :log
|
||||
attr_reader :init_args
|
||||
attr_accessor :log_static
|
||||
|
||||
@@mutex = {}
|
||||
attr_reader :colorize_logging
|
||||
|
||||
##
|
||||
# Configuration for a given environment, possible options are:
|
||||
|
@ -233,6 +229,7 @@ module Padrino
|
|||
# :format_datetime:: Format of datetime. Defaults to: "%d/%b/%Y %H:%M:%S"
|
||||
# :format_message:: Format of message. Defaults to: ""%s - - [%s] \"%s\"""
|
||||
# :log_static:: Whether or not to show log messages for static files. Defaults to: false
|
||||
# :colorize_logging:: Whether or not to colorize log messages. Defaults to: true
|
||||
#
|
||||
# @example
|
||||
# Padrino::Logger::Config[:development] = { :log_level => :debug, :stream => :to_file }
|
||||
|
@ -254,11 +251,22 @@ module Padrino
|
|||
#
|
||||
Config = {
|
||||
:production => { :log_level => :warn, :stream => :to_file },
|
||||
:development => { :log_level => :debug, :stream => :stdout, :format_datetime => ' ' },
|
||||
:development => { :log_level => :debug, :stream => :stdout, :format_datetime => '' },
|
||||
:test => { :log_level => :debug, :stream => :null }
|
||||
}
|
||||
Config.merge!(PADRINO_LOGGER) if PADRINO_LOGGER
|
||||
|
||||
@@mutex = Mutex.new
|
||||
def self.logger
|
||||
@_logger || setup!
|
||||
end
|
||||
|
||||
def self.logger=(logger)
|
||||
logger.extend(Padrino::Logger::Extensions)
|
||||
|
||||
@_logger = logger
|
||||
end
|
||||
|
||||
##
|
||||
# Setup a new logger
|
||||
#
|
||||
|
@ -266,25 +274,27 @@ module Padrino
|
|||
# A {Padrino::Logger} instance
|
||||
#
|
||||
def self.setup!
|
||||
config_level = (PADRINO_LOG_LEVEL || Padrino.env || :test).to_sym # need this for PADRINO_LOG_LEVEL
|
||||
config = Config[config_level]
|
||||
self.logger = begin
|
||||
config_level = (PADRINO_LOG_LEVEL || Padrino.env || :test).to_sym # need this for PADRINO_LOG_LEVEL
|
||||
config = Config[config_level]
|
||||
|
||||
unless config
|
||||
warn("No logging configuration for :#{config_level} found, falling back to :production")
|
||||
config = Config[:production]
|
||||
unless config
|
||||
warn("No logging configuration for :#{config_level} found, falling back to :production")
|
||||
config = Config[:production]
|
||||
end
|
||||
|
||||
stream = case config[:stream]
|
||||
when :to_file
|
||||
FileUtils.mkdir_p(Padrino.root('log')) unless File.exists?(Padrino.root('log'))
|
||||
File.new(Padrino.root('log', "#{Padrino.env}.log"), 'a+')
|
||||
when :null then StringIO.new
|
||||
when :stdout then $stdout
|
||||
when :stderr then $stderr
|
||||
else config[:stream] # return itself, probabilly is a custom stream.
|
||||
end
|
||||
|
||||
Padrino::Logger.new(config.merge(:stream => stream))
|
||||
end
|
||||
|
||||
stream = case config[:stream]
|
||||
when :to_file
|
||||
FileUtils.mkdir_p(Padrino.root('log')) unless File.exists?(Padrino.root('log'))
|
||||
File.new(Padrino.root('log', "#{Padrino.env}.log"), 'a+')
|
||||
when :null then StringIO.new
|
||||
when :stdout then $stdout
|
||||
when :stderr then $stderr
|
||||
else config[:stream] # return itself, probabilly is a custom stream.
|
||||
end
|
||||
|
||||
Thread.current[:padrino_logger] = Padrino::Logger.new(config.merge(:stream => stream))
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -311,16 +321,20 @@ module Padrino
|
|||
# @option options [Symbol] :log_static (false)
|
||||
# Whether or not to show log messages for static files.
|
||||
#
|
||||
# @option options [Symbol] :colorize_logging (true)
|
||||
# Whether or not to colorize log messages. Defaults to: true
|
||||
#
|
||||
def initialize(options={})
|
||||
@buffer = []
|
||||
@auto_flush = options.has_key?(:auto_flush) ? options[:auto_flush] : true
|
||||
@level = options[:log_level] ? Padrino::Logger::Levels[options[:log_level]] : Padrino::Logger::Levels[:debug]
|
||||
@log = options[:stream] || $stdout
|
||||
@log.sync = true
|
||||
@mutex = @@mutex[@log] ||= Mutex.new
|
||||
@format_datetime = options[:format_datetime] || "%d/%b/%Y %H:%M:%S"
|
||||
@format_message = options[:format_message] || "%s -%s%s"
|
||||
@format_message = options[:format_message] || "%s - %s %s"
|
||||
@log_static = options.has_key?(:log_static) ? options[:log_static] : false
|
||||
@colorize_logging = options.has_key?(:colorize_logging) ? options[:colorize_logging] : true
|
||||
colorize! if @colorize_logging
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -328,8 +342,9 @@ module Padrino
|
|||
#
|
||||
def flush
|
||||
return unless @buffer.size > 0
|
||||
@mutex.synchronize do
|
||||
@log.write(@buffer.slice!(0..-1).join(''))
|
||||
@@mutex.synchronize do
|
||||
@log.write(@buffer.join(''))
|
||||
@buffer.clear
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -360,7 +375,9 @@ module Padrino
|
|||
#
|
||||
def <<(message = nil)
|
||||
message << "\n" unless message[-1] == ?\n
|
||||
@buffer << message
|
||||
@@mutex.synchronize {
|
||||
@buffer << message
|
||||
}
|
||||
flush if @auto_flush
|
||||
message
|
||||
end
|
||||
|
@ -425,4 +442,3 @@ module Kernel # @private
|
|||
Padrino.logger
|
||||
end
|
||||
end # Kernel
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
module Padrino
|
||||
module Module
|
||||
attr_accessor :root
|
||||
|
||||
##
|
||||
# Register this module as being loaded from a gem. This automatically
|
||||
# sets the root and therefore the dependency paths correctly.
|
||||
#
|
||||
# @param [String] name
|
||||
# The name of the gem. Has to be the name as stated in the gemspec.
|
||||
#
|
||||
# @returns the gems root.
|
||||
def gem!(name)
|
||||
self.root = Padrino.gem(name, self)
|
||||
end
|
||||
|
||||
##
|
||||
# Helper method for file references within a Padrino module.
|
||||
#
|
||||
# @param [Array<String>] args
|
||||
# The directories to join to {Module.root}.
|
||||
#
|
||||
# @return [String]
|
||||
# The absolute path.
|
||||
#
|
||||
# @example
|
||||
# module MyModule
|
||||
# extend Padrino::Module
|
||||
# gem! 'my_gem'
|
||||
# end
|
||||
# Module.root!
|
||||
def root(*args)
|
||||
File.expand_path(File.join(@root, *args))
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the list of path globs to load as dependencies
|
||||
# Appends custom dependency patterns to the be loaded for Padrino.
|
||||
#
|
||||
# @return [Array<String>]
|
||||
# The dependency paths.
|
||||
#
|
||||
# @example
|
||||
# module MyModule
|
||||
# extend Padrino::Module
|
||||
# gem! 'my_gem'
|
||||
# end
|
||||
#
|
||||
# Module.dependency_paths << "#{MyModule.root}/uploaders/*.rb"
|
||||
#
|
||||
def dependency_paths
|
||||
[
|
||||
"#{root}/lib/**/*.rb", "#{root}/shared/lib/**/*.rb",
|
||||
"#{root}/models/**/*.rb", "#{root}/shared/models/**/*.rb"
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,10 +22,12 @@ module Padrino
|
|||
# @option options [Symbol] :app_file (Automatically detected)
|
||||
# @option options [Symbol] :app_obj (Detected)
|
||||
# @option options [Symbol] :app_root (Directory of :app_file)
|
||||
# @option options [Symbol] :gem The gem to load the app from (Detected from name)
|
||||
#
|
||||
def initialize(name, options={})
|
||||
@name = name.to_s
|
||||
@app_class = options[:app_class] || @name.camelize
|
||||
@gem = options[:gem] || @app_class.split("::").first.underscore
|
||||
@app_file = options[:app_file] || locate_app_file
|
||||
@app_obj = options[:app_obj] || app_constant || locate_app_object
|
||||
ensure_app_file! || ensure_app_object!
|
||||
|
@ -104,11 +106,12 @@ module Padrino
|
|||
#
|
||||
def named_routes
|
||||
app_obj.routes.map { |route|
|
||||
name_array = "(#{route.named.to_s.split("_").map { |piece| %Q[:#{piece}] }.join(", ")})"
|
||||
request_method = route.conditions[:request_method][0]
|
||||
full_path = File.join(uri_root, route.original_path)
|
||||
next if route.named.blank? || request_method == 'HEAD'
|
||||
OpenStruct.new(:verb => request_method, :identifier => route.named, :name => name_array, :path => full_path)
|
||||
name_array = "(#{route.name.to_s.split("_").map { |piece| %Q[:#{piece}] }.join(", ")})"
|
||||
request_method = route.request_methods.first
|
||||
next if route.name.blank? || request_method == 'HEAD'
|
||||
original_path = route.original_path.is_a?(Regexp) ? route.original_path.inspect : route.original_path
|
||||
full_path = File.join(uri_root, original_path)
|
||||
OpenStruct.new(:verb => request_method, :identifier => route.name, :name => name_array, :path => full_path)
|
||||
}.compact
|
||||
end
|
||||
|
||||
|
@ -158,6 +161,13 @@ module Padrino
|
|||
candidates << app_constant.app_file if app_constant.respond_to?(:app_file) && File.exist?(app_constant.app_file.to_s)
|
||||
candidates << Padrino.first_caller if File.identical?(Padrino.first_caller.to_s, Padrino.called_from.to_s)
|
||||
candidates << Padrino.mounted_root(name.downcase, "app.rb")
|
||||
simple_name = name.split("::").last.downcase
|
||||
mod_name = name.split("::")[0..-2].join("::")
|
||||
Padrino.modules.each do |mod|
|
||||
if mod.name == mod_name
|
||||
candidates << mod.root(simple_name, "app.rb")
|
||||
end
|
||||
end
|
||||
candidates << Padrino.root("app", "app.rb")
|
||||
candidates.find { |candidate| File.exist?(candidate) }
|
||||
end
|
|
@ -33,7 +33,7 @@ module Padrino
|
|||
# Specified constants can be excluded from the code unloading process.
|
||||
#
|
||||
def exclude_constants
|
||||
@_exclude_constants ||= []
|
||||
@_exclude_constants ||= Set.new
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -41,7 +41,7 @@ module Padrino
|
|||
# Default included constants are: [none]
|
||||
#
|
||||
def include_constants
|
||||
@_include_constants ||= []
|
||||
@_include_constants ||= Set.new
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -51,7 +51,7 @@ module Padrino
|
|||
# Detect changed files
|
||||
rotation do |file, mtime|
|
||||
# Retrive the last modified time
|
||||
new_file = MTIMES[file].nil?
|
||||
new_file = MTIMES[file].nil?
|
||||
previous_mtime = MTIMES[file] ||= mtime
|
||||
logger.devel "Detected a new file #{file}" if new_file
|
||||
# We skip to next file if it is not new and not modified
|
||||
|
@ -74,15 +74,9 @@ module Padrino
|
|||
# Remove files and classes loaded with stat
|
||||
#
|
||||
def clear!
|
||||
MTIMES.clear
|
||||
LOADED_CLASSES.each do |file, klasses|
|
||||
klasses.each { |klass| remove_constant(klass) }
|
||||
LOADED_CLASSES.delete(file)
|
||||
end
|
||||
LOADED_FILES.each do |file, dependencies|
|
||||
dependencies.each { |dependency| $LOADED_FEATURES.delete(dependency) }
|
||||
$LOADED_FEATURES.delete(file)
|
||||
end
|
||||
clear_modification_times
|
||||
clear_loaded_classes
|
||||
clear_loaded_files_and_features
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -103,67 +97,59 @@ module Padrino
|
|||
# We lock dependencies sets to prevent reloading of protected constants
|
||||
#
|
||||
def lock!
|
||||
klasses = ObjectSpace.classes.map { |klass| klass._orig_klass_name.split('::')[0] }.uniq
|
||||
klasses = ObjectSpace.classes do |klass|
|
||||
klass._orig_klass_name.split('::')[0]
|
||||
end
|
||||
|
||||
klasses = klasses | Padrino.mounted_apps.map { |app| app.app_class }
|
||||
Padrino::Reloader.exclude_constants.concat(klasses)
|
||||
Padrino::Reloader.exclude_constants.merge(klasses)
|
||||
end
|
||||
|
||||
##
|
||||
# A safe Kernel::require which issues the necessary hooks depending on results
|
||||
#
|
||||
def safe_load(file, options={})
|
||||
began_at = Time.now
|
||||
force, file = options[:force], figure_path(file)
|
||||
began_at = Time.now
|
||||
force = options[:force]
|
||||
file = figure_path(file)
|
||||
reload = should_reload?(file)
|
||||
m_time = modification_time(file)
|
||||
|
||||
# Check if file was changed or if force a reload
|
||||
reload = MTIMES[file] && File.mtime(file) > MTIMES[file]
|
||||
return if !force && !reload && MTIMES[file]
|
||||
return if !force && m_time && !reload
|
||||
|
||||
# Removes all classes declared in the specified file
|
||||
if klasses = LOADED_CLASSES.delete(file)
|
||||
klasses.each { |klass| remove_constant(klass) }
|
||||
end
|
||||
|
||||
# Remove all loaded fatures with our file
|
||||
if features = LOADED_FILES[file]
|
||||
features.each { |feature| $LOADED_FEATURES.delete(feature) }
|
||||
end
|
||||
remove_loaded_file_classes(file)
|
||||
remove_loaded_file_features(file)
|
||||
|
||||
# Duplicate objects and loaded features before load file
|
||||
klasses = ObjectSpace.classes.dup
|
||||
files = $LOADED_FEATURES.dup
|
||||
klasses = ObjectSpace.classes
|
||||
files = Set.new($LOADED_FEATURES.dup)
|
||||
|
||||
# Now we can reload dependencies of our file
|
||||
if features = LOADED_FILES.delete(file)
|
||||
features.each { |feature| safe_load(feature, :force => true) }
|
||||
end
|
||||
reload_deps_of_file(file)
|
||||
|
||||
# And finally load the specified file
|
||||
begin
|
||||
logger.devel :loading, began_at, file if !reload
|
||||
logger.debug :reload, began_at, file if reload
|
||||
$LOADED_FEATURES.delete(file)
|
||||
verbosity_was, $-v = $-v, nil
|
||||
|
||||
$LOADED_FEATURES.delete(file) if files.include?(file)
|
||||
Padrino::Utils.silence_output
|
||||
loaded = false
|
||||
require(file)
|
||||
loaded = true
|
||||
MTIMES[file] = File.mtime(file)
|
||||
update_modification_time(file)
|
||||
rescue SyntaxError => e
|
||||
logger.error "Cannot require #{file} due to a syntax error: #{e.message}"
|
||||
ensure
|
||||
$-v = verbosity_was
|
||||
new_constants = (ObjectSpace.classes - klasses).uniq
|
||||
Padrino::Utils.unsilence_output
|
||||
new_constants = ObjectSpace.new_classes(klasses)
|
||||
if loaded
|
||||
# Store the file details
|
||||
LOADED_CLASSES[file] = new_constants
|
||||
LOADED_FILES[file] = ($LOADED_FEATURES - files - [file]).uniq
|
||||
# Track only features in our Padrino.root
|
||||
LOADED_FILES[file].delete_if { |feature| !in_root?(feature) }
|
||||
process_loaded_file(:file => file,
|
||||
:constants => new_constants,
|
||||
:files => files)
|
||||
else
|
||||
logger.devel "Failed to load #{file}; removing partially defined constants"
|
||||
new_constants.each { |klass| remove_constant(klass) }
|
||||
unload_constants(new_constants)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -183,8 +169,8 @@ module Padrino
|
|||
# Removes the specified class and constant.
|
||||
#
|
||||
def remove_constant(const)
|
||||
return if exclude_constants.compact.uniq.any? { |c| const._orig_klass_name.index(c) == 0 } &&
|
||||
!include_constants.compact.uniq.any? { |c| const._orig_klass_name.index(c) == 0 }
|
||||
return if exclude_constants.any? { |c| const._orig_klass_name.index(c) == 0 } &&
|
||||
!include_constants.any? { |c| const._orig_klass_name.index(c) == 0 }
|
||||
begin
|
||||
parts = const.to_s.sub(/^::(Object)?/, 'Object::').split('::')
|
||||
object = parts.pop
|
||||
|
@ -195,6 +181,101 @@ module Padrino
|
|||
end
|
||||
|
||||
private
|
||||
|
||||
###
|
||||
# Clear instance variables that keep track of
|
||||
# loaded features/files/mtimes
|
||||
#
|
||||
def clear_modification_times
|
||||
MTIMES.clear
|
||||
end
|
||||
|
||||
def clear_loaded_classes
|
||||
LOADED_CLASSES.each do |file, klasses|
|
||||
klasses.each { |klass| remove_constant(klass) }
|
||||
LOADED_CLASSES.delete(file)
|
||||
end
|
||||
end
|
||||
|
||||
def clear_loaded_files_and_features
|
||||
LOADED_FILES.each do |file, dependencies|
|
||||
dependencies.each { |dependency| $LOADED_FEATURES.delete(dependency) }
|
||||
$LOADED_FEATURES.delete(file)
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
# Macro for mtime query
|
||||
#
|
||||
def modification_time(file)
|
||||
MTIMES[file]
|
||||
end
|
||||
|
||||
###
|
||||
# Macro for mtime update
|
||||
#
|
||||
def update_modification_time(file)
|
||||
MTIMES[file] = File.mtime(file)
|
||||
end
|
||||
|
||||
###
|
||||
# Tracks loaded file features/classes/constants
|
||||
#
|
||||
def process_loaded_file(*args)
|
||||
options = args.extract_options!
|
||||
new_constants = options[:constants]
|
||||
files = options[:files]
|
||||
file = options[:file]
|
||||
|
||||
# Store the file details
|
||||
LOADED_CLASSES[file] = new_constants
|
||||
LOADED_FILES[file] = Set.new($LOADED_FEATURES) - files - [file]
|
||||
|
||||
# Track only features in our Padrino.root
|
||||
LOADED_FILES[file].delete_if { |feature| !in_root?(feature) }
|
||||
end
|
||||
|
||||
###
|
||||
# Unloads all constants in new_constants
|
||||
#
|
||||
def unload_constants(new_constants)
|
||||
new_constants.each { |klass| remove_constant(klass) }
|
||||
end
|
||||
|
||||
###
|
||||
# Safe load dependencies of a file
|
||||
#
|
||||
def reload_deps_of_file(file)
|
||||
if features = LOADED_FILES.delete(file)
|
||||
features.each { |feature| safe_load(feature, :force => true) }
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Check if file was changed or if force a reload
|
||||
#
|
||||
def should_reload?(file)
|
||||
MTIMES[file] && File.mtime(file) > MTIMES[file]
|
||||
end
|
||||
|
||||
##
|
||||
# Removes all classes declared in the specified file
|
||||
#
|
||||
def remove_loaded_file_classes(file)
|
||||
if klasses = LOADED_CLASSES.delete(file)
|
||||
klasses.each { |klass| remove_constant(klass) }
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Remove all loaded fatures with our file
|
||||
#
|
||||
def remove_loaded_file_features(file)
|
||||
if features = LOADED_FILES[file]
|
||||
features.each { |feature| $LOADED_FEATURES.delete(feature) }
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Return the mounted_apps providing the app location
|
||||
# Can be an array because in one app.rb we can define multiple Padrino::Appplications
|
||||
|
@ -218,15 +299,21 @@ module Padrino
|
|||
# and monitors them for any changes.
|
||||
#
|
||||
def rotation
|
||||
files = Padrino.load_paths.map { |path| Dir["#{path}/**/*.rb"] }.flatten
|
||||
files = files | Padrino.mounted_apps.map { |app| app.app_file }
|
||||
files = files | Padrino.mounted_apps.map { |app| app.app_obj.dependencies }.flatten
|
||||
files.uniq.map do |file|
|
||||
files_for_rotation.uniq.map do |file|
|
||||
file = File.expand_path(file)
|
||||
next if Padrino::Reloader.exclude.any? { |base| file.index(base) == 0 } || !File.exist?(file)
|
||||
yield file, File.mtime(file)
|
||||
end.compact
|
||||
end
|
||||
|
||||
##
|
||||
# Creates an array of paths for use in #rotation
|
||||
#
|
||||
def files_for_rotation
|
||||
files = Padrino.load_paths.map { |path| Dir["#{path}/**/*.rb"] }.flatten
|
||||
files = files | Padrino.mounted_apps.map { |app| app.app_file }
|
||||
files = files | Padrino.mounted_apps.map { |app| app.app_obj.dependencies }.flatten
|
||||
end
|
||||
end # self
|
||||
|
||||
##
|
|
@ -4,8 +4,8 @@ module Padrino
|
|||
# thin, mongrel, or webrick in that order.
|
||||
#
|
||||
# @example
|
||||
# Padrino.run! # with these defaults => host: "localhost", port: "3000", adapter: the first found
|
||||
# Padrino.run!("localhost", "4000", "mongrel") # use => host: "0.0.0.0", port: "3000", adapter: "mongrel"
|
||||
# Padrino.run! # with these defaults => host: "127.0.0.1", port: "3000", adapter: the first found
|
||||
# Padrino.run!("0.0.0.0", "4000", "mongrel") # use => host: "0.0.0.0", port: "4000", adapter: "mongrel"
|
||||
#
|
||||
def self.run!(options={})
|
||||
Padrino.load!
|
||||
|
@ -17,17 +17,17 @@ module Padrino
|
|||
#
|
||||
class Server < Rack::Server
|
||||
# Server Handlers
|
||||
Handlers = [:thin, :mongrel, :trinidad, :webrick]
|
||||
Handlers = [:thin, :puma, :mongrel, :trinidad, :webrick]
|
||||
|
||||
# Starts the application on the available server with specified options.
|
||||
def self.start(app, opts={})
|
||||
options = {}.merge(opts) # We use a standard hash instead of Thor::CoreExt::HashWithIndifferentAccess
|
||||
options.symbolize_keys!
|
||||
options[:Host] = options.delete(:host) || '0.0.0.0'
|
||||
options[:Host] = options.delete(:host) || '127.0.0.1'
|
||||
options[:Port] = options.delete(:port) || 3000
|
||||
options[:AccessLog] = []
|
||||
if options[:daemonize]
|
||||
options[:pid] = options[:pid].blank? ? File.expand_path('tmp/pids/server.pid') : opts[:pid]
|
||||
options[:pid] = File.expand_path(options[:pid].blank? ? 'tmp/pids/server.pid' : opts[:pid])
|
||||
FileUtils.mkdir_p(File.dirname(options[:pid]))
|
||||
end
|
||||
options[:server] = detect_rack_handler if options[:server].blank?
|
|
@ -9,6 +9,7 @@ require 'active_support/core_ext/object/blank' # present?
|
|||
require 'active_support/core_ext/array/extract_options' # extract_options
|
||||
require 'active_support/inflector/methods' # constantize
|
||||
require 'active_support/inflector/inflections' # pluralize
|
||||
require 'active_support/core_ext/string/output_safety' # SafeBuffer and html_safe
|
||||
require 'active_support/inflections' # load default inflections
|
||||
require 'yaml' unless defined?(YAML) # load yaml for i18n
|
||||
require 'win32console' if RUBY_PLATFORM =~ /(win|m)32/ # ruby color support for win
|
||||
|
@ -110,13 +111,49 @@ end
|
|||
|
||||
module ObjectSpace
|
||||
class << self
|
||||
##
|
||||
# Returns all the classes in the object space.
|
||||
def classes
|
||||
ObjectSpace.each_object(Module).select do |klass|
|
||||
# Why? Ruby, when you remove a costant dosen't remove it from
|
||||
# rb_tables, this mean that here we can find classes that was
|
||||
# removed.
|
||||
klass.name rescue false
|
||||
# Optionally, a block can be passed, for example the following code
|
||||
# would return the classes that start with the character "A":
|
||||
#
|
||||
# ObjectSpace.classes do |klass|
|
||||
# if klass.to_s[0] == "A"
|
||||
# klass
|
||||
# end
|
||||
# end
|
||||
#
|
||||
def classes(&block)
|
||||
rs = Set.new
|
||||
|
||||
ObjectSpace.each_object(Class).each do |klass|
|
||||
if block
|
||||
if r = block.call(klass)
|
||||
# add the returned value if the block returns something
|
||||
rs << r
|
||||
end
|
||||
else
|
||||
rs << klass
|
||||
end
|
||||
end
|
||||
|
||||
rs
|
||||
end
|
||||
|
||||
##
|
||||
# Returns a list of existing classes that are not included in "snapshot"
|
||||
# This method is useful to get the list of new classes that were loaded
|
||||
# after an event like requiring a file.
|
||||
# Usage:
|
||||
#
|
||||
# snapshot = ObjectSpace.classes
|
||||
# # require a file
|
||||
# ObjectSpace.new_classes(snapshot)
|
||||
#
|
||||
def new_classes(snapshot)
|
||||
self.classes do |klass|
|
||||
if !snapshot.include?(klass)
|
||||
klass
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -205,3 +242,19 @@ I18n.load_path += Dir["#{File.dirname(__FILE__)}/locale/*.yml"] if defined?(I18n
|
|||
# Used to determine if this file has already been required
|
||||
#
|
||||
module SupportLite; end
|
||||
|
||||
module Padrino
|
||||
class Utils
|
||||
###
|
||||
# Silences output verbosity level so load
|
||||
# errors are not visible when safe_load(file)
|
||||
#
|
||||
def self.silence_output
|
||||
@verbosity_level, $-v = $-v, nil
|
||||
end
|
||||
|
||||
def self.unsilence_output
|
||||
$-v = @verbosity_level
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,7 +6,7 @@
|
|||
#
|
||||
module Padrino
|
||||
# The version constant for the current version of Padrino.
|
||||
VERSION = '0.10.7' unless defined?(Padrino::VERSION)
|
||||
VERSION = '0.11.2' unless defined?(Padrino::VERSION)
|
||||
|
||||
#
|
||||
# The current Padrino version.
|
|
@ -30,9 +30,14 @@ Gem::Specification.new do |s|
|
|||
# s.post_install_message << " as shown here:\e[0m https://gist.github.com/1d36a35794dbbd664ea4"
|
||||
# s.post_install_message << "\n\e[32m" + ("*" * 20) + "\n\e[0m"
|
||||
|
||||
s.add_dependency("tilt", "~> 1.3.0")
|
||||
s.add_dependency("sinatra", "~> 1.3.1")
|
||||
s.add_dependency("http_router", "~> 0.10.2")
|
||||
s.add_dependency("thor", "~> 0.15.2")
|
||||
s.add_dependency("activesupport", "~> 3.2.0")
|
||||
s.add_dependency("tilt", "~> 1.3.7")
|
||||
if ENV["SINATRA_EDGE"]
|
||||
s.add_dependency("sinatra")
|
||||
else
|
||||
s.add_dependency("sinatra", "~> 1.4.2")
|
||||
end
|
||||
s.add_dependency("http_router", "~> 0.11.0")
|
||||
s.add_dependency("thor", "~> 0.17.0")
|
||||
s.add_dependency("activesupport", ">= 3.1.0")
|
||||
s.add_dependency("rack-protection", ">= 1.5.0")
|
||||
end
|
4
middleman-core/lib/vendored-middleman-deps/padrino-core-0.11.2/test/fixtures/app_gem/Gemfile
vendored
Normal file
4
middleman-core/lib/vendored-middleman-deps/padrino-core-0.11.2/test/fixtures/app_gem/Gemfile
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in app_gem.gemspec
|
||||
gemspec
|
|
@ -0,0 +1,3 @@
|
|||
class AppGem::App < Padrino::Application
|
||||
set :version, AppGem::VERSION
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../lib/app_gem/version', __FILE__)
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.authors = ["Florian Gilcher"]
|
||||
gem.email = ["florian.gilcher@asquera.de"]
|
||||
gem.description = %q{TODO: Write a gem description}
|
||||
gem.summary = %q{TODO: Write a gem summary}
|
||||
gem.homepage = ""
|
||||
|
||||
gem.files = `git ls-files`.split($\)
|
||||
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
||||
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
||||
gem.name = "app_gem"
|
||||
gem.require_paths = ["app", "lib"]
|
||||
gem.version = AppGem::VERSION
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
require 'padrino'
|
||||
|
||||
module AppGem
|
||||
extend Padrino::Module
|
||||
|
||||
gem! 'app_gem'
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
module AppGem
|
||||
VERSION = "0.0.1"
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
gem 'minitest'
|
||||
require 'minitest/spec'
|
||||
require 'minitest/autorun'
|
||||
require 'mocha' # Load mocha after minitest
|
||||
require 'minitest/spec'
|
||||
require 'mocha/setup'
|
||||
|
||||
begin
|
||||
require 'ruby-debug'
|
|
@ -1,17 +1,13 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
||||
require 'haml'
|
||||
|
||||
class PadrinoPristine < Padrino::Application; end
|
||||
class PadrinoTestApp < Padrino::Application; end
|
||||
class PadrinoTestApp < Padrino::Application; end
|
||||
class PadrinoTestApp2 < Padrino::Application; end
|
||||
|
||||
describe "Application" do
|
||||
def setup
|
||||
Padrino.clear!
|
||||
end
|
||||
|
||||
def teardown
|
||||
remove_views
|
||||
end
|
||||
before { Padrino.clear! }
|
||||
after { remove_views }
|
||||
|
||||
context 'for application functionality' do
|
||||
|
||||
|
@ -19,24 +15,36 @@ describe "Application" do
|
|||
assert File.identical?(__FILE__, PadrinoPristine.app_file)
|
||||
assert_equal :padrino_pristine, PadrinoPristine.app_name
|
||||
assert_equal :test, PadrinoPristine.environment
|
||||
assert_equal Padrino.root("views"), PadrinoPristine.views
|
||||
assert PadrinoPristine.raise_errors
|
||||
assert_equal Padrino.root('views'), PadrinoPristine.views
|
||||
assert PadrinoPristine.raise_errors
|
||||
assert !PadrinoPristine.logging
|
||||
assert !PadrinoPristine.sessions
|
||||
assert !PadrinoPristine.dump_errors
|
||||
assert !PadrinoPristine.show_exceptions
|
||||
assert PadrinoPristine.raise_errors
|
||||
assert PadrinoPristine.raise_errors
|
||||
assert !Padrino.configure_apps
|
||||
end
|
||||
|
||||
should 'check haml options on production' do
|
||||
assert defined?(Haml), 'Haml not defined'
|
||||
assert_equal :test, PadrinoPristine.environment
|
||||
assert !PadrinoPristine.haml[:ugly]
|
||||
Padrino.stub :env, :production do
|
||||
PadrinoPristine.send :default_configuration!
|
||||
assert_equal :production, Padrino.env
|
||||
assert_equal :production, PadrinoPristine.environment
|
||||
assert PadrinoPristine.haml[:ugly]
|
||||
PadrinoPristine.environment = :test
|
||||
end
|
||||
end
|
||||
|
||||
should 'check padrino specific options' do
|
||||
assert !PadrinoPristine.instance_variable_get(:@_configured)
|
||||
PadrinoPristine.send(:setup_application!)
|
||||
assert_equal :padrino_pristine, PadrinoPristine.app_name
|
||||
assert_equal 'StandardFormBuilder', PadrinoPristine.default_builder
|
||||
assert PadrinoPristine.instance_variable_get(:@_configured)
|
||||
assert PadrinoPristine.instance_variable_get(:@_configured)
|
||||
assert !PadrinoPristine.reload?
|
||||
assert !PadrinoPristine.flash
|
||||
end
|
||||
|
||||
should 'set global project settings' do
|
||||
|
@ -48,18 +56,27 @@ describe "Application" do
|
|||
assert_equal PadrinoTestApp.session_secret, PadrinoTestApp2.session_secret
|
||||
end
|
||||
|
||||
should 'be able to configure_apps multiple times' do
|
||||
Padrino.configure_apps { set :foo1, "bar" }
|
||||
Padrino.configure_apps { set :foo1, "bam" }
|
||||
Padrino.configure_apps { set :foo2, "baz" }
|
||||
PadrinoTestApp.send(:default_configuration!)
|
||||
assert_equal "bam", PadrinoTestApp.settings.foo1, "should have foo1 assigned to bam"
|
||||
assert_equal "baz", PadrinoTestApp.settings.foo2, "should have foo2 assigned to baz"
|
||||
end
|
||||
|
||||
should "have shared sessions accessible in project" do
|
||||
Padrino.configure_apps { enable :sessions; set :session_secret, 'secret' }
|
||||
Padrino.mount("PadrinoTestApp").to("/write")
|
||||
Padrino.mount("PadrinoTestApp2").to("/read")
|
||||
PadrinoTestApp.tap { |app| app.send(:default_configuration!)
|
||||
app.get("/") { session[:foo] = "shared" } }
|
||||
PadrinoTestApp2.tap { |app| app.send(:default_configuration!)
|
||||
app.get("/") { session[:foo] } }
|
||||
browser = Rack::Test::Session.new(Rack::MockSession.new(Padrino.application))
|
||||
browser.get '/write'
|
||||
browser.get '/read'
|
||||
assert_equal 'shared', browser.last_response.body
|
||||
PadrinoTestApp.send :default_configuration!
|
||||
PadrinoTestApp.get('/') { session[:foo] = "shared" }
|
||||
PadrinoTestApp2.send(:default_configuration!)
|
||||
PadrinoTestApp2.get('/') { session[:foo] }
|
||||
@app = Padrino.application
|
||||
get '/write'
|
||||
get '/read'
|
||||
assert_equal 'shared', body
|
||||
end
|
||||
|
||||
# compare to: test_routing: allow global provides
|
|
@ -0,0 +1,80 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
||||
|
||||
describe "Application" do
|
||||
before { Padrino.clear! }
|
||||
after { remove_views }
|
||||
|
||||
context 'CSRF protection' do
|
||||
context "with CSRF protection on" do
|
||||
before do
|
||||
mock_app do
|
||||
enable :sessions
|
||||
enable :protect_from_csrf
|
||||
post('/'){ 'HI' }
|
||||
end
|
||||
end
|
||||
|
||||
should "not allow requests without tokens" do
|
||||
post "/"
|
||||
assert_equal 403, status
|
||||
end
|
||||
|
||||
should "allow requests with correct tokens" do
|
||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}
|
||||
assert_equal 200, status
|
||||
end
|
||||
|
||||
should "not allow requests with incorrect tokens" do
|
||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
|
||||
assert_equal 403, status
|
||||
end
|
||||
end
|
||||
|
||||
context "without CSRF protection on" do
|
||||
before do
|
||||
mock_app do
|
||||
enable :sessions
|
||||
disable :protect_from_csrf
|
||||
post('/'){ 'HI' }
|
||||
end
|
||||
end
|
||||
|
||||
should "allows requests without tokens" do
|
||||
post "/"
|
||||
assert_equal 200, status
|
||||
end
|
||||
|
||||
should "allow requests with correct tokens" do
|
||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}
|
||||
assert_equal 200, status
|
||||
end
|
||||
|
||||
should "allow requests with incorrect tokens" do
|
||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
|
||||
assert_equal 200, status
|
||||
end
|
||||
end
|
||||
|
||||
context "with optional CSRF protection" do
|
||||
before do
|
||||
mock_app do
|
||||
enable :sessions
|
||||
enable :protect_from_csrf
|
||||
set :allow_disabled_csrf, true
|
||||
post('/on') { 'HI' }
|
||||
post('/off', :csrf_protection => false) { 'HI' }
|
||||
end
|
||||
end
|
||||
|
||||
should "allow access to routes with csrf_protection off" do
|
||||
post "/off"
|
||||
assert_equal 200, status
|
||||
end
|
||||
|
||||
should "not allow access to routes with csrf_protection on" do
|
||||
post "/on"
|
||||
assert_equal 403, status
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -275,4 +275,74 @@ describe "Filters" do
|
|||
get '/foo'
|
||||
assert_equal 'before', test
|
||||
end
|
||||
|
||||
should "call before filters only once" do
|
||||
once = ''
|
||||
mock_app do
|
||||
error 500 do
|
||||
'error 500'
|
||||
end
|
||||
before do
|
||||
once += 'before'
|
||||
end
|
||||
get :index do
|
||||
raise Exception, 'Oops'
|
||||
end
|
||||
end
|
||||
|
||||
get '/'
|
||||
assert_equal 'before', once
|
||||
end
|
||||
|
||||
should 'catch exceptions in before filters' do
|
||||
doodle = nil
|
||||
mock_app do
|
||||
after do
|
||||
doodle = 'Been after'
|
||||
end
|
||||
before do
|
||||
raise StandardError, "before"
|
||||
end
|
||||
get :index do
|
||||
doodle = 'Been now'
|
||||
end
|
||||
error 500 do
|
||||
"We broke #{env['sinatra.error'].message}"
|
||||
end
|
||||
end
|
||||
|
||||
get '/'
|
||||
assert_equal 'We broke before', body
|
||||
assert_equal nil, doodle
|
||||
end
|
||||
|
||||
should 'catch exceptions in after filters if no exceptions caught before' do
|
||||
doodle = ''
|
||||
mock_app do
|
||||
after do
|
||||
doodle += ' and after'
|
||||
raise StandardError, "after"
|
||||
end
|
||||
get :foo do
|
||||
doodle = 'Been now'
|
||||
raise StandardError, "now"
|
||||
end
|
||||
get :index do
|
||||
doodle = 'Been now'
|
||||
end
|
||||
error 500 do
|
||||
"We broke #{env['sinatra.error'].message}"
|
||||
end
|
||||
end
|
||||
|
||||
get '/foo'
|
||||
assert_equal 'We broke now', body
|
||||
assert_equal 'Been now', doodle
|
||||
|
||||
doodle = ''
|
||||
get '/'
|
||||
assert_equal 'We broke after', body
|
||||
assert_equal 'Been now and after', doodle
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,168 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
||||
|
||||
describe Padrino::Flash do
|
||||
context 'storage' do
|
||||
before do
|
||||
@storage = Padrino::Flash::Storage.new(
|
||||
:success => 'Success msg',
|
||||
:error => 'Error msg',
|
||||
:notice => 'Notice msg',
|
||||
:custom => 'Custom msg'
|
||||
)
|
||||
@storage[:one] = 'One msg'
|
||||
@storage[:two] = 'Two msg'
|
||||
end
|
||||
|
||||
should 'acts like hash' do
|
||||
assert_respond_to @storage, :[]
|
||||
end
|
||||
|
||||
should 'know its size' do
|
||||
assert_equal 4, @storage.length
|
||||
assert_equal @storage.length, @storage.size
|
||||
end
|
||||
|
||||
should 'sweep its content' do
|
||||
assert_equal 2, @storage.sweep.size
|
||||
assert_empty @storage.sweep
|
||||
end
|
||||
|
||||
should 'discard everything' do
|
||||
assert_empty @storage.discard.sweep
|
||||
end
|
||||
|
||||
should 'discard specified key' do
|
||||
assert_equal 1, @storage.discard(:one).sweep.size
|
||||
end
|
||||
|
||||
should 'keep everything' do
|
||||
assert_equal 2, @storage.sweep.keep.sweep.size
|
||||
end
|
||||
|
||||
should 'keep only specified key' do
|
||||
assert_equal 1, @storage.sweep.keep(:one).sweep.size
|
||||
end
|
||||
|
||||
should 'not know the values you set right away' do
|
||||
@storage[:foo] = 'bar'
|
||||
assert_nil @storage[:foo]
|
||||
end
|
||||
|
||||
should 'knows the values you set next time' do
|
||||
@storage[:foo] = 'bar'
|
||||
@storage.sweep
|
||||
assert_equal 'bar', @storage[:foo]
|
||||
end
|
||||
|
||||
should 'set values for now' do
|
||||
@storage.now[:foo] = 'bar'
|
||||
assert_equal 'bar', @storage[:foo]
|
||||
end
|
||||
|
||||
should 'forgets values you set only for now next time' do
|
||||
@storage.now[:foo] = 'bar'
|
||||
@storage.sweep
|
||||
assert_nil @storage[:foo]
|
||||
end
|
||||
end
|
||||
|
||||
routes = Proc.new do
|
||||
get :index do
|
||||
params[:key] ? flash[params[:key].to_sym].to_s : flash.now.inspect
|
||||
end
|
||||
|
||||
post :index do
|
||||
params.each { |k,v| flash[k.to_sym] = v.to_s }
|
||||
flash.next.inspect
|
||||
end
|
||||
|
||||
get :session do
|
||||
settings.sessions?.inspect
|
||||
end
|
||||
|
||||
get :redirect do
|
||||
redirect url(:index, :key => :foo), 301, :foo => 'redirected!'
|
||||
end
|
||||
|
||||
get :success do
|
||||
flash.success = 'Yup'
|
||||
end
|
||||
|
||||
get :error do
|
||||
flash.error = 'Arg'
|
||||
end
|
||||
|
||||
get :notice do
|
||||
flash.notice = 'Mmm'
|
||||
end
|
||||
end
|
||||
|
||||
context 'padrino application without sessions' do
|
||||
before { mock_app(&routes) }
|
||||
|
||||
should 'show nothing' do
|
||||
get '/'
|
||||
assert_equal '{}', body
|
||||
end
|
||||
|
||||
should 'set a flash' do
|
||||
post '/', :foo => :bar
|
||||
assert_equal '{:foo=>"bar"}', body
|
||||
end
|
||||
end
|
||||
|
||||
context 'padrino application with sessions' do
|
||||
before do
|
||||
mock_app { enable :sessions; class_eval(&routes) }
|
||||
end
|
||||
|
||||
should 'be sure have sessions enabled' do
|
||||
assert @app.sessions
|
||||
get '/session'
|
||||
assert_equal 'true', body
|
||||
end
|
||||
|
||||
should 'show nothing' do
|
||||
get '/'
|
||||
assert_equal '{}', body
|
||||
end
|
||||
|
||||
should 'set a flash' do
|
||||
post '/', :foo => :bar
|
||||
assert_equal '{:foo=>"bar"}', body
|
||||
end
|
||||
|
||||
should 'get a flash' do
|
||||
post '/', :foo => :bar
|
||||
get '/', :key => :foo
|
||||
assert_equal 'bar', body
|
||||
post '/'
|
||||
assert_equal '{}', body
|
||||
end
|
||||
|
||||
should 'follow redirects with flash' do
|
||||
get '/redirect'
|
||||
follow_redirect!
|
||||
assert_equal 'redirected!', body
|
||||
assert 301, status
|
||||
end
|
||||
|
||||
should 'set success' do
|
||||
get '/success'
|
||||
get '/', :key => :success
|
||||
assert_equal 'Yup', body
|
||||
end
|
||||
|
||||
should 'set error' do
|
||||
get '/error'
|
||||
get '/', :key => :error
|
||||
assert_equal 'Arg', body
|
||||
end
|
||||
|
||||
should 'set notice' do
|
||||
get '/notice'
|
||||
get '/', :key => :notice
|
||||
assert_equal 'Mmm', body
|
||||
end
|
||||
end
|
||||
end
|
|
@ -152,3 +152,30 @@ describe "alternate logger: stdlib logger" do
|
|||
assert_match /\e\[1m200\e\[0m OK/, @log.string
|
||||
end
|
||||
end
|
||||
|
||||
describe "options :colorize_logging" do
|
||||
def access_to_mock_app
|
||||
mock_app do
|
||||
enable :logging
|
||||
get("/"){ "Foo" }
|
||||
end
|
||||
get "/"
|
||||
end
|
||||
context 'default' do
|
||||
should 'use colorize logging' do
|
||||
Padrino::Logger.setup!
|
||||
|
||||
access_to_mock_app
|
||||
assert_match /\e\[1m200\e\[0m OK/, Padrino.logger.log.string
|
||||
end
|
||||
end
|
||||
context 'set value is false' do
|
||||
should 'not use colorize logging' do
|
||||
Padrino::Logger::Config[:test][:colorize_logging] = false
|
||||
Padrino::Logger.setup!
|
||||
|
||||
access_to_mock_app
|
||||
assert_match /200 OK/, Padrino.logger.log.string
|
||||
end
|
||||
end
|
||||
end
|
|
@ -113,11 +113,13 @@ describe "Mounter" do
|
|||
class ::OneApp < Padrino::Application
|
||||
get("/test") { "test" }
|
||||
get(:index, :provides => [:js, :json]) { "index" }
|
||||
get(%r{/foo|/baz}) { "regexp" }
|
||||
controllers :posts do
|
||||
get(:index) { "index" }
|
||||
get(:new, :provides => :js) { "new" }
|
||||
get(:show, :provides => [:js, :html], :with => :id) { "show" }
|
||||
post(:create, :provides => :js, :with => :id) { "create" }
|
||||
get(:regexp, :map => %r{/foo|/baz}) { "regexp" }
|
||||
end
|
||||
end
|
||||
class ::TwoApp < Padrino::Application
|
||||
|
@ -133,9 +135,9 @@ describe "Mounter" do
|
|||
Padrino.mount("one_app").to("/")
|
||||
Padrino.mount("two_app").to("/two_app")
|
||||
|
||||
assert_equal 11, Padrino.mounted_apps[0].routes.size
|
||||
assert_equal 15, Padrino.mounted_apps[0].routes.size
|
||||
assert_equal 7, Padrino.mounted_apps[1].routes.size
|
||||
assert_equal 5, Padrino.mounted_apps[0].named_routes.size
|
||||
assert_equal 6, Padrino.mounted_apps[0].named_routes.size
|
||||
assert_equal 5, Padrino.mounted_apps[1].named_routes.size
|
||||
|
||||
first_route = Padrino.mounted_apps[0].named_routes[3]
|
||||
|
@ -148,6 +150,10 @@ describe "Mounter" do
|
|||
assert_equal "(:users, :create)", another_route.name
|
||||
assert_equal "POST", another_route.verb
|
||||
assert_equal "/two_app/users/create", another_route.path
|
||||
regexp_route = Padrino.mounted_apps[0].named_routes[5]
|
||||
assert_equal "posts_regexp", regexp_route.identifier.to_s
|
||||
assert_equal "(:posts, :regexp)", regexp_route.name
|
||||
assert_equal "/\\/foo|\\/baz/", regexp_route.path
|
||||
end
|
||||
|
||||
should 'correctly instantiate a new padrino application' do
|
||||
|
@ -173,5 +179,21 @@ describe "Mounter" do
|
|||
assert res.ok?
|
||||
assert_equal File.read(__FILE__), res.body
|
||||
end
|
||||
|
||||
should "load apps from gems" do
|
||||
spec_file = Padrino.root("fixtures", "app_gem", "app_gem.gemspec")
|
||||
spec = Gem::Specification.load(spec_file)
|
||||
spec.activate
|
||||
def spec.full_gem_path
|
||||
Padrino.root("fixtures", "app_gem")
|
||||
end
|
||||
|
||||
require Padrino.root("fixtures", "app_gem", "lib", "app_gem")
|
||||
|
||||
Padrino.mount("AppGem::App").to("/from_gem")
|
||||
mounter = Padrino.mounted_apps[0]
|
||||
assert_equal AppGem::App, mounter.app_obj
|
||||
assert_equal Padrino.root('public'), mounter.app_obj.public_folder
|
||||
end
|
||||
end
|
||||
end
|
|
@ -78,20 +78,20 @@ describe "SimpleReloader" do
|
|||
last_body = body
|
||||
assert_equal 2, @app.filters[:before].size # one is ours the other is default_filter for content type
|
||||
assert_equal 1, @app.errors.size
|
||||
assert_equal 1, @app.filters[:after].size
|
||||
assert_equal 2, @app.filters[:after].size # app + content-type + padrino-flash
|
||||
assert_equal 0, @app.middleware.size
|
||||
assert_equal 4, @app.routes.size # GET+HEAD of "/" + GET+HEAD of "/rand" = 4
|
||||
assert_equal 2, @app.extensions.size # [Padrino::Routing, Padrino::Rendering]
|
||||
assert_equal 3, @app.extensions.size # [Padrino::Routing, Padrino::Rendering, Padrino::Flash]
|
||||
assert_equal 0, @app.templates.size
|
||||
@app.reload!
|
||||
get "/rand"
|
||||
assert_not_equal last_body, body
|
||||
assert_equal 2, @app.filters[:before].size # one is ours the other is default_filter for content type
|
||||
assert_equal 1, @app.errors.size
|
||||
assert_equal 1, @app.filters[:after].size
|
||||
assert_equal 2, @app.filters[:after].size
|
||||
assert_equal 0, @app.middleware.size
|
||||
assert_equal 4, @app.routes.size # GET+HEAD of "/" = 2
|
||||
assert_equal 2, @app.extensions.size # [Padrino::Routing, Padrino::Rendering]
|
||||
assert_equal 3, @app.extensions.size # [Padrino::Routing, Padrino::Rendering, Padrino::Flash]
|
||||
assert_equal 0, @app.templates.size
|
||||
end
|
||||
end
|
|
@ -1,5 +1,6 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
||||
require 'i18n'
|
||||
require 'slim'
|
||||
|
||||
describe "Rendering" do
|
||||
def setup
|
||||
|
@ -28,7 +29,7 @@ describe "Rendering" do
|
|||
"this is a <%= yield %>"
|
||||
end
|
||||
|
||||
get("/"){ render :erb, "sinatra layout" }
|
||||
get("/"){ render :erb, "sinatra layout", :layout => true }
|
||||
end
|
||||
|
||||
get "/"
|
||||
|
@ -137,6 +138,7 @@ describe "Rendering" do
|
|||
should 'use correct layout with each controller' do
|
||||
create_layout :foo, "foo layout at <%= yield %>"
|
||||
create_layout :bar, "bar layout at <%= yield %>"
|
||||
create_layout :baz, "baz layout at <%= yield %>"
|
||||
create_layout :application, "default layout at <%= yield %>"
|
||||
mock_app do
|
||||
get("/"){ render :erb, "application" }
|
||||
|
@ -148,6 +150,10 @@ describe "Rendering" do
|
|||
layout :bar
|
||||
get("/"){ render :erb, "bar" }
|
||||
end
|
||||
controller :baz do
|
||||
layout :baz
|
||||
get("/"){ render :erb, "baz", :layout => true }
|
||||
end
|
||||
controller :none do
|
||||
get("/") { render :erb, "none" }
|
||||
get("/with_foo_layout") { render :erb, "none with layout", :layout => :foo }
|
||||
|
@ -157,6 +163,8 @@ describe "Rendering" do
|
|||
assert_equal "foo layout at foo", body
|
||||
get "/bar"
|
||||
assert_equal "bar layout at bar", body
|
||||
get "/baz"
|
||||
assert_equal "baz layout at baz", body
|
||||
get "/none"
|
||||
assert_equal "default layout at none", body
|
||||
get "/none/with_foo_layout"
|
||||
|
@ -207,7 +215,7 @@ describe "Rendering" do
|
|||
create_view :index, "<%= foo %>"
|
||||
mock_app do
|
||||
enable :logging
|
||||
get("/") { render "index", { :layout => true }, { :foo => "bar" } }
|
||||
get("/") { render "index", { :layout => nil }, { :foo => "bar" } }
|
||||
end
|
||||
get "/"
|
||||
assert_equal "bar", body
|
||||
|
@ -396,7 +404,7 @@ describe "Rendering" do
|
|||
assert_equal "Im Italian Js", body
|
||||
I18n.locale = :en
|
||||
get "/foo.pk"
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
end
|
||||
|
||||
should 'resolve template content_type and locale with layout' do
|
||||
|
@ -438,7 +446,7 @@ describe "Rendering" do
|
|||
get "/bar.json"
|
||||
assert_equal "Im a json", body
|
||||
get "/bar.pk"
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
end
|
||||
|
||||
should 'renders erb with blocks' do
|
||||
|
@ -457,5 +465,68 @@ describe "Rendering" do
|
|||
assert ok?
|
||||
assert_equal 'THIS. IS. SPARTA!', body
|
||||
end
|
||||
|
||||
should 'render erb to a SafeBuffer' do
|
||||
mock_app do
|
||||
layout do
|
||||
"this is a <%= yield %>"
|
||||
end
|
||||
get '/' do
|
||||
render :erb, '<p><%= %q{<script lang="ronin">alert("https://github.com/ronin-ruby/ronin")</script>} %></p>', :layout => false
|
||||
end
|
||||
get '/with_layout' do
|
||||
render :erb, '<span>span</span>', :layout => true
|
||||
end
|
||||
end
|
||||
get '/'
|
||||
assert ok?
|
||||
assert_equal '<p><script lang="ronin">alert("https://github.com/ronin-ruby/ronin")</script></p>', body
|
||||
|
||||
get '/with_layout'
|
||||
assert ok?
|
||||
assert_equal 'this is a <span>span</span>', body
|
||||
end
|
||||
|
||||
should 'render haml to a SafeBuffer' do
|
||||
mock_app do
|
||||
layout do
|
||||
"%p= yield"
|
||||
end
|
||||
get '/' do
|
||||
render :haml, '%p= %s{<script lang="ronin">alert("https://github.com/ronin-ruby/ronin")</script>}', :layout => false
|
||||
end
|
||||
get '/with_layout' do
|
||||
render :haml, "%div\n foo", :layout => true
|
||||
end
|
||||
end
|
||||
get '/'
|
||||
assert ok?
|
||||
assert_equal '<p><script lang="ronin">alert("https://github.com/ronin-ruby/ronin")</script></p>', body.strip
|
||||
|
||||
get 'with_layout'
|
||||
assert ok?
|
||||
assert_equal '<p><div>foo</div></p>', body.gsub(/\s+/, "")
|
||||
end
|
||||
|
||||
should 'render slim to a SafeBuffer' do
|
||||
mock_app do
|
||||
layout do
|
||||
"p= yield"
|
||||
end
|
||||
get '/' do
|
||||
render :slim, 'p = %q{<script lang="ronin">alert("https://github.com/ronin-ruby/ronin")</script>}', :layout => false
|
||||
end
|
||||
get "/with_layout" do
|
||||
render :slim, 'div foo', :layout => true
|
||||
end
|
||||
end
|
||||
get '/'
|
||||
assert ok?
|
||||
assert_equal '<p><script lang="ronin">alert("https://github.com/ronin-ruby/ronin")</script></p>', body.strip
|
||||
|
||||
get '/with_layout'
|
||||
assert ok?
|
||||
assert_equal '<p><div>foo</div></p>', body.strip
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,3 +1,4 @@
|
|||
#encoding: utf-8
|
||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
||||
|
||||
class FooError < RuntimeError; end
|
||||
|
@ -57,12 +58,12 @@ describe "Routing" do
|
|||
|
||||
should 'accept regexp routes' do
|
||||
mock_app do
|
||||
get(%r{/fob|/baz}) { "regexp" }
|
||||
get(%r./fob|/baz.) { "regexp" }
|
||||
get("/foo") { "str" }
|
||||
get %r{/([0-9]+)/} do |num|
|
||||
"Your lucky number: #{num} #{params[:captures].first}"
|
||||
get %r./([0-9]+)/. do |num|
|
||||
"Your lucky number: #{num} #{params[:captures].first}"
|
||||
end
|
||||
get /\/page\/([0-9]+)|\// do |num|
|
||||
get %r./page/([0-9]+)|/. do |num|
|
||||
"My lucky number: #{num} #{params[:captures].first}"
|
||||
end
|
||||
end
|
||||
|
@ -72,8 +73,8 @@ describe "Routing" do
|
|||
assert_equal "regexp", body
|
||||
get "/baz"
|
||||
assert_equal "regexp", body
|
||||
get "/1234/"
|
||||
assert_equal "Your lucky number: 1234 1234", body
|
||||
get "/321/"
|
||||
assert_equal "Your lucky number: 321 321", body
|
||||
get "/page/99"
|
||||
assert_equal "My lucky number: 99 99", body
|
||||
end
|
||||
|
@ -100,6 +101,24 @@ describe "Routing" do
|
|||
assert_equal "no access", body
|
||||
end
|
||||
|
||||
should 'parse routes that are encoded' do
|
||||
mock_app do
|
||||
get('/щч') { 'success!' }
|
||||
end
|
||||
get(URI.escape('/щч'))
|
||||
assert_equal 'success!', body
|
||||
end
|
||||
|
||||
should 'encode params using UTF-8' do
|
||||
skip unless ''.respond_to?(:encoding) # for 1.8.7
|
||||
|
||||
mock_app do
|
||||
get('/:foo') { params[:foo].encoding.name }
|
||||
end
|
||||
get '/bar'
|
||||
assert_equal 'UTF-8', body
|
||||
end
|
||||
|
||||
should 'match correctly similar paths' do
|
||||
mock_app do
|
||||
get("/my/:foo_id"){ params[:foo_id] }
|
||||
|
@ -138,9 +157,9 @@ describe "Routing" do
|
|||
post("/main"){ "hello" }
|
||||
end
|
||||
assert_equal 3, app.routes.size, "should generate GET, HEAD and PUT"
|
||||
assert_equal ["GET"], app.routes[0].conditions[:request_method]
|
||||
assert_equal ["HEAD"], app.routes[1].conditions[:request_method]
|
||||
assert_equal ["POST"], app.routes[2].conditions[:request_method]
|
||||
assert_equal "GET", app.routes[0].request_methods.first
|
||||
assert_equal "HEAD", app.routes[1].request_methods.first
|
||||
assert_equal "POST", app.routes[2].request_methods.first
|
||||
end
|
||||
|
||||
should 'generate basic urls' do
|
||||
|
@ -192,13 +211,13 @@ describe "Routing" do
|
|||
get "/b.js"
|
||||
assert_equal "/b.js", body
|
||||
get "/b.ru"
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
get "/c.js"
|
||||
assert_equal "/c.json", body
|
||||
get "/c.json"
|
||||
assert_equal "/c.json", body
|
||||
get "/c.ru"
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
get "/d"
|
||||
assert_equal "/d.js?foo=bar", body
|
||||
get "/d.js"
|
||||
|
@ -207,6 +226,14 @@ describe "Routing" do
|
|||
assert_equal 404, status
|
||||
end
|
||||
|
||||
should 'allow regex url with format' do
|
||||
mock_app do
|
||||
get(/.*/, :provides => :any) { "regexp" }
|
||||
end
|
||||
get "/anything"
|
||||
assert_equal "regexp", body
|
||||
end
|
||||
|
||||
should 'use padrino url method' do
|
||||
mock_app do
|
||||
end
|
||||
|
@ -255,7 +282,7 @@ describe "Routing" do
|
|||
end
|
||||
|
||||
get "/a.xml", {}, {}
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
end
|
||||
|
||||
should "not set content_type to :html if Accept */* and html not in provides" do
|
||||
|
@ -276,15 +303,6 @@ describe "Routing" do
|
|||
assert_equal 'json', body
|
||||
end
|
||||
|
||||
should "set content_type to :json if render => :json" do
|
||||
mock_app do
|
||||
get("/foo"){ render :foo => :bar }
|
||||
end
|
||||
|
||||
get '/foo'
|
||||
assert_equal 'application/json;charset=utf-8', content_type
|
||||
end
|
||||
|
||||
should 'set and get content_type' do
|
||||
mock_app do
|
||||
get("/foo"){ content_type(:json); content_type.to_s }
|
||||
|
@ -303,6 +321,7 @@ describe "Routing" do
|
|||
end
|
||||
|
||||
should "allow .'s in param values" do
|
||||
skip
|
||||
mock_app do
|
||||
get('/id/:email', :provides => [:json]) { |email, format| [email, format] * '/' }
|
||||
end
|
||||
|
@ -343,7 +362,7 @@ describe "Routing" do
|
|||
end
|
||||
|
||||
get "/a.xml", {}, {"HTTP_ACCEPT" => "text/html"}
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
end
|
||||
|
||||
should "generate routes for format simple" do
|
||||
|
@ -371,20 +390,32 @@ describe "Routing" do
|
|||
assert_equal "mini", body
|
||||
end
|
||||
|
||||
should "should inject the action name into the request" do
|
||||
mock_app do
|
||||
controller :posts do
|
||||
get('/omnomnom(/:id)') { request.action.inspect }
|
||||
controller :mini do
|
||||
get([:a, :b, :c]) { request.action.inspect }
|
||||
end
|
||||
end
|
||||
end
|
||||
get "/posts/omnomnom"
|
||||
assert_equal "\"/omnomnom(/:id)\"", body
|
||||
get "/mini/a/b/c"
|
||||
assert_equal ":a", body
|
||||
end
|
||||
|
||||
should "support not_found" do
|
||||
mock_app do
|
||||
not_found do
|
||||
response.status = 404
|
||||
'whatever'
|
||||
end
|
||||
not_found { 'whatever' }
|
||||
|
||||
get :index, :map => "/" do
|
||||
'index'
|
||||
end
|
||||
end
|
||||
get '/something'
|
||||
assert_equal 'whatever', body
|
||||
get '/wrong'
|
||||
assert_equal 404, status
|
||||
assert_equal 'whatever', body
|
||||
get '/'
|
||||
assert_equal 'index', body
|
||||
assert_equal 200, status
|
||||
|
@ -393,7 +424,7 @@ describe "Routing" do
|
|||
should "should inject the route into the request" do
|
||||
mock_app do
|
||||
controller :posts do
|
||||
get(:index) { request.route_obj.named.to_s }
|
||||
get(:index) { request.route_obj.name.to_s }
|
||||
end
|
||||
end
|
||||
get "/posts"
|
||||
|
@ -741,7 +772,27 @@ describe "Routing" do
|
|||
assert_equal 404, status
|
||||
end
|
||||
|
||||
should "match params and format" do
|
||||
app = mock_app do
|
||||
get '/:id', :provides => [:json, :html] do |id, _|
|
||||
id
|
||||
end
|
||||
|
||||
get 'format/:id', :provides => [:json, :html] do |id, format|
|
||||
format
|
||||
end
|
||||
end
|
||||
|
||||
get '/123.html'
|
||||
assert_equal '123', body
|
||||
|
||||
get 'format/123.html'
|
||||
assert_equal 'html', body
|
||||
end
|
||||
|
||||
|
||||
should 'respect priorities' do
|
||||
skip
|
||||
route_order = []
|
||||
mock_app do
|
||||
get(:index, :priority => :normal) { route_order << :normal; pass }
|
||||
|
@ -815,6 +866,55 @@ describe "Routing" do
|
|||
assert_equal "show 3 1 2", body
|
||||
end
|
||||
|
||||
should "respect parent precedence: controllers parents go before route parents" do
|
||||
mock_app do
|
||||
controllers :project do
|
||||
get(:index, :parent => :user) { "index #{params[:user_id]}" }
|
||||
end
|
||||
|
||||
controllers :bar, :parent => :foo do
|
||||
get(:index) { "index on foo #{params[:foo_id]} @ bar" }
|
||||
get(:index, :parent => :baz) { "index on foo #{params[:foo_id]} @ baz #{params[:baz_id]} @ bar" }
|
||||
end
|
||||
end
|
||||
|
||||
get "/user/1/project"
|
||||
assert_equal "index 1", body
|
||||
get "/foo/1/bar"
|
||||
assert_equal "index on foo 1 @ bar", body
|
||||
get "/foo/1/baz/2/bar"
|
||||
assert_equal "index on foo 1 @ baz 2 @ bar", body
|
||||
end
|
||||
|
||||
should "keep a reference to the parent on the route" do
|
||||
mock_app do
|
||||
controllers :project do
|
||||
get(:index, :parent => :user) { "index #{params[:user_id]}" }
|
||||
get(:index, :parent => [:user, :section]) { "index #{params[:user_id]} #{params[:section_id]}" }
|
||||
get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
|
||||
get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
|
||||
end
|
||||
|
||||
controllers :bar, :parent => :foo do
|
||||
get(:index) { "index on foo/bar" }
|
||||
get(:index, :parent => :baz) { "index on foo/baz/bar" }
|
||||
end
|
||||
end
|
||||
|
||||
# get "/user/1/project"
|
||||
assert_equal :user, @app.routes[0].parent
|
||||
# get "/user/1/section/3/project"
|
||||
assert_equal [:user, :section], @app.routes[2].parent
|
||||
# get "/user/1/project/edit/2"
|
||||
assert_equal :user, @app.routes[4].parent
|
||||
# get "/user/1/product/2/project/show/3"
|
||||
assert_equal [:user, :product], @app.routes[6].parent
|
||||
# get "/foo/1/bar"
|
||||
assert_equal :foo, @app.routes[8].parent
|
||||
# get "/foo/1/baz/2/bar"
|
||||
assert_equal [:foo, :baz], @app.routes[10].parent
|
||||
end
|
||||
|
||||
should "apply parent to controller" do
|
||||
mock_app do
|
||||
controller :project, :parent => :user do
|
||||
|
@ -1041,6 +1141,24 @@ describe "Routing" do
|
|||
assert_equal 'js', body
|
||||
end
|
||||
|
||||
should "set content_type to :html if Accept */* and provides of :any" do
|
||||
mock_app do
|
||||
get("/foo", :provides => :any) { content_type.to_s }
|
||||
end
|
||||
|
||||
get '/foo', {}, { 'HTTP_ACCEPT' => '*/*' }
|
||||
assert_equal 'html', body
|
||||
end
|
||||
|
||||
should "set content_type to :js if Accept includes both application/javascript, */*;q=0.5 and provides of :any" do
|
||||
mock_app do
|
||||
get("/foo", :provides => :any) { content_type.to_s }
|
||||
end
|
||||
|
||||
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
|
||||
assert_equal 'js', body
|
||||
end
|
||||
|
||||
should 'allows custom route-conditions to be set via route options and halt' do
|
||||
protector = Module.new do
|
||||
def protect(*args)
|
||||
|
@ -1323,11 +1441,11 @@ describe "Routing" do
|
|||
get "/.json"
|
||||
assert_equal "This is the get index.json", body
|
||||
get "/.js"
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
post "/.json"
|
||||
assert_equal "This is the post index.json", body
|
||||
post "/.js"
|
||||
assert_equal 405, status
|
||||
assert_equal 404, status
|
||||
end
|
||||
|
||||
should "allow controller level mapping" do
|
||||
|
@ -1349,6 +1467,33 @@ describe "Routing" do
|
|||
assert_equal "1, 2", body
|
||||
end
|
||||
|
||||
should "replace name of named controller with mapping path" do
|
||||
mock_app do
|
||||
controller :ugly, :map => "/pretty/:id" do
|
||||
get(:url3) { "#{params[:id]}" }
|
||||
get(:url4, :map => 'test-:id2') { "#{params[:id]}, #{params[:id2]}" }
|
||||
end
|
||||
controller :voldemort, :map => "" do
|
||||
get(:url5) { "okay" }
|
||||
end
|
||||
end
|
||||
|
||||
url = @app.url(:ugly, :url3, :id => 1)
|
||||
assert_equal "/pretty/1/url3", url
|
||||
get url
|
||||
assert_equal "1", body
|
||||
|
||||
url = @app.url(:ugly, :url4, 3, 5)
|
||||
assert_equal "/pretty/3/test-5", url
|
||||
get url
|
||||
assert_equal "3, 5", body
|
||||
|
||||
url = @app.url(:voldemort, :url5)
|
||||
assert_equal "/url5", url
|
||||
get url
|
||||
assert_equal 'okay', body
|
||||
end
|
||||
|
||||
should 'use absolute and relative maps' do
|
||||
mock_app do
|
||||
controller :one do
|
||||
|
@ -1544,8 +1689,8 @@ describe "Routing" do
|
|||
end
|
||||
|
||||
should "have overideable format" do
|
||||
::Rack::Mime::MIME_TYPES[".other"] = "text/html"
|
||||
mock_app do
|
||||
::Rack::Mime::MIME_TYPES[".other"] = "text/html"
|
||||
before do
|
||||
params[:format] ||= :other
|
||||
end
|
||||
|
@ -1553,6 +1698,7 @@ describe "Routing" do
|
|||
end
|
||||
get "/format_test"
|
||||
assert_equal "other", body
|
||||
::Rack::Mime::MIME_TYPES.delete('.other')
|
||||
end
|
||||
|
||||
should 'invokes handlers registered with ::error when raised' do
|
||||
|
@ -1626,13 +1772,33 @@ describe "Routing" do
|
|||
assert_match /not found/, body
|
||||
end
|
||||
|
||||
should 'render a custom 404 page' do
|
||||
should 'render a custom 404 page using not_found' do
|
||||
mock_app do
|
||||
error(404) { "not found" }
|
||||
not_found { "custom 404 not found" }
|
||||
end
|
||||
get "/"
|
||||
assert_equal 404, status
|
||||
assert_match /not found/, body
|
||||
assert_equal "custom 404 not found", body
|
||||
end
|
||||
|
||||
should 'render a custom error page using error method' do
|
||||
skip
|
||||
mock_app do
|
||||
error(404) { "custom 404 error" }
|
||||
end
|
||||
get "/"
|
||||
assert_equal 404, status
|
||||
assert_equal "custom 404 error", body
|
||||
end
|
||||
|
||||
should 'render a custom 403 page' do
|
||||
mock_app do
|
||||
error(403) { "custom 403 not found" }
|
||||
get("/") { status 403 }
|
||||
end
|
||||
get "/"
|
||||
assert_equal 403, status
|
||||
assert_equal "custom 403 not found", body
|
||||
end
|
||||
|
||||
should 'recognize paths' do
|
||||
|
@ -1692,4 +1858,12 @@ describe "Routing" do
|
|||
get @app.url(:index, :page => 10)
|
||||
assert_equal "/paginate/66", body
|
||||
end
|
||||
|
||||
should 'not route get :users, :with => :id to /users//' do
|
||||
mock_app do
|
||||
get(:users, :with => :id) { 'boo' }
|
||||
end
|
||||
get '/users//'
|
||||
assert_equal 404, status
|
||||
end
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
||||
|
||||
describe "ObjectSpace" do
|
||||
def setup
|
||||
end
|
||||
|
||||
def teardown
|
||||
end
|
||||
|
||||
context "#classes" do
|
||||
should "take an snapshot of the current loaded classes" do
|
||||
snapshot = ObjectSpace.classes
|
||||
assert_equal snapshot.include?(Padrino::Logger), true
|
||||
end
|
||||
|
||||
should "return a Set object" do
|
||||
snapshot = ObjectSpace.classes
|
||||
assert_equal snapshot.kind_of?(Set), true
|
||||
end
|
||||
|
||||
should "be able to process a the class name given a block" do
|
||||
klasses = ObjectSpace.classes do |klass|
|
||||
if klass.name =~ /^Padrino::/
|
||||
klass
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal (klasses.size > 1), true
|
||||
klasses.each do |klass|
|
||||
assert_match /^Padrino::/, klass.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "#new_classes" do
|
||||
setup do
|
||||
@snapshot = ObjectSpace.classes
|
||||
end
|
||||
|
||||
should "return list of new classes" do
|
||||
class OSTest; end
|
||||
module OSTestModule; class B; end; end
|
||||
|
||||
new_classes = ObjectSpace.new_classes(@snapshot)
|
||||
|
||||
assert_equal new_classes.size, 2
|
||||
assert_equal new_classes.include?(OSTest), true
|
||||
assert_equal new_classes.include?(OSTestModule::B), true
|
||||
end
|
||||
|
||||
should "return a Set object" do
|
||||
new_classes = ObjectSpace.new_classes(@snapshot)
|
||||
assert_equal new_classes.kind_of?(Set), true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
==content_tag :p, "Test 1", :class => 'test', :id => "test1"
|
||||
|
||||
== content_tag :p, "Test 2"
|
||||
|
||||
==content_tag(:p, :class => 'test', :id => 'test3') do
|
||||
span Test 3
|
||||
|
||||
==content_tag(:p) do
|
||||
span Test 4
|
|
@ -1,15 +0,0 @@
|
|||
- @user = MarkupUser.new
|
||||
== form_for @user , '/demo1', :id => 'demo-fields-for' do |f|
|
||||
== f.text_field :gender
|
||||
== fields_for @user.permission do |permission|
|
||||
== permission.check_box :can_edit
|
||||
== permission.check_box :can_delete
|
||||
== f.fields_for :telephone do |child_form|
|
||||
== child_form.label :number
|
||||
== child_form.text_field :number
|
||||
== f.fields_for :addresses do |child_form|
|
||||
== child_form.label :name
|
||||
== child_form.text_field :name
|
||||
- unless child_form.object.new_record?
|
||||
== child_form.check_box '_destroy'
|
||||
== child_form.label '_destroy', :caption => 'Remove'
|
|
@ -1,59 +0,0 @@
|
|||
== form_for MarkupUser.new, '/demo', :id => 'demo' do |f|
|
||||
== f.error_messages(:header_message => "custom MarkupUser cannot be saved!")
|
||||
== f.hidden_field :session_id
|
||||
p
|
||||
== f.label :username, :caption => "Login: ", :class => 'user-label'
|
||||
== f.text_field :username, :class => 'user-text', :value => "John"
|
||||
p
|
||||
== f.label :password
|
||||
== f.password_field :password, :class => 'user-password', :value => "secret"
|
||||
p
|
||||
== f.label :age
|
||||
== f.number_field :age, :class => 'numeric'
|
||||
p
|
||||
== f.label :telephone
|
||||
== f.telephone_field :telephone, :class => 'numeric'
|
||||
p
|
||||
== f.label :email, :caption => 'Email Address: '
|
||||
== f.email_field :email, :class => 'string'
|
||||
p
|
||||
== f.label :webpage, :caption => 'Your Web Page: '
|
||||
== f.url_field :webpage, :class => 'string'
|
||||
p
|
||||
== f.label :search
|
||||
== f.search_field :search, :class => 'string'
|
||||
p
|
||||
== f.label :photo
|
||||
== f.file_field :photo, :class => 'user-photo'
|
||||
p
|
||||
== f.label :about, :caption => "About Me: "
|
||||
== f.text_area :about, :class => 'user-about'
|
||||
p
|
||||
== f.label :gender, :caption => "Your gender: "
|
||||
== f.radio_button :gender, :value => 'male'
|
||||
== f.radio_button :gender, :value => 'female'
|
||||
p
|
||||
== f.label :country, :caption => "Your country"
|
||||
== f.select :country, :options => ['USA', 'Canada', 'Mexico'], :selected => 'USA', :class => 'selector'
|
||||
p
|
||||
== f.label :remember_me
|
||||
== f.check_box :remember_me, :value => "1"
|
||||
p
|
||||
== f.submit "Create", :class => 'success', :id => 'demo-button'
|
||||
p
|
||||
== f.image_submit "buttons/post.png", :class => 'success', :id => 'image-button'
|
||||
|
||||
== form_for MarkupUser.new, '/another_demo', :id => 'demo2', :method => 'get' do |f|
|
||||
== f.error_messages :header_message => "custom MarkupUser cannot be saved!"
|
||||
== f.hidden_field :session_id
|
||||
== f.text_field_block :username, { :class => 'input' }, { :caption => 'Nickname: ', :class => 'label' }
|
||||
== f.password_field_block :code, { :class => 'input' }
|
||||
== f.text_area_block :about, { :class => 'textarea' }
|
||||
== f.file_field_block :photo, { :class => 'upload' }
|
||||
== f.check_box_block :remember_me, { :class => 'checker' }
|
||||
== f.select_block :state, :options => ['California', 'Texas'], :class => 'selector'
|
||||
== f.submit_block "Create", { :class => 'button' }
|
||||
== f.image_submit_block "buttons/ok.png", { :class => 'image' }
|
||||
|
||||
== form_for :markup_user, '/third_demo', :id => 'demo3', :method => 'get' do |f|
|
||||
== f.text_field_block :username
|
|
@ -1,70 +0,0 @@
|
|||
== form_tag '/simple', :class => 'simple-form' do
|
||||
== error_messages_for nil
|
||||
== field_set_tag do
|
||||
== hidden_field_tag :session_id, :value => "__secret__"
|
||||
== label_tag :username
|
||||
== text_field_tag :username
|
||||
== label_tag :password
|
||||
== password_field_tag :password
|
||||
== label_tag :email
|
||||
== email_field_tag :email
|
||||
== label_tag :age
|
||||
== number_field_tag :age
|
||||
== label_tag :telephone
|
||||
== telephone_field_tag :telephone
|
||||
== label_tag :webpage
|
||||
== url_field_tag :webpage
|
||||
== label_tag :search
|
||||
== search_field_tag :search
|
||||
== label_tag :color
|
||||
== select_tag :color, :options => ['green', 'orange', 'purple']
|
||||
== label_tag :gender
|
||||
== radio_button_tag :gender, :value => 'male'
|
||||
== radio_button_tag :gender, :value => 'female'
|
||||
== check_box_tag :remember_me
|
||||
== submit_tag
|
||||
|
||||
== form_tag '/advanced', :id => 'advanced', :class => 'advanced-form', :method => 'get' do
|
||||
== error_messages_for MarkupUser.new, :header_message => "There are problems with saving user!"
|
||||
== hidden_field_tag :session_id, :value => "__secret__"
|
||||
== field_set_tag "Advanced", :class => 'advanced-field-set' do
|
||||
p
|
||||
== label_tag :username, :class => 'first', :caption => "Nickname"
|
||||
== text_field_tag :username, :value => params[:username], :id => 'the_username'
|
||||
p
|
||||
== label_tag :password, :class => 'first'
|
||||
== password_field_tag :password, :value => params[:password]
|
||||
p
|
||||
== label_tag :email, :caption => 'Email Address'
|
||||
== email_field_tag :email, :class => 'string'
|
||||
p
|
||||
== label_tag :age, :class => 'age'
|
||||
== number_field_tag :age, :class => 'numeric'
|
||||
p
|
||||
== label_tag :telephone, :class => 'telephone'
|
||||
== telephone_field_tag :telephone, :class => 'numeric'
|
||||
p
|
||||
== label_tag :webpage, :caption => 'Your Home Page'
|
||||
== url_field_tag :webpage, :class => 'string'
|
||||
p
|
||||
== label_tag :search
|
||||
== search_field_tag :search, :class => 'string'
|
||||
p
|
||||
== label_tag :about, :class => 'about', :caption => "About Me"
|
||||
== text_area_tag :about, :class => 'large'
|
||||
p
|
||||
== label_tag :gender, :class => 'gender'
|
||||
== radio_button_tag :gender, :value => 'male', :checked => true
|
||||
== radio_button_tag :gender, :value => 'female'
|
||||
p
|
||||
== label_tag :photo, :class => 'photo'
|
||||
== file_field_tag :photo, :class => 'upload'
|
||||
p
|
||||
== label_tag :fav_color
|
||||
== select_tag :fav_color, :options => [ ['green', '1'], ['orange', '2'], ['purple', '3'] ], :selected => '2'
|
||||
p
|
||||
== check_box_tag :remember_me, :value => "1", :checked => true
|
||||
== field_set_tag(:class => 'buttons') do
|
||||
== submit_tag "Login"
|
||||
== button_tag "Cancel"
|
||||
== image_submit_tag "buttons/submit.png"
|
|
@ -1,4 +0,0 @@
|
|||
== link_to "Test 1 No Block", '/test1', :class => 'test', :id => 'test1'
|
||||
|
||||
== link_to("/test2", :class => 'test', :id => 'test2') do
|
||||
span Test 2 With Block
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue