Merge pull request #357 from trevor/padrino0.10.6

update vendor'd padrino 0.10.5 -> 0.10.6
This commit is contained in:
Thomas Reynolds 2012-04-14 14:16:05 -07:00
commit 2afbb40925
179 changed files with 1619 additions and 744 deletions

View file

@ -28,7 +28,8 @@
* Add pid for cleanup
* Use guard/listen for file watching
* Merge full i18n support
* Implied file extensions (style.scss => sytle.css)
* Implied file extensions (style.scss => style.css)
* Padrino 0.10.6
2.0.14
====

View file

@ -1,4 +1,4 @@
require 'middleman-core/vendor/padrino-helpers-0.10.5/lib/padrino-helpers'
require 'middleman-core/vendor/padrino-helpers-0.10.6/lib/padrino-helpers'
# Built-in helpers
module Middleman::CoreExtensions::DefaultHelpers
@ -19,7 +19,7 @@ module Middleman::CoreExtensions::DefaultHelpers
app.helpers Helpers
app.ready do
::I18n.load_path += Dir["#{File.dirname(__FILE__)}/../vendor/padrino-helpers-0.10.5/lib/padrino-helpers/locale/*.yml"]
::I18n.load_path += Dir["#{File.dirname(__FILE__)}/../vendor/padrino-helpers-0.10.6/lib/padrino-helpers/locale/*.yml"]
end
end
alias :included :registered

View file

@ -1,270 +0,0 @@
module Padrino
class ApplicationSetupError < RuntimeError # @private
end
##
# Subclasses of this become independent Padrino applications (stemming from Sinatra::Application)
# These subclassed applications can be easily mounted into other Padrino applications as well.
#
class Application < Sinatra::Base
# Support for advanced routing, controllers, url_for
register Padrino::Routing
##
# Returns the logger for this application.
#
# @return [Padrino::Logger] Logger associated with this app.
#
def logger
Padrino.logger
end
class << self
def inherited(base) # @private
logger.devel "Setup #{base}"
CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
base.default_configuration!
base.prerequisites.concat([
File.join(base.root, "/models.rb"),
File.join(base.root, "/models/**/*.rb"),
File.join(base.root, "/lib.rb"),
File.join(base.root, "/lib/**/*.rb")
]).uniq!
Padrino.require_dependencies(base.prerequisites)
super(base) # Loading the subclass inherited method
end
##
# Reloads the application files from all defined load paths
#
# This method is used from our Padrino Reloader during development mode
# in order to reload the source files.
#
# @return [TrueClass]
#
# @example
# MyApp.reload!
#
def reload!
logger.devel "Reloading #{self}"
@_dependencies = nil # Reset dependencies
reset! # Reset sinatra app
reset_router! # Reset all routes
Padrino.require_dependencies(self.app_file, :force => true) # Reload the app file
require_dependencies # Reload dependencies
default_filters! # Reload filters
default_routes! # Reload default routes
default_errors! # Reload our errors
I18n.reload! if defined?(I18n) # Reload also our translations
true
end
##
# Resets application routes to only routes not defined by the user
#
# @return [TrueClass]
#
# @example
# MyApp.reset_routes!
#
def reset_routes!
reset_router!
default_routes!
true
end
##
# Returns the routes of our app.
#
# @example
# MyApp.routes
#
def routes
router.routes
end
##
# Setup the application by registering initializers, load paths and logger
# Invoked automatically when an application is first instantiated
#
# @return [TrueClass]
#
def setup_application!
return if @_configured
self.require_dependencies
self.default_filters!
self.default_routes!
self.default_errors!
if defined?(I18n)
I18n.load_path << self.locale_path
I18n.reload!
end
@_configured = true
@_configured
end
##
# Run the Padrino app as a self-hosted server using
# Thin, Mongrel or WEBrick (in that order)
#
# @see Padrino::Server#start
#
def run!(options={})
return unless Padrino.load!
Padrino.mount(self.to_s).to("/")
Padrino.run!(options)
end
##
# @return [Array]
# directory that need to be added to +$LOAD_PATHS+ from this application
#
def load_paths
@_load_paths ||= %w(models lib mailers controllers helpers).map { |path| File.join(self.root, path) }
end
##
# Returns default list of path globs to load as dependencies
# Appends custom dependency patterns to the be loaded for your Application
#
# @return [Array]
# list of path globs to load as dependencies
#
# @example
# MyApp.dependencies << "#{Padrino.root}/uploaders/**/*.rb"
# MyApp.dependencies << Padrino.root('other_app', 'controllers.rb')
#
def dependencies
@_dependencies ||= [
"urls.rb", "config/urls.rb", "mailers/*.rb", "mailers.rb",
"controllers/**/*.rb", "controllers.rb", "helpers/**/*.rb", "helpers.rb"
].map { |file| Dir[File.join(self.root, file)] }.flatten
end
##
# An array of file to load before your app.rb, basically are files wich our app depends on.
#
# By default we look for files:
#
# # List of default files that we are looking for:
# yourapp/models.rb
# yourapp/models/**/*.rb
# yourapp/lib.rb
# yourapp/lib/**/*.rb
#
# @example Adding a custom perequisite
# MyApp.prerequisites << Padrino.root('my_app', 'custom_model.rb')
#
def prerequisites
@_prerequisites ||= []
end
protected
##
# Defines default settings for Padrino application
#
def default_configuration!
# Overwriting Sinatra defaults
set :app_file, File.expand_path(caller_files.first || $0) # Assume app file is first caller
set :environment, Padrino.env
set :reload, Proc.new { development? }
set :logging, Proc.new { development? }
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
# Padrino specific
set :uri_root, "/"
set :app_name, self.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(self.root, "/locale/**/*.{rb,yml}")] }
# Load the Global Configurations
class_eval(&Padrino.apps_configuration) if Padrino.apps_configuration
end
##
# We need to add almost __sinatra__ images.
#
def default_routes!
configure :development do
get '*__sinatra__/:image.png' do
content_type :png
filename = File.dirname(__FILE__) + "/images/#{params[:image]}.png"
send_file filename
end
end
end
##
# This filter it's used for know the format of the request, and automatically set the content type.
#
def default_filters!
before do
unless @_content_type
@_content_type = :html
response['Content-Type'] = 'text/html;charset=utf-8'
end
end
end
##
# This log errors for production environments
#
def default_errors!
configure :production do
error ::Exception do
boom = env['sinatra.error']
logger.error ["#{boom.class} - #{boom.message}:", *boom.backtrace].join("\n ")
response.status = 500
content_type 'text/html'
'<h1>Internal Server Error</h1>'
end unless errors.has_key?(::Exception)
end
end
##
# Requires all files within the application load paths
#
def require_dependencies
Padrino.set_load_paths(*load_paths)
Padrino.require_dependencies(dependencies, :force => true)
end
private
# Overrides the default middleware for Sinatra based on Padrino conventions
# 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
setup_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?
end
end
end # self
end # Application
end # Padrino

View file

@ -112,21 +112,6 @@ module Padrino
nil
end
##
# Determines whether the dependencies are locked by Bundler.
# otherwise return nil
#
# @return [:locked, :unlocked, nil]
# Returns +:locked+ if the +Gemfile.lock+ file exists, or +:unlocked+
# if only the +Gemfile+ exists.
#
# @deprecated Will be removed in 1.0.0
#
def bundle
return :locked if File.exist?(root('Gemfile.lock'))
return :unlocked if File.exist?(root("Gemfile"))
end
##
# A Rack::Builder object that allows to add middlewares in front of all
# Padrino applications.

View file

