update padrino to 0.10.6 vanilla

This commit is contained in:
Trevor Wennblom 2012-04-13 07:33:52 -05:00
parent 094de61e92
commit b514b7ea6e
34 changed files with 1391 additions and 518 deletions

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

@ -22,16 +22,17 @@ module Padrino
class << self
def inherited(base) # @private
logger.devel "Setup #{base}"
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")
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
@ -47,11 +48,10 @@ module Padrino
# MyApp.reload!
#
def reload!
logger.devel "Reloading #{self}"
@_dependencies = nil # Reset dependencies
logger.devel "Reloading #{settings}"
reset! # Reset sinatra app
reset_router! # Reset all routes
Padrino.require_dependencies(self.app_file, :force => true) # Reload the app file
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
@ -92,12 +92,12 @@ module Padrino
#
def setup_application!
return if @_configured
self.require_dependencies
self.default_filters!
self.default_routes!
self.default_errors!
settings.require_dependencies
settings.default_filters!
settings.default_routes!
settings.default_errors!
if defined?(I18n)
I18n.load_path << self.locale_path
I18n.load_path << settings.locale_path
I18n.reload!
end
@_configured = true
@ -112,7 +112,7 @@ module Padrino
#
def run!(options={})
return unless Padrino.load!
Padrino.mount(self.to_s).to("/")
Padrino.mount(settings.to_s).to('/')
Padrino.run!(options)
end
@ -121,7 +121,7 @@ module Padrino
# 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) }
@_load_paths ||= %w[models lib mailers controllers helpers].map { |path| File.join(settings.root, path) }
end
##
@ -136,10 +136,10 @@ module Padrino
# 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
[
'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
##
@ -161,110 +161,109 @@ module Padrino
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
##
# 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
##
# 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
##
# 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
##
# 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
##
# 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
# 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
# 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

@ -13,7 +13,7 @@ it:
abbr_day_names: [Dom, Lun, Mar, Mer, Gio, Ven, Sab]
month_names: [~, Gennaio, Febbraio, Marzo, Aprile, Maggio, Giugno, Luglio, Agosto, Settembre, Ottobre, Novembre, Dicembre]
abbr_month_names: [~, Gen, Feb, Mar, Apr, Mag, Giu, Lug, Ago, Set, Ott, Nov, Dic]
order:
order:
- day
- month
- year

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)
##
# 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,6 +1,6 @@
require 'middleman-core/vendor/padrino-core-0.10.5/lib/padrino-core/support_lite' unless defined?(SupportLite)
require 'padrino-core/support_lite' unless defined?(SupportLite)
require 'cgi'
# require 'i18n'
require 'i18n'
require 'enumerator'
require 'active_support/core_ext/string/conversions' # to_date
require 'active_support/core_ext/float/rounding' # round
@ -11,7 +11,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"]
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

View file