@ -0,0 +1,269 @@
module Padrino
class ApplicationSetupError < RuntimeError # @private
end
##
# Subclasses of this become independent Padrino applications (stemming from Sinatra::Application)
# These subclassed applications can be easily mounted into other Padrino applications as well.
#
class Application < Sinatra::Base
# Support for advanced routing, controllers, url_for
register Padrino::Routing
##
# Returns the logger for this application.
#
# @return [Padrino::Logger] Logger associated with this app.
#
def logger
Padrino.logger
end
class << self
def inherited(base) # @private
begun_at = Time.now
CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
base.default_configuration!
base.prerequisites.concat([
File.join(base.root, '/models.rb'),
File.join(base.root, '/models/**/*.rb'),
File.join(base.root, '/lib.rb'),
File.join(base.root, '/lib/**/*.rb')
]).uniq!
Padrino.require_dependencies(base.prerequisites)
logger.devel :setup, begun_at, base
super(base) # Loading the subclass inherited method
end
##
# Reloads the application files from all defined load paths
#
# This method is used from our Padrino Reloader during development mode
# in order to reload the source files.
#
# @return [TrueClass]
#
# @example
# MyApp.reload!
#
def reload!
logger.devel "Reloading #{settings}"
reset! # Reset sinatra app
reset_router! # Reset all routes
Padrino.require_dependencies(settings.app_file, :force => true) # Reload the app file
require_dependencies # Reload dependencies
default_filters! # Reload filters
default_routes! # Reload default routes
default_errors! # Reload our errors
I18n.reload! if defined?(I18n) # Reload also our translations
true
end
##
# Resets application routes to only routes not defined by the user
#
# @return [TrueClass]
#
# @example
# MyApp.reset_routes!
#
def reset_routes!
reset_router!
default_routes!
true
end
##
# Returns the routes of our app.
#
# @example
# MyApp.routes
#
def routes
router.routes
end
##
# Setup the application by registering initializers, load paths and logger
# Invoked automatically when an application is first instantiated
#
# @return [TrueClass]
#
def setup_application!
return if @_configured
settings.require_dependencies
settings.default_filters!
settings.default_routes!
settings.default_errors!
if defined?(I18n)
I18n.load_path << settings.locale_path
I18n.reload!
end
@_configured = true
@_configured
end
##
# Run the Padrino app as a self-hosted server using
# Thin, Mongrel or WEBrick (in that order)
#
# @see Padrino::Server#start
#
def run!(options={})
return unless Padrino.load!
Padrino.mount(settings.to_s).to('/')
Padrino.run!(options)
end
##
# @return [Array]
# directory that need to be added to +$LOAD_PATHS+ from this application
#
def load_paths
@_load_paths ||= %w[models lib mailers controllers helpers].map { |path| File.join(settings.root, path) }
end
##
# Returns default list of path globs to load as dependencies
# Appends custom dependency patterns to the be loaded for your Application
#
# @return [Array]
# list of path globs to load as dependencies
#
# @example
# MyApp.dependencies << "#{Padrino.root}/uploaders/**/*.rb"
# MyApp.dependencies << Padrino.root('other_app', 'controllers.rb')
#
def dependencies
[
'urls.rb', 'config/urls.rb', 'mailers/*.rb', 'mailers.rb',
'controllers/**/*.rb', 'controllers.rb', 'helpers/**/*.rb', 'helpers.rb'
].map { |file| Dir[File.join(settings.root, file)] }.flatten
end
##
# An array of file to load before your app.rb, basically are files wich our app depends on.
#
# By default we look for files:
#
# # List of default files that we are looking for:
# yourapp/models.rb
# yourapp/models/**/*.rb
# yourapp/lib.rb
# yourapp/lib/**/*.rb
#
# @example Adding a custom perequisite
# MyApp.prerequisites << Padrino.root('my_app', 'custom_model.rb')
#
def prerequisites
@_prerequisites ||= []
end
protected
##
# Defines default settings for Padrino application
#
def default_configuration!
# Overwriting Sinatra defaults
set :app_file, File.expand_path(caller_files.first || $0) # Assume app file is first caller
set :environment, Padrino.env
set :reload, Proc.new { development? }
set :logging, Proc.new { development? }
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
# 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}')] }
# Load the Global Configurations
class_eval(&Padrino.apps_configuration) if Padrino.apps_configuration
end
##
# We need to add almost __sinatra__ images.
#
def default_routes!
configure :development do
get '*__sinatra__/:image.png' do
content_type :png
filename = File.dirname(__FILE__) + "/images/#{params[:image]}.png"
send_file filename
end
end
end
##
# This filter it's used for know the format of the request, and automatically set the content type.
#
def default_filters!
before do
unless @_content_type
@_content_type = :html
response['Content-Type'] = 'text/html;charset=utf-8'
end
end
end
##
# This log errors for production environments
#
def default_errors!
configure :production do
error ::Exception do
boom = env['sinatra.error']
logger.error ["#{boom.class} - #{boom.message}:", *boom.backtrace].join("\n ")
response.status = 500
content_type 'text/html'
'<h1>Internal Server Error</h1>'
end unless errors.has_key?(::Exception)
end
end
##
# Requires all files within the application load paths
#
def require_dependencies
Padrino.set_load_paths(*load_paths)
Padrino.require_dependencies(dependencies, :force => true)
end
private
# Overrides the default middleware for Sinatra based on Padrino conventions
# 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
setup_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?
end
end
end # self
end # Application
end # Padrino

View file

@ -519,24 +519,24 @@ module Padrino
# Rewrite default routes.
#
# @example
# get :index # => "/"
# get :index, "/" # => "/"
# get :index, :map => "/" # => "/"
# get :show, "/show-me" # => "/show-me"
# get :show, :map => "/show-me" # => "/show-me"
# get "/foo/bar" # => "/show"
# get :index, :parent => :user # => "/user/:user_id/index"
# get :show, :with => :id, :parent => :user # => "/user/:user_id/show/:id"
# get :show, :with => :id # => "/show/:id"
# get [:show, :id] # => "/show/:id"
# get :show, :with => [:id, :name] # => "/show/:id/:name"
# get [:show, :id, :name] # => "/show/:id/:name"
# get :list, :provides => :js # => "/list.{:format,js)"
# get :list, :provides => :any # => "/list(.:format)"
# get :list, :provides => [:js, :json] # => "/list.{!format,js|json}"
# get :list, :provides => [:html, :js, :json] # => "/list(.{!format,js|json})"
# get :list, :priority => :low # Defers route to be last
#
# get :index # => "/"
# get :index, "/" # => "/"
# get :index, :map => "/" # => "/"
# get :show, "/show-me" # => "/show-me"
# get :show, :map => "/show-me" # => "/show-me"
# get "/foo/bar" # => "/show"
# get :index, :parent => :user # => "/user/:user_id/index"
# get :show, :with => :id, :parent => :user # => "/user/:user_id/show/:id"
# get :show, :with => :id # => "/show/:id"
# get [:show, :id] # => "/show/:id"
# get :show, :with => [:id, :name] # => "/show/:id/:name"
# get [:show, :id, :name] # => "/show/:id/:name"
# get :list, :provides => :js # => "/list.{:format,js)"
# get :list, :provides => :any # => "/list(.:format)"
# get :list, :provides => [:js, :json] # => "/list.{!format,js|json}"
# get :list, :provides => [:html, :js, :json] # => "/list(.{!format,js|json})"
# get :list, :priority => :low # Defers route to be last
# get /pattern/, :name => :foo, :generate_with => '/foo' # Generates :foo as /foo
def route(verb, path, *args, &block)
options = case args.size
when 2
@ -557,7 +557,7 @@ module Padrino
route_options = options.dup
route_options[:provides] = @_provides if @_provides
path, *route_options[:with] = path if path.is_a?(Array)
path, name, options = *parse_route(path, route_options, verb)
path, name, options, route_options = *parse_route(path, route_options, verb)
options.reverse_merge!(@_conditions) if @_conditions
# Sinatra defaults
@ -571,7 +571,7 @@ module Padrino
invoke_hook(:route_added, verb, path, block)
# HTTPRouter route construction
route = router.add(path)
route = router.add(path, route_options)
route.name(name) if name
priority_name = options.delete(:priority) || :normal
priority = ROUTE_PRIORITY[priority_name] or raise("Priority #{priority_name} not recognized, try #{ROUTE_PRIORITY.keys.join(', ')}")
@ -620,6 +620,9 @@ module Padrino
# We need save our originals path/options so we can perform correctly cache.
original = [path, options.dup]
# options for the route directly
route_options = {}
# We need check if path is a symbol, if that it's a named route
map = options.delete(:map)
@ -628,7 +631,11 @@ module Padrino
path = map ? map.dup : (path == :index ? '/' : path.to_s) # The route path
end
if path.kind_of?(String) # path i.e "/index" or "/show"
# Build our controller
controller = Array(@_controller).map { |c| c.to_s }
case path
when String # path i.e "/index" or "/show"
# Now we need to parse our 'with' params
if with_params = options.delete(:with)
path = process_path_for_with_params(path, with_params)
@ -643,9 +650,6 @@ module Padrino
options[:matching][:format] = /[^\.]+/
end
# Build our controller
controller = Array(@_controller).map { |c| c.to_s }
absolute_map = map && map[0] == ?/
unless controller.empty?
@ -656,10 +660,6 @@ module Padrino
path = File.join(controller_path, path)
end
# Here we build the correct name route
if name
controller_name = controller.join("_")
name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
end
end
# Now we need to parse our 'parent' params and parent scope
@ -678,12 +678,21 @@ module Padrino
path.sub!(%r{/(\))?$}, '\\1') if path != "/" # Remove latest trailing delimiter
path.gsub!(/\/(\(\.|$)/, '\\1') # Remove trailing slashes
path.squeeze!('/')
when Regexp
route_options[:path_for_generation] = options.delete(:generate_with) if options.key?(:generate_with)
end
name = options.delete(:route_name) if name.nil? && options.key?(:route_name)
name = options.delete(:name) if name.nil? && options.key?(:name)
if name
controller_name = controller.join("_")
name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
end
# Merge in option defaults
options.reverse_merge!(:default_values => @_defaults)
[path, name, options]
[path, name, options, route_options]
end
##

View file

@ -41,7 +41,6 @@ module Padrino
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."
method_option :verbose, :type => :boolean, :aliases => "-v", :desc => "Log message to standard output."
def rake(*args)
prepare :rake
args << "-T" if options[:list]
@ -51,9 +50,8 @@ module Padrino
ARGV.clear
ARGV.concat(args)
puts "=> Executing Rake #{ARGV.join(' ')} ..."
ENV['PADRINO_LOG_LEVEL'] ||= "test"
load File.expand_path('../rake.rb', __FILE__)
silence(:stdout) { require File.expand_path('config/boot.rb') }
require File.expand_path('config/boot.rb')
PadrinoTasks.init(true)
end
@ -62,10 +60,10 @@ module Padrino
prepare :console
require File.expand_path("../../version", __FILE__)
ARGV.clear
puts "=> Loading #{options.environment} console (Padrino v.#{Padrino.version})"
require 'irb'
require "irb/completion"
require File.expand_path('config/boot.rb')
puts "=> Loading #{Padrino.env} console (Padrino v.#{Padrino.version})"
require File.expand_path('../console', __FILE__)
IRB.start
end
@ -80,7 +78,8 @@ module Padrino
require 'padrino-core/command'
require 'padrino-gen/command'
ARGV.shift
Padrino.bin_gen(ARGV)
ARGV << 'help' if ARGV.empty?
Padrino.bin_gen(*ARGV)
rescue
puts "<= You need padrino-gen! Run: gem install padrino-gen"
end

View file

@ -94,6 +94,7 @@ module Padrino
# Method for reloading required applications and their files.
#
def reload!
return unless Padrino::Reloader.changed?
Padrino.before_load.each(&:call) # Run before hooks
Padrino::Reloader.reload! # detects the modified files
Padrino.after_load.each(&:call) # Run after hooks

View file

@ -4,7 +4,7 @@ lv:
# 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: "%d.%m.%Y."
default: "%d.%m.%Y"
short: "%e. %B"
long: "%Y. gada %e. %B"
only_day: "%e"
@ -21,7 +21,7 @@ lv:
time:
formats:
default: "%Y. gada %e. %B, %H:%M"
short: "%d.%m.%Y., %H:%M"
short: "%d.%m.%Y, %H:%M"
long: "%Y. gada %e. %B, %H:%M:%S"
am: "priekšpusdiena"
pm: "pēcpusdiena"

View file

@ -1,10 +1,10 @@
# Defines the log level for a Padrino project.
PADRINO_LOG_LEVEL = ENV['PADRINO_LOG_LEVEL'] unless defined?(PADRINO_LOG_LEVEL)
# Defines the logger used for a Padrino project.
PADRINO_LOGGER = ENV['PADRINO_LOGGER'] unless defined?(PADRINO_LOGGER)
PADRINO_LOGGER = ENV['PADRINO_LOGGER'] unless defined?(PADRINO_LOGGER)
module Padrino
##
# @return [Padrino::Logger]
#
@ -35,21 +35,14 @@ 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
end
##
# Extensions to the built in Ruby logger.
# Padrinos internal logger, using all of Padrino log extensions.
#
class Logger
attr_accessor :level
attr_accessor :auto_flush
attr_reader :buffer
attr_reader :log
attr_reader :init_args
attr_accessor :log_static
##
# Ruby (standard) logger levels:
#
@ -58,6 +51,7 @@ module Padrino
# :warn:: A warning
# :info:: generic (useful) information about system operation
# :debug:: low-level information for developers
# :devel:: Development-related information that is unnecessary in debug mode
#
Levels = {
:fatal => 7,
@ -68,6 +62,161 @@ module Padrino
:devel => -1,
} unless const_defined?(:Levels)
module Extensions
##
# Generate the logging methods for {Padrino.logger} for each log level.
#
Padrino::Logger::Levels.each_pair do |name, number|
define_method(name) do |*args|
return if number < level
if args.size > 1
bench(args[0], args[1], args[2], name)
else
push(args * '', name)
end
end
define_method(:"#{name}?") do
number >= level
end
end
##
# Append a to development logger a given action with time
#
# @param [string] action
# The action
#
# @param [float] time
# Time duration for the given action
#
# @param [message] string
# The message that you want to log
#
# @example
# logger.bench 'GET', started_at, '/blog/categories'
# # => DEBUG - GET (0.056ms) - /blog/categories
#
def bench(action, began_at, message, level=:debug, color=:yellow)
@_pad ||= 8
@_pad = action.to_s.size if action.to_s.size > @_pad
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)
push "#{action} (#{duration}) #{message}", level
end
##
# Appends a message to the log. The methods yield to an optional block and
# the output of this block will be appended to the message.
#
# @param [String] message
# The message that you want write to your stream
#
# @param [String] level
# The level one of :debug, :warn etc...
#
#
def push(message = nil, level = nil)
add(Padrino::Logger::Levels[level], format(message, level))
end
##
# Formats the log message. This method is a noop and should be implemented by other
# logger components such as {Padrino::Logger}.
#
# @param [String] message
# The message to format
#
# @param [String,Symbol] level
# The log level, one of :debug, :warn...
def format(message, level)
message
end
##
# The debug level, with some style added. May be reimplemented.
#
# @example
# stylized_level(:debug) => DEBUG
#
# @param [String,Symbol] level
# The log level
#
def stylized_level(level)
level.to_s.upcase.rjust(7)
end
##
# Colorizes a string for colored console output. This is a noop and can be reimplemented
# to colorize the string as needed.
#
# @see
# ColorizedLogger
#
# @param [string]
# The string to be colorized.
#
# @param [Array<Symbol>]
# The colors to use. Should be applied in the order given.
def colorize(string, *colors)
string
end
##
# Turns a logger with LoggingExtensions into a logger with colorized output.
#
# @example
# Padrino.logger = Logger.new($stdout)
# Padrino.logger.colorize!
# Padrino.logger.debug("Fancy Padrino debug string")
def colorize!
self.extend(Colorize)
end
end
module Colorize
# Colors for levels
ColoredLevels = {
:fatal => [:bold, :red],
:error => [:red],
:warn => [:yellow],
:info => [:green],
:debug => [:cyan],
:devel => [:magenta]
} unless defined?(ColoredLevels)
##
# Colorize our level
#
# @param [String, Symbol] level
#
# @see Padrino::Logging::ColorizedLogger::ColoredLevels
#
def colorize(string, *colors)
colors.each do |c|
string = string.send(c)
end
string
end
def stylized_level(level)
style = ColoredLevels[level].map { |c| "\e[%dm" % String.colors[c] } * ''
[style, super, "\e[0m"] * ''
end
end
include Extensions
include Colorize
attr_accessor :level
attr_accessor :auto_flush
attr_reader :buffer
attr_reader :log
attr_reader :init_args
attr_accessor :log_static
@@mutex = {}
##
@ -110,16 +259,6 @@ module Padrino
}
Config.merge!(PADRINO_LOGGER) if PADRINO_LOGGER
# Colors for levels
ColoredLevels = {
:fatal => [:bold, :red],
:error => [:red],
:warn => [:yellow],
:info => [:green],
:debug => [:cyan],
:devel => [:magenta]
} unless defined?(ColoredLevels)
##
# Setup a new logger
#
@ -137,13 +276,14 @@ module Padrino
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+")
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
@ -174,7 +314,7 @@ module Padrino
def initialize(options={})
@buffer = []
@auto_flush = options.has_key?(:auto_flush) ? options[:auto_flush] : true
@level = options[:log_level] ? Levels[options[:log_level]] : Levels[:debug]
@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
@ -183,18 +323,6 @@ module Padrino
@log_static = options.has_key?(:log_static) ? options[:log_static] : false
end
##
# Colorize our level
#
# @param [String, Symbol] level
#
# @see Padrino::Logger::ColoredLevels
#
def colored_level(level)
style = ColoredLevels[level].map { |c| "\e[%dm" % String.colors[c] } * ''
[style, level.to_s.upcase.rjust(7), "\e[0m"] * ''
end
##
# Flush the entire buffer to the log object.
#
@ -217,42 +345,11 @@ module Padrino
end
##
# Appends a message to the log. The methods yield to an optional block and
# the output of this block will be appended to the message.
# Adds a message to the log - for compatibility with other loggers.
#
# @param [String] message
# The message that you want write to your stream
#
# @param [String] level
# The level one of :debug, :warn etc...
#
#
def push(message = nil, level = nil)
write @format_message % [colored_level(level), Time.now.strftime(@format_datetime).yellow, message.to_s.strip]
end
##
# Append a to development logger a given action with time
#
# @param [string] action
# The action
#
# @param [float] time
# Time duration for the given action
#
# @param [message] string
# The message that you want to log
#
# @example
# logger.bench 'GET', started_at, '/blog/categories'
# # => DEBUG - GET (0.056ms) - /blog/categories
#
def bench(action, began_at, message, level=:debug, color=:yellow)
@_pad ||= 8
@_pad = action.to_s.size if action.to_s.size > @_pad
duration = Time.now - began_at
color = :red if duration > 1
push "%s (" % action.to_s.upcase.rjust(@_pad).send(color) + "%0.4fms".bold.send(color) % duration + ") %s" % message.to_s, level
# @private
def add(level, message = nil)
write(message)
end
##
@ -269,22 +366,8 @@ module Padrino
end
alias :write :<<
##
# Generate the logging methods for {Padrino.logger} for each log level.
#
Levels.each_pair do |name, number|
define_method(name) do |*args|
return if number < level
if args.size > 1
bench(*args)
else
push(args * '', name)
end
end
define_method(:"#{name}?") do
number >= level
end
def format(message, level)
@format_message % [stylized_level(level), colorize(Time.now.strftime(@format_datetime), :yellow), message.to_s.strip]
end
##
@ -301,7 +384,6 @@ module Padrino
def call(env) # @private
env['rack.logger'] = Padrino.logger
env['rack.errors'] = Padrino.logger.log
began_at = Time.now
status, header, body = @app.call(env)
log(env, status, header, began_at)
@ -309,28 +391,28 @@ module Padrino
end
private
def log(env, status, header, began_at)
return if env['sinatra.static_file'] and !logger.log_static
logger.bench(
env["REQUEST_METHOD"],
began_at,
[
@uri_root.to_s,
env["PATH_INFO"],
env["QUERY_STRING"].empty? ? "" : "?" + env["QUERY_STRING"],
' - ',
status.to_s[0..3].bold,
' ',
code_to_name(status)
] * '',
:debug,
:magenta
)
end
def log(env, status, header, began_at)
return if env['sinatra.static_file'] && (!logger.respond_to?(:log_static) || !logger.log_static)
logger.bench(
env["REQUEST_METHOD"],
began_at,
[
@uri_root.to_s,
env["PATH_INFO"],
env["QUERY_STRING"].empty? ? "" : "?" + env["QUERY_STRING"],
' - ',
logger.colorize(status.to_s[0..3], :bold),
' ',
code_to_name(status)
] * '',
:debug,
:magenta
)
end
def code_to_name(status)
::Rack::Utils::HTTP_STATUS_CODES[status.to_i] || ''
end
def code_to_name(status)
::Rack::Utils::HTTP_STATUS_CODES[status.to_i] || ''
end
end # Rack
end # Logger
end # Padrino
@ -343,3 +425,4 @@ module Kernel # @private
Padrino.logger
end
end # Kernel