@ -13,91 +13,248 @@ module Padrino
'"' => "&quot;"
}
BOOLEAN_ATTRIBUTES = [
:autoplay,
:autofocus,
:formnovalidate,
:checked,
:disabled,
:hidden,
:loop,
:multiple,
:muted,
:readonly,
:required,
:selected
]
##
# Creates an html tag with given name, content and options
# Custom data attributes,
# feel free to update with yours:
#
# @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
# Padrino::Helpers::TagHelpers::DATA_ATTRIBUTES.push(:dialog)
# text_field :foo, :dialog => true
# # Generates: <input type="text" data-dialog="true" name="foo" />
#
# @return [String] The html generated for the tag.
DATA_ATTRIBUTES = [
:method,
:remote,
:confirm
]
##
# Creates an HTML tag with given name, content, and options
#
# @overload content_tag(name, content, options = nil)
# @param [Symbol] name
# The name of the HTML tag to create.
# @param [String] content
# The content inside of the the tag.
# @param [Hash] options
# The HTML options to include in this tag.
#
# @overload content_tag(name, options = nil, &block)
# @param [Symbol] name
# The name of the HTML tag to create.
# @param [Hash] options
# The HTML options to include in this tag.
# @param [Proc] block
# The block returning HTML content.
#
# @macro [new] global_html_attributes
# @option options [String] :id
# Specifies a unique identifier for the element.
# @option options [String] :class
# Specifies the stylesheet class of the element.
# @option options [String] :title
# Specifies the title for the element.
# @option options [String] :accesskey
# Specifies a shortcut key to access the element.
# @option options [Symbol] :dropzone
# Specifies what happens when dragged items are dropped on the element. (:copy, :link, :move)
# @option options [Boolean] :hidden
# Specifies whether or not the element is hidden from view.
# @option options [Boolean] :draggable
# Specifies whether or not the element is draggable. (true, false, :auto)
# @option options [Boolean] :contenteditable
# Specifies whether or not the element is editable.
#
# @return [String]
# Generated HTML with specified +options+
#
# @example
# content_tag(:p, "hello", :class => 'light')
# content_tag(:p, :class => 'dark') { ... }
# content_tag(:p, 'Hello World', :class => 'light')
#
# # => <p class="light">
# # => Hello World
# # => </p>
#
# content_tag(:p, :class => 'dark') do
# link_to 'Padrino', 'http://www.padrinorb.com'
# end
#
# # => <p class="dark">
# # => <a href="http://www.padrinorb.com">Padrino</a>
# # => </p>
#
# @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
def content_tag(name, content = nil, options = nil, &block)
if block_given?
options = content if content.is_a?(Hash)
content = capture_html(&block)
end
content = content.join("\n") if content.respond_to?(:join)
options = parse_data_options(name, options)
attributes = tag_attributes(options)
output = "<#{name}#{attributes}>#{content}</#{name}>"
block_is_template?(block) ? concat_content(output) : output
end
##
# Creates an html input field with given type and options
# Creates an HTML input field with the given type and options
#
# @param [Symbol] type
# The html type of tag to create.
# The type of input to create.
# @param [Hash] options
# The html options to include in this tag.
# The HTML options to include in this input.
#
# @return [String] The html for the input tag.
# @option options [String] :id
# Specifies a unique identifier for the input.
# @option options [String] :class
# Specifies the stylesheet class of the input.
# @option options [String] :name
# Specifies the name of the input.
# @option options [String] :accesskey
# Specifies a shortcut key to access the input.
# @option options [Integer] :tabindex
# Specifies the tab order of the input.
# @option options [Boolean] :hidden
# Specifies whether or not the input is hidden from view.
# @option options [Boolean] :spellcheck
# Specifies whether or not the input should have it's spelling and grammar checked for errors.
# @option options [Boolean] :draggable
# Specifies whether or not the input is draggable. (true, false, :auto)
# @option options [String] :pattern
# Specifies the regular expression pattern that the input's value is checked against.
# @option options [Symbol] :autocomplete
# Specifies whether or not the input should have autocomplete enabled. (:on, :off)
# @option options [Boolean] :autofocus
# Specifies whether or not the input should automatically get focus when the page loads.
# @option options [Boolean] :required
# Specifies whether or not the input is required to be completeled before the form is submitted.
# @option options [Boolean] :readonly
# Specifies whether or not the input is read only.
# @option options [Boolean] :disabled
# Specifies whether or not the input is disabled.
#
# @return [String]
# Generated HTML with specified +options+
#
# @example
# input_tag :text, :class => "test"
# input_tag :password, :size => "20"
# input_tag :text, :name => 'handle'
# # => <input type="test" name="handle" />
#
# input_tag :password, :name => 'password', :size => 20
# # => <input type="password" name="password" size="20" />
#
# input_tag :text, :name => 'username', :required => true, :autofocus => true
# # => <input type="text" name="username" required autofocus />
#
# input_tag :number, :name => 'credit_card', :autocomplete => :off
# # => <input type="number" autocomplete="off" />
#
# @api semipublic
def input_tag(type, options = {})
options.reverse_merge!(:type => type)
tag(:input, options)
tag(:input, options.reverse_merge!(:type => type))
end
##
# Creates an html tag with the given name and options
# Creates an HTML tag with the given name and options
#
# @param [Symbol] type
# The html type of tag to create.
# @param [Symbol] name
# The name of the HTML tag to create.
# @param [Hash] options
# The html options to include in this tag.
# The HTML options to include in this tag.
#
# @return [String] The html for the input tag.
# @macro global_html_attributes
#
# @return [String]
# Generated HTML with specified +options+
#
# @example
# tag(:br, :style => 'clear:both')
# tag(:p, :content => "hello", :class => 'large')
# tag :hr, :class => 'dotted'
# # => <hr class="dotted">
#
# tag :input, :name => 'username', :type => :text
# # => <input name="username" type="text" />
#
# tag :img, :src => 'images/pony.jpg', :alt => 'My Little Pony'
# # => <img src="images/pony.jpg" alt="My Little Pony" />
#
# tag :img, :src => 'sinatra.jpg, :data => { :nsfw => false, :geo => [34.087, -118.407] }
# # => <img src="sinatra.jpg" data-nsfw="false" data-geo="34.087 -118.407" />
#
# @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}>" : " />"))
def tag(name, options = nil, open = false)
options = parse_data_options(name, options)
attributes = tag_attributes(options)
"<#{name}#{attributes}#{open ? '>' : ' />'}"
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
##
# Returns a compiled list of HTML attributes
##
def tag_attributes(options)
return '' if options.nil?
attributes = options.map do |k, v|
next if v.nil? || v == false
if v.is_a?(Hash)
nested_values(k, v)
elsif BOOLEAN_ATTRIBUTES.include?(k)
k.to_s
else
%(#{k}="#{escape_value(v)}")
end
end.compact
attributes.empty? ? '' : " #{attributes * ' '}"
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] }
##
# 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
##
# Iterate through nested values
#
def nested_values(attribute, hash)
hash.map do |k, v|
if v.is_a?(Hash)
nested_values("#{attribute}-#{k.to_s.dasherize}", v)
else
%(#{attribute}-#{k.to_s.dasherize}="#{escape_value(v)}")
end
end * ' '
end
##
# Parses custom data attributes
#
def parse_data_options(tag, options)
return if options.nil?
parsed_options = options.dup
options.each do |k, v|
next if !DATA_ATTRIBUTES.include?(k) || (tag.to_s == 'form' && k == :method)
parsed_options["data-#{k}"] = parsed_options.delete(k)
parsed_options[:rel] = 'nofollow' if k == :method
end
parsed_options
end
end # TagHelpers
end # Helpers
end # Padrino

View file

@ -5,14 +5,30 @@
<%= f.label :username, :caption => "Login: ", :class => 'user-label' %>
<%= f.text_field :username, :class => 'user-text', :value => "John" %>
</p>
<p>
<%= f.label :email, :caption => "Email", :class => 'user-email' %>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %>
<%= f.password_field :password, :class => 'user-password', :value => "secret" %>
</p>
<p>
<%= f.label :age %>
<%= f.number_field :age, :class => 'numeric '%>
</p>
<p>
<%= f.label :telephone %>
<%= f.telephone_field :telephone, :class => 'numeric' %>
</p>
<p>
<%= f.label :email, :caption => 'Email Address: ' %>
<%= f.email_field :email, :class => 'string' %>
</p>
<p>
<%= f.label :webpage, :caption => 'Your Web Page: ' %>
<%= f.url_field :webpage, :class => 'string' %>
</p>
<p>
<%= f.label :search %>
<%= f.search_field :search, :class => 'string' %>
</p>
<p>
<%= f.label :photo %>
<%= f.file_field :photo, :class => 'user-photo' %>

View file

@ -4,12 +4,24 @@
%p
= f.label :username, :caption => "Login: ", :class => 'user-label'
= f.text_field :username, :class => 'user-text', :value => "John"
%p
= f.label :email, :caption => "Email", :class => 'user-email'
= f.text_field :email
%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'

View file

@ -4,12 +4,24 @@
p
== f.label :username, :caption => "Login: ", :class => 'user-label'
== f.text_field :username, :class => 'user-text', :value => "John"
p
== f.label :email, :caption => "Email", :class => 'user-email'
== f.text_field :email
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'

View file

@ -5,6 +5,16 @@
<%= 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 %>
<%= check_box_tag :remember_me %>
<%= label_tag :gender %>
<%= label_tag :color %>
@ -27,6 +37,26 @@
<%= label_tag :password, :class => 'first' %>
<%= password_field_tag :password, :value => params[:password] %>
</p>
<p>
<%= label_tag :email, :caption => 'Email Address' %>
<%= email_field_tag :email, :class => 'string' %>
</p>
<p>
<%= label_tag :age, :class => 'age' %>
<%= number_field_tag :age, :class => 'numeric' %>
</p>
<p>
<%= label_tag :telephone, :class => 'telephone' %>
<%= telephone_field_tag :telephone, :class => 'numeric' %>
</p>
<p>
<%= label_tag :webpage, :caption => 'Your Home Page' %>
<%= url_field_tag :webpage, :class => 'string' %>
</p>
<p>
<%= label_tag :search %>
<%= search_field_tag :search, :class => 'string' %>
</p>
<p>
<%= label_tag :about, :class => 'about', :caption => "About Me" %>
<%= text_area_tag :about, :class => 'large' %>

View file

@ -6,6 +6,16 @@
= 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
@ -24,6 +34,21 @@
%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'

View file

@ -6,6 +6,16 @@
== 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
@ -24,6 +34,21 @@
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'

View file

@ -9,7 +9,7 @@ describe "AssetTagHelpers" do
end
def flash
{ :notice => "Demo notice" }
@_flash ||= { :notice => "Demo notice" }
end
context 'for #flash_tag method' do
@ -20,6 +20,14 @@ describe "AssetTagHelpers" do
actual_html = flash_tag(:notice, :class => 'notice', :id => 'notice-area')
assert_has_tag('div.notice#notice-area', :content => "Demo notice") { actual_html }
end
should "display multiple flash tags with given attributes" do
flash[:error] = 'wrong'
flash[:success] = 'okey'
actual_html = flash_tag(:success, :error, :id => 'area')
assert_has_tag('div.success#area', :content => flash[:success]) { actual_html }
assert_has_tag('div.error#area', :content => flash[:error]) { actual_html }
assert_has_no_tag('div.notice') { actual_html }
end
end
context 'for #link_to method' do
@ -39,7 +47,7 @@ describe "AssetTagHelpers" do
should "display link element with void url and options" do
actual_link = link_to('Sign up', :class => "test")
assert_has_tag('a', :content => "Sign up", :href => 'javascript:void(0);', :class => 'test') { actual_link }
assert_has_tag('a', :content => "Sign up", :href => '#', :class => 'test') { actual_link }
end
should "display link element with remote option" do
@ -146,10 +154,10 @@ describe "AssetTagHelpers" do
context 'for #image_tag method' do
should "display image tag absolute link with no options" do
time = stop_time_for_test
assert_has_tag('img', :src => "/absolute/pic.gif?#{time.to_i}") { image_tag('/absolute/pic.gif') }
assert_has_tag('img', :src => "/absolute/pic.gif") { image_tag('/absolute/pic.gif') }
end
should "display image tag absolute link with specified uri root" do
should "display image tag relative link with specified uri root" do
time = stop_time_for_test
self.class.stubs(:uri_root).returns("/blog")
assert_has_tag('img', :src => "/blog/images/relative/pic.gif?#{time.to_i}") { image_tag('relative/pic.gif') }
@ -201,7 +209,7 @@ describe "AssetTagHelpers" do
time = stop_time_for_test
expected_options = { :media => "screen", :rel => "stylesheet", :type => "text/css" }
actual_html = stylesheet_link_tag('/css/style')
assert_has_tag('link', expected_options.merge(:href => "/css/style.css?#{time.to_i}")) { actual_html }
assert_has_tag('link', expected_options.merge(:href => "/css/style.css")) { actual_html }
end
should "display stylesheet link item with uri root" do
@ -257,7 +265,7 @@ describe "AssetTagHelpers" do
should "display javascript item with absolute path" do
time = stop_time_for_test
actual_html = javascript_include_tag('/js/application')
assert_has_tag('script', :src => "/js/application.js?#{time.to_i}", :type => "text/javascript") { actual_html }
assert_has_tag('script', :src => "/js/application.js", :type => "text/javascript") { actual_html }
end
should "display javascript item with uri root" do

View file

@ -63,7 +63,7 @@ describe "FormBuilder" do
should "display correct form html with remote option and method put" do
actual_html = form_for(@user, '/update', :"accept-charset" => "UTF-8", :remote => true, :method => 'put') { "Demo" }
assert_has_tag('form', :"accept-charset" => "UTF-8", :method => 'post', "data-method" => 'put', "data-remote" => 'true') { actual_html }
assert_has_tag('form', :"accept-charset" => "UTF-8", :method => 'post', "data-remote" => 'true') { actual_html }
assert_has_tag('form input', :type => 'hidden', :name => "_method", :value => 'put') { actual_html }
end
@ -199,7 +199,7 @@ describe "FormBuilder" do
assert_have_selector '#demo2 div.field-errors ul li', :content => "Fake must be valid"
assert_have_selector '#demo2 div.field-errors ul li', :content => "Second must be present"
assert_have_selector '#demo2 div.field-errors ul li', :content => "Third must be a number"
assert_have_selector '#demo input', :name => 'markup_user[email]', :class => 'invalid'
assert_have_selector '#demo input', :name => 'markup_user[email]', :class => 'string invalid'
end
should "display correct form in erb" do
@ -212,7 +212,7 @@ describe "FormBuilder" do
assert_have_selector '#demo2 div.field-errors ul li', :content => "Fake must be valid"
assert_have_selector '#demo2 div.field-errors ul li', :content => "Second must be present"
assert_have_selector '#demo2 div.field-errors ul li', :content => "Third must be a number"
assert_have_selector '#demo input', :name => 'markup_user[email]', :class => 'invalid'
assert_have_selector '#demo input', :name => 'markup_user[email]', :class => 'string invalid'
end
should "display correct form in slim" do
@ -225,7 +225,7 @@ describe "FormBuilder" do
assert_have_selector '#demo2 div.field-errors ul li', :content => "Fake must be valid"
assert_have_selector '#demo2 div.field-errors ul li', :content => "Second must be present"
assert_have_selector '#demo2 div.field-errors ul li', :content => "Third must be a number"
assert_have_selector '#demo input', :name => 'markup_user[email]', :class => 'invalid'
assert_have_selector '#demo input', :name => 'markup_user[email]', :class => 'string invalid'
end
end
@ -325,6 +325,116 @@ describe "FormBuilder" do
end
end
context 'for #number_field method' do
should "display correct number field html" do
actual_html = standard_builder.number_field(:age, :class => 'numeric')
assert_has_tag('input.numeric[type=number]', :id => 'user_age', :name => 'user[age]') { actual_html }
end
should "display correct number field in haml" do
visit '/haml/form_for'
assert_have_selector '#demo input.numeric[type=number]', :id => 'markup_user_age'
end
should "display correct number field in erb" do
visit '/erb/form_for'
assert_have_selector '#demo input.numeric[type=number]', :id => 'markup_user_age'
end
should "display correct number field in slim" do
visit '/slim/form_for'
assert_have_selector '#demo input.numeric[type=number]', :id => 'markup_user_age'
end
end
context 'for #telephone_field method' do
should "display correct telephone field html" do
actual_html = standard_builder.telephone_field(:telephone, :class => 'numeric')
assert_has_tag('input.numeric[type=tel]', :id => 'user_telephone', :name => 'user[telephone]') { actual_html }
end
should "display correct telephone field in haml" do
visit '/haml/form_for'
assert_have_selector '#demo input.numeric[type=tel]', :id => 'markup_user_telephone'
end
should "display correct telephone field in erb" do
visit '/erb/form_for'
assert_have_selector '#demo input.numeric[type=tel]', :id => 'markup_user_telephone'
end
should "display correct telephone field in slim" do
visit '/slim/form_for'
assert_have_selector '#demo input.numeric[type=tel]', :id => 'markup_user_telephone'
end
end
context 'for #search_field method' do
should "display correct search field html" do
actual_html = standard_builder.search_field(:search, :class => 'string')
assert_has_tag('input.string[type=search]', :id => 'user_search', :name => 'user[search]') { actual_html }
end
should "display correct search field in haml" do
visit '/haml/form_for'
assert_have_selector '#demo input.string[type=search]', :id => 'markup_user_search'
end
should "display correct search field in erb" do
visit '/erb/form_for'
assert_have_selector '#demo input.string[type=search]', :id => 'markup_user_search'
end
should "display correct search field in slim" do
visit '/slim/form_for'
assert_have_selector '#demo input.string[type=search]', :id => 'markup_user_search'
end
end
context 'for #email_field method' do
should "display correct email field html" do
actual_html = standard_builder.email_field(:email, :class => 'string')
assert_has_tag('input.string[type=email]', :id => 'user_email', :name => 'user[email]') { actual_html }
end
should "display correct email field in haml" do
visit '/haml/form_for'
assert_have_selector '#demo input.string[type=email]', :id => 'markup_user_email'
end
should "display correct email field in erb" do
visit '/erb/form_for'
assert_have_selector '#demo input.string[type=email]', :id => 'markup_user_email'
end
should "display correct email field in slim" do
visit '/slim/form_for'
assert_have_selector '#demo input.string[type=email]', :id => 'markup_user_email'
end
end
context 'for #url_field method' do
should "display correct url field html" do
actual_html = standard_builder.url_field(:webpage, :class => 'string')
assert_has_tag('input.string[type=url]', :id => 'user_webpage', :name => 'user[webpage]') { actual_html }
end
should "display correct url field in haml" do
visit '/haml/form_for'
assert_have_selector '#demo input.string[type=url]', :id => 'markup_user_webpage'
end
should "display correct url field in erb" do
visit '/erb/form_for'
assert_have_selector '#demo input.string[type=url]', :id => 'markup_user_webpage'
end
should "display correct url field in slim" do
visit '/slim/form_for'
assert_have_selector '#demo input.string[type=url]', :id => 'markup_user_webpage'
end
end
context 'for #check_box method' do
should "display correct checkbox html" do
actual_html = standard_builder.check_box(:confirm_destroy, :class => 'large')
@ -430,7 +540,7 @@ describe "FormBuilder" do
context 'for #text_area method' do
should "display correct text_area html" do
actual_html = standard_builder.text_area(:about, :class => 'large')
assert_has_tag('textarea.large', :id => 'user_about', :name => 'user[about]', :rows => '', :cols => '') { actual_html }
assert_has_tag('textarea.large', :id => 'user_about', :name => 'user[about]') { actual_html }
end
should "display correct text_area html and content" do
@ -628,7 +738,7 @@ describe "FormBuilder" do
should "display correct image submit button html" do
actual_html = standard_builder.image_submit('/system/ok.png', :class => 'large')
assert_has_tag('input.large[type=image]', :src => "/system/ok.png?#{@stamp}") { actual_html }
assert_has_tag('input.large[type=image]', :src => "/system/ok.png") { actual_html }
end
should "display correct image submit button in haml" do

View file

@ -28,7 +28,7 @@ describe "FormHelpers" do
should "display correct form with remote and method is put" do
actual_html = form_tag('/update', :"accept-charset" => "UTF-8", :method => 'put', :remote => true) { "Demo" }
assert_has_tag(:form, "data-remote" => 'true', :"accept-charset" => "UTF-8", :"data-method" => 'put') { actual_html }
assert_has_tag(:form, "data-remote" => 'true', :"accept-charset" => "UTF-8") { actual_html }
assert_has_tag('form input', :type => 'hidden', :name => "_method", :value => 'put') { actual_html }
end
@ -193,14 +193,14 @@ describe "FormHelpers" do
should "display label tag in erb for simple form" do
visit '/erb/form_tag'
assert_have_selector 'form.simple-form label', :count => 4
assert_have_selector 'form.simple-form label', :count => 9
assert_have_selector 'form.simple-form label', :content => "Username", :for => 'username'
assert_have_selector 'form.simple-form label', :content => "Password", :for => 'password'
assert_have_selector 'form.simple-form label', :content => "Gender", :for => 'gender'
end
should "display label tag in erb for advanced form" do
visit '/erb/form_tag'
assert_have_selector 'form.advanced-form label', :count => 6
assert_have_selector 'form.advanced-form label', :count => 11
assert_have_selector 'form.advanced-form label.first', :content => "Nickname", :for => 'username'
assert_have_selector 'form.advanced-form label.first', :content => "Password", :for => 'password'
assert_have_selector 'form.advanced-form label.about', :content => "About Me", :for => 'about'
@ -210,7 +210,7 @@ describe "FormHelpers" do
should "display label tag in haml for simple form" do
visit '/haml/form_tag'
assert_have_selector 'form.simple-form label', :count => 4
assert_have_selector 'form.simple-form label', :count => 9
assert_have_selector 'form.simple-form label', :content => "Username", :for => 'username'
assert_have_selector 'form.simple-form label', :content => "Password", :for => 'password'
assert_have_selector 'form.simple-form label', :content => "Gender", :for => 'gender'
@ -218,7 +218,7 @@ describe "FormHelpers" do
should "display label tag in haml for advanced form" do
visit '/haml/form_tag'
assert_have_selector 'form.advanced-form label', :count => 6
assert_have_selector 'form.advanced-form label', :count => 11
assert_have_selector 'form.advanced-form label.first', :content => "Nickname", :for => 'username'
assert_have_selector 'form.advanced-form label.first', :content => "Password", :for => 'password'
assert_have_selector 'form.advanced-form label.about', :content => "About Me", :for => 'about'
@ -228,7 +228,7 @@ describe "FormHelpers" do
should "display label tag in slim for simple form" do
visit '/slim/form_tag'
assert_have_selector 'form.simple-form label', :count => 4
assert_have_selector 'form.simple-form label', :count => 9
assert_have_selector 'form.simple-form label', :content => "Username", :for => 'username'
assert_have_selector 'form.simple-form label', :content => "Password", :for => 'password'
assert_have_selector 'form.simple-form label', :content => "Gender", :for => 'gender'
@ -236,7 +236,7 @@ describe "FormHelpers" do
should "display label tag in slim for advanced form" do
visit '/slim/form_tag'
assert_have_selector 'form.advanced-form label', :count => 6
assert_have_selector 'form.advanced-form label', :count => 11
assert_have_selector 'form.advanced-form label.first', :content => "Nickname", :for => 'username'
assert_have_selector 'form.advanced-form label.first', :content => "Password", :for => 'password'
assert_have_selector 'form.advanced-form label.about', :content => "About Me", :for => 'about'
@ -295,10 +295,135 @@ describe "FormHelpers" do
end
end
context 'for #number_field_tag method' do
should "display number field in ruby" do
actual_html = number_field_tag(:age, :class => 'numeric')
assert_has_tag(:input, :type => 'number', :class => 'numeric', :name => 'age') { actual_html }
end
should "display number field in erb" do
visit '/erb/form_tag'
assert_have_selector 'form.simple-form input[type=number]', :count => 1, :name => 'age'
assert_have_selector 'form.advanced-form fieldset input[type=number]', :count => 1, :name => 'age', :class => 'numeric'
end
should "display number field in haml" do
visit '/haml/form_tag'
assert_have_selector 'form.simple-form input[type=number]', :count => 1, :name => 'age'
assert_have_selector 'form.advanced-form fieldset input[type=number]', :count => 1, :name => 'age', :class => 'numeric'
end
should "display number field in slim" do
visit '/slim/form_tag'
assert_have_selector 'form.simple-form input[type=number]', :count => 1, :name => 'age'
assert_have_selector 'form.advanced-form fieldset input[type=number]', :count => 1, :name => 'age', :class => 'numeric'
end
end
context 'for #telephone_field_tag method' do
should "display number field in ruby" do
actual_html = telephone_field_tag(:telephone, :class => 'numeric')
assert_has_tag(:input, :type => 'tel', :class => 'numeric', :name => 'telephone') { actual_html }
end
should "display telephone field in erb" do
visit '/erb/form_tag'
assert_have_selector 'form.simple-form input[type=tel]', :count => 1, :name => 'telephone'
assert_have_selector 'form.advanced-form fieldset input[type=tel]', :count => 1, :name => 'telephone', :class => 'numeric'
end
should "display telephone field in haml" do
visit '/haml/form_tag'
assert_have_selector 'form.simple-form input[type=tel]', :count => 1, :name => 'telephone'
assert_have_selector 'form.advanced-form fieldset input[type=tel]', :count => 1, :name => 'telephone', :class => 'numeric'
end
should "display telephone field in slim" do
visit '/slim/form_tag'
assert_have_selector 'form.simple-form input[type=tel]', :count => 1, :name => 'telephone'
assert_have_selector 'form.advanced-form fieldset input[type=tel]', :count => 1, :name => 'telephone', :class => 'numeric'
end
end
context 'for #search_field_tag method' do
should "display search field in ruby" do
actual_html = search_field_tag(:search, :class => 'string')
assert_has_tag(:input, :type => 'search', :class => 'string', :name => 'search') { actual_html }
end
should "display search field in erb" do
visit '/erb/form_tag'
assert_have_selector 'form.simple-form input[type=search]', :count => 1, :name => 'search'
assert_have_selector 'form.advanced-form fieldset input[type=search]', :count => 1, :name => 'search', :class => 'string'
end
should "display search field in haml" do
visit '/haml/form_tag'
assert_have_selector 'form.simple-form input[type=search]', :count => 1, :name => 'search'
assert_have_selector 'form.advanced-form fieldset input[type=search]', :count => 1, :name => 'search', :class => 'string'
end
should "display search field in slim" do
visit '/slim/form_tag'
assert_have_selector 'form.simple-form input[type=search]', :count => 1, :name => 'search'
assert_have_selector 'form.advanced-form fieldset input[type=search]', :count => 1, :name => 'search', :class => 'string'
end
end
context 'for #email_field_tag method' do
should "display email field in ruby" do
actual_html = email_field_tag(:email, :class => 'string')
assert_has_tag(:input, :type => 'email', :class => 'string', :name => 'email') { actual_html }
end
should "display email field in erb" do
visit '/erb/form_tag'
assert_have_selector 'form.simple-form input[type=email]', :count => 1, :name => 'email'
assert_have_selector 'form.advanced-form fieldset input[type=email]', :count => 1, :name => 'email', :class => 'string'
end
should "display email field in haml" do
visit '/haml/form_tag'
assert_have_selector 'form.simple-form input[type=email]', :count => 1, :name => 'email'
assert_have_selector 'form.advanced-form fieldset input[type=email]', :count => 1, :name => 'email', :class => 'string'
end
should "display email field in slim" do
visit '/slim/form_tag'
assert_have_selector 'form.simple-form input[type=email]', :count => 1, :name => 'email'
assert_have_selector 'form.advanced-form fieldset input[type=email]', :count => 1, :name => 'email', :class => 'string'
end
end
context 'for #url_field_tag method' do
should "display url field in ruby" do
actual_html = url_field_tag(:webpage, :class => 'string')
assert_has_tag(:input, :type => 'url', :class => 'string', :name => 'webpage') { actual_html }
end
should "display url field in erb" do
visit '/erb/form_tag'
assert_have_selector 'form.simple-form input[type=url]', :count => 1, :name => 'webpage'
assert_have_selector 'form.advanced-form fieldset input[type=url]', :count => 1, :name => 'webpage', :class => 'string'
end
should "display url field in haml" do
visit '/haml/form_tag'
assert_have_selector 'form.simple-form input[type=url]', :count => 1, :name => 'webpage'
assert_have_selector 'form.advanced-form fieldset input[type=url]', :count => 1, :name => 'webpage', :class => 'string'
end
should "display url field in slim" do
visit '/slim/form_tag'
assert_have_selector 'form.simple-form input[type=url]', :count => 1, :name => 'webpage'
assert_have_selector 'form.advanced-form fieldset input[type=url]', :count => 1, :name => 'webpage', :class => 'string'
end
end
context 'for #text_area_tag method' do
should "display text area in ruby" do
actual_html = text_area_tag(:about, :class => 'long')
assert_has_tag(:textarea, :class => "long", :name => 'about', :rows => '', :cols => '') { actual_html }
assert_has_tag(:textarea, :class => "long", :name => 'about') { actual_html }
end
should "display text area in ruby with specified content" do
@ -624,7 +749,7 @@ describe "FormHelpers" do
should "display image submit tag in ruby with absolute path" do
actual_html = image_submit_tag('/system/ok.png', :class => 'success')
assert_has_tag(:input, :type => 'image', :class => "success", :src => "/system/ok.png?#{@stamp}") { actual_html }
assert_has_tag(:input, :type => 'image', :class => "success", :src => "/system/ok.png") { actual_html }
end
should "display image submit tag in erb" do

View file

@ -1,3 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/helper')
require File.expand_path(File.dirname(__FILE__) + '/fixtures/markup_app/app')
describe "NumberHelpers" do
include Padrino::Helpers::NumberHelpers

View file

@ -21,17 +21,18 @@ describe "TagHelpers" do
assert_has_tag('option', :selected => 'selected') { actual_html }
end
should "support tags with content no attributes" do
assert_has_tag(:p, :content => "Demo String") { tag(:p, :content => "Demo String") }
should "support data attributes" do
actual_html = tag(:a, :data => { :remote => true, :method => 'post'})
assert_has_tag(:a, 'data-remote' => 'true', 'data-method' => 'post') { actual_html }
end
should "support tags with content and attributes" do
actual_html = tag(:p, :content => "Demo", :class => 'large', :id => 'intro')
assert_has_tag('p#intro.large', :content => "Demo") { actual_html }
should "support nested attributes" do
actual_html = tag(:div, :data => {:dojo => {:type => 'dijit.form.TextBox', :props => 'readOnly: true'}})
assert_has_tag(:div, 'data-dojo-type' => 'dijit.form.TextBox', 'data-dojo-props' => 'readOnly: true') { actual_html }
end
should "support open tags" do
actual_html = tag(:p, :class => 'demo', :open => true)
actual_html = tag(:p, { :class => 'demo' }, true)
assert_equal "<p class=\"demo\">", actual_html
end