View file

@ -92,7 +92,7 @@ module Padrino
changed = false
rotation do |file, mtime|
new_file = MTIMES[file].nil?
previous_mtime = MTIMES[file] ||= mtime
previous_mtime = MTIMES[file]
changed = true if new_file || mtime > previous_mtime
end
changed
@ -103,7 +103,7 @@ module Padrino
# We lock dependencies sets to prevent reloading of protected constants
#
def lock!
klasses = ObjectSpace.classes.map { |klass| klass.name.to_s.split("::")[0] }.uniq
klasses = ObjectSpace.classes.map { |klass| klass.name.split('::')[0] }.uniq
klasses = klasses | Padrino.mounted_apps.map { |app| app.app_class }
Padrino::Reloader.exclude_constants.concat(klasses)
end
@ -183,50 +183,50 @@ module Padrino
# Removes the specified class and constant.
#
def remove_constant(const)
return if exclude_constants.compact.uniq.any? { |c| (const.to_s =~ %r{^#{Regexp.escape(c)}}) } &&
!include_constants.compact.uniq.any? { |c| (const.to_s =~ %r{^#{Regexp.escape(c)}}) }
return if exclude_constants.compact.uniq.any? { |c| const.name.index(c) == 0 } &&
!include_constants.compact.uniq.any? { |c| const.name.index(c) == 0 }
begin
parts = const.to_s.split("::")
base = parts.size == 1 ? Object : parts[0..-2].join("::").constantize
object = parts[-1].to_s
base.send(:remove_const, object)
logger.devel "Removed constant: #{const}"
parts = const.to_s.sub(/^::(Object)?/, 'Object::').split('::')
object = parts.pop
base = parts.empty? ? Object : Inflector.constantize(parts * '::')
base.send :remove_const, object
logger.devel "Removed constant: #{const} from #{base}"
rescue NameError; end
end
private
##
# Return the mounted_apps providing the app location
# Can be an array because in one app.rb we can define multiple Padrino::Appplications
#
def mounted_apps_of(file)
file = figure_path(file)
Padrino.mounted_apps.find_all { |app| File.identical?(file, app.app_file) }
end
##
# Return the mounted_apps providing the app location
# Can be an array because in one app.rb we can define multiple Padrino::Appplications
#
def mounted_apps_of(file)
file = figure_path(file)
Padrino.mounted_apps.find_all { |app| File.identical?(file, app.app_file) }
end
##
# Returns true if file is in our Padrino.root
#
def in_root?(file)
# This is better but slow:
# Pathname.new(Padrino.root).find { |f| File.identical?(Padrino.root(f), figure_path(file)) }
figure_path(file) =~ %r{^#{Regexp.escape(Padrino.root)}}
end
##
# Returns true if file is in our Padrino.root
#
def in_root?(file)
# This is better but slow:
# Pathname.new(Padrino.root).find { |f| File.identical?(Padrino.root(f), figure_path(file)) }
figure_path(file).index(Padrino.root) == 0
end
##
# Searches Ruby files in your +Padrino.load_paths+ , Padrino::Application.load_paths
# 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 { |file|
file = File.expand_path(file)
next if Padrino::Reloader.exclude.any? { |base| file =~ %r{^#{Regexp.escape(base)}} } || !File.exist?(file)
yield(file, File.mtime(file))
}.compact
end
##
# Searches Ruby files in your +Padrino.load_paths+ , Padrino::Application.load_paths
# 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|
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
end # self
##

View file

@ -17,7 +17,7 @@ module Padrino
#
class Server < Rack::Server
# Server Handlers
Handlers = [:thin, :mongrel, :webrick]
Handlers = [:thin, :mongrel, :trinidad, :webrick]
# Starts the application on the available server with specified options.
def self.start(app, opts={})
@ -44,7 +44,7 @@ module Padrino
[:INT, :TERM].each { |sig| trap(sig) { exit } }
super
ensure
puts "<= Padrino has ended his set (crowd applauds)" unless options[:daemonize]
puts "<= Padrino leaves the gun, takes the cannoli" unless options[:daemonize]
end
# The application the server will run.

View file

@ -11,7 +11,7 @@ require 'active_support/inflector/methods' # constantize
require 'active_support/inflector/inflections' # pluralize
require 'active_support/inflections' # load default inflections
require 'yaml' unless defined?(YAML) # load yaml for i18n
require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/ # ruby color suppor for win
require 'win32console' if RUBY_PLATFORM =~ /(win|m)32/ # ruby color support for win
##
# This is an adapted version of active_support/core_ext/string/inflections.rb
@ -113,8 +113,8 @@ module ObjectSpace
# Returns all the classes in the object space.
def classes
ObjectSpace.each_object(Module).select do |klass|
# Why this? Ruby when you remove a constant don't clean it from
# rb_tables, this mean that here we can found classes that was
# 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
end
@ -191,8 +191,7 @@ end
##
# Loads our locale configuration files
#
# I18n.load_path += Dir["#{File.dirname(__FILE__)}/locale/*.yml"] if defined?(I18n)
### I18n.load_path += Dir["#{File.dirname(__FILE__)}/locale/*.yml"] if defined?(I18n) ### !!! FIXME middleman ###
##
# Used to determine if this file has already been required

View file

@ -6,7 +6,7 @@
#
module Padrino
# The version constant for the current version of Padrino.
VERSION = '0.10.5' unless defined?(Padrino::VERSION)
VERSION = '0.10.6' unless defined?(Padrino::VERSION)
#
# The current Padrino version.

View file

@ -34,5 +34,5 @@ Gem::Specification.new do |s|
s.add_dependency("sinatra", "~> 1.3.1")
s.add_dependency("http_router", "~> 0.10.2")
s.add_dependency("thor", "~> 0.14.3")
s.add_dependency("activesupport", "~> 3.1.0")
s.add_dependency("activesupport", "~> 3.2.0")
end

View file

@ -44,6 +44,8 @@ class MiniTest::Spec
else
super(name, *args, &block)
end
rescue Rack::Test::Error # no response yet
super(name, *args, &block)
end
alias :response :last_response

View file

@ -15,7 +15,6 @@ describe "Core" do
assert_respond_to Padrino, :load!
assert_respond_to Padrino, :reload!
assert_respond_to Padrino, :version
assert_respond_to Padrino, :bundle
assert_respond_to Padrino, :configure_apps
end
@ -23,7 +22,6 @@ describe "Core" do
should 'validate global helpers' do
assert_equal :test, Padrino.env
assert_match /\/test/, Padrino.root
assert_equal nil, Padrino.bundle
assert_not_nil Padrino.version
end

View file

@ -1,4 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/helper')
require 'lumberjack'
require 'logger'
describe "PadrinoLogger" do
@ -98,3 +100,55 @@ describe "PadrinoLogger" do
end
end
end
describe "alternate logger: Lumberjack" do
def setup_logger
@log = StringIO.new
Padrino.logger = Lumberjack::Logger.new(@log, :level => :debug)
end
should "annotate the logger to support additional Padrino fancyness" do
setup_logger
Padrino.logger.debug("Debug message")
assert_match(/Debug message/, @log.string)
end
should "colorize log output after colorize! is called" do
setup_logger
Padrino.logger.colorize!
mock_app do
enable :logging
get("/"){ "Foo" }
end
get "/"
assert_match /\e\[1m200\e\[0m OK/, @log.string
end
end
describe "alternate logger: stdlib logger" do
def setup_logger
@log = StringIO.new
Padrino.logger = Logger.new(@log)
end
should "annotate the logger to support additional Padrino fancyness" do
setup_logger
Padrino.logger.debug("Debug message")
assert_match(/Debug message/, @log.string)
end
should "colorize log output after colorize! is called" do
setup_logger
Padrino.logger.colorize!
mock_app do
enable :logging
get("/"){ "Foo" }
end
get "/"
assert_match /\e\[1m200\e\[0m OK/, @log.string
end
end

View file

@ -78,6 +78,13 @@ describe "Routing" do
assert_equal "My lucky number: 99 99", body
end
should 'accept regexp routes with generate with :generate_with' do
mock_app do
get(%r{/fob|/baz}, :name => :foo, :generate_with => '/fob') { "regexp" }
end
assert_equal "/fob", @app.url(:foo)
end
should "parse routes with question marks" do
mock_app do
get("/foo/?"){ "okey" }

View file

@ -1,103 +0,0 @@
module Padrino
module Helpers
##
# Helpers related to producing html tags within templates.
#
module TagHelpers
##
# Tag values escaped to html entities
#
ESCAPE_VALUES = {
"<" => "&lt;",
">" => "&gt;",
'"' => "&quot;"
}
##
# Creates an html tag with given name, content and options
#
# @overload content_tag(name, content, options)
# @param [Symbol] name The html type of tag.
# @param [String] content The contents in the tag.
# @param [Hash] options The html options to include in this tag.
# @overload content_tag(name, options, &block)
# @param [Symbol] name The html type of tag.
# @param [Hash] options The html options to include in this tag.
# @param [Proc] block The block returning html content
#
# @return [String] The html generated for the tag.
#
# @example
# content_tag(:p, "hello", :class => 'light')
# content_tag(:p, :class => 'dark') { ... }
#
# @api public
def content_tag(*args, &block)
name = args.first
options = args.extract_options!
tag_html = block_given? ? capture_html(&block) : args[1]
tag_result = tag(name, options.merge(:content => tag_html))
block_is_template?(block) ? concat_content(tag_result) : tag_result
end
##
# Creates an html input field with given type and options
#
# @param [Symbol] type
# The html type of tag to create.
# @param [Hash] options
# The html options to include in this tag.
#
# @return [String] The html for the input tag.
#
# @example
# input_tag :text, :class => "test"
# input_tag :password, :size => "20"
#
# @api semipublic
def input_tag(type, options = {})
options.reverse_merge!(:type => type)
tag(:input, options)
end
##
# Creates an html tag with the given name and options
#
# @param [Symbol] type
# The html type of tag to create.
# @param [Hash] options
# The html options to include in this tag.
#
# @return [String] The html for the input tag.
#
# @example
# tag(:br, :style => 'clear:both')
# tag(:p, :content => "hello", :class => 'large')
#
# @api public
def tag(name, options={})
content, open_tag = options.delete(:content), options.delete(:open)
content = content.join("\n") if content.respond_to?(:join)
identity_tag_attributes.each { |attr| options[attr] = attr.to_s if options[attr] }
html_attrs = options.map { |a, v| v.nil? || v == false ? nil : "#{a}=\"#{escape_value(v)}\"" }.compact.join(" ")
base_tag = (html_attrs.present? ? "<#{name} #{html_attrs}" : "<#{name}")
base_tag << (open_tag ? ">" : (content ? ">#{content}</#{name}>" : " />"))
end
private
##
# Returns a list of attributes which can only contain an identity value (i.e selected)
#
def identity_tag_attributes
[:checked, :disabled, :selected, :multiple]
end
##
# Escape tag values to their HTML/XML entities.
#
def escape_value(string)
string.to_s.gsub(Regexp.union(*ESCAPE_VALUES.keys)){|c| ESCAPE_VALUES[c] }
end
end # TagHelpers
end # Helpers
end # Padrino

View file

@ -1,6 +1,7 @@
require 'middleman-core/vendor/padrino-core-0.10.5/lib/padrino-core/support_lite' unless defined?(SupportLite)
require 'middleman-core/vendor/padrino-core-0.10.6/lib/padrino-core/support_lite' unless defined?(SupportLite) ### !!! FIXME middleman ###
### require 'padrino-core/support_lite' unless defined?(SupportLite) ### !!! FIXME middleman ###
require 'cgi'
# require 'i18n'
### require 'i18n' ### !!! FIXME middleman ###
require 'enumerator'
require 'active_support/core_ext/string/conversions' # to_date
require 'active_support/core_ext/float/rounding' # round
@ -11,7 +12,7 @@ require 'active_support/inflector' # humanize
FileSet.glob_require('padrino-helpers/**/*.rb', __FILE__)
# Load our locales
# I18n.load_path += Dir["#{File.dirname(__FILE__)}/padrino-helpers/locale/*.yml"]
### I18n.load_path += Dir["#{File.dirname(__FILE__)}/padrino-helpers/locale/*.yml"] ### !!! FIXME middleman ###
module Padrino
##

View file

@ -17,13 +17,18 @@ module Padrino
# @example
# flash_tag(:notice, :id => 'flash-notice')
# # Generates: <div class="notice">flash-notice</div>
# flash_tag(:error, :success)
# # Generates: <div class="error">flash-error</div>
# # <div class="success">flash-success</div>
#
# @api public
def flash_tag(kind, options={})
flash_text = flash[kind]
return '' if flash_text.blank?
options.reverse_merge!(:class => kind)
content_tag(:div, flash_text, options)
def flash_tag(*args)
options = args.extract_options!
args.map do |kind|
flash_text = flash[kind]
next if flash_text.blank?
content_tag(:div, flash_text, options.reverse_merge(:class => kind))
end.compact * "\n"
end
##
@ -65,18 +70,17 @@ module Padrino
# @api public
def link_to(*args, &block)
options = args.extract_options!
options = parse_js_attributes(options) # parses remote, method and confirm options
anchor = "##{CGI.escape options.delete(:anchor).to_s}" if options[:anchor]
if block_given?
url = args[0] ? args[0] + anchor.to_s : anchor || 'javascript:void(0);'
url = args[0] ? args[0] + anchor.to_s : anchor || '#'
options.reverse_merge!(:href => url)
link_content = capture_html(&block)
return '' unless parse_conditions(url, options)
result_link = content_tag(:a, link_content, options)
block_is_template?(block) ? concat_content(result_link) : result_link
else
name, url = args[0], (args[1] ? args[1] + anchor.to_s : anchor || 'javascript:void(0);')
name, url = args[0], (args[1] ? args[1] + anchor.to_s : anchor || '#')
return name unless parse_conditions(url, options)
options.reverse_merge!(:href => url)
content_tag(:a, name, options)
@ -119,8 +123,8 @@ module Padrino
desired_method = options[:method]
options.delete(:method) if options[:method].to_s !~ /get|post/i
options.reverse_merge!(:method => 'post', :action => url)
options[:enctype] = "multipart/form-data" if options.delete(:multipart)
options["data-remote"] = "true" if options.delete(:remote)
options[:enctype] = 'multipart/form-data' if options.delete(:multipart)
options['data-remote'] = 'true' if options.delete(:remote)
inner_form_html = hidden_form_method_field(desired_method)
inner_form_html += block_given? ? capture_html(&block) : submit_tag(name)
content_tag('form', inner_form_html, options)
@ -153,7 +157,7 @@ module Padrino
# @api public
def feed_tag(mime, url, options={})
full_mime = (mime == :atom) ? 'application/atom+xml' : 'application/rss+xml'
content_tag(:link, options.reverse_merge(:rel => 'alternate', :type => full_mime, :title => mime, :href => url))
tag(:link, options.reverse_merge(:rel => 'alternate', :type => full_mime, :title => mime, :href => url))
end
##
@ -291,9 +295,9 @@ module Padrino
# @api public
def javascript_include_tag(*sources)
options = sources.extract_options!.symbolize_keys
options.reverse_merge!(:type => 'text/javascript', :content => "")
options.reverse_merge!(:type => 'text/javascript')
sources.flatten.map { |source|
tag(:script, options.reverse_merge(:src => asset_path(:js, source)))
content_tag(:script, nil, options.reverse_merge(:src => asset_path(:js, source)))
}.join("\n")
end
@ -338,83 +342,76 @@ module Padrino
# @api semipublic
def asset_path(kind, source)
return source if source =~ /^http/
asset_folder = case kind
when :css then 'stylesheets'
when :js then 'javascripts'
else kind.to_s
end
is_absolute = source =~ %r{^/}
asset_folder = asset_folder_name(kind)
source = source.to_s.gsub(/\s/, '%20')
ignore_extension = (asset_folder.to_s == kind.to_s) # don't append extension
ignore_extension = (asset_folder.to_s == kind.to_s) # don't append an extension
source << ".#{kind}" unless ignore_extension or source =~ /\.#{kind}/
result_path = source if source =~ %r{^/} # absolute path
result_path ||= uri_root_path(asset_folder, source)
timestamp = asset_timestamp(result_path)
result_path = is_absolute ? source : uri_root_path(asset_folder, source)
timestamp = asset_timestamp(result_path, is_absolute)
"#{result_path}#{timestamp}"
end
private
##
# Returns the uri root of the application with optional paths appended.
#
# @example
# uri_root_path("/some/path") => "/root/some/path"
# uri_root_path("javascripts", "test.js") => "/uri/root/javascripts/test.js"
#
def uri_root_path(*paths)
root_uri = self.class.uri_root if self.class.respond_to?(:uri_root)
File.join(ENV['RACK_BASE_URI'].to_s, root_uri || '/', *paths)
end
##
# Returns the uri root of the application.
#
# @example
# uri_root_path("/some/path") => "/base/some/path"
#
def uri_root_path(*paths)
root_uri = self.class.uri_root if self.class.respond_to?(:uri_root)
File.join(ENV['RACK_BASE_URI'].to_s, root_uri || '/', *paths)
end
##
# Returns the timestamp mtime for an asset
#
# @example
# asset_timestamp("some/path/to/file.png") => "?154543678"
# asset_timestamp("/some/absolute/path.png", true) => nil
#
def asset_timestamp(file_path, absolute=false)
return nil if file_path =~ /\?/ || (self.class.respond_to?(:asset_stamp) && !self.class.asset_stamp)
public_file_path = Padrino.root("public", file_path) if Padrino.respond_to?(:root)
stamp = File.mtime(public_file_path).to_i if public_file_path && File.exist?(public_file_path)
stamp ||= Time.now.to_i unless absolute
"?#{stamp}" if stamp
end
##
# Returns the timestamp mtime for an asset
#
# @example
# asset_timestamp("some/path/to/file.png") => "?154543678"
#
def asset_timestamp(file_path)
return nil if file_path =~ /\?/ || (self.class.respond_to?(:asset_stamp) && !self.class.asset_stamp)
public_path = Padrino.root("public", file_path) if Padrino.respond_to?(:root)
stamp = Time.now.to_i unless public_path && File.exist?(public_path)
stamp ||= File.mtime(public_path).to_i
"?#{stamp}"
###
# Returns the asset folder given a kind.
#
# @example
# asset_folder_name(:css) => 'stylesheets'
# asset_folder_name(:js) => 'javascripts'
# asset_folder_name(:images) => 'images'
#
def asset_folder_name(kind)
case kind
when :css then 'stylesheets'
when :js then 'javascripts'
else kind.to_s
end
end
##
# Parses link_to options for given correct conditions
#
# @example
# parse_conditions("/some/url", :if => false) => true
#
def parse_conditions(url, options)
if options.has_key?(:if)
condition = options.delete(:if)
condition == :current ? url == request.path_info : condition
elsif condition = options.delete(:unless)
condition == :current ? url != request.path_info : !condition
else
true
end
end
##
# Parses link_to options for given js declarations (remote, method, confirm)
# Not destructive on options; returns updated options
#
# parse_js_attributes(:remote => true, :confirm => "test", :method => :delete)
# => { "data-remote" => true, "data-method" => "delete", "data-confirm" => "test" }
#
def parse_js_attributes(options)
options = options.dup
options["data-remote"] = "true" if options.delete(:remote)
if link_confirm = options.delete(:confirm)
options["data-confirm"] = link_confirm
end
if link_method = options.delete(:method)
options["data-method"] = link_method
options["rel"] = "nofollow"
end
options
##
# Parses link_to options for given correct conditions
#
# @example
# parse_conditions("/some/url", :if => false) => true
#
def parse_conditions(url, options)
if options.has_key?(:if)
condition = options.delete(:if)
condition == :current ? url == request.path_info : condition
elsif condition = options.delete(:unless)
condition == :current ? url != request.path_info : !condition
else
true
end
end
end # AssetTagHelpers
end # Helpers
end # Padrino

View file

@ -42,6 +42,37 @@ module Padrino
@template.text_field_tag field_name(field), options
end
def number_field(field, options={})
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
options.merge!(:class => field_error(field, options))
@template.number_field_tag field_name(field), options
end
def telephone_field(field, options={})
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
options.merge!(:class => field_error(field, options))
@template.telephone_field_tag field_name(field), options
end
alias_method :phone_field, :telephone_field
def email_field(field, options={})
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
options.merge!(:class => field_error(field, options))
@template.email_field_tag field_name(field), options
end
def search_field(field, options={})
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
options.merge!(:class => field_error(field, options))
@template.search_field_tag field_name(field), options
end
def url_field(field, options={})
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
options.merge!(:class => field_error(field, options))
@template.url_field_tag field_name(field), options
end
# f.text_area :summary, :value => "(enter summary)", :id => 'summary'
def text_area(field, options={})
options.reverse_merge!(:value => field_value(field), :id => field_id(field))

View file

@ -74,13 +74,11 @@ module Padrino
#
# @api public
def form_tag(url, options={}, &block)
desired_method = options[:method]
data_method = options.delete(:method) if options[:method].to_s !~ /get|post/i
options.reverse_merge!(:method => "post", :action => url)
options[:enctype] = "multipart/form-data" if options.delete(:multipart)
options["data-remote"] = "true" if options.delete(:remote)
options["data-method"] = data_method if data_method
options["accept-charset"] ||= "UTF-8"
desired_method = options[:method].to_s
options.delete(:method) unless desired_method =~ /get|post/i
options.reverse_merge!(:method => 'post', :action => url)
options[:enctype] = 'multipart/form-data' if options.delete(:multipart)
options['accept-charset'] ||= 'UTF-8'
inner_form_html = hidden_form_method_field(desired_method)
inner_form_html += capture_html(&block)
concat_content content_tag(:form, inner_form_html, options)
@ -140,9 +138,9 @@ module Padrino
# @param [Hash] options Error message display options.
# @option options [String] :header_tag ("h2")
# Used for the header of the error div
# @option options [String] :id ("errorExplanation")
# @option options [String] :id ("field-errors")
# The id of the error div.
# @option options [String] :class ("errorExplanation")
# @option options [String] :class ("field-errors")
# The class of the error div.
# @option options [Array<Object>] :object
# The object (or array of objects) for which to display errors,
@ -222,7 +220,7 @@ module Padrino
# The field on the +object+ to display the error for.
# @param [Hash] options
# The options to control the error display.
# @option options [String] :tag ("div")
# @option options [String] :tag ("span")
# The tag that encloses the error.
# @option options [String] :prepend ("")
# The text to prepend before the field error.
@ -289,29 +287,216 @@ module Padrino
end
##
# Constructs a text field input from the given options
# Creates a text field input with the given name and options
#
# @macro [new] input_field_doc
# @param [String] name
# The name of the input field.
# @macro [new] text_field
# @param [Symbol] name
# The name of the input to create.
# @param [Hash] options
# The html options for the input field.
# The HTML options to include in this field.
#
# @return [String] The html input field based on the +options+ specified
# @option options [String] :id
# Specifies a unique identifier for the field.
# @option options [String] :class
# Specifies the stylesheet class of the field.
# @option options [String] :name
# Specifies the name of the field.
# @option options [String] :accesskey
# Specifies a shortcut key to access the field.
# @option options [Integer] :tabindex
# Specifies the tab order of the field.
# @option options [Integer] :maxlength
# Specifies the maximum length, in characters, of the field.
# @option options [Integer] :size
# Specifies the width, in characters, of the field.
# @option options [String] :placeholder
# Specifies a short hint that describes the expected value of the field.
# @option options [Boolean] :hidden
# Specifies whether or not the field is hidden from view.
# @option options [Boolean] :spellcheck
# Specifies whether or not the field should have it's spelling and grammar checked for errors.
# @option options [Boolean] :draggable
# Specifies whether or not the field is draggable. (true, false, :auto)
# @option options [String] :pattern
# Specifies the regular expression pattern that the field's value is checked against.
# @option options [Symbol] :autocomplete
# Specifies whether or not the field should have autocomplete enabled. (:on, :off)
# @option options [Boolean] :autofocus
# Specifies whether or not the field should automatically get focus when the page loads.
# @option options [Boolean] :required
# Specifies whether or not the field is required to be completeled before the form is submitted.
# @option options [Boolean] :readonly
# Specifies whether or not the field is read only.
# @option options [Boolean] :disabled
# Specifies whether or not the field is disabled.
#
# @return [String]
# Generated HTML with specified +options+
#
# @example
# text_field_tag :username, :class => 'long'
# text_field_tag :first_name, :maxlength => 40, :required => true
# # => <input name="first_name" maxlength="40" required type="text">
#
# text_field_tag :last_name, :class => 'string', :size => 40
# # => <input name="last_name" class="string" size="40" type="text">
#
# text_field_tag :username, :placeholder => 'Your Username'
# # => <input name="username" placeholder="Your Username" type="text">
#
# @api public
def text_field_tag(name, options={})
options.reverse_merge!(:name => name)
input_tag(:text, options)
input_tag(:text, options.reverse_merge!(:name => name))
end
##
# Creates a number field input with the given name and options
#
# @macro [new] number_field
# @param [Symbol] name
# The name of the input to create.
# @param [Hash] options
# The HTML options to include in this field.
#
# @option options [String] :id
# Specifies a unique identifier for the field.
# @option options [String] :class
# Specifies the stylesheet class of the field.
# @option options [String] :name
# Specifies the name of the field.
# @option options [String] :accesskey
# Specifies a shortcut key to access the field.
# @option options [Integer] :tabindex
# Specifies the tab order of the field.
# @option options [Integer] :min
# Specifies the minimum value of the field.
# @option options [Integer] :max
# Specifies the maximum value of the field.
# @option options [Integer] :step
# Specifies the legal number intervals of the field.
# @option options [Boolean] :hidden
# Specifies whether or not the field is hidden from view.
# @option options [Boolean] :spellcheck
# Specifies whether or not the field should have it's spelling and grammar checked for errors.
# @option options [Boolean] :draggable
# Specifies whether or not the field is draggable. (true, false, :auto)
# @option options [String] :pattern
# Specifies the regular expression pattern that the field's value is checked against.
# @option options [Symbol] :autocomplete
# Specifies whether or not the field should have autocomplete enabled. (:on, :off)
# @option options [Boolean] :autofocus
# Specifies whether or not the field should automatically get focus when the page loads.
# @option options [Boolean] :required
# Specifies whether or not the field is required to be completeled before the form is submitted.
# @option options [Boolean] :readonly
# Specifies whether or not the field is read only.
# @option options [Boolean] :disabled
# Specifies whether or not the field is disabled.
#
# @return [String]
# Generated HTML with specified +options+
#
# @example
# number_field_tag :quanity, :class => 'numeric'
# # => <input name="quanity" class="numeric" type="number">
#
# number_field_tag :zip_code, :pattern => /[0-9]{5}/
# # => <input name="zip_code" pattern="[0-9]{5}" type="number">
#
# number_field_tag :credit_card, :autocomplete => :off
# # => <input name="credit_card" autocomplete="off" type="number">
#
# number_field_tag :age, :min => 18, :max => 120, :step => 1
# # => <input name="age" min="18" max="120" step="1" type="number">
#
# @api public
def number_field_tag(name, options={})
input_tag(:number, options.reverse_merge(:name => name))
end
##
# Creates a telephone field input with the given name and options
#
# @macro text_field
#
# @example
# telephone_field_tag :phone_number, :class => 'string'
# # => <input name="phone_number" class="string" type="tel">
#
# telephone_field_tag :cell_phone, :tabindex => 1
# telephone_field_tag :work_phone, :tabindex => 2
# telephone_field_tag :home_phone, :tabindex => 3
#
# # => <input name="cell_phone" tabindex="1" type="tel">
# # => <input name="work_phone" tabindex="2" type="tel">
# # => <input name="home_phone" tabindex="3" type="tel">
#
# @api public
def telephone_field_tag(name, options={})
input_tag(:tel, options.reverse_merge(:name => name))
end
alias_method :phone_field_tag, :telephone_field_tag
##
# Creates an email field input with the given name and options
#
# @macro text_field
#
# @example
# email_field_tag :email, :placeholder => 'you@example.com'
# # => <input name="email" placeholder="you@example.com" type="email">
#
# email_field_tag :email, :value => 'padrinorb@gmail.com', :readonly => true
# # => <input name="email" value="padrinorb@gmail.com" readonly type="email">
#
# @api public
def email_field_tag(name, options={})
input_tag(:email, options.reverse_merge(:name => name))
end
##
# Creates a search field input with the given name and options
#
# @macro text_field
#
# @example
# search_field_tag :search, :placeholder => 'Search this website...'
# # => <input name="search" placeholder="Search this website..." type="search">
#
# search_field_tag :search, :maxlength => 15, :class => ['search', 'string']
# # => <input name="search" maxlength="15" class="search string">
#
# search_field_tag :search, :id => 'search'
# # => <input name="search" id="search" type="search">
#
# search_field_tag :search, :autofocus => true
# # => <input name="search" autofocus type="search">
#
# @api public
def search_field_tag(name, options={})
input_tag(:search, options.reverse_merge(:name => name))
end
##
# Creates a url field input with the given name and options
#
# @macro text_field
#
# @example
# url_field_tag :favorite_website, :placeholder => 'http://padrinorb.com'
# <input name="favorite_website" placeholder="http://padrinorb.com." type="url">
#
# url_field_tag :home_page, :class => 'string url'
# <input name="home_page" class="string url", type="url">
#
# @api public
def url_field_tag(name, options={})
input_tag(:url, options.reverse_merge(:name => name))
end
##
# Constructs a hidden field input from the given options
#
# @macro input_field_doc
# @macro text_field
#
# @example
# hidden_field_tag :session_key, :value => "__secret__"
@ -325,7 +510,7 @@ module Padrino
##
# Constructs a text area input from the given options
#
# @macro input_field_doc
# @macro text_field
#
# @example
# text_area_tag :username, :class => 'long', :value => "Demo?"
@ -339,7 +524,7 @@ module Padrino
##
# Constructs a password field input from the given options
#
# @macro input_field_doc
# @macro text_field
#
# @example
# password_field_tag :password, :class => 'long'
@ -353,7 +538,7 @@ module Padrino
##
# Constructs a check_box from the given options
#
# @macro input_field_doc
# @macro text_field
#
# @example
# check_box_tag :remember_me, :value => 'Yes'
@ -367,7 +552,7 @@ module Padrino
##
# Constructs a radio_button from the given options
#
# @macro input_field_doc
# @macro text_field
#
# @example
# radio_button_tag :remember_me, :value => 'true'
@ -381,7 +566,7 @@ module Padrino
##
# Constructs a file field input from the given options
#
# @macro input_field_doc
# @macro text_field
#
# @example
# file_field_tag :photo, :class => 'long'

View file

@ -81,7 +81,7 @@ module Padrino
# @api public
def simple_format(text, options={})
t = options.delete(:tag) || :p
start_tag = tag(t, options.merge(:open => true))
start_tag = tag(t, options, true)
text = text.to_s.dup
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
text.gsub!(/\n\n+/, "</#{t}>\n\n#{start_tag}") # 2+ newline -> paragraph
@ -375,7 +375,7 @@ module Padrino
javascript_mapping = { '\\' => '\\\\', '</' => '<\/', "\r\n" => '\n', "\n" => '\n', "\r" => '\n', '"' => '\\"', "'" => "\\'" }
html_content.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { javascript_mapping[$1] }
end
alias :escape_javascript :js_escape_html
end # FormatHelpers
end # Helpers
end # Padrino

Some files were not shown because too many files have changed in this diff Show more