update to padrino 0.10.2, activesupport 3.1
This commit is contained in:
parent
a5cc87d247
commit
8fb0f4ad39
|
@ -55,12 +55,6 @@
|
||||||
libdir = File.dirname(__FILE__)
|
libdir = File.dirname(__FILE__)
|
||||||
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
||||||
|
|
||||||
padrino_core_path = File.join(libdir, "middleman", "vendor", "padrino-core-0.10.0", "lib")
|
|
||||||
$LOAD_PATH.unshift(padrino_core_path) unless $LOAD_PATH.include?(padrino_core_path)
|
|
||||||
|
|
||||||
padrino_helpers_path = File.join(libdir, "middleman", "vendor", "padrino-helpers-0.10.0", "lib")
|
|
||||||
$LOAD_PATH.unshift(padrino_helpers_path) unless $LOAD_PATH.include?(padrino_helpers_path)
|
|
||||||
|
|
||||||
# We're riding on Sinatra, so let's include it.
|
# We're riding on Sinatra, so let's include it.
|
||||||
require "sinatra/base"
|
require "sinatra/base"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
README.rdoc
|
|
||||||
lib/**/*.rb
|
|
||||||
bin/*
|
|
||||||
features/**/*.feature
|
|
||||||
LICENSE
|
|
|
@ -1,22 +0,0 @@
|
||||||
## MAC OS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
## TEXTMATE
|
|
||||||
*.tmproj
|
|
||||||
tmtags
|
|
||||||
|
|
||||||
## EMACS
|
|
||||||
*~
|
|
||||||
\#*
|
|
||||||
.\#*
|
|
||||||
|
|
||||||
## VIM
|
|
||||||
*.swp
|
|
||||||
|
|
||||||
## PROJECT::GENERAL
|
|
||||||
coverage
|
|
||||||
rdoc
|
|
||||||
pkg
|
|
||||||
|
|
||||||
## PROJECT::SPECIFIC
|
|
||||||
test/tmp/*
|
|
20
lib/middleman/vendor/padrino-core-0.10.0/LICENSE
vendored
20
lib/middleman/vendor/padrino-core-0.10.0/LICENSE
vendored
|
@ -1,20 +0,0 @@
|
||||||
Copyright (c) 2011 Padrino
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
294
lib/middleman/vendor/padrino-core-0.10.0/README.rdoc
vendored
294
lib/middleman/vendor/padrino-core-0.10.0/README.rdoc
vendored
|
@ -1,294 +0,0 @@
|
||||||
= Padrino (padrino-core)
|
|
||||||
|
|
||||||
Padrino is the godfather of Sinatra.
|
|
||||||
|
|
||||||
== Preface
|
|
||||||
|
|
||||||
Padrino is a ruby framework built upon the excellent {Sinatra Microframework}[http://www.sinatrarb.com].
|
|
||||||
Sinatra is a DSL for creating simple web applications in Ruby with speed and minimal effort.
|
|
||||||
This framework tries hard to make it as fun and easy as possible to code much more advanced web applications by
|
|
||||||
building upon the Sinatra philosophies and foundation.
|
|
||||||
|
|
||||||
== Introduction
|
|
||||||
|
|
||||||
Many people love Sinatra's simplicity and lightweight but often quickly come to miss a great deal
|
|
||||||
of functionality provided by other web frameworks such as Rails when building non-trivial applications.
|
|
||||||
|
|
||||||
Our goal with this framework is to match the essence of Sinatra and at the same time create a standard library
|
|
||||||
of tools, helpers and components that will make Sinatra suitable for more complex applications.
|
|
||||||
|
|
||||||
Here is a brief overview of functionality provided by the Padrino framework:
|
|
||||||
|
|
||||||
Agnostic:: Full support for many popular testing, templating, mocking, and data storage choices.
|
|
||||||
Generators:: Create Padrino applications, models, controllers i.e: padrino-gen project.
|
|
||||||
Mountable:: Unlike other ruby frameworks, principally designed for mounting multiple apps.
|
|
||||||
Routing:: Full url named routes, named params, respond_to support, before/after filter support.
|
|
||||||
Tag Helpers:: View helpers such as: tag, content_tag, input_tag.
|
|
||||||
Asset Helpers:: View helpers such as: link_to, image_tag, javascript_include_tag.
|
|
||||||
Form Helpers:: Builder support such as: form_tag, form_for, field_set_tag, text_field.
|
|
||||||
Text Helpers:: Useful formatting like: relative_time_ago, js_escape_html, sanitize_html.
|
|
||||||
Mailer:: Fast and simple delivery support for sending emails (akin to ActionMailer).
|
|
||||||
Admin:: Builtin Admin interface (like Django)
|
|
||||||
Logging:: Provide a unified logger that can interact with your ORM or any library.
|
|
||||||
Reloading:: Automatically reloads server code during development.
|
|
||||||
Localization:: Full support of I18n language localization and can auto-set user’s locale.
|
|
||||||
|
|
||||||
Keep in mind, the user will be able to pull in these components
|
|
||||||
{seperately into existing Sinatra applications}[http://www.padrinorb.com/guides/standalone-usage-in-sinatra]
|
|
||||||
or use them altogether for a comprehensive upgrade to Sinatra (a full-stack Padrino application).
|
|
||||||
|
|
||||||
== Installation
|
|
||||||
|
|
||||||
To install the padrino framework, simply grab the latest version from gemcutter:
|
|
||||||
|
|
||||||
$ sudo gem install padrino
|
|
||||||
|
|
||||||
This will install the necessary padrino gems to get you started.
|
|
||||||
Now you are ready to use this gem to enhance your sinatra projects or to create new Padrino applications.
|
|
||||||
|
|
||||||
For a more detailed look at Padrino installation,
|
|
||||||
check out the {Installation Guide}[http://www.padrinorb.com/guides/installation].
|
|
||||||
|
|
||||||
== Usage
|
|
||||||
|
|
||||||
Padrino is a framework which builds on the existing functionality and Sinatra and provides a variety of
|
|
||||||
additional tools and helpers to build upon that foundation. This README and Padrino documentation in general will focus
|
|
||||||
on the enhancements to the core Sinatra functionality. To use Padrino, one should be familiar with the basic
|
|
||||||
usage of Sinatra itself.
|
|
||||||
|
|
||||||
Please check out the
|
|
||||||
{Understanding Sinatra}[http://www.padrinorb.com/guides/underlying-sinatra-overview] guide
|
|
||||||
to learn more about these fundamentals.
|
|
||||||
|
|
||||||
For information on how to use a specific gem in isolation within an existing Sinatra project, checkout the guide for
|
|
||||||
{Using Padrino in Sinatra}[http://www.padrinorb.com/guides/standalone-usage-in-sinatra].
|
|
||||||
|
|
||||||
== Getting Started
|
|
||||||
|
|
||||||
Once a developer understands Sinatra, Padrino is quite easy to get comfortable with since Padrino is simply a superset
|
|
||||||
of existing Sinatra Functionality! Best way to get started with building Padrino applications is to read following resources:
|
|
||||||
|
|
||||||
* {Blog Tutorial}[http://www.padrinorb.com/guides/blog-tutorial] - Step-by-step guide to building a blog application with Padrino.
|
|
||||||
* {Quick Overview}[http://www.padrinorb.com/guides/basic-projects] - Outlines basic generation commands.
|
|
||||||
* {Padrino Examples}[http://www.padrinorb.com/guides/examples] - List of known Padrino applications which can serve as examples.
|
|
||||||
|
|
||||||
== Enhanced Base Application (padrino-core)
|
|
||||||
|
|
||||||
Sinatra has support for classes which can be extended to create an application: <tt>Sinatra::Base</tt> and <tt>Sinatra::Application</tt>
|
|
||||||
These classes can be extended in order to create a Sinatra web application. These classes provide support for all the basic
|
|
||||||
functionality afforded by Sinatra.
|
|
||||||
|
|
||||||
Padrino has support for an enhanced base application class <tt>Padrino::Application</tt>. <tt>Padrino::Application</tt>
|
|
||||||
expands the capabilities of Sinatra::Application and automatically provides the resulting application access to all of
|
|
||||||
the padrino framework's functionalities.
|
|
||||||
|
|
||||||
=== Simple Application Definition
|
|
||||||
|
|
||||||
Let us first take a look at the simplest possible Padrino application:
|
|
||||||
|
|
||||||
# app.rb
|
|
||||||
PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
|
|
||||||
require 'padrino'
|
|
||||||
Padrino.load!
|
|
||||||
|
|
||||||
class SimpleApp < Padrino::Application
|
|
||||||
get '/' do
|
|
||||||
'Hello world'
|
|
||||||
end
|
|
||||||
|
|
||||||
# and for read better we can divide with controllers
|
|
||||||
controller '/admin' do
|
|
||||||
get '/foo' do
|
|
||||||
'Url is /admin/foo'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
=== Enhanced Route Definitions and Controllers
|
|
||||||
|
|
||||||
For a complete overview of the Padrino routing and controller system,
|
|
||||||
check out the {Routing and Controller guide}[http://www.padrinorb.com/guides/controllers].
|
|
||||||
|
|
||||||
Suppose we wanted to add additional routes to our Padrino application, and we want to organize the routes
|
|
||||||
within a more structured layout. Simply add a <tt>controllers</tt> or <tt>app/controllers</tt> folder and create a file as such:
|
|
||||||
|
|
||||||
# Simple Example
|
|
||||||
SimpleApp.controllers do
|
|
||||||
get "/test" do
|
|
||||||
"Text to return"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
You can also do more complex route alias definitions:
|
|
||||||
|
|
||||||
# app/controllers/example.rb
|
|
||||||
SimpleApp.controllers :posts do
|
|
||||||
get :index do
|
|
||||||
...
|
|
||||||
end
|
|
||||||
|
|
||||||
get :show, :with => :id do
|
|
||||||
# url generated is '/posts/show/:id'
|
|
||||||
# access params[:id]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
as well as mapping the route aliases to an explicit url:
|
|
||||||
|
|
||||||
# app/controllers/example.rb
|
|
||||||
SimpleApp.controllers do
|
|
||||||
get :index, :map => '/index' do
|
|
||||||
...
|
|
||||||
end
|
|
||||||
|
|
||||||
get :account, :map => '/the/accounts/:name/and/:id' do
|
|
||||||
# access params[:name] and params[:index]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
and even configure the respond_to for each route:
|
|
||||||
|
|
||||||
# app/controllers/example.rb
|
|
||||||
SimpleApp.controllers :admin do
|
|
||||||
get :show, :with => :id, :provides => :js do
|
|
||||||
"Url is /admin/show/#{params[:id]}.#{params[:format]}"
|
|
||||||
end
|
|
||||||
|
|
||||||
get :other, with => [:id, :name], respond_to => [:html, :json] do
|
|
||||||
case content_type
|
|
||||||
when :js then ... end
|
|
||||||
when :json then ... end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
or auto lookup for current locale or content_type
|
|
||||||
|
|
||||||
# app/controllers/example.rb
|
|
||||||
SimpleApp.controllers :admin do
|
|
||||||
get :show, :with => :id, :provides => [html, :js] do
|
|
||||||
render "admin/show"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
When you visit :+show+ and your I18n.locale == :ru Padrino try to look for "admin/show.ru.js.*" if nothing match that path
|
|
||||||
they try "admin/show.ru.*" then "admin/show.js.*" if none match return "admin/show.erb" (or other engine i.e. haml)
|
|
||||||
|
|
||||||
For a complete overview of the routing and controller system, check out the
|
|
||||||
{Routing and Controller guide}[http://www.padrinorb.com/guides/controllers].
|
|
||||||
|
|
||||||
=== Rendering
|
|
||||||
|
|
||||||
Unlike Sinatra, Padrino supports automatic template lookups such as:
|
|
||||||
|
|
||||||
# searches for 'account/index.{erb,haml,...}
|
|
||||||
render 'account/index'
|
|
||||||
|
|
||||||
This render does not require any template engine to be specified and will choose the first one that is discovered.
|
|
||||||
The existing render function works as well if an engine type should be specified:
|
|
||||||
|
|
||||||
# example.haml
|
|
||||||
render :haml, 'account/index'
|
|
||||||
|
|
||||||
For a complete overview of the Padrino rendering system, check out the
|
|
||||||
{Routing and Controller guide}[http://www.padrinorb.com/guides/controllers].
|
|
||||||
|
|
||||||
=== Layout
|
|
||||||
|
|
||||||
With Padrino you can (like rails do) use for your custom layout, disable it
|
|
||||||
|
|
||||||
class SimpleApp < Padrino::Application
|
|
||||||
|
|
||||||
# Disable layouts
|
|
||||||
disable layout
|
|
||||||
|
|
||||||
# Use the layout located in views/layouts/custom.haml
|
|
||||||
layout :custom
|
|
||||||
|
|
||||||
For a complete overview of the layout functionality,
|
|
||||||
check out the {Routing and Controller guide}[http://www.padrinorb.com/guides/controllers].
|
|
||||||
|
|
||||||
=== Mounting Applications
|
|
||||||
|
|
||||||
Padrino applications are all automatically mountable into other Padrino projects. This means that a given Padrino
|
|
||||||
project directory can easily mount multiple applications. This allows for better organization of complex applications,
|
|
||||||
re-usable applications that can be applied (i.e admin, auth, blog) and even more flexibility.
|
|
||||||
|
|
||||||
You can think of mountable applications as a 'full-featured' merb slice or rails engine. Instead of a separate construct,
|
|
||||||
any application can simply be packaged and mounted into another project.
|
|
||||||
|
|
||||||
Padrino stores application mounting information by default within <tt>config/apps.rb</tt>. This file is intended
|
|
||||||
to keep all information regarding what applications are mounted to which uri's.
|
|
||||||
|
|
||||||
For a complete look at mounting applications within a Padrino project,
|
|
||||||
check out the guide on {Mounting Applications}[http://www.padrinorb.com/guides/mounting-applications].
|
|
||||||
|
|
||||||
=== Auto Load Paths
|
|
||||||
|
|
||||||
Padrino also intelligently supports requiring useful files within your application automatically and provides
|
|
||||||
functionality for easily splitting up your application into separate files. Padrino automatically requires <tt>config/database.rb</tt>
|
|
||||||
as a convention for establishing database connection. Also, any files within the <tt>lib</tt> folder will be required
|
|
||||||
automatically by Padrino.
|
|
||||||
|
|
||||||
For a complete overview of auto-loaded paths within Padrino,
|
|
||||||
check out the {Padrino Development Guide}[http://www.padrinorb.com/guides/development-and-terminal-commands].
|
|
||||||
|
|
||||||
=== Application Logging
|
|
||||||
|
|
||||||
Padrino also supports robust logging capabilities. By default, logging information will
|
|
||||||
go to the STDOUT in development (for use in a console) and in an environment-specific log file <tt>log/development.log</tt>
|
|
||||||
in test and production environments.
|
|
||||||
|
|
||||||
To use the logger within a Padrino application, simply refer to the <tt>logger</tt> method accessible
|
|
||||||
within your app and any controller or views:
|
|
||||||
|
|
||||||
# controllers/example.rb
|
|
||||||
SimpleApp.controllers do
|
|
||||||
get("/test") { logger.info "This is a test" }
|
|
||||||
end
|
|
||||||
|
|
||||||
For a complete overview of Padrino logger functionality, check out the
|
|
||||||
{Padrino Development Guide}[http://www.padrinorb.com/guides/development-and-terminal-commands].
|
|
||||||
|
|
||||||
=== Development Reloader
|
|
||||||
|
|
||||||
Padrino applications also have the enabled ability to automatically reload all changing application files without
|
|
||||||
the need to restart the server. Through the use of a customized Rack middleware, all files on the 'load path'
|
|
||||||
are monitored and reloaded whenever changes are applied.
|
|
||||||
|
|
||||||
This makes rapid development much easier and provides a better alternative to 'shotgun' or 'rerun'
|
|
||||||
which requires the application server to be restarted which makes requests take much longer to complete.
|
|
||||||
|
|
||||||
For a complete overview of code reloading in development,
|
|
||||||
check out the {Padrino Development Guide}[http://www.padrinorb.com/guides/development-and-terminal-commands].
|
|
||||||
|
|
||||||
=== Terminal Commands
|
|
||||||
|
|
||||||
Padrino also comes equipped with multiple useful terminal commands which can be activated to perform
|
|
||||||
common tasks such as starting / stopping the application, executing the unit tests or activating an irb session.
|
|
||||||
|
|
||||||
The following commands are available:
|
|
||||||
|
|
||||||
# starts the app server (non-daemonized)
|
|
||||||
$ padrino start
|
|
||||||
# starts the app server (daemonized) with given port, environment and adapter
|
|
||||||
$ padrino start -d -p 3000 -e development -a thin
|
|
||||||
|
|
||||||
# Stops a daemonized app server
|
|
||||||
$ padrino stop
|
|
||||||
|
|
||||||
# Bootup the Padrino console (irb)
|
|
||||||
$ padrino console
|
|
||||||
|
|
||||||
# Run/List tasks
|
|
||||||
$ padrino rake
|
|
||||||
|
|
||||||
You can also create custom rake tasks as well. Using these commands can simplify common tasks
|
|
||||||
making development that much smoother.
|
|
||||||
|
|
||||||
For a complete overview of Padrino terminal commands, check out the
|
|
||||||
{Padrino Commands Guide}[http://www.padrinorb.com/guides/development-and-terminal-commands].
|
|
||||||
|
|
||||||
== Copyright
|
|
||||||
|
|
||||||
Copyright (c) 2011 Padrino. See LICENSE for details.
|
|
|
@ -1,5 +0,0 @@
|
||||||
# coding:utf-8
|
|
||||||
RAKE_ROOT = __FILE__
|
|
||||||
|
|
||||||
require 'rubygems'
|
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/../gem_rake_helper')
|
|
|
@ -1,9 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
require 'rubygems' unless defined?(Gem)
|
|
||||||
require 'bundler/setup' if %w(Gemfile .components).all? { |f| File.exist?(f) }
|
|
||||||
|
|
||||||
padrino_core_path = File.expand_path('../../lib', __FILE__)
|
|
||||||
$:.unshift(padrino_core_path) if File.directory?(padrino_core_path) && !$:.include?(padrino_core_path)
|
|
||||||
|
|
||||||
require 'padrino-core/cli/base'
|
|
||||||
Padrino::Cli::Base.start(ARGV)
|
|
|
@ -1,119 +0,0 @@
|
||||||
require 'sinatra/base'
|
|
||||||
require 'padrino-core/support_lite' unless defined?(SupportLite)
|
|
||||||
|
|
||||||
FileSet.glob_require('padrino-core/application/*.rb', __FILE__)
|
|
||||||
FileSet.glob_require('padrino-core/*.rb', __FILE__)
|
|
||||||
|
|
||||||
# Defines our Constants
|
|
||||||
PADRINO_ENV = ENV["PADRINO_ENV"] ||= ENV["RACK_ENV"] ||= "development" unless defined?(PADRINO_ENV)
|
|
||||||
PADRINO_ROOT = ENV["PADRINO_ROOT"] ||= File.dirname(Padrino.first_caller) unless defined?(PADRINO_ROOT)
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
class ApplicationLoadError < RuntimeError #:nodoc:
|
|
||||||
end
|
|
||||||
|
|
||||||
class << self
|
|
||||||
##
|
|
||||||
# Helper method for file references.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # Referencing a file in config called settings.yml
|
|
||||||
# Padrino.root("config", "settings.yml")
|
|
||||||
# # returns PADRINO_ROOT + "/config/setting.yml"
|
|
||||||
#
|
|
||||||
def root(*args)
|
|
||||||
File.expand_path(File.join(PADRINO_ROOT, *args))
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Helper method that return PADRINO_ENV
|
|
||||||
#
|
|
||||||
def env
|
|
||||||
@_env ||= PADRINO_ENV.to_s.downcase.to_sym
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the resulting rack builder mapping each 'mounted' application
|
|
||||||
#
|
|
||||||
def application
|
|
||||||
raise ApplicationLoadError, "At least one app must be mounted!" unless Padrino.mounted_apps && Padrino.mounted_apps.any?
|
|
||||||
router = Padrino::Router.new
|
|
||||||
Padrino.mounted_apps.each { |app| app.map_onto(router) }
|
|
||||||
|
|
||||||
unless middleware.empty?
|
|
||||||
builder = Rack::Builder.new
|
|
||||||
middleware.each { |c,a,b| builder.use(c, *a, &b) }
|
|
||||||
builder.run(router)
|
|
||||||
builder.to_app
|
|
||||||
else
|
|
||||||
router
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Configure Global Project Settings for mounted apps. These can be overloaded
|
|
||||||
# in each individual app's own personal configuration. This can be used like:
|
|
||||||
#
|
|
||||||
# Padrino.configure_apps do
|
|
||||||
# enable :sessions
|
|
||||||
# disable :raise_errors
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
def configure_apps(&block)
|
|
||||||
@_global_configuration = block if block_given?
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Returns project-wide configuration settings
|
|
||||||
# defined in 'configure_apps' block
|
|
||||||
#
|
|
||||||
def apps_configuration
|
|
||||||
@_global_configuration
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Default encoding to UTF8.
|
|
||||||
#
|
|
||||||
def set_encoding
|
|
||||||
if RUBY_VERSION < '1.9'
|
|
||||||
$KCODE='u'
|
|
||||||
else
|
|
||||||
Encoding.default_external = Encoding::UTF_8
|
|
||||||
Encoding.default_internal = nil # Encoding::UTF_8
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Return bundle status :+:locked+ if .bundle/environment.rb exist :+:unlocked if Gemfile exist
|
|
||||||
# otherwise return nil
|
|
||||||
#
|
|
||||||
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
|
|
||||||
#
|
|
||||||
def middleware
|
|
||||||
@middleware ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Clears all previously configured middlewares
|
|
||||||
#
|
|
||||||
def clear_middleware!
|
|
||||||
@middleware = []
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Convenience method for adding a Middleware to the whole padrino app.
|
|
||||||
#
|
|
||||||
def use(m, *args, &block)
|
|
||||||
middleware << [m, args, block]
|
|
||||||
end
|
|
||||||
end # self
|
|
||||||
end # Padrino
|
|
|
@ -1,259 +0,0 @@
|
||||||
module Padrino
|
|
||||||
class ApplicationSetupError < RuntimeError #:nodoc:
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Subclasses of this become independent Padrino applications (stemming from Sinatra::Application)
|
|
||||||
# These subclassed applications can be easily mounted into other Padrino applications as well.
|
|
||||||
#
|
|
||||||
class Application < Sinatra::Base
|
|
||||||
register Padrino::Routing # Support for advanced routing, controllers, url_for
|
|
||||||
|
|
||||||
class << self
|
|
||||||
|
|
||||||
def inherited(base) #:nodoc:
|
|
||||||
logger.devel "Setup #{base}"
|
|
||||||
CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
|
|
||||||
base.default_configuration!
|
|
||||||
base.prerequisites.concat([
|
|
||||||
File.join(base.root, "/models.rb"),
|
|
||||||
File.join(base.root, "/models/**/*.rb"),
|
|
||||||
File.join(base.root, "/lib.rb"),
|
|
||||||
File.join(base.root, "/lib/**/*.rb")
|
|
||||||
]).uniq!
|
|
||||||
Padrino.require_dependencies(base.prerequisites)
|
|
||||||
super(base) # Loading the subclass inherited method
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Hooks into when a new instance of the application is created
|
|
||||||
# This is used because putting the configuration into inherited doesn't
|
|
||||||
# take into account overwritten app settings inside subclassed definitions
|
|
||||||
# Only performs the setup first time application is initialized.
|
|
||||||
#
|
|
||||||
def new(*args, &bk)
|
|
||||||
setup_application!
|
|
||||||
logging, logging_was = false, logging
|
|
||||||
show_exceptions, show_exceptions_was = false, show_exceptions
|
|
||||||
super(*args, &bk)
|
|
||||||
ensure
|
|
||||||
logging, show_exceptions = logging_was, show_exceptions_was
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Reloads the application files from all defined load paths
|
|
||||||
#
|
|
||||||
# This method is used from our Padrino Reloader during development mode
|
|
||||||
# in order to reload the source files.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# MyApp.reload!
|
|
||||||
#
|
|
||||||
def reload!
|
|
||||||
logger.devel "Reloading #{self}"
|
|
||||||
@_dependencies = nil # Reset dependencies
|
|
||||||
reset! # Reset sinatra app
|
|
||||||
reset_routes! # Remove all existing user-defined application routes
|
|
||||||
Padrino.require_dependencies(self.app_file, :force => true) # Reload the app file
|
|
||||||
require_dependencies # Reload dependencies
|
|
||||||
register_initializers # Reload our middlewares
|
|
||||||
default_filters! # Reload filters
|
|
||||||
default_errors! # Reload our errors
|
|
||||||
I18n.reload! if defined?(I18n) # Reload also our translations
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Resets application routes to only routes not defined by the user
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# MyApp.reset_routes!
|
|
||||||
#
|
|
||||||
def reset_routes!
|
|
||||||
reset_router!
|
|
||||||
default_routes!
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the routes of our app.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# MyApp.routes
|
|
||||||
#
|
|
||||||
def routes
|
|
||||||
router.routes
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Setup the application by registering initializers, load paths and logger
|
|
||||||
# Invoked automatically when an application is first instantiated
|
|
||||||
#
|
|
||||||
def setup_application!
|
|
||||||
return if @_configured
|
|
||||||
self.register_initializers
|
|
||||||
self.require_dependencies
|
|
||||||
self.disable :logging # We need do that as default because Sinatra use commonlogger.
|
|
||||||
self.default_filters!
|
|
||||||
self.default_routes!
|
|
||||||
self.default_errors!
|
|
||||||
if defined?(I18n)
|
|
||||||
I18n.load_path << self.locale_path
|
|
||||||
I18n.reload!
|
|
||||||
end
|
|
||||||
@_configured = true
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Run the Padrino app as a self-hosted server using
|
|
||||||
# Thin, Mongrel or WEBrick (in that order)
|
|
||||||
#
|
|
||||||
def run!(options={})
|
|
||||||
return unless Padrino.load!
|
|
||||||
Padrino.mount(self.to_s).to("/")
|
|
||||||
Padrino.run!(options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the used $LOAD_PATHS from this application
|
|
||||||
#
|
|
||||||
def load_paths
|
|
||||||
@_load_paths ||= %w(models lib mailers controllers helpers).map { |path| File.join(self.root, path) }
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns default list of path globs to load as dependencies
|
|
||||||
# Appends custom dependency patterns to the be loaded for your Application
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
# MyApp.dependencies << "#{Padrino.root}/uploaders/**/*.rb"
|
|
||||||
# MyApp.dependencies << Padrino.root('other_app', 'controllers.rb')
|
|
||||||
#
|
|
||||||
def dependencies
|
|
||||||
@_dependencies ||= [
|
|
||||||
"urls.rb", "config/urls.rb", "mailers/*.rb", "mailers.rb",
|
|
||||||
"controllers/**/*.rb", "controllers.rb", "helpers/**/*.rb", "helpers.rb"
|
|
||||||
].map { |file| Dir[File.join(self.root, file)] }.flatten
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# An array of file to load before your app.rb, basically are files wich our app depends on.
|
|
||||||
#
|
|
||||||
# By default we look for files:
|
|
||||||
#
|
|
||||||
# yourapp/models.rb
|
|
||||||
# yourapp/models/**/*.rb
|
|
||||||
# yourapp/lib.rb
|
|
||||||
# yourapp/lib/**/*.rb
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
# MyApp.prerequisites << Padrino.root('my_app', 'custom_model.rb')
|
|
||||||
#
|
|
||||||
def prerequisites
|
|
||||||
@_prerequisites ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
##
|
|
||||||
# Defines default settings for Padrino application
|
|
||||||
#
|
|
||||||
def default_configuration!
|
|
||||||
# Overwriting Sinatra defaults
|
|
||||||
set :app_file, File.expand_path(caller_files.first || $0) # Assume app file is first caller
|
|
||||||
set :environment, Padrino.env
|
|
||||||
set :reload, Proc.new { development? }
|
|
||||||
set :logging, Proc.new { development? }
|
|
||||||
set :method_override, true
|
|
||||||
set :sessions, false
|
|
||||||
set :public, Proc.new { Padrino.root('public', uri_root) }
|
|
||||||
set :views, Proc.new { File.join(root, "views") }
|
|
||||||
set :images_path, Proc.new { File.join(public, "images") }
|
|
||||||
# Padrino specific
|
|
||||||
set :uri_root, "/"
|
|
||||||
set :app_name, self.to_s.underscore.to_sym
|
|
||||||
set :default_builder, 'StandardFormBuilder'
|
|
||||||
set :flash, defined?(Rack::Flash)
|
|
||||||
set :authentication, false
|
|
||||||
# Padrino locale
|
|
||||||
set :locale_path, Proc.new { Dir[File.join(self.root, "/locale/**/*.{rb,yml}")] }
|
|
||||||
# Load the Global Configurations
|
|
||||||
class_eval(&Padrino.apps_configuration) if Padrino.apps_configuration
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# We need to add almost __sinatra__ images.
|
|
||||||
#
|
|
||||||
def default_routes!
|
|
||||||
configure :development do
|
|
||||||
get '/__sinatra__/:image.png' do
|
|
||||||
content_type :png
|
|
||||||
filename = File.dirname(__FILE__) + "/images/#{params[:image]}.png"
|
|
||||||
send_file filename
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# This filter it's used for know the format of the request, and automatically set the content type.
|
|
||||||
#
|
|
||||||
def default_filters!
|
|
||||||
before do
|
|
||||||
unless @_content_type
|
|
||||||
@_content_type = :html
|
|
||||||
response['Content-Type'] = 'text/html;charset=utf-8'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# This log errors for production environments
|
|
||||||
#
|
|
||||||
def default_errors!
|
|
||||||
configure :production do
|
|
||||||
error ::Exception do
|
|
||||||
boom = env['sinatra.error']
|
|
||||||
logger.error ["#{boom.class} - #{boom.message}:", *boom.backtrace].join("\n ")
|
|
||||||
response.status = 500
|
|
||||||
content_type 'text/html'
|
|
||||||
'<h1>Internal Server Error</h1>'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Requires the Padrino middleware
|
|
||||||
#
|
|
||||||
def register_initializers
|
|
||||||
use Padrino::ShowExceptions if show_exceptions?
|
|
||||||
use Padrino::Logger::Rack, uri_root if Padrino.logger && logging?
|
|
||||||
use Padrino::Reloader::Rack if reload?
|
|
||||||
use Rack::Flash, :sweep => true if flash?
|
|
||||||
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
|
|
||||||
end # self
|
|
||||||
|
|
||||||
# TODO Remove deprecated render inclusion in a few versions
|
|
||||||
# Detects if a user is incorrectly using 'render' and warns them about the fix
|
|
||||||
# In 0.10.0, Padrino::Rendering now has to be explicitly included in the application
|
|
||||||
def render(*args)
|
|
||||||
if !defined?(DEFAULT_RENDERING_OPTIONS) && !@_render_included &&
|
|
||||||
(args.size == 1 || (args.size == 2 && args[0].is_a?(String) && args[1].is_a?(Hash)))
|
|
||||||
logger.warn "[Deprecation] Please 'register Padrino::Rendering' for each application as shown here:
|
|
||||||
https://gist.github.com/1d36a35794dbbd664ea4 for 'render' to function as expected"
|
|
||||||
self.class.instance_eval { register Padrino::Rendering }
|
|
||||||
@_render_included = true
|
|
||||||
render(*args)
|
|
||||||
else # pass through, rendering is valid
|
|
||||||
super(*args)
|
|
||||||
end
|
|
||||||
end # render method
|
|
||||||
end # Application
|
|
||||||
end # Padrino
|
|
|
@ -1,228 +0,0 @@
|
||||||
require 'padrino-core/support_lite' unless defined?(SupportLite)
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# Padrino enhances the Sinatra ‘render’ method to have support for automatic template engine detection,
|
|
||||||
# enhanced layout functionality, locale enabled rendering, among other features.
|
|
||||||
#
|
|
||||||
module Rendering
|
|
||||||
class TemplateNotFound < RuntimeError #:nodoc:
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# This is an array of file patterns to ignore.
|
|
||||||
# If your editor add a suffix during editing to your files please add it like:
|
|
||||||
#
|
|
||||||
# Padrino::Rendering::IGNORE_FILE_PATTERN << /~$/
|
|
||||||
#
|
|
||||||
IGNORE_FILE_PATTERN = [
|
|
||||||
/~$/ # This is for Gedit
|
|
||||||
] unless defined?(IGNORE_FILE_PATTERN)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Default rendering options used in the #render-method
|
|
||||||
#
|
|
||||||
DEFAULT_RENDERING_OPTIONS = { :strict_format => false, :raise_exceptions => true } unless defined?(DEFAULT_RENDERING_OPTIONS)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Main class that register this extension
|
|
||||||
#
|
|
||||||
class << self
|
|
||||||
def registered(app)
|
|
||||||
app.send(:include, InstanceMethods)
|
|
||||||
app.extend(ClassMethods)
|
|
||||||
end
|
|
||||||
alias :included :registered
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
|
||||||
##
|
|
||||||
# Use layout like rails does or if a block given then like sinatra.
|
|
||||||
# If used without a block, sets the current layout for the route.
|
|
||||||
#
|
|
||||||
# By default, searches in your:
|
|
||||||
#
|
|
||||||
# +app+/+views+/+layouts+/+application+.(+haml+|+erb+|+xxx+)
|
|
||||||
# +app+/+views+/+layout_name+.(+haml+|+erb+|+xxx+)
|
|
||||||
#
|
|
||||||
# If you define +layout+ :+custom+ then searches for your layouts in
|
|
||||||
# +app+/+views+/+layouts+/+custom+.(+haml+|+erb+|+xxx+)
|
|
||||||
# +app+/+views+/+custom+.(+haml+|+erb+|+xxx+)
|
|
||||||
#
|
|
||||||
def layout(name=:layout, &block)
|
|
||||||
return super(name, &block) if block_given?
|
|
||||||
@layout = name
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the cached template file to render for a given url, content_type and locale.
|
|
||||||
#
|
|
||||||
# render_options = [template_path, content_type, locale]
|
|
||||||
#
|
|
||||||
def fetch_template_file(render_options)
|
|
||||||
(@_cached_templates ||= {})[render_options]
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Caches the template file for the given rendering options
|
|
||||||
#
|
|
||||||
# render_options = [template_path, content_type, locale]
|
|
||||||
#
|
|
||||||
def cache_template_file!(template_file, render_options)
|
|
||||||
(@_cached_templates ||= {})[render_options] = template_file || []
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the cached layout path.
|
|
||||||
#
|
|
||||||
def fetch_layout_path(given_layout=nil)
|
|
||||||
layout_name = given_layout || @layout || :application
|
|
||||||
@_cached_layout ||= {}
|
|
||||||
cached_layout_path = @_cached_layout[layout_name]
|
|
||||||
return cached_layout_path if cached_layout_path
|
|
||||||
has_layout_at_root = Dir["#{views}/#{layout_name}.*"].any?
|
|
||||||
layout_path = has_layout_at_root ? layout_name.to_sym : File.join('layouts', layout_name.to_s).to_sym
|
|
||||||
@_cached_layout[layout_name] = layout_path unless reload_templates?
|
|
||||||
layout_path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
attr_reader :current_engine
|
|
||||||
|
|
||||||
def content_type(type=nil, params={}) #:nodoc:
|
|
||||||
type.nil? ? @_content_type : super(type, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
##
|
|
||||||
# Enhancing Sinatra render functionality for:
|
|
||||||
#
|
|
||||||
# * Using layout similar to rails
|
|
||||||
# * Use render 'path/to/my/template' (without symbols)
|
|
||||||
# * Use render 'path/to/my/template' (with engine lookup)
|
|
||||||
# * Use render 'path/to/template.haml' (with explicit engine lookup)
|
|
||||||
# * Use render 'path/to/template', :layout => false
|
|
||||||
# * Use render 'path/to/template', :layout => false, :engine => 'haml'
|
|
||||||
# * Use render { :a => 1, :b => 2, :c => 3 } # => return a json string
|
|
||||||
#
|
|
||||||
def render(engine, data=nil, options={}, locals={}, &block)
|
|
||||||
# If engine is a hash then render data converted to json
|
|
||||||
return engine.to_json if engine.is_a?(Hash)
|
|
||||||
|
|
||||||
# If engine is nil, ignore engine parameter and shift up all arguments
|
|
||||||
# render nil, "index", { :layout => true }, { :localvar => "foo" }
|
|
||||||
engine, data, options = data, options, locals if engine.nil? && data
|
|
||||||
|
|
||||||
# Data is a hash of options when no engine isn't explicit
|
|
||||||
# render "index", { :layout => true }, { :localvar => "foo" }
|
|
||||||
# Data is options, and options is locals in this case
|
|
||||||
data, options, locals = nil, data, options if data.is_a?(Hash)
|
|
||||||
|
|
||||||
# If data is unassigned then this is a likely a template to be resolved
|
|
||||||
# This means that no engine was explicitly defined
|
|
||||||
data, engine = *resolve_template(engine, options) if data.nil?
|
|
||||||
|
|
||||||
# Setup root
|
|
||||||
root = settings.respond_to?(:root) ? settings.root : ""
|
|
||||||
|
|
||||||
# Use @layout if it exists
|
|
||||||
options[:layout] = @layout if options[:layout].nil?
|
|
||||||
|
|
||||||
# Resolve layouts similar to in Rails
|
|
||||||
if (options[:layout].nil? || options[:layout] == true) && !settings.templates.has_key?(:layout)
|
|
||||||
layout_path, layout_engine = *resolved_layout
|
|
||||||
options[:layout] = layout_path || false # We need to force layout false so sinatra don't try to render it
|
|
||||||
options[:layout] = false unless layout_engine == engine # TODO allow different layout engine
|
|
||||||
options[:layout_engine] = layout_engine || engine if options[:layout]
|
|
||||||
logger.debug "Resolving layout #{root}/views#{options[:layout]}" if defined?(logger) && options[:layout].present?
|
|
||||||
elsif options[:layout].present?
|
|
||||||
options[:layout] = settings.fetch_layout_path(options[:layout] || @layout)
|
|
||||||
logger.debug "Resolving layout #{root}/views#{options[:layout]}" if defined?(logger)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Cleanup the template
|
|
||||||
@current_engine, engine_was = engine, @current_engine
|
|
||||||
@_out_buf, _buf_was = "", @_out_buf
|
|
||||||
|
|
||||||
# Pass arguments to Sinatra render method
|
|
||||||
super(engine, data, options.dup, locals, &block)
|
|
||||||
ensure
|
|
||||||
@current_engine = engine_was
|
|
||||||
@_out_buf = _buf_was
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the located layout tuple to be used for the rendered template (if available)
|
|
||||||
#
|
|
||||||
# ==== Example
|
|
||||||
#
|
|
||||||
# resolve_layout
|
|
||||||
# => ["/layouts/custom", :erb]
|
|
||||||
# => [nil, nil]
|
|
||||||
#
|
|
||||||
def resolved_layout
|
|
||||||
located_layout = resolve_template(settings.fetch_layout_path, :raise_exceptions => false, :strict_format => true)
|
|
||||||
located_layout ? located_layout : [nil, nil]
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the template path and engine that match content_type (if present), I18n.locale.
|
|
||||||
#
|
|
||||||
# === Options
|
|
||||||
#
|
|
||||||
# :strict_format:: The resolved template must match the content_type of the request (defaults to false)
|
|
||||||
# :raise_exceptions:: Raises a +TemplateNotFound+ exception if the template cannot be located.
|
|
||||||
#
|
|
||||||
# ==== Example
|
|
||||||
#
|
|
||||||
# get "/foo", :provides => [:html, :js] do; render 'path/to/foo'; end
|
|
||||||
# # If you request "/foo.js" with I18n.locale == :ru => [:"/path/to/foo.ru.js", :erb]
|
|
||||||
# # If you request "/foo" with I18n.locale == :de => [:"/path/to/foo.de.haml", :haml]
|
|
||||||
#
|
|
||||||
def resolve_template(template_path, options={})
|
|
||||||
# Fetch cached template for rendering options
|
|
||||||
template_path = "/#{template_path}" unless template_path.to_s[0] == ?/
|
|
||||||
rendering_options = [template_path, content_type, locale]
|
|
||||||
cached_template = settings.fetch_template_file(rendering_options)
|
|
||||||
return cached_template if cached_template
|
|
||||||
|
|
||||||
# Resolve view path and options
|
|
||||||
options.reverse_merge!(DEFAULT_RENDERING_OPTIONS)
|
|
||||||
view_path = options.delete(:views) || settings.views || "./views"
|
|
||||||
target_extension = File.extname(template_path)[1..-1] || "none" # explicit template extension
|
|
||||||
template_path = template_path.chomp(".#{target_extension}")
|
|
||||||
|
|
||||||
# Generate potential template candidates
|
|
||||||
templates = Dir[File.join(view_path, template_path) + ".*"].map do |file|
|
|
||||||
template_engine = File.extname(file)[1..-1].to_sym # retrieves engine extension
|
|
||||||
template_file = file.sub(view_path, '').chomp(".#{template_engine}").to_sym # retrieves template filename
|
|
||||||
[template_file, template_engine] unless IGNORE_FILE_PATTERN.any? { |pattern| template_engine.to_s =~ pattern }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if we have a simple content type
|
|
||||||
simple_content_type = [:html, :plain].include?(content_type)
|
|
||||||
|
|
||||||
# Resolve final template to render
|
|
||||||
located_template =
|
|
||||||
templates.find { |file, e| file.to_s == "#{template_path}.#{locale}.#{content_type}" } ||
|
|
||||||
templates.find { |file, e| file.to_s == "#{template_path}.#{locale}" && simple_content_type } ||
|
|
||||||
templates.find { |file, e| File.extname(file.to_s) == ".#{target_extension}" or e.to_s == target_extension.to_s } ||
|
|
||||||
templates.find { |file, e| file.to_s == "#{template_path}.#{content_type}" } ||
|
|
||||||
templates.find { |file, e| file.to_s == "#{template_path}" && simple_content_type } ||
|
|
||||||
(!options[:strict_format] && templates.first) # If not strict, fall back to the first located template
|
|
||||||
|
|
||||||
raise TemplateNotFound, "Template '#{template_path}' not found in '#{view_path}'!" if !located_template && options[:raise_exceptions]
|
|
||||||
settings.cache_template_file!(located_template, rendering_options) unless settings.reload_templates?
|
|
||||||
located_template
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Return the I18n.locale if I18n is defined
|
|
||||||
#
|
|
||||||
def locale
|
|
||||||
I18n.locale if defined?(I18n)
|
|
||||||
end
|
|
||||||
end # InstanceMethods
|
|
||||||
end # Rendering
|
|
||||||
end # Padrino
|
|
|
@ -1,821 +0,0 @@
|
||||||
require 'http_router' unless defined?(HttpRouter)
|
|
||||||
require 'padrino-core/support_lite' unless defined?(SupportLite)
|
|
||||||
|
|
||||||
class Sinatra::Request #:nodoc:
|
|
||||||
attr_accessor :route_obj, :runner
|
|
||||||
|
|
||||||
def runner=(runner)
|
|
||||||
@runner = runner
|
|
||||||
env['padrino.instance'] = runner
|
|
||||||
end
|
|
||||||
|
|
||||||
def controller
|
|
||||||
route_obj && route_obj.controller
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class HttpRouter #:nodoc:
|
|
||||||
def rewrite_partial_path_info(env, request); end
|
|
||||||
def rewrite_path_info(env, request); end
|
|
||||||
|
|
||||||
def process_destination_path(path, env)
|
|
||||||
env['padrino.instance'].instance_eval do
|
|
||||||
request.route_obj = path.route
|
|
||||||
@_response_buffer = nil
|
|
||||||
@params ||= {}
|
|
||||||
@params.update(env['router.params'])
|
|
||||||
@block_params = if path.route.is_a?(HttpRouter::RegexRoute)
|
|
||||||
params_list = env['router.request'].extra_env['router.regex_match'].to_a
|
|
||||||
params_list.shift
|
|
||||||
@params[:captures] = params_list
|
|
||||||
params_list
|
|
||||||
else
|
|
||||||
env['router.request'].params
|
|
||||||
end
|
|
||||||
# Provide access to the current controller to the request
|
|
||||||
# Now we can eval route, but because we have "throw halt" we need to be
|
|
||||||
# (en)sure to reset old layout and run controller after filters.
|
|
||||||
old_params = @params
|
|
||||||
parent_layout = @layout
|
|
||||||
successful = false
|
|
||||||
begin
|
|
||||||
filter! :before
|
|
||||||
(path.route.before_filters - self.class.filters[:before]).each { |filter| instance_eval(&filter)} if path.route.before_filters
|
|
||||||
# If present set current controller layout
|
|
||||||
@layout = path.route.use_layout if path.route.use_layout
|
|
||||||
@route = path.route
|
|
||||||
@route.custom_conditions.each { |blk| pass if instance_eval(&blk) == false } if @route.custom_conditions
|
|
||||||
@block_params = @block_params.slice(0, path.route.dest.arity) if path.route.dest.arity > 0
|
|
||||||
halt_response = catch(:halt) { route_eval(&path.route.dest) }
|
|
||||||
@_response_buffer = halt_response.is_a?(Array) ? halt_response.last : halt_response
|
|
||||||
successful = true
|
|
||||||
halt @_response_buffer
|
|
||||||
ensure
|
|
||||||
(@_pending_after_filters ||= []).concat(path.route.after_filters) if path.route.after_filters && successful
|
|
||||||
@layout = parent_layout
|
|
||||||
@params = old_params
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Route #:nodoc:
|
|
||||||
attr_reader :before_filters, :after_filters
|
|
||||||
attr_accessor :custom_conditions, :use_layout, :controller, :cache
|
|
||||||
|
|
||||||
def add_before_filter(filter)
|
|
||||||
@before_filters ||= []
|
|
||||||
@before_filters << filter
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_after_filter(filter)
|
|
||||||
@after_filters ||= []
|
|
||||||
@after_filters << filter
|
|
||||||
end
|
|
||||||
|
|
||||||
def before_filters=(filters)
|
|
||||||
filters.each { |filter| add_before_filter(filter) } if filters
|
|
||||||
end
|
|
||||||
|
|
||||||
def after_filters=(filters)
|
|
||||||
filters.each { |filter| add_after_filter(filter) } if filters
|
|
||||||
end
|
|
||||||
|
|
||||||
def custom_conditions=(custom_conditions)
|
|
||||||
@custom_conditions = custom_conditions
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
class Filter
|
|
||||||
attr_reader :block
|
|
||||||
|
|
||||||
def initialize(mode, scoped_controller, options, args, &block)
|
|
||||||
@mode, @scoped_controller, @options, @args, @block = mode, scoped_controller, options, args, block
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply?(request)
|
|
||||||
return true if @args.empty? && @options.empty?
|
|
||||||
detect = @args.any? do |arg|
|
|
||||||
case arg
|
|
||||||
when Symbol then request.route_obj.named == arg or request.route_obj.named == [@scoped_controller, arg].flatten.join("_").to_sym
|
|
||||||
else arg === request.path_info
|
|
||||||
end
|
|
||||||
end || @options.any? { |name, val|
|
|
||||||
case name
|
|
||||||
when :agent then val === request.user_agent
|
|
||||||
else val === request.send(name)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
detect ^ !@mode
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_proc
|
|
||||||
filter = self
|
|
||||||
proc {
|
|
||||||
instance_eval(&filter.block) if filter.apply?(request)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Padrino provides advanced routing definition support to make routes and url generation much easier.
|
|
||||||
# This routing system supports named route aliases and easy access to url paths.
|
|
||||||
# The benefits of this is that instead of having to hard-code route urls into every area of your application,
|
|
||||||
# now we can just define the urls in a single spot and then attach an alias which can be used to refer
|
|
||||||
# to the url throughout the application.
|
|
||||||
#
|
|
||||||
module Routing
|
|
||||||
CONTENT_TYPE_ALIASES = { :htm => :html } unless defined?(CONTENT_TYPE_ALIASES)
|
|
||||||
ROUTE_PRIORITY = {:high => 0, :normal => 1, :low => 2}
|
|
||||||
|
|
||||||
class UnrecognizedException < RuntimeError #:nodoc:
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Keeps information about parent scope.
|
|
||||||
#
|
|
||||||
class Parent < String
|
|
||||||
attr_reader :map
|
|
||||||
attr_reader :optional
|
|
||||||
attr_reader :options
|
|
||||||
|
|
||||||
alias_method :optional?, :optional
|
|
||||||
|
|
||||||
def initialize(value, options={})
|
|
||||||
super(value.to_s)
|
|
||||||
@map = options.delete(:map)
|
|
||||||
@optional = options.delete(:optional)
|
|
||||||
@options = options
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Main class that register this extension
|
|
||||||
#
|
|
||||||
class << self
|
|
||||||
def registered(app)
|
|
||||||
app.send(:include, InstanceMethods)
|
|
||||||
app.extend(ClassMethods)
|
|
||||||
end
|
|
||||||
alias :included :registered
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
|
||||||
##
|
|
||||||
# Method for organize in a better way our routes like:
|
|
||||||
#
|
|
||||||
# controller :admin do
|
|
||||||
# get :index do; ...; end
|
|
||||||
# get :show, :with => :id do; ...; end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# Now you can call your actions with:
|
|
||||||
#
|
|
||||||
# url(:admin_index) # => "/admin"
|
|
||||||
# url(:admin_show, :id => 1) # "/admin/show/1"
|
|
||||||
#
|
|
||||||
# You can instead using named routes follow the sinatra way like:
|
|
||||||
#
|
|
||||||
# controller "/admin" do
|
|
||||||
# get "/index" do; ...; end
|
|
||||||
# get "/show/:id" do; ...; end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# and you can call directly these urls:
|
|
||||||
#
|
|
||||||
# # => "/admin"
|
|
||||||
# # => "/admin/show/1"
|
|
||||||
#
|
|
||||||
# You can supply provides to all controller routes:
|
|
||||||
#
|
|
||||||
# controller :provides => [:html, :xml, :json] do
|
|
||||||
# get :index do; "respond to html, xml and json"; end
|
|
||||||
# post :index do; "respond to html, xml and json"; end
|
|
||||||
# get :foo do; "respond to html, xml and json"; end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# You can specify parent resources in padrino with the :parent option on the controller:
|
|
||||||
#
|
|
||||||
# controllers :product, :parent => :user do
|
|
||||||
# get :index do
|
|
||||||
# # url is generated as "/user/#{params[:user_id]}/product"
|
|
||||||
# # url_for(:product, :index, :user_id => 5) => "/user/5/product"
|
|
||||||
# end
|
|
||||||
# get :show, :with => :id do
|
|
||||||
# # url is generated as "/user/#{params[:user_id]}/product/show/#{params[:id]}"
|
|
||||||
# # url_for(:product, :show, :user_id => 5, :id => 10) => "/user/5/product/show/10"
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# You can specify conditions to run for all routes:
|
|
||||||
#
|
|
||||||
# controller :conditions => {:protect => true} do
|
|
||||||
# def self.protect(protected)
|
|
||||||
# condition do
|
|
||||||
# halt 403, "No secrets for you!" unless params[:key] == "s3cr3t"
|
|
||||||
# end if protected
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # This route will only return "secret stuff" if the user goes to
|
|
||||||
# # `/private?key=s3cr3t`.
|
|
||||||
# get("/private") { "secret stuff" }
|
|
||||||
#
|
|
||||||
# # And this one, too!
|
|
||||||
# get("/also-private") { "secret stuff" }
|
|
||||||
#
|
|
||||||
# # But you can override the conditions for each route as needed.
|
|
||||||
# # This route will be publicly accessible without providing the
|
|
||||||
# # secret key.
|
|
||||||
# get :index, :protect => false do
|
|
||||||
# "Welcome!"
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# You can supply default values:
|
|
||||||
#
|
|
||||||
# controller :lang => :de do
|
|
||||||
# get :index, :map => "/:lang" do; "params[:lang] == :de"; end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# In a controller before and after filters are scoped and didn't affect other controllers or main app.
|
|
||||||
# In a controller layout are scoped and didn't affect others controllers and main app.
|
|
||||||
#
|
|
||||||
# controller :posts do
|
|
||||||
# layout :post
|
|
||||||
# before { foo }
|
|
||||||
# after { bar }
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
def controller(*args, &block)
|
|
||||||
if block_given?
|
|
||||||
options = args.extract_options!
|
|
||||||
|
|
||||||
# Controller defaults
|
|
||||||
@_controller, original_controller = args, @_controller
|
|
||||||
@_parents, original_parent = options.delete(:parent), @_parents
|
|
||||||
@_provides, original_provides = options.delete(:provides), @_provides
|
|
||||||
@_use_format, original_use_format = options.delete(:use_format), @_use_format
|
|
||||||
@_cache, original_cache = options.delete(:cache), @_cache
|
|
||||||
@_map, original_map = options.delete(:map), @_map
|
|
||||||
@_conditions, original_conditions = options.delete(:conditions), @_conditions
|
|
||||||
@_defaults, original_defaults = options, @_defaults
|
|
||||||
|
|
||||||
# Application defaults
|
|
||||||
@filters, original_filters = { :before => @filters[:before].dup, :after => @filters[:after].dup }, @filters
|
|
||||||
@layout, original_layout = nil, @layout
|
|
||||||
|
|
||||||
instance_eval(&block)
|
|
||||||
|
|
||||||
# Application defaults
|
|
||||||
@filters = original_filters
|
|
||||||
@layout = original_layout
|
|
||||||
|
|
||||||
# Controller defaults
|
|
||||||
@_controller, @_parents, @_cache = original_controller, original_parent, original_cache
|
|
||||||
@_defaults, @_provides, @_map = original_defaults, original_provides, original_map
|
|
||||||
@_conditions, @_use_format = original_conditions, original_use_format
|
|
||||||
else
|
|
||||||
include(*args) if extensions.any?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
alias :controllers :controller
|
|
||||||
|
|
||||||
def before(*args, &block)
|
|
||||||
add_filter :before, &(args.empty? ? block : construct_filter(*args, &block))
|
|
||||||
end
|
|
||||||
|
|
||||||
def after(*args, &block)
|
|
||||||
add_filter :after, &(args.empty? ? block : construct_filter(*args, &block))
|
|
||||||
end
|
|
||||||
|
|
||||||
def construct_filter(*args, &block)
|
|
||||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
||||||
except = options.key?(:except) && Array(options.delete(:except))
|
|
||||||
raise("You cannot use except with other options specified") if except && (!args.empty? || !options.empty?)
|
|
||||||
options = except.last.is_a?(Hash) ? except.pop : {} if except
|
|
||||||
Filter.new(!except, @_controller, options, Array(except || args), &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Provides many parents with shallowing.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# controllers :product do
|
|
||||||
# parent :shop, :optional => true, :map => "/my/stand"
|
|
||||||
# parent :category, :optional => true
|
|
||||||
# get :show, :with => :id do
|
|
||||||
# # generated urls:
|
|
||||||
# # "/product/show/#{params[:id]}"
|
|
||||||
# # "/my/stand/#{params[:shop_id]}/product/show/#{params[:id]}"
|
|
||||||
# # "/my/stand/#{params[:shop_id]}/category/#{params[:category_id]}/product/show/#{params[:id]}"
|
|
||||||
# # url_for(:product, :show, :id => 10) => "/product/show/10"
|
|
||||||
# # url_for(:product, :show, :shop_id => 5, :id => 10) => "/my/stand/5/product/show/10"
|
|
||||||
# # url_for(:product, :show, :shop_id => 5, :category_id => 1, :id => 10) => "/my/stand/5/category/1/product/show/10"
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
def parent(name, options={})
|
|
||||||
defaults = { :optional => false, :map => name.to_s }
|
|
||||||
options = defaults.merge(options)
|
|
||||||
@_parents = Array(@_parents) unless @_parents.is_a?(Array)
|
|
||||||
@_parents << Parent.new(name, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Using HTTPRouter, for features and configurations see: http://github.com/joshbuddy/http_router
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# router.add('/greedy/:greed')
|
|
||||||
# router.recognize('/simple')
|
|
||||||
#
|
|
||||||
def router
|
|
||||||
@router ||= HttpRouter.new
|
|
||||||
block_given? ? yield(@router) : @router
|
|
||||||
end
|
|
||||||
alias :urls :router
|
|
||||||
|
|
||||||
def compiled_router
|
|
||||||
if deferred_routes.empty?
|
|
||||||
router
|
|
||||||
else
|
|
||||||
deferred_routes.each { |_, routes| routes.each { |(route, dest)| route.to(dest) } }
|
|
||||||
@deferred_routes = nil
|
|
||||||
router
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def deferred_routes
|
|
||||||
@deferred_routes ||= Hash[ROUTE_PRIORITY.values.sort.map{|p| [p, []]}]
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_router!
|
|
||||||
@deferred_routes = nil
|
|
||||||
router.reset!
|
|
||||||
end
|
|
||||||
|
|
||||||
def recognize_path(path)
|
|
||||||
if response = @router.recognize(Rack::MockRequest.env_for(path))
|
|
||||||
[response.path.route.named, response.params]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Instance method for url generation like:
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# url(:show, :id => 1)
|
|
||||||
# url(:show, :name => 'test', :id => 24)
|
|
||||||
# url(:show, 1)
|
|
||||||
#
|
|
||||||
def url(*args)
|
|
||||||
params = args.extract_options! # parameters is hash at end
|
|
||||||
names, params_array = args.partition{|a| a.is_a?(Symbol)}
|
|
||||||
name = names.join("_").to_sym # route name is concatenated with underscores
|
|
||||||
if params.is_a?(Hash)
|
|
||||||
params[:format] = params[:format].to_s unless params[:format].nil?
|
|
||||||
params = value_to_param(params)
|
|
||||||
end
|
|
||||||
url = if params_array.empty?
|
|
||||||
compiled_router.url(name, params)
|
|
||||||
else
|
|
||||||
compiled_router.url(name, *(params_array << params))
|
|
||||||
end
|
|
||||||
url[0,0] = conform_uri(uri_root) if defined?(uri_root)
|
|
||||||
url[0,0] = conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
|
|
||||||
url = "/" if url.blank?
|
|
||||||
url
|
|
||||||
rescue HttpRouter::InvalidRouteException
|
|
||||||
route_error = "route mapping for url(#{name.inspect}) could not be found!"
|
|
||||||
raise Padrino::Routing::UnrecognizedException.new(route_error)
|
|
||||||
end
|
|
||||||
alias :url_for :url
|
|
||||||
|
|
||||||
def get(path, *args, &block)
|
|
||||||
conditions = @conditions.dup
|
|
||||||
route('GET', path, *args, &block)
|
|
||||||
|
|
||||||
@conditions = conditions
|
|
||||||
route('HEAD', path, *args, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_controller
|
|
||||||
@_controller && @_controller.last
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
# Parse params from the url method
|
|
||||||
def value_to_param(value)
|
|
||||||
case value
|
|
||||||
when Array
|
|
||||||
value.map { |v| value_to_param(v) }.compact
|
|
||||||
when Hash
|
|
||||||
value.inject({}) do |memo, (k,v)|
|
|
||||||
v = value_to_param(v)
|
|
||||||
memo[k] = v unless v.nil?
|
|
||||||
memo
|
|
||||||
end
|
|
||||||
when nil then nil
|
|
||||||
else value.respond_to?(:to_param) ? value.to_param : value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Add prefix slash if its not present and remove trailing slashes.
|
|
||||||
def conform_uri(uri_string)
|
|
||||||
uri_string.gsub(/^(?!\/)(.*)/, '/\1').gsub(/[\/]+$/, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Rewrite default because now routes can be:
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
#
|
|
||||||
def route(verb, path, *args, &block)
|
|
||||||
options = case args.size
|
|
||||||
when 2
|
|
||||||
args.last.merge(:map => args.first)
|
|
||||||
when 1
|
|
||||||
map = args.shift if args.first.is_a?(String)
|
|
||||||
if args.first.is_a?(Hash)
|
|
||||||
map ? args.first.merge(:map => map) : args.first
|
|
||||||
else
|
|
||||||
{:map => map || args.first}
|
|
||||||
end
|
|
||||||
when 0
|
|
||||||
{}
|
|
||||||
else raise
|
|
||||||
end
|
|
||||||
|
|
||||||
# Do padrino parsing. We dup options so we can build HEAD request correctly
|
|
||||||
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)
|
|
||||||
options.reverse_merge!(@_conditions) if @_conditions
|
|
||||||
|
|
||||||
# Sinatra defaults
|
|
||||||
method_name = "#{verb} #{path}"
|
|
||||||
define_method(method_name, &block)
|
|
||||||
unbound_method = instance_method("#{verb} #{path}")
|
|
||||||
remove_method(method_name)
|
|
||||||
|
|
||||||
block_arity = block.arity
|
|
||||||
block = block_arity != 0 ?
|
|
||||||
proc { @block_params = @block_params[0, block_arity]; unbound_method.bind(self).call(*@block_params) } :
|
|
||||||
proc { unbound_method.bind(self).call }
|
|
||||||
|
|
||||||
invoke_hook(:route_added, verb, path, block)
|
|
||||||
|
|
||||||
# HTTPRouter route construction
|
|
||||||
route = router.add(path)
|
|
||||||
|
|
||||||
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(', ')}")
|
|
||||||
route.cache = options.key?(:cache) ? options.delete(:cache) : @_cache
|
|
||||||
route.send(verb.downcase.to_sym)
|
|
||||||
route.host(options.delete(:host)) if options.key?(:host)
|
|
||||||
route.user_agent(options.delete(:agent)) if options.key?(:agent)
|
|
||||||
if options.key?(:default_values)
|
|
||||||
defaults = options.delete(:default_values)
|
|
||||||
route.default(defaults) if defaults
|
|
||||||
end
|
|
||||||
options.delete_if do |option, args|
|
|
||||||
if route.send(:significant_variable_names).include?(option)
|
|
||||||
route.matching(option => Array(args).first)
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Add Sinatra conditions
|
|
||||||
options.each { |o, a| route.respond_to?(o) ? route.send(o, *a) : send(o, *a) }
|
|
||||||
conditions, @conditions = @conditions, []
|
|
||||||
route.custom_conditions = conditions
|
|
||||||
|
|
||||||
invoke_hook(:padrino_route_added, route, verb, path, args, options, block)
|
|
||||||
|
|
||||||
# Add Application defaults
|
|
||||||
route.before_filters = @filters[:before]
|
|
||||||
route.after_filters = @filters[:after]
|
|
||||||
if @_controller
|
|
||||||
route.use_layout = @layout
|
|
||||||
route.controller = Array(@_controller).first.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
deferred_routes[priority] << [route, block]
|
|
||||||
route
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the final parsed route details (modified to reflect all Padrino options)
|
|
||||||
# given the raw route. Raw route passed in could be a named alias or a string and
|
|
||||||
# is parsed to reflect provides formats, controllers, parents, 'with' parameters,
|
|
||||||
# and other options.
|
|
||||||
#
|
|
||||||
def parse_route(path, options, verb)
|
|
||||||
# We need save our originals path/options so we can perform correctly cache.
|
|
||||||
original = [path, options.dup]
|
|
||||||
|
|
||||||
# We need check if path is a symbol, if that it's a named route
|
|
||||||
map = options.delete(:map)
|
|
||||||
|
|
||||||
if path.kind_of?(Symbol) # path i.e :index or :show
|
|
||||||
name = path # The route name
|
|
||||||
path = map ? map.dup : path.to_s # The route path
|
|
||||||
end
|
|
||||||
|
|
||||||
if path.kind_of?(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)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Now we need to parse our provides
|
|
||||||
options.delete(:provides) if options[:provides].nil?
|
|
||||||
|
|
||||||
if @_use_format or format_params = options[:provides]
|
|
||||||
process_path_for_provides(path, format_params)
|
|
||||||
options[:matching] ||= {}
|
|
||||||
options[:matching][:format] = /[^\.]+/
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build our controller
|
|
||||||
controller = Array(@_controller).map { |c| c.to_s }
|
|
||||||
|
|
||||||
absolute_map = map && map[0] == ?/
|
|
||||||
|
|
||||||
unless controller.empty?
|
|
||||||
# Now we need to add our controller path only if not mapped directly
|
|
||||||
if map.blank? and !absolute_map
|
|
||||||
controller_path = controller.join("/")
|
|
||||||
path.gsub!(%r{^\(/\)|/\?}, "")
|
|
||||||
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
|
|
||||||
if !absolute_map and parent_params = options.delete(:parent) || @_parents
|
|
||||||
parent_params = Array(@_parents) + Array(parent_params)
|
|
||||||
path = process_path_for_parent_params(path, parent_params)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Add any controller level map to the front of the path
|
|
||||||
path = "#{@_map}/#{path}".squeeze('/') unless absolute_map or @_map.blank?
|
|
||||||
|
|
||||||
# Small reformats
|
|
||||||
path.gsub!(%r{/\?$}, '(/)') # Remove index path
|
|
||||||
path.gsub!(%r{/?index/?}, '/') # Remove index path
|
|
||||||
path.gsub!(%r{//$}, '/') # Remove index path
|
|
||||||
path[0,0] = "/" unless path =~ %r{^\(?/} # Paths must start with a /
|
|
||||||
path.sub!(%r{/(\))?$}, '\\1') if path != "/" # Remove latest trailing delimiter
|
|
||||||
path.gsub!(/\/(\(\.|$)/, '\\1') # Remove trailing slashes
|
|
||||||
end
|
|
||||||
|
|
||||||
# Merge in option defaults
|
|
||||||
options.reverse_merge!(:default_values => @_defaults)
|
|
||||||
|
|
||||||
[path, name, options]
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Processes the existing path and appends the 'with' parameters onto the route
|
|
||||||
# Used for calculating path in route method
|
|
||||||
#
|
|
||||||
def process_path_for_with_params(path, with_params)
|
|
||||||
File.join(path, Array(with_params).map(&:inspect).join("/"))
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Processes the existing path and prepends the 'parent' parameters onto the route
|
|
||||||
# Used for calculating path in route method
|
|
||||||
#
|
|
||||||
def process_path_for_parent_params(path, parent_params)
|
|
||||||
parent_prefix = parent_params.flatten.compact.uniq.map do |param|
|
|
||||||
map = (param.respond_to?(:map) && param.map ? param.map : param.to_s)
|
|
||||||
part = "#{map}/:#{param}_id/"
|
|
||||||
part = "(#{part})" if param.respond_to?(:optional) && param.optional?
|
|
||||||
part
|
|
||||||
end
|
|
||||||
[parent_prefix, path].flatten.join("")
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Processes the existing path and appends the 'format' suffix onto the route
|
|
||||||
# Used for calculating path in route method
|
|
||||||
#
|
|
||||||
def process_path_for_provides(path, format_params)
|
|
||||||
path << "(.:format)" unless path[-10, 10] == '(.:format)'
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Allows routing by MIME-types specified in the URL or ACCEPT header.
|
|
||||||
#
|
|
||||||
# By default, if a non-provided mime-type is specified in a URL, the
|
|
||||||
# route will not match an thus return a 404.
|
|
||||||
#
|
|
||||||
# Setting the :treat_format_as_accept option to true allows treating
|
|
||||||
# missing mime types specified in the URL as if they were specified
|
|
||||||
# in the ACCEPT header and thus return 406.
|
|
||||||
#
|
|
||||||
# If no type is specified, the first in the provides-list will be
|
|
||||||
# returned.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
# get "/a", :provides => [:html, :js]
|
|
||||||
# # => GET /a => :html
|
|
||||||
# # => GET /a.js => :js
|
|
||||||
# # => GET /a.xml => 404
|
|
||||||
#
|
|
||||||
# get "/b", :provides => [:html]
|
|
||||||
# # => GET /b; ACCEPT: html => html
|
|
||||||
# # => GET /b; ACCEPT: js => 406
|
|
||||||
#
|
|
||||||
# enable :treat_format_as_accept
|
|
||||||
# get "/c", :provides => [:html, :js]
|
|
||||||
# # => GET /c.xml => 406
|
|
||||||
#
|
|
||||||
def provides(*types)
|
|
||||||
@_use_format = true
|
|
||||||
condition do
|
|
||||||
mime_types = types.map { |t| mime_type(t) }
|
|
||||||
request.path_info =~ /\.([^\.\/]+)$/
|
|
||||||
url_format = $1.to_sym if $1
|
|
||||||
accepts = request.accept.map { |a| a.split(";")[0].strip }
|
|
||||||
|
|
||||||
# per rfc2616-sec14:
|
|
||||||
# Assume */* if no ACCEPT header is given.
|
|
||||||
catch_all = (accepts.delete "*/*" || accepts.empty?)
|
|
||||||
matching_types = accepts.empty? ? mime_types.slice(0,1) : (accepts & mime_types)
|
|
||||||
|
|
||||||
if params[:format]
|
|
||||||
accept_format = params[:format]
|
|
||||||
elsif !url_format && matching_types.first
|
|
||||||
type = ::Rack::Mime::MIME_TYPES.find { |k, v| v == matching_types.first }[0].sub(/\./,'').to_sym
|
|
||||||
accept_format = CONTENT_TYPE_ALIASES[type] || type
|
|
||||||
elsif catch_all
|
|
||||||
type = types.first
|
|
||||||
accept_format = CONTENT_TYPE_ALIASES[type] || type
|
|
||||||
end
|
|
||||||
|
|
||||||
matched_format = types.include?(:any) ||
|
|
||||||
types.include?(accept_format) ||
|
|
||||||
types.include?(url_format) ||
|
|
||||||
((!url_format) && request.accept.empty? && types.include?(:html))
|
|
||||||
|
|
||||||
# per rfc2616-sec14:
|
|
||||||
# answer with 406 if accept is given but types to not match any
|
|
||||||
# provided type
|
|
||||||
halt 406 if
|
|
||||||
(!url_format && !accepts.empty? && !matched_format) ||
|
|
||||||
(settings.respond_to?(:treat_format_as_accept) && settings.treat_format_as_accept && url_format && !matched_format)
|
|
||||||
|
|
||||||
if matched_format
|
|
||||||
@_content_type = url_format || accept_format || :html
|
|
||||||
content_type(@_content_type, :charset => 'utf-8')
|
|
||||||
end
|
|
||||||
|
|
||||||
matched_format
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
|
||||||
##
|
|
||||||
# Instance method for url generation like:
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# url(:show, :id => 1)
|
|
||||||
# url(:show, :name => :test)
|
|
||||||
# url(:show, 1)
|
|
||||||
# url("/foo")
|
|
||||||
#
|
|
||||||
def url(*args)
|
|
||||||
# Delegate to Sinatra 1.2 for simple url("/foo")
|
|
||||||
# http://www.sinatrarb.com/intro#Generating%20URLs
|
|
||||||
return super if args.first.is_a?(String) && !args[1].is_a?(Hash)
|
|
||||||
# Delegate to Padrino named route url generation
|
|
||||||
self.class.url(*args)
|
|
||||||
end
|
|
||||||
alias :url_for :url
|
|
||||||
|
|
||||||
def recognize_path(path)
|
|
||||||
self.class.recognize_path(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_path(*path_params)
|
|
||||||
if path_params.last.is_a?(Hash)
|
|
||||||
path_params[-1] = params.merge(path_params[-1])
|
|
||||||
else
|
|
||||||
path_params << params
|
|
||||||
end
|
|
||||||
@route.url(*path_params)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# This is mostly just a helper so request.path_info isn't changed when
|
|
||||||
# serving files from the public directory
|
|
||||||
#
|
|
||||||
def static_file?(path_info)
|
|
||||||
return if (public_dir = settings.public).nil?
|
|
||||||
public_dir = File.expand_path(public_dir)
|
|
||||||
|
|
||||||
path = File.expand_path(public_dir + unescape(path_info))
|
|
||||||
return if path[0, public_dir.length] != public_dir
|
|
||||||
return unless File.file?(path)
|
|
||||||
return path
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Method for deliver static files.
|
|
||||||
#
|
|
||||||
def static!
|
|
||||||
if path = static_file?(request.path_info)
|
|
||||||
env['sinatra.static_file'] = path
|
|
||||||
send_file(path, :disposition => nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Return the request format, this is useful when we need to respond to a given content_type like:
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# get :index, :provides => :any do
|
|
||||||
# case content_type
|
|
||||||
# when :js then ...
|
|
||||||
# when :json then ...
|
|
||||||
# when :html then ...
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
def content_type(type=nil, params={})
|
|
||||||
type.nil? ? @_content_type : super(type, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def dispatch!
|
|
||||||
static! if settings.static? && (request.get? || request.head?)
|
|
||||||
route!
|
|
||||||
rescue Sinatra::NotFound => boom
|
|
||||||
handle_not_found!(boom)
|
|
||||||
rescue ::Exception => boom
|
|
||||||
handle_exception!(boom)
|
|
||||||
ensure
|
|
||||||
@_pending_after_filters.each { |filter| instance_eval(&filter)} if @_pending_after_filters
|
|
||||||
end
|
|
||||||
|
|
||||||
def route!(base=self.class, pass_block=nil)
|
|
||||||
@request.env['padrino.instance'] = self
|
|
||||||
if base.compiled_router and match = base.router.call(@request.env)
|
|
||||||
if match.respond_to?(:each)
|
|
||||||
route_eval do
|
|
||||||
match[1].each {|k,v| response[k] = v}
|
|
||||||
status match[0]
|
|
||||||
route_missing if match[0] == 404
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
filter! :before
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run routes defined in superclass.
|
|
||||||
if base.superclass.respond_to?(:router)
|
|
||||||
route!(base.superclass, pass_block)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
route_eval(&pass_block) if pass_block
|
|
||||||
|
|
||||||
route_missing
|
|
||||||
ensure
|
|
||||||
end
|
|
||||||
end # InstanceMethods
|
|
||||||
end # Routing
|
|
||||||
end # Padrino
|
|
|
@ -1,18 +0,0 @@
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# This module extend Sinatra::ShowExceptions adding Padrino as "Framework"
|
|
||||||
#
|
|
||||||
class ShowExceptions < Sinatra::ShowExceptions
|
|
||||||
def frame_class(frame)
|
|
||||||
if frame.filename =~ /lib\/sinatra.*\.rb|lib\/padrino.*\.rb/
|
|
||||||
"framework"
|
|
||||||
elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) ||
|
|
||||||
frame.filename =~ /\/bin\/(\w+)$/ ||
|
|
||||||
frame.filename =~ /Ruby\/Gems/
|
|
||||||
"system"
|
|
||||||
else
|
|
||||||
"app"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end # ShowExceptions
|
|
||||||
end # Padrino
|
|
|
@ -1,45 +0,0 @@
|
||||||
module Padrino
|
|
||||||
PADRINO_IGNORE_CALLERS = [
|
|
||||||
%r{lib/padrino-.*$}, # all padrino code
|
|
||||||
%r{/padrino-.*/(lib|bin)}, # all padrino code
|
|
||||||
%r{/bin/padrino$}, # all padrino code
|
|
||||||
%r{/sinatra(/(base|main|showexceptions))?\.rb$}, # all sinatra code
|
|
||||||
%r{lib/tilt.*\.rb$}, # all tilt code
|
|
||||||
%r{lib/rack.*\.rb$}, # all rack code
|
|
||||||
%r{lib/mongrel.*\.rb$}, # all mongrel code
|
|
||||||
%r{lib/shotgun.*\.rb$}, # all shotgun lib
|
|
||||||
%r{bin/shotgun$}, # shotgun binary
|
|
||||||
%r{\(.*\)}, # generated code
|
|
||||||
%r{shoulda/context\.rb$}, # shoulda hacks
|
|
||||||
%r{mocha/integration}, # mocha hacks
|
|
||||||
%r{test/unit}, # test unit hacks
|
|
||||||
%r{rake_test_loader\.rb}, # rake hacks
|
|
||||||
%r{custom_require\.rb$}, # rubygems require hacks
|
|
||||||
%r{active_support}, # active_support require hacks
|
|
||||||
%r{/thor} # thor require hacks
|
|
||||||
] unless defined?(PADRINO_IGNORE_CALLERS)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Add rubinius (and hopefully other VM impls) ignore patterns ...
|
|
||||||
#
|
|
||||||
PADRINO_IGNORE_CALLERS.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
|
|
||||||
|
|
||||||
private
|
|
||||||
##
|
|
||||||
# Returns the filename for the file that is the direct caller (first caller)
|
|
||||||
#
|
|
||||||
def self.first_caller
|
|
||||||
caller_files.first
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Like Kernel#caller but excluding certain magic entries and without
|
|
||||||
# line / method information; the resulting array contains filenames only.
|
|
||||||
#
|
|
||||||
def self.caller_files
|
|
||||||
caller(1).
|
|
||||||
map { |line| line.split(/:(?=\d|in )/)[0,2] }.
|
|
||||||
reject { |file,line| PADRINO_IGNORE_CALLERS.any? { |pattern| file =~ pattern } }.
|
|
||||||
map { |file,line| file }
|
|
||||||
end
|
|
||||||
end # Padrino
|
|
|
@ -1,24 +0,0 @@
|
||||||
module Padrino
|
|
||||||
module Cli
|
|
||||||
module Adapter
|
|
||||||
class << self
|
|
||||||
# Start for the given options a rackup handler
|
|
||||||
def start(options)
|
|
||||||
Padrino.run!(options.symbolize_keys)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Method that stop (if exist) a running Padrino.application
|
|
||||||
def stop(options)
|
|
||||||
options.symbolize_keys!
|
|
||||||
if File.exist?(options[:pid])
|
|
||||||
pid = File.read(options[:pid]).to_i
|
|
||||||
print "=> Sending INT to process with pid #{pid} wait "
|
|
||||||
Process.kill(2, pid) rescue nil
|
|
||||||
else
|
|
||||||
puts "=> #{options[:pid]} not found!"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end # self
|
|
||||||
end # Adapter
|
|
||||||
end # Cli
|
|
||||||
end # Padrino
|
|
|
@ -1,152 +0,0 @@
|
||||||
require 'thor'
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
module Cli
|
|
||||||
|
|
||||||
class Base < Thor
|
|
||||||
include Thor::Actions
|
|
||||||
|
|
||||||
class_option :chdir, :type => :string, :aliases => "-c", :desc => "Change to dir before starting"
|
|
||||||
class_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development, :desc => "Padrino Environment"
|
|
||||||
class_option :help, :type => :boolean, :desc => "Show help usage"
|
|
||||||
|
|
||||||
desc "start", "Starts the Padrino application"
|
|
||||||
method_option :server, :type => :string, :aliases => "-a", :desc => "Rack Handler (default: autodetect)"
|
|
||||||
method_option :host, :type => :string, :aliases => "-h", :required => true, :default => "0.0.0.0", :desc => "Bind to HOST address"
|
|
||||||
method_option :port, :type => :numeric, :aliases => "-p", :required => true, :default => 3000, :desc => "Use PORT"
|
|
||||||
method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background"
|
|
||||||
method_option :pid, :type => :string, :aliases => "-i", :desc => "File to store pid"
|
|
||||||
method_option :debug, :type => :boolean, :desc => "Set debugging flags"
|
|
||||||
def start
|
|
||||||
prepare :start
|
|
||||||
require File.expand_path("../adapter", __FILE__)
|
|
||||||
require File.expand_path('config/boot.rb')
|
|
||||||
Padrino::Cli::Adapter.start(options)
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "s", "Starts the Padrino application"
|
|
||||||
def s
|
|
||||||
invoke :start
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "stop", "Stops the Padrino application"
|
|
||||||
method_option :pid, :type => :string, :aliases => "-p", :desc => "File to store pid", :default => 'tmp/pids/server.pid'
|
|
||||||
def stop
|
|
||||||
prepare :stop
|
|
||||||
require File.expand_path("../adapter", __FILE__)
|
|
||||||
Padrino::Cli::Adapter.stop(options)
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "rake", "Execute rake tasks"
|
|
||||||
method_option :environment, :type => :string, :aliases => "-e", :required => true, :default => :development
|
|
||||||
method_option :list, :type => :string, :aliases => "-T", :desc => "Display the tasks (matching optional PATTERN) with descriptions, then exit."
|
|
||||||
method_option :trace, :type => :boolean, :aliases => "-t", :desc => "Turn on invoke/execute tracing, enable full backtrace."
|
|
||||||
method_option :verbose, :type => :boolean, :aliases => "-v", :desc => "Log message to standard output."
|
|
||||||
def rake(*args)
|
|
||||||
prepare :rake
|
|
||||||
args << "-T" if options[:list]
|
|
||||||
args << options[:list] unless options[:list].nil? || options[:list].to_s == "list"
|
|
||||||
args << "--trace" if options[:trace]
|
|
||||||
args << "--verbose" if options[:verbose]
|
|
||||||
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') }
|
|
||||||
PadrinoTasks.init(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "console", "Boots up the Padrino application irb console"
|
|
||||||
def console
|
|
||||||
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')
|
|
||||||
require File.expand_path('../console', __FILE__)
|
|
||||||
IRB.start
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "generate", "Executes the Padrino generator with given options."
|
|
||||||
def generate(*args)
|
|
||||||
# Build Padrino g as an alias of padrino-gen
|
|
||||||
begin
|
|
||||||
# We try to load the vendored padrino-gen if exist
|
|
||||||
padrino_gen_path = File.expand_path('../../../../../padrino-gen/lib', __FILE__)
|
|
||||||
$:.unshift(padrino_gen_path) if File.directory?(padrino_gen_path) && !$:.include?(padrino_gen_path)
|
|
||||||
require 'padrino-core/command'
|
|
||||||
require 'padrino-gen/command'
|
|
||||||
ARGV.shift
|
|
||||||
Padrino.bin_gen(ARGV)
|
|
||||||
rescue
|
|
||||||
puts "<= You need padrino-gen! Run: gem install padrino-gen"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "g", "Executes the Padrino generator with given options."
|
|
||||||
def g(*args)
|
|
||||||
invoke(:generate, args)
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "gen", "Executes the Padrino generator with given options."
|
|
||||||
def gen(*args)
|
|
||||||
invoke(:generate, args)
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "version", "Show current Padrino Version"
|
|
||||||
map "-v" => :version, "--version" => :version
|
|
||||||
def version
|
|
||||||
require 'padrino-core/version'
|
|
||||||
puts "Padrino v. #{Padrino.version}"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def prepare(task)
|
|
||||||
if options.help?
|
|
||||||
help(task.to_s)
|
|
||||||
raise SystemExit
|
|
||||||
end
|
|
||||||
ENV["PADRINO_ENV"] ||= options.environment.to_s
|
|
||||||
ENV["RACK_ENV"] = ENV["PADRINO_ENV"] # Also set this for middleware
|
|
||||||
chdir(options.chdir)
|
|
||||||
unless File.exist?('config/boot.rb')
|
|
||||||
puts "=> Could not find boot file in: #{options.chdir}/config/boot.rb !!!"
|
|
||||||
raise SystemExit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
def self.banner(task=nil, *args)
|
|
||||||
"padrino #{task.name}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def chdir(dir)
|
|
||||||
return unless dir
|
|
||||||
begin
|
|
||||||
Dir.chdir(dir.to_s)
|
|
||||||
rescue Errno::ENOENT
|
|
||||||
puts "=> Specified Padrino root '#{dir}' does not appear to exist!"
|
|
||||||
rescue Errno::EACCES
|
|
||||||
puts "=> Specified Padrino root '#{dir}' cannot be accessed by the current user!"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def capture(stream)
|
|
||||||
begin
|
|
||||||
stream = stream.to_s
|
|
||||||
eval "$#{stream} = StringIO.new"
|
|
||||||
yield
|
|
||||||
result = eval("$#{stream}").string
|
|
||||||
ensure
|
|
||||||
eval("$#{stream} = #{stream.upcase}")
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
alias :silence :capture
|
|
||||||
end # Base
|
|
||||||
end # Cli
|
|
||||||
end # Padrino
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Reloads classes
|
|
||||||
def reload!
|
|
||||||
Padrino.reload!
|
|
||||||
end
|
|
||||||
|
|
||||||
# Show applications
|
|
||||||
def applications
|
|
||||||
puts "==== List of Mounted Applications ====\n\n"
|
|
||||||
Padrino.mounted_apps.each do |app|
|
|
||||||
puts " * %-10s mapped to %s" % [app.name, app.uri_root]
|
|
||||||
end
|
|
||||||
puts
|
|
||||||
Padrino.mounted_apps.map { |app| "#{app.name} => #{app.uri_root}" }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Load apps
|
|
||||||
Padrino.mounted_apps.each do |app|
|
|
||||||
puts "=> Loading Application #{app.app_class}"
|
|
||||||
app.app_obj.setup_application!
|
|
||||||
end
|
|
|
@ -1,24 +0,0 @@
|
||||||
require File.expand_path('../../tasks', __FILE__)
|
|
||||||
require 'rake'
|
|
||||||
require 'thor'
|
|
||||||
require 'securerandom' unless defined?(SecureRandom)
|
|
||||||
|
|
||||||
module PadrinoTasks
|
|
||||||
def self.init(init=false)
|
|
||||||
Padrino::Tasks.files.flatten.uniq.each { |rakefile| Rake.application.add_import(rakefile) rescue puts "<= Failed load #{ext}" }
|
|
||||||
if init
|
|
||||||
Rake.application.init
|
|
||||||
Rake.application.instance_variable_set(:@rakefile, __FILE__)
|
|
||||||
load(File.expand_path('../rake_tasks.rb', __FILE__))
|
|
||||||
Rake.application.load_imports
|
|
||||||
Rake.application.top_level
|
|
||||||
else
|
|
||||||
load(File.expand_path('../rake_tasks.rb', __FILE__))
|
|
||||||
Rake.application.load_imports
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def shell
|
|
||||||
@_shell ||= Thor::Base.shell.new
|
|
||||||
end
|
|
|
@ -1,59 +0,0 @@
|
||||||
# Load rake tasks from common rake task definition locations
|
|
||||||
Dir["lib/tasks/**/*.rake"].
|
|
||||||
concat(Dir["tasks/**/*.rake"]).
|
|
||||||
concat(Dir["{test,spec}/*.rake"]).each { |rake| load(rake) }
|
|
||||||
|
|
||||||
# Loads the Padrino applications mounted within the project
|
|
||||||
# setting up the required environment for Padrino
|
|
||||||
task :environment do
|
|
||||||
Padrino.mounted_apps.each do |app|
|
|
||||||
app.app_obj.setup_application!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Generate a secret key"
|
|
||||||
task :secret do
|
|
||||||
shell.say SecureRandom.hex(32)
|
|
||||||
end
|
|
||||||
|
|
||||||
# lists all routes of a given app
|
|
||||||
def list_app_routes(app, args)
|
|
||||||
app_routes = app.named_routes
|
|
||||||
app_routes.reject! { |r| r.identifier.to_s !~ /#{args.query}/ } if args.query.present?
|
|
||||||
app_routes.map! { |r| [r.verb, r.name, r.path] }
|
|
||||||
return if app_routes.empty?
|
|
||||||
shell.say "\nApplication: #{app.app_class}", :yellow
|
|
||||||
app_routes.unshift(["REQUEST", "URL", "PATH"])
|
|
||||||
max_col_1 = app_routes.max { |a, b| a[0].size <=> b[0].size }[0].size
|
|
||||||
max_col_2 = app_routes.max { |a, b| a[1].size <=> b[1].size }[1].size
|
|
||||||
app_routes.each_with_index do |row, i|
|
|
||||||
message = [row[1].ljust(max_col_2+2), row[0].center(max_col_1+2), row[2]]
|
|
||||||
shell.say(" " + message.join(" "), i==0 ? :bold : nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Displays a listing of the named routes within a project, optionally only those matched by [query]"
|
|
||||||
task :routes, [:query] => :environment do |t, args|
|
|
||||||
Padrino.mounted_apps.each do |app|
|
|
||||||
list_app_routes(app, args)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Displays a listing of the named routes a given app [app]"
|
|
||||||
namespace :routes do
|
|
||||||
task :app, [:app] => :environment do |t, args|
|
|
||||||
app = Padrino.mounted_apps.find { |app| app.app_class == args.app }
|
|
||||||
list_app_routes(app, args) if app
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Generate the Rakefile"
|
|
||||||
task :gen do
|
|
||||||
File.open(Padrino.root("Rakefile"), "w") do |file|
|
|
||||||
file.puts <<-RUBY.gsub(/^ {6}/, '')
|
|
||||||
require File.expand_path('../config/boot.rb', __FILE__)
|
|
||||||
require 'padrino-core/cli/rake'
|
|
||||||
PadrinoTasks.init
|
|
||||||
RUBY
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,27 +0,0 @@
|
||||||
require 'rbconfig'
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# This method return the correct location of padrino bin or
|
|
||||||
# exec it using Kernel#system with the given args
|
|
||||||
#
|
|
||||||
def self.bin(*args)
|
|
||||||
@_padrino_bin ||= [self.ruby_command, File.expand_path("../../../bin/padrino", __FILE__)]
|
|
||||||
args.empty? ? @_padrino_bin : system(args.unshift(@_padrino_bin).join(" "))
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Return the path to the ruby interpreter taking into account multiple
|
|
||||||
# installations and windows extensions.
|
|
||||||
#
|
|
||||||
def self.ruby_command
|
|
||||||
@ruby_command ||= begin
|
|
||||||
ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
|
|
||||||
ruby << Config::CONFIG['EXEEXT']
|
|
||||||
|
|
||||||
# escape string in case path to ruby executable contain spaces.
|
|
||||||
ruby.sub!(/.*\s.*/m, '"\&"')
|
|
||||||
ruby
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end # Padrino
|
|
Binary file not shown.
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
|
@ -1,182 +0,0 @@
|
||||||
module Padrino
|
|
||||||
class << self
|
|
||||||
|
|
||||||
##
|
|
||||||
# Hooks to be called before a load/reload
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# before_load do
|
|
||||||
# pre_initialize_something
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
#
|
|
||||||
def before_load(&block)
|
|
||||||
@_before_load ||= []
|
|
||||||
@_before_load << block if block_given?
|
|
||||||
@_before_load
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Hooks to be called after a load/reload
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# after_load do
|
|
||||||
# DataMapper.finalize
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
#
|
|
||||||
def after_load(&block)
|
|
||||||
@_after_load ||= []
|
|
||||||
@_after_load << block if block_given?
|
|
||||||
@_after_load
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the used $LOAD_PATHS from padrino
|
|
||||||
#
|
|
||||||
def load_paths
|
|
||||||
@_load_paths_was = %w(lib models shared).map { |path| Padrino.root(path) }
|
|
||||||
@_load_paths ||= @_load_paths_was
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Requires necessary dependencies as well as application files from root lib and models
|
|
||||||
#
|
|
||||||
def load!
|
|
||||||
return false if loaded?
|
|
||||||
@_called_from = first_caller
|
|
||||||
Padrino.set_encoding
|
|
||||||
Padrino.set_load_paths(*load_paths) # We set the padrino load paths
|
|
||||||
Padrino::Logger.setup! # Initialize our logger
|
|
||||||
Padrino.require_dependencies("#{root}/config/database.rb", :nodeps => true) # Be sure to don't remove constants from dbs.
|
|
||||||
Padrino::Reloader.lock! # Now we can remove constant from here to down
|
|
||||||
Padrino.before_load.each(&:call) # Run before hooks
|
|
||||||
Padrino.dependency_paths.each { |path| Padrino.require_dependencies(path) }
|
|
||||||
Padrino.after_load.each(&:call) # Run after hooks
|
|
||||||
Padrino::Reloader.run!
|
|
||||||
Thread.current[:padrino_loaded] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Clear the padrino env
|
|
||||||
#
|
|
||||||
def clear!
|
|
||||||
Padrino.clear_middleware!
|
|
||||||
Padrino.mounted_apps.clear
|
|
||||||
@_load_paths = nil
|
|
||||||
@_dependency_paths = nil
|
|
||||||
@_global_configuration = nil
|
|
||||||
Padrino.before_load.clear
|
|
||||||
Padrino.after_load.clear
|
|
||||||
Padrino::Reloader.clear!
|
|
||||||
Thread.current[:padrino_loaded] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Method for reloading required applications and their files
|
|
||||||
#
|
|
||||||
def reload!
|
|
||||||
Padrino.before_load.each(&:call) # Run before hooks
|
|
||||||
Padrino::Reloader.reload! # detects the modified files
|
|
||||||
Padrino.after_load.each(&:call) # Run after hooks
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# This adds the ablity to instantiate Padrino.load! after Padrino::Application definition.
|
|
||||||
#
|
|
||||||
def called_from
|
|
||||||
@_called_from || first_caller
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Return true if Padrino was loaded with Padrino.load!
|
|
||||||
#
|
|
||||||
def loaded?
|
|
||||||
Thread.current[:padrino_loaded]
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Attempts to require all dependency libs that we need.
|
|
||||||
# If you use this method we can perform correctly a Padrino.reload!
|
|
||||||
# Another good thing that this method are dependency check, for example:
|
|
||||||
#
|
|
||||||
# models
|
|
||||||
# \-- a.rb => require something of b.rb
|
|
||||||
# \-- b.rb
|
|
||||||
#
|
|
||||||
# In the example above if we do:
|
|
||||||
#
|
|
||||||
# Dir["/models/*.rb"].each { |r| require r }
|
|
||||||
#
|
|
||||||
# we get an error, because we try to require first a.rb that need +something+ of b.rb.
|
|
||||||
#
|
|
||||||
# With +require_dependencies+ we don't have this problem.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # For require all our app libs we need to do:
|
|
||||||
# require_dependencies("#{Padrino.root}/lib/**/*.rb")
|
|
||||||
#
|
|
||||||
def require_dependencies(*paths)
|
|
||||||
options = paths.extract_options!
|
|
||||||
|
|
||||||
# Extract all files to load
|
|
||||||
files = paths.flatten.map { |path| Dir[path] }.flatten.uniq.sort
|
|
||||||
|
|
||||||
while files.present?
|
|
||||||
# List of errors and failed files
|
|
||||||
errors, failed = [], []
|
|
||||||
|
|
||||||
# We need a size to make sure things are loading
|
|
||||||
size_at_start = files.size
|
|
||||||
|
|
||||||
# Now we try to require our dependencies, we dup files
|
|
||||||
# so we don't perform delete on the original array during
|
|
||||||
# iteration, this prevent problems with rubinus
|
|
||||||
files.dup.each do |file|
|
|
||||||
begin
|
|
||||||
Padrino::Reloader.safe_load(file, options.dup)
|
|
||||||
files.delete(file)
|
|
||||||
rescue LoadError => e
|
|
||||||
errors << e
|
|
||||||
failed << file
|
|
||||||
rescue NameError => e
|
|
||||||
errors << e
|
|
||||||
failed << file
|
|
||||||
rescue Exception => e
|
|
||||||
raise e
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Stop processing if nothing loads or if everything has loaded
|
|
||||||
raise errors.last if files.size == size_at_start && files.present?
|
|
||||||
break if files.empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns default list of path globs to load as dependencies
|
|
||||||
# Appends custom dependency patterns to the be loaded for Padrino
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
# Padrino.dependency_paths << "#{Padrino.root}/uploaders/*.rb"
|
|
||||||
#
|
|
||||||
def dependency_paths
|
|
||||||
@_dependency_paths_was = [
|
|
||||||
"#{root}/config/database.rb", "#{root}/lib/**/*.rb", "#{root}/shared/lib/**/*.rb",
|
|
||||||
"#{root}/models/**/*.rb", "#{root}/shared/models/**/*.rb", "#{root}/config/apps.rb"
|
|
||||||
]
|
|
||||||
@_dependency_paths ||= @_dependency_paths_was
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Concat to $LOAD_PATH the given paths
|
|
||||||
#
|
|
||||||
def set_load_paths(*paths)
|
|
||||||
$:.concat(paths); load_paths.concat(paths)
|
|
||||||
$:.uniq!; load_paths.uniq!
|
|
||||||
end
|
|
||||||
end # self
|
|
||||||
end # Padrino
|
|
|
@ -1,30 +0,0 @@
|
||||||
cz:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%d. %B %Y"
|
|
||||||
|
|
||||||
day_names: [Neděle, Pondělí, Úterý, Středa, Čtvrtek, Pátek, Sobota]
|
|
||||||
abbr_day_names: [Ne, Po, Út, St, Čt, Pá, So]
|
|
||||||
month_names: [~, Leden, Únor, Březen, Duben, Květen, Červen, Červenec, Srpen, Září, Říjen, Listopad, Prosinec]
|
|
||||||
abbr_month_names: [~, Led, Úno, Bře, Dub, Kvě, Čvn, Čvc, Srp, Zář, Říj, Lis, Pro]
|
|
||||||
order: [:day, :month, :year]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a %d. %B %Y %H:%M %z"
|
|
||||||
short: "%d. %m. %H:%M"
|
|
||||||
long: "%A %d. %B %Y %H:%M"
|
|
||||||
am: "dop"
|
|
||||||
pm: "odp"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " a "
|
|
||||||
last_word_connector: " a "
|
|
|
@ -1,30 +0,0 @@
|
||||||
da:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%e. %b %Y"
|
|
||||||
long: "%e. %B %Y"
|
|
||||||
|
|
||||||
day_names: [søndag, mandag, tirsdag, onsdag, torsdag, fredag, lørdag]
|
|
||||||
abbr_day_names: [sø, ma, ti, 'on', to, fr, lø]
|
|
||||||
month_names: [~, januar, februar, marts, april, maj, juni, juli, august, september, oktober, november, december]
|
|
||||||
abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, dec]
|
|
||||||
order: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%e. %B %Y, %H:%M"
|
|
||||||
short: "%e. %b %Y, %H:%M"
|
|
||||||
long: "%A, %e. %B %Y, %H:%M"
|
|
||||||
am: ""
|
|
||||||
pm: ""
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " og "
|
|
||||||
last_word_connector: " og "
|
|
|
@ -1,30 +0,0 @@
|
||||||
de:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# Benutze die strftime Parameter für die Formatierung
|
|
||||||
# Wenn keine Formate angegeben werden, wird "default" benutzt.
|
|
||||||
# Du kannst auch weitere Formate hinzufügen, wenn Du möchtest.
|
|
||||||
default: "&d.&m.%Y"
|
|
||||||
short: "%b %d"
|
|
||||||
long: "%B %d, %Y"
|
|
||||||
|
|
||||||
day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag]
|
|
||||||
abbr_day_names: [So, Mo, Di, Mi, Do, Fr, Sa]
|
|
||||||
month_names: [~, Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember]
|
|
||||||
abbr_month_names: [~, Jan, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez]
|
|
||||||
order: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %d %b %Y %H:%M:%S %z"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%B %d, %Y %H:%M"
|
|
||||||
am: "am"
|
|
||||||
pm: "pm"
|
|
||||||
|
|
||||||
# Benutzt in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " und "
|
|
||||||
last_word_connector: ", und "
|
|
|
@ -1,30 +0,0 @@
|
||||||
en:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# Use the strftime parameters for formats.
|
|
||||||
# When no format has been given, it uses default.
|
|
||||||
# You can provide other formats here if you like!
|
|
||||||
default: "%Y-%m-%d"
|
|
||||||
short: "%b %d"
|
|
||||||
long: "%B %d, %Y"
|
|
||||||
|
|
||||||
day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
|
|
||||||
abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
|
|
||||||
month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
|
|
||||||
abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %d %b %Y %H:%M:%S %z"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%B %d, %Y %H:%M"
|
|
||||||
am: "am"
|
|
||||||
pm: "pm"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " and "
|
|
||||||
last_word_connector: ", and "
|
|
|
@ -1,30 +0,0 @@
|
||||||
es:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%b %d"
|
|
||||||
long: "%B %d, %Y"
|
|
||||||
|
|
||||||
day_names: [Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado]
|
|
||||||
abbr_day_names: [Dom, Lun, Mar, Mie, Jue, Vie, Sab]
|
|
||||||
month_names: [~, Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Septiembre, Octubre, Noviembre, Diciembre]
|
|
||||||
abbr_month_names: [~, Ene, Feb, Mar, Abr, May, Jun, Jul, Ago, Sep, Oct, Nov, Dic]
|
|
||||||
order: [ :day, :month, :year]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %d %b %Y %H:%M:%S %z"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%B %d, %Y %H:%M"
|
|
||||||
am: "am"
|
|
||||||
pm: "pm"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " y "
|
|
||||||
last_word_connector: ", y "
|
|
|
@ -1,30 +0,0 @@
|
||||||
fr:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%b %d"
|
|
||||||
long: "%B %d, %Y"
|
|
||||||
|
|
||||||
day_names: [Dimanche, Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi]
|
|
||||||
abbr_day_names: [Lun, Mar, Mer, Jeu, Ven, Sam, Dim]
|
|
||||||
month_names: [~, Janvier, Février, Mars, Avril, Mai, Juin, Juillet, Août, Septembre, Octobre, Novembre, Décembre]
|
|
||||||
abbr_month_names: [~, Jan, Fev, Mar, Avr, Mai, Jui, Jui, Aou, Sep, Oct, Nov, Dec]
|
|
||||||
order: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %d %b %Y %H:%M:%S %z"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%B %d, %Y %H:%M"
|
|
||||||
am: "am"
|
|
||||||
pm: "pm"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " et "
|
|
||||||
last_word_connector: ", et "
|
|
|
@ -1,30 +0,0 @@
|
||||||
hu:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# Use the strftime parameters for formats.
|
|
||||||
# When no format has been given, it uses default.
|
|
||||||
# You can provide other formats here if you like!
|
|
||||||
default: "%Y-%m-%d"
|
|
||||||
short: "%b. %d."
|
|
||||||
long: "%Y. %B %d."
|
|
||||||
|
|
||||||
day_names: [vasárnap, hétfő, kedd, szerda, csütörtök, péntek, szombat]
|
|
||||||
abbr_day_names: [vas, hét, kedd, sze, csüt, pén, szo]
|
|
||||||
month_names: [~, január, február, március, április, május, június, július, augusztus, szeptember, oktober, november, december]
|
|
||||||
abbr_month_names: [~, jan, febr, márc, ápr, máj, jún, júl, aug, szept, okt, nov, dec]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%Y. %B %d. %H:%M:%S %z, %A"
|
|
||||||
short: "%B %d. %H:%M"
|
|
||||||
long: "%Y. %B %d. %H:%M"
|
|
||||||
am: "de"
|
|
||||||
pm: "du"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " és "
|
|
||||||
last_word_connector: " és "
|
|
|
@ -1,37 +0,0 @@
|
||||||
it:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%d %B %Y"
|
|
||||||
only_day: "%e"
|
|
||||||
|
|
||||||
day_names: [Domenica, Lunedì, Martedì, Mercoledì, Giovedì, Venerdì, Sabato]
|
|
||||||
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: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a %d %b %Y, %H:%M:%S %z"
|
|
||||||
time: "%H:%M"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%d %B %Y %H:%M"
|
|
||||||
only_second: "%S"
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
formats:
|
|
||||||
default: "%d-%m-%YT%H:%M:%S%Z"
|
|
||||||
|
|
||||||
am: 'am'
|
|
||||||
pm: 'pm'
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
sentence_connector: "e"
|
|
||||||
skip_last_comma: false
|
|
|
@ -1,30 +0,0 @@
|
||||||
ja:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# Use the strftime parameters for formats.
|
|
||||||
# When no format has been given, it uses default.
|
|
||||||
# You can provide other formats here if you like!
|
|
||||||
default: "%Y/%m/%d"
|
|
||||||
short: "%m/%d"
|
|
||||||
long: "%Y年%m月%d日"
|
|
||||||
|
|
||||||
day_names: [日曜日, 月曜日, 火曜日, 水曜日, 木曜日, 金曜日, 土曜日]
|
|
||||||
abbr_day_names: [日, 月, 火, 水, 木, 金, 土]
|
|
||||||
month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]
|
|
||||||
abbr_month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%Y/%m/%d %H:%M:%S"
|
|
||||||
short: "%m/%d %H:%M"
|
|
||||||
long: "%Y年%m月%d日 %H時%M分%S秒"
|
|
||||||
am: "午前"
|
|
||||||
pm: "午後"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " と "
|
|
||||||
last_word_connector: ", と "
|
|
|
@ -1,30 +0,0 @@
|
||||||
nl:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%d %B %Y"
|
|
||||||
|
|
||||||
day_names: [zondag, maandag, dinsdag, woensdag, donderdag, vrijdag, zaterdag]
|
|
||||||
abbr_day_names: [zo, ma, di, wo, do, vr, za]
|
|
||||||
month_names: [~, januari, februari, maart, april, mei, juni, juli, augustus, september, oktober, november]
|
|
||||||
abbr_month_names: [~, jan, feb, maa, apr, mei, jun, jul, aug, sep, okt, nov, dec]
|
|
||||||
order: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a %d %b %Y %H:%M:%S %z"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%d %B %Y %H:%M"
|
|
||||||
am: "am"
|
|
||||||
pm: "pm"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " en "
|
|
||||||
last_word_connector: " en "
|
|
|
@ -1,31 +0,0 @@
|
||||||
"no":
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%e. %b %Y"
|
|
||||||
long: "%e. %B %Y"
|
|
||||||
|
|
||||||
day_names: [søndag, mandag, tirsdag, onsdag, torsdag, fredag, lørdag]
|
|
||||||
abbr_day_names: [sø, ma, ti, 'on', to, fr, lø]
|
|
||||||
month_names: [~, januar, februar, mars, april, mai, juni, juli, august, september, oktober, november, desember]
|
|
||||||
abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, des]
|
|
||||||
order: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%e. %B %Y, %H:%M"
|
|
||||||
short: "%e. %b %Y, %H:%M"
|
|
||||||
long: "%A, %e. %B %Y, %H:%M"
|
|
||||||
am: ""
|
|
||||||
pm: ""
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " og "
|
|
||||||
last_word_connector: " og "
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
pl:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# Use the strftime parameters for formats.
|
|
||||||
# When no format has been given, it uses default.
|
|
||||||
# You can provide other formats here if you like!
|
|
||||||
default: "%Y-%m-%d"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%d %B %Y"
|
|
||||||
|
|
||||||
day_names: [Niedziela, Poniedziałek, Wtorek, Środa, Czwartek, Piątek, Sobota]
|
|
||||||
abbr_day_names: [nie, pon, wto, śro, czw, pia, sob]
|
|
||||||
month_names: [~, Styczeń, Luty, Marzec, Kwiecień, Maj, Czerwiec, Lipiec, Sierpień, Wrzesień, Październik, Listopad, Grudzień]
|
|
||||||
abbr_month_names: [~, sty, lut, mar, kwi, maj, cze, lip, sie, wrz, paź, lis, gru]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %d %b %Y, %H:%M:%S %z"
|
|
||||||
short: "%d %b, %H:%M"
|
|
||||||
long: "%d %B %Y, %H:%M"
|
|
||||||
am: "przed południem"
|
|
||||||
pm: "po południu"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " i "
|
|
||||||
last_word_connector: " i "
|
|
|
@ -1,37 +0,0 @@
|
||||||
it:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%d %B %Y"
|
|
||||||
only_day: "%e"
|
|
||||||
|
|
||||||
day_names: [Domingo, Segunda-feira, Terça-feira, Quarta-feira, Quinta-feira, Sexta-feira, Sábado]
|
|
||||||
abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sab]
|
|
||||||
month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro]
|
|
||||||
abbr_month_names: [~, Jan, Fev, Mar, Abr, Maio, Jun, Jul, Ago, Set, Out, Nov, Dez]
|
|
||||||
order: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a %d %b %Y, %H:%M:%S %z"
|
|
||||||
time: "%H:%M"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%d %B %Y %H:%M"
|
|
||||||
only_second: "%S"
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
formats:
|
|
||||||
default: "%d-%m-%YT%H:%M:%S%Z"
|
|
||||||
|
|
||||||
am: 'am'
|
|
||||||
pm: 'pm'
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
sentence_connector: "e"
|
|
||||||
skip_last_comma: false
|
|
|
@ -1,30 +0,0 @@
|
||||||
ru:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%e %B, %Y"
|
|
||||||
|
|
||||||
day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота]
|
|
||||||
abbr_day_names: [Вс, Пн, Вт, Ср, Чт, Пт, Сб]
|
|
||||||
month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь]
|
|
||||||
abbr_month_names: [~, Янв, Феб, Мар, Апр, Май, Июн, Июл, Авг, Сен, Окт, Нов, Дек]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %d %b %Y %H:%M:%S %z"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%e %B, %Y %H:%M"
|
|
||||||
am: "д.п."
|
|
||||||
pm: "п.п"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " и "
|
|
||||||
last_word_connector: ", и "
|
|
|
@ -1,30 +0,0 @@
|
||||||
tr:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%d %B %Y"
|
|
||||||
|
|
||||||
day_names: [Pazar, Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi]
|
|
||||||
abbr_day_names: [Paz, Pts, Sal, Çar, Per, Cum, Cts]
|
|
||||||
month_names: [~, Ocak, Şubat, Mart, Nisan, Mayıs, Haziran, Temmuz, Ağustos, Eylül, Ekim, Kasım, Aralık]
|
|
||||||
abbr_month_names: [~, Oca, Şub, Mar, Nis, May, Haz, Tem, Ağu, Eyl, Eki, Kas, Ara]
|
|
||||||
order: [ :day, :month, :year ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %b %b %Y %H:%M:%S %z"
|
|
||||||
short: "%b %d %H:%M"
|
|
||||||
long: "%d %B, %Y %H:%M"
|
|
||||||
am: "öö"
|
|
||||||
pm: "ös"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " ve "
|
|
||||||
last_word_connector: " ve "
|
|
|
@ -1,30 +0,0 @@
|
||||||
uk:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# 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"
|
|
||||||
short: "%d %b"
|
|
||||||
long: "%e %B, %Y"
|
|
||||||
|
|
||||||
day_names: [Неділя, Понеділок, Вівторок, Середа, Четвер, Пятница, Субота]
|
|
||||||
abbr_day_names: [Нд, Пн, Вт, Ср, Чт, Пт, Сб]
|
|
||||||
month_names: [~, Січено, Лютий, Березень, Квітень, Травень, Червень, Липень, Серпень, Вересень, Жовтень, Листопад, Грудень]
|
|
||||||
abbr_month_names: [~, Січ, Лют, Бер, Кві, Тра, Чер, Лип, Сер, Вер, Жов, Лис, Гру]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%a, %d %b %Y %H:%M:%S %z"
|
|
||||||
short: "%d %b %H:%M"
|
|
||||||
long: "%e %B, %Y %H:%M"
|
|
||||||
am: "д.п."
|
|
||||||
pm: "п.п"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " і "
|
|
||||||
last_word_connector: ", і "
|
|
|
@ -1,30 +0,0 @@
|
||||||
zh_cn:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# Use the strftime parameters for formats.
|
|
||||||
# When no format has been given, it uses default.
|
|
||||||
# You can provide other formats here if you like!
|
|
||||||
default: "%Y-%m-%d"
|
|
||||||
short: "%b%d日"
|
|
||||||
long: "%Y年%b%d日"
|
|
||||||
|
|
||||||
day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
|
|
||||||
abbr_day_names: [日, 一, 二, 三, 四, 五, 六]
|
|
||||||
month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]
|
|
||||||
abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%Y年%b%d日 %A %H:%M:%S %Z"
|
|
||||||
short: "%b%d日 %H:%M"
|
|
||||||
long: "%Y年%b%d日 %H:%M"
|
|
||||||
am: "上午"
|
|
||||||
pm: "下午"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " 和 "
|
|
||||||
last_word_connector: ", 和 "
|
|
|
@ -1,30 +0,0 @@
|
||||||
zh_tw:
|
|
||||||
date:
|
|
||||||
formats:
|
|
||||||
# Use the strftime parameters for formats.
|
|
||||||
# When no format has been given, it uses default.
|
|
||||||
# You can provide other formats here if you like!
|
|
||||||
default: "%Y-%m-%d"
|
|
||||||
short: "%b%d日"
|
|
||||||
long: "%Y年%b%d日"
|
|
||||||
|
|
||||||
day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
|
|
||||||
abbr_day_names: [日, 一, 二, 三, 四, 五, 六]
|
|
||||||
month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月]
|
|
||||||
abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
|
|
||||||
order: [ :year, :month, :day ]
|
|
||||||
|
|
||||||
time:
|
|
||||||
formats:
|
|
||||||
default: "%Y年%b%d日 %A %H:%M:%S %Z"
|
|
||||||
short: "%b%d日 %H:%M"
|
|
||||||
long: "%Y年%b%d日 %H:%M"
|
|
||||||
am: "上午"
|
|
||||||
pm: "下午"
|
|
||||||
|
|
||||||
# Used in array.to_sentence.
|
|
||||||
support:
|
|
||||||
array:
|
|
||||||
words_connector: ", "
|
|
||||||
two_words_connector: " 和 "
|
|
||||||
last_word_connector: ", 和 "
|
|
|
@ -1,344 +0,0 @@
|
||||||
# Defines our PADRINO_LOG_LEVEL
|
|
||||||
PADRINO_LOG_LEVEL = ENV['PADRINO_LOG_LEVEL'] unless defined?(PADRINO_LOG_LEVEL)
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the padrino logger
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# logger.debug "foo"
|
|
||||||
# logger.warn "bar"
|
|
||||||
#
|
|
||||||
def self.logger
|
|
||||||
Padrino::Logger.setup! if Thread.current[:padrino_logger].nil?
|
|
||||||
Thread.current[:padrino_logger]
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Set the padrino logger
|
|
||||||
#
|
|
||||||
def self.logger=(value)
|
|
||||||
Thread.current[:padrino_logger] = value
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Extensions to the built in Ruby logger.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# logger.debug "foo"
|
|
||||||
# logger.warn "bar"
|
|
||||||
#
|
|
||||||
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:
|
|
||||||
#
|
|
||||||
# :fatal:: An unhandleable error that results in a program crash
|
|
||||||
# :error:: A handleable error condition
|
|
||||||
# :warn:: A warning
|
|
||||||
# :info:: generic (useful) information about system operation
|
|
||||||
# :debug:: low-level information for developers
|
|
||||||
#
|
|
||||||
Levels = {
|
|
||||||
:fatal => 7,
|
|
||||||
:error => 6,
|
|
||||||
:warn => 4,
|
|
||||||
:info => 3,
|
|
||||||
:debug => 0,
|
|
||||||
:devel => -1,
|
|
||||||
} unless const_defined?(:Levels)
|
|
||||||
|
|
||||||
@@mutex = {}
|
|
||||||
|
|
||||||
##
|
|
||||||
# Configuration for a given environment, possible options are:
|
|
||||||
#
|
|
||||||
# :log_level:: Once of [:fatal, :error, :warn, :info, :debug]
|
|
||||||
# :stream:: Once of [:to_file, :null, :stdout, :stderr] our your custom stream
|
|
||||||
# :log_level::
|
|
||||||
# The log level from, e.g. :fatal or :info. Defaults to :debug in the
|
|
||||||
# production environment and :debug otherwise.
|
|
||||||
# :auto_flush::
|
|
||||||
# Whether the log should automatically flush after new messages are
|
|
||||||
# added. Defaults to true.
|
|
||||||
# :format_datetime:: Format of datetime. Defaults to: "%d/%b/%Y %H:%M:%S"
|
|
||||||
# :format_message:: Format of message. Defaults to: ""%s - - [%s] \"%s\"""
|
|
||||||
# :log_static:: Whether or not to show log messages for static files. Defaults to: false
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# Padrino::Logger::Config[:development] = { :log_level => :debug, :stream => :to_file }
|
|
||||||
# # or you can edit our defaults
|
|
||||||
# Padrino::Logger::Config[:development][:log_level] = :error
|
|
||||||
# # or you can use your stream
|
|
||||||
# Padrino::Logger::Config[:development][:stream] = StringIO.new
|
|
||||||
#
|
|
||||||
# Defaults are:
|
|
||||||
#
|
|
||||||
# :production => { :log_level => :warn, :stream => :to_file }
|
|
||||||
# :development => { :log_level => :debug, :stream => :stdout }
|
|
||||||
# :test => { :log_level => :fatal, :stream => :null }
|
|
||||||
#
|
|
||||||
Config = {
|
|
||||||
:production => { :log_level => :warn, :stream => :to_file },
|
|
||||||
:development => { :log_level => :debug, :stream => :stdout },
|
|
||||||
:test => { :log_level => :debug, :stream => :null }
|
|
||||||
}
|
|
||||||
|
|
||||||
# Embed in a String to clear all previous ANSI sequences.
|
|
||||||
CLEAR = "\e[0m"
|
|
||||||
# The start of an ANSI bold sequence.
|
|
||||||
BOLD = "\e[1m"
|
|
||||||
# Set the terminal's foreground ANSI color to black.
|
|
||||||
BLACK = "\e[30m"
|
|
||||||
# Set the terminal's foreground ANSI color to red.
|
|
||||||
RED = "\e[31m"
|
|
||||||
# Set the terminal's foreground ANSI color to green.
|
|
||||||
GREEN = "\e[32m"
|
|
||||||
# Set the terminal's foreground ANSI color to yellow.
|
|
||||||
YELLOW = "\e[33m"
|
|
||||||
# Set the terminal's foreground ANSI color to blue.
|
|
||||||
BLUE = "\e[34m"
|
|
||||||
# Set the terminal's foreground ANSI color to magenta.
|
|
||||||
MAGENTA = "\e[35m"
|
|
||||||
# Set the terminal's foreground ANSI color to cyan.
|
|
||||||
CYAN = "\e[36m"
|
|
||||||
# Set the terminal's foreground ANSI color to white.
|
|
||||||
WHITE = "\e[37m"
|
|
||||||
|
|
||||||
# Colors for levels
|
|
||||||
ColoredLevels = {
|
|
||||||
:fatal => [BOLD, RED],
|
|
||||||
:error => [RED],
|
|
||||||
:warn => [YELLOW],
|
|
||||||
:info => [GREEN],
|
|
||||||
:debug => [CYAN],
|
|
||||||
:devel => [MAGENTA]
|
|
||||||
} unless defined?(ColoredLevels)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Setup a new logger
|
|
||||||
#
|
|
||||||
def self.setup!
|
|
||||||
config_level = (PADRINO_LOG_LEVEL || Padrino.env || :test).to_sym # need this for PADRINO_LOG_LEVEL
|
|
||||||
config = Config[config_level]
|
|
||||||
stream = case config[:stream]
|
|
||||||
when :to_file
|
|
||||||
FileUtils.mkdir_p(Padrino.root("log")) unless File.exists?(Padrino.root("log"))
|
|
||||||
File.new(Padrino.root("log", "#{Padrino.env}.log"), "a+")
|
|
||||||
when :null then StringIO.new
|
|
||||||
when :stdout then $stdout
|
|
||||||
when :stderr then $stderr
|
|
||||||
else config[:stream] # return itself, probabilly is a custom stream.
|
|
||||||
end
|
|
||||||
Thread.current[:padrino_logger] = Padrino::Logger.new(config.merge(:stream => stream))
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# To initialize the logger you create a new object, proxies to set_log.
|
|
||||||
#
|
|
||||||
# ==== Options
|
|
||||||
#
|
|
||||||
# :stream:: Either an IO object or a name of a logfile. Defaults to $stdout
|
|
||||||
# :log_level::
|
|
||||||
# The log level from, e.g. :fatal or :info. Defaults to :debug in the
|
|
||||||
# production environment and :debug otherwise.
|
|
||||||
# :auto_flush::
|
|
||||||
# Whether the log should automatically flush after new messages are
|
|
||||||
# added. Defaults to true.
|
|
||||||
# :format_datetime:: Format of datetime. Defaults to: "%d/%b/%Y %H:%M:%S"
|
|
||||||
# :format_message:: Format of message. Defaults to: ""%s - - [%s] \"%s\"""
|
|
||||||
# :log_static:: Whether or not to show log messages for static files. Defaults to: false
|
|
||||||
#
|
|
||||||
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]
|
|
||||||
@log = options[:stream] || $stdout
|
|
||||||
@log.sync = true
|
|
||||||
@mutex = @@mutex[@log] ||= Mutex.new
|
|
||||||
@format_datetime = options[:format_datetime] || "%d/%b/%Y %H:%M:%S"
|
|
||||||
@format_message = options[:format_message] || "%s - [%s] \"%s\""
|
|
||||||
@log_static = options.has_key?(:log_static) ? options[:log_static] : false
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Colorize our level
|
|
||||||
#
|
|
||||||
def colored_level(level)
|
|
||||||
style = ColoredLevels[level.to_s.downcase.to_sym].join("")
|
|
||||||
"#{style}#{level.to_s.upcase.rjust(7)}#{CLEAR}"
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Set a color for our string. Color can be a symbol/string
|
|
||||||
#
|
|
||||||
def set_color(string, color, bold=false)
|
|
||||||
color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
|
||||||
bold = bold ? BOLD : ""
|
|
||||||
"#{bold}#{color}#{string}#{CLEAR}"
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Flush the entire buffer to the log object.
|
|
||||||
#
|
|
||||||
def flush
|
|
||||||
return unless @buffer.size > 0
|
|
||||||
@mutex.synchronize do
|
|
||||||
@log.write(@buffer.slice!(0..-1).join(''))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Close and remove the current log object.
|
|
||||||
#
|
|
||||||
def close
|
|
||||||
flush
|
|
||||||
@log.close if @log.respond_to?(:close) && !@log.tty?
|
|
||||||
@log = nil
|
|
||||||
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.
|
|
||||||
#
|
|
||||||
def push(message = nil, level = nil)
|
|
||||||
self << @format_message % [colored_level(level), set_color(Time.now.strftime(@format_datetime), :yellow), message.to_s.strip]
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Directly append message to the log.
|
|
||||||
#
|
|
||||||
def <<(message = nil)
|
|
||||||
message << "\n" unless message[-1] == ?\n
|
|
||||||
@buffer << message
|
|
||||||
flush if @auto_flush
|
|
||||||
message
|
|
||||||
end
|
|
||||||
alias :write :<<
|
|
||||||
|
|
||||||
##
|
|
||||||
# Generate the logging methods for Padrino.logger for each log level.
|
|
||||||
#
|
|
||||||
Levels.each_pair do |name, number|
|
|
||||||
class_eval <<-LEVELMETHODS, __FILE__, __LINE__
|
|
||||||
|
|
||||||
# Appends a message to the log if the log level is at least as high as
|
|
||||||
# the log level of the logger.
|
|
||||||
#
|
|
||||||
# ==== Parameters
|
|
||||||
# message:: The message to be logged. Defaults to nil.
|
|
||||||
#
|
|
||||||
# ==== Returns
|
|
||||||
# self:: The logger object for chaining.
|
|
||||||
def #{name}(message = nil)
|
|
||||||
if #{number} >= level
|
|
||||||
message = block_given? ? yield : message
|
|
||||||
self.push(message, :#{name}) if #{number} >= level
|
|
||||||
end
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
# Appends a message to the log if the log level is at least as high as
|
|
||||||
# the log level of the logger. The bang! version of the method also auto
|
|
||||||
# flushes the log buffer to disk.
|
|
||||||
#
|
|
||||||
# ==== Parameters
|
|
||||||
# message:: The message to be logged. Defaults to nil.
|
|
||||||
#
|
|
||||||
# ==== Returns
|
|
||||||
# self:: The logger object for chaining.
|
|
||||||
def #{name}!(message = nil)
|
|
||||||
if #{number} >= level
|
|
||||||
message = block_given? ? yield : message
|
|
||||||
self.push(message, :#{name}) if #{number} >= level
|
|
||||||
flush if #{number} >= level
|
|
||||||
end
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
# ==== Returns
|
|
||||||
# Boolean:: True if this level will be logged by this logger.
|
|
||||||
def #{name}?
|
|
||||||
#{number} >= level
|
|
||||||
end
|
|
||||||
LEVELMETHODS
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Padrino::Loggger::Rack forwards every request to an +app+ given, and
|
|
||||||
# logs a line in the Apache common log format to the +logger+, or
|
|
||||||
# rack.errors by default.
|
|
||||||
#
|
|
||||||
class Rack
|
|
||||||
##
|
|
||||||
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
|
||||||
# "lilith.local - - GET / HTTP/1.1 500 -"
|
|
||||||
# %{%s - %s %s %s%s %s - %d %s %0.4f}
|
|
||||||
#
|
|
||||||
FORMAT = %{%s (%0.4fms) %s - %s %s%s%s %s - %d %s}
|
|
||||||
|
|
||||||
def initialize(app, uri_root)
|
|
||||||
@app = app
|
|
||||||
@uri_root = uri_root.sub(/\/$/,"")
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
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)
|
|
||||||
[status, header, body]
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def log(env, status, header, began_at)
|
|
||||||
now = Time.now
|
|
||||||
length = extract_content_length(header)
|
|
||||||
|
|
||||||
return if env['sinatra.static_file'] and !logger.log_static
|
|
||||||
|
|
||||||
logger.debug FORMAT % [
|
|
||||||
env["REQUEST_METHOD"],
|
|
||||||
now - began_at,
|
|
||||||
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
|
||||||
env["REMOTE_USER"] || "-",
|
|
||||||
@uri_root || "",
|
|
||||||
env["PATH_INFO"],
|
|
||||||
env["QUERY_STRING"].empty? ? "" : "?" + env["QUERY_STRING"],
|
|
||||||
env["HTTP_VERSION"],
|
|
||||||
status.to_s[0..3],
|
|
||||||
length]
|
|
||||||
end
|
|
||||||
|
|
||||||
def extract_content_length(headers)
|
|
||||||
headers.each do |key, value|
|
|
||||||
if key.downcase == 'content-length'
|
|
||||||
return value.to_s == '0' ? '-' : value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
'-'
|
|
||||||
end
|
|
||||||
end # Rack
|
|
||||||
end # Logger
|
|
||||||
end # Padrino
|
|
||||||
|
|
||||||
module Kernel #:nodoc:
|
|
||||||
##
|
|
||||||
# Define a logger available every where in our app
|
|
||||||
#
|
|
||||||
def logger
|
|
||||||
Padrino.logger
|
|
||||||
end
|
|
||||||
end # Kernel
|
|
|
@ -1,192 +0,0 @@
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# Represents a particular mounted padrino application
|
|
||||||
# Stores the name of the application (app folder name) and url mount path
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# Mounter.new("blog_app", :app_class => "Blog").to("/blog")
|
|
||||||
# Mounter.new("blog_app", :app_file => "/path/to/blog/app.rb").to("/blog")
|
|
||||||
#
|
|
||||||
class Mounter
|
|
||||||
class MounterException < RuntimeError #:nodoc:
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :name, :uri_root, :app_file, :app_class, :app_root, :app_obj, :app_host
|
|
||||||
|
|
||||||
def initialize(name, options={})
|
|
||||||
@name = name.to_s
|
|
||||||
@app_class = options[:app_class] || @name.camelize
|
|
||||||
@app_file = options[:app_file] || locate_app_file
|
|
||||||
@app_obj = options[:app_obj] || app_constant || locate_app_object
|
|
||||||
ensure_app_file! || ensure_app_object!
|
|
||||||
@app_root = options[:app_root] || File.dirname(@app_file)
|
|
||||||
@uri_root = "/"
|
|
||||||
Padrino::Reloader.exclude_constants << @app_class
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Registers the mounted application onto Padrino
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# Mounter.new("blog_app").to("/blog")
|
|
||||||
#
|
|
||||||
def to(mount_url)
|
|
||||||
@uri_root = mount_url
|
|
||||||
Padrino.insert_mounted_app(self)
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Registers the mounted application onto Padrino for the given host
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# Mounter.new("blog_app").to("/blog").host("blog.padrino.org")
|
|
||||||
# Mounter.new("blog_app").host("blog.padrino.org")
|
|
||||||
# Mounter.new("catch_all").host(/.*\.padrino.org/)
|
|
||||||
#
|
|
||||||
def host(mount_host)
|
|
||||||
@app_host = mount_host
|
|
||||||
Padrino.insert_mounted_app(self)
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Maps Padrino application onto a Padrino::Router
|
|
||||||
# For use in constructing a Rack application
|
|
||||||
#
|
|
||||||
# @app.map_onto(router)
|
|
||||||
#
|
|
||||||
def map_onto(router)
|
|
||||||
app_data, app_obj = self, @app_obj
|
|
||||||
app_obj.set :uri_root, app_data.uri_root
|
|
||||||
app_obj.set :app_name, app_data.name
|
|
||||||
app_obj.set :app_file, app_data.app_file unless ::File.exist?(app_obj.app_file)
|
|
||||||
app_obj.set :root, app_data.app_root unless app_data.app_root.blank?
|
|
||||||
app_obj.set :public, Padrino.root('public', app_data.uri_root) unless File.exists?(app_obj.public)
|
|
||||||
app_obj.set :static, File.exist?(app_obj.public) if app_obj.nil?
|
|
||||||
app_obj.setup_application! # We need to initialize here the app.
|
|
||||||
router.map(:to => app_obj, :path => app_data.uri_root, :host => app_data.app_host)
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Returns the route objects for the mounted application
|
|
||||||
#
|
|
||||||
def routes
|
|
||||||
app_obj.routes
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Returns the basic route information for each named route
|
|
||||||
#
|
|
||||||
#
|
|
||||||
def named_routes
|
|
||||||
app_obj.routes.map { |route|
|
|
||||||
name_array = "(#{route.named.to_s.split("_").map { |piece| %Q[:#{piece}] }.join(", ")})"
|
|
||||||
request_method = route.conditions[:request_method][0]
|
|
||||||
full_path = File.join(uri_root, route.original_path)
|
|
||||||
next if route.named.blank? || request_method == 'HEAD'
|
|
||||||
OpenStruct.new(:verb => request_method, :identifier => route.named, :name => name_array, :path => full_path)
|
|
||||||
}.compact
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Makes two Mounters equal if they have the same name and uri_root
|
|
||||||
#
|
|
||||||
def ==(other)
|
|
||||||
other.is_a?(Mounter) && self.app_class == other.app_class && self.uri_root == other.uri_root
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the class object for the app if defined, nil otherwise
|
|
||||||
#
|
|
||||||
def app_constant
|
|
||||||
klass = Object
|
|
||||||
for piece in app_class.split("::")
|
|
||||||
piece = piece.to_sym
|
|
||||||
if klass.const_defined?(piece)
|
|
||||||
klass = klass.const_get(piece)
|
|
||||||
else
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
klass
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
##
|
|
||||||
# Locates and requires the file to load the app constant
|
|
||||||
#
|
|
||||||
def locate_app_object
|
|
||||||
@_app_object ||= begin
|
|
||||||
ensure_app_file!
|
|
||||||
Padrino.require_dependencies(app_file)
|
|
||||||
app_constant
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the determined location of the mounted application main file
|
|
||||||
#
|
|
||||||
def locate_app_file
|
|
||||||
candidates = []
|
|
||||||
candidates << app_constant.app_file if app_constant.respond_to?(:app_file) && File.exist?(app_constant.app_file.to_s)
|
|
||||||
candidates << Padrino.first_caller if File.identical?(Padrino.first_caller.to_s, Padrino.called_from.to_s)
|
|
||||||
candidates << Padrino.mounted_root(name.downcase, "app.rb")
|
|
||||||
candidates << Padrino.root("app", "app.rb")
|
|
||||||
candidates.find { |candidate| File.exist?(candidate) }
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Raises an exception unless app_file is located properly
|
|
||||||
#
|
|
||||||
def ensure_app_file!
|
|
||||||
message = "Unable to locate source file for app '#{app_class}', try with :app_file => '/path/app.rb'"
|
|
||||||
raise MounterException, message unless @app_file
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Raises an exception unless app_obj is defined properly
|
|
||||||
#
|
|
||||||
def ensure_app_object!
|
|
||||||
message = "Unable to locate app for '#{app_class}', try with :app_class => 'MyAppClass'"
|
|
||||||
raise MounterException, message unless @app_obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class << self
|
|
||||||
attr_writer :mounted_root # Set root directory where padrino searches mounted apps
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the root to the mounted apps base directory
|
|
||||||
#
|
|
||||||
def mounted_root(*args)
|
|
||||||
Padrino.root(@mounted_root ||= "", *args)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the mounted padrino applications (MountedApp objects)
|
|
||||||
#
|
|
||||||
def mounted_apps
|
|
||||||
@mounted_apps ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Inserts a Mounter object into the mounted applications (avoids duplicates)
|
|
||||||
#
|
|
||||||
def insert_mounted_app(mounter)
|
|
||||||
Padrino.mounted_apps.push(mounter) unless Padrino.mounted_apps.include?(mounter)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Mounts a new sub-application onto Padrino project
|
|
||||||
#
|
|
||||||
# Padrino.mount("blog_app").to("/blog")
|
|
||||||
#
|
|
||||||
def mount(name, options={})
|
|
||||||
Mounter.new(name, options)
|
|
||||||
end
|
|
||||||
end # Mounter
|
|
||||||
end # Padrino
|
|
|
@ -1,247 +0,0 @@
|
||||||
require 'pathname'
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# High performance source code reloader middleware
|
|
||||||
#
|
|
||||||
module Reloader
|
|
||||||
##
|
|
||||||
# This reloader is suited for use in a many environments because each file
|
|
||||||
# will only be checked once and only one system call to stat(2) is made.
|
|
||||||
#
|
|
||||||
# Please note that this will not reload files in the background, and does so
|
|
||||||
# only when explicitly invoked.
|
|
||||||
#
|
|
||||||
MTIMES = {}
|
|
||||||
LOADED_FILES = {}
|
|
||||||
LOADED_CLASSES = {}
|
|
||||||
|
|
||||||
class << self
|
|
||||||
##
|
|
||||||
# Specified folders can be excluded from the code reload detection process.
|
|
||||||
# Default excluded directories at Padrino.root are: test, spec, features, tmp, config, db and public
|
|
||||||
#
|
|
||||||
def exclude
|
|
||||||
@_exclude ||= %w(test spec tmp features config public db).map { |path| Padrino.root(path) }
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Specified constants can be excluded from the code unloading process.
|
|
||||||
#
|
|
||||||
def exclude_constants
|
|
||||||
@_exclude_constants ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Specified constants can be configured to be reloaded on every request.
|
|
||||||
# Default included constants are: [none]
|
|
||||||
#
|
|
||||||
def include_constants
|
|
||||||
@_include_constants ||= []
|
|
||||||
end
|
|
||||||
##
|
|
||||||
# Reload all files with changes detected.
|
|
||||||
#
|
|
||||||
def reload!
|
|
||||||
# Detect changed files
|
|
||||||
rotation do |file, mtime|
|
|
||||||
# Retrive the last modified time
|
|
||||||
new_file = MTIMES[file].nil?
|
|
||||||
previous_mtime = MTIMES[file] ||= mtime
|
|
||||||
logger.devel "Detected a new file #{file}" if new_file
|
|
||||||
# We skip to next file if it is not new and not modified
|
|
||||||
next unless new_file || mtime > previous_mtime
|
|
||||||
# Now we can reload our file
|
|
||||||
apps = mounted_apps_of(file)
|
|
||||||
if apps.present?
|
|
||||||
apps.each { |app| app.app_obj.reload! }
|
|
||||||
else
|
|
||||||
safe_load(file, :force => new_file)
|
|
||||||
# Reload also apps
|
|
||||||
Padrino.mounted_apps.each do |app|
|
|
||||||
app.app_obj.reload! if app.app_obj.dependencies.include?(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Remove files and classes loaded with stat
|
|
||||||
#
|
|
||||||
def clear!
|
|
||||||
MTIMES.clear
|
|
||||||
LOADED_CLASSES.each do |file, klasses|
|
|
||||||
klasses.each { |klass| remove_constant(klass) }
|
|
||||||
LOADED_CLASSES.delete(file)
|
|
||||||
end
|
|
||||||
LOADED_FILES.each do |file, dependencies|
|
|
||||||
dependencies.each { |dependency| $LOADED_FEATURES.delete(dependency) }
|
|
||||||
$LOADED_FEATURES.delete(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns true if any file changes are detected and populates the MTIMES cache
|
|
||||||
#
|
|
||||||
def changed?
|
|
||||||
changed = false
|
|
||||||
rotation do |file, mtime|
|
|
||||||
new_file = MTIMES[file].nil?
|
|
||||||
previous_mtime = MTIMES[file] ||= mtime
|
|
||||||
changed = true if new_file || mtime > previous_mtime
|
|
||||||
end
|
|
||||||
changed
|
|
||||||
end
|
|
||||||
alias :run! :changed?
|
|
||||||
|
|
||||||
##
|
|
||||||
# We lock dependencies sets to prevent reloading of protected constants
|
|
||||||
#
|
|
||||||
def lock!
|
|
||||||
klasses = ObjectSpace.classes.map { |klass| klass.to_s.split("::")[0] }.uniq
|
|
||||||
klasses = klasses | Padrino.mounted_apps.map { |app| app.app_class }
|
|
||||||
Padrino::Reloader.exclude_constants.concat(klasses)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# A safe Kernel::require which issues the necessary hooks depending on results
|
|
||||||
#
|
|
||||||
def safe_load(file, options={})
|
|
||||||
force, file = options[:force], figure_path(file)
|
|
||||||
|
|
||||||
# Check if file was changed or if force a reload
|
|
||||||
reload = MTIMES[file] && File.mtime(file) > MTIMES[file]
|
|
||||||
return if !force && !reload && MTIMES[file]
|
|
||||||
|
|
||||||
# Removes all classes declared in the specified file
|
|
||||||
if klasses = LOADED_CLASSES.delete(file)
|
|
||||||
klasses.each { |klass| remove_constant(klass) }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Remove all loaded fatures with our file
|
|
||||||
if features = LOADED_FILES[file]
|
|
||||||
features.each { |feature| $LOADED_FEATURES.delete(feature) }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Duplicate objects and loaded features before load file
|
|
||||||
klasses = ObjectSpace.classes.dup
|
|
||||||
files = $LOADED_FEATURES.dup
|
|
||||||
|
|
||||||
# Now we can reload dependencies of our file
|
|
||||||
if features = LOADED_FILES.delete(file)
|
|
||||||
features.each { |feature| safe_load(feature, :force => true) }
|
|
||||||
end
|
|
||||||
|
|
||||||
# And finally load the specified file
|
|
||||||
begin
|
|
||||||
logger.devel "Loading #{file}" if !reload
|
|
||||||
logger.debug "Reloading #{file}" if reload
|
|
||||||
$LOADED_FEATURES.delete(file)
|
|
||||||
verbosity_was, $-v = $-v, nil
|
|
||||||
loaded = false
|
|
||||||
require(file)
|
|
||||||
loaded = true
|
|
||||||
MTIMES[file] = File.mtime(file)
|
|
||||||
rescue SyntaxError => e
|
|
||||||
logger.error "Cannot require #{file} because of syntax error: #{e.message}"
|
|
||||||
ensure
|
|
||||||
$-v = verbosity_was
|
|
||||||
new_constants = (ObjectSpace.classes - klasses).uniq
|
|
||||||
if loaded
|
|
||||||
# Store the file details
|
|
||||||
LOADED_CLASSES[file] = new_constants
|
|
||||||
LOADED_FILES[file] = ($LOADED_FEATURES - files - [file]).uniq
|
|
||||||
# Track only features in our Padrino.root
|
|
||||||
LOADED_FILES[file].delete_if { |feature| !in_root?(feature) }
|
|
||||||
else
|
|
||||||
logger.devel "Failed to load #{file}; removing partially defined constants"
|
|
||||||
new_constants.each { |klass| remove_constant(klass) }
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns true if the file is defined in our padrino root
|
|
||||||
#
|
|
||||||
def figure_path(file)
|
|
||||||
return file if Pathname.new(file).absolute?
|
|
||||||
$:.each do |path|
|
|
||||||
found = File.join(path, file)
|
|
||||||
return File.expand_path(found) if File.exist?(found)
|
|
||||||
end
|
|
||||||
file
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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)}}) }
|
|
||||||
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}"
|
|
||||||
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
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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
|
|
||||||
end # self
|
|
||||||
|
|
||||||
##
|
|
||||||
# This class acts as a Rack middleware to be added to the application stack. This middleware performs a
|
|
||||||
# check and reload for source files at the start of each request, but also respects a specified cool down time
|
|
||||||
# during which no further action will be taken.
|
|
||||||
#
|
|
||||||
class Rack
|
|
||||||
def initialize(app, cooldown=1)
|
|
||||||
@app = app
|
|
||||||
@cooldown = cooldown
|
|
||||||
@last = (Time.now - cooldown)
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
if @cooldown && Time.now > @last + @cooldown
|
|
||||||
Thread.list.size > 1 ? Thread.exclusive { Padrino.reload! } : Padrino.reload!
|
|
||||||
@last = Time.now
|
|
||||||
end
|
|
||||||
@app.call(env)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end # Reloader
|
|
||||||
end # Padrino
|
|
|
@ -1,79 +0,0 @@
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# This class is an extended version of Rack::URLMap
|
|
||||||
#
|
|
||||||
# Padrino::Router like Rack::URLMap dispatches in such a way that the
|
|
||||||
# longest paths are tried first, since they are most specific.
|
|
||||||
#
|
|
||||||
# Features:
|
|
||||||
#
|
|
||||||
# * Map a path to the specified App
|
|
||||||
# * Ignore server names (this solve issues with vhost and domain aliases)
|
|
||||||
# * Use hosts instead of server name for mappings (this help us with our vhost and doman aliases)
|
|
||||||
#
|
|
||||||
# ==== Options
|
|
||||||
#
|
|
||||||
# :to:: The class of application that you want mount
|
|
||||||
# :path:: Map the app to the given path
|
|
||||||
# :host:: Map the app to the given host
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# routes = Padrino::Router.new do
|
|
||||||
# map(:path => "/", :to => PadrinoWeb, :host => "padrino.local")
|
|
||||||
# map(:path => "/", :to => Admin, :host => "admin.padrino.local")
|
|
||||||
# end
|
|
||||||
# run routes
|
|
||||||
#
|
|
||||||
# routes = Padrino::Router.new do
|
|
||||||
# map(:path => "/", :to => PadrinoWeb, :host => /*.padrino.local/)
|
|
||||||
# end
|
|
||||||
# run routes
|
|
||||||
#
|
|
||||||
class Router
|
|
||||||
def initialize(*mapping, &block)
|
|
||||||
@mapping = []
|
|
||||||
mapping.each { |m| map(m) }
|
|
||||||
instance_eval(&block) if block
|
|
||||||
end
|
|
||||||
|
|
||||||
def sort!
|
|
||||||
@mapping = @mapping.sort_by { |h, p, m, a| -p.size }
|
|
||||||
end
|
|
||||||
|
|
||||||
def map(options={})
|
|
||||||
path = options[:path] || "/"
|
|
||||||
host = options[:host]
|
|
||||||
app = options[:to]
|
|
||||||
|
|
||||||
raise ArgumentError, "paths need to start with /" if path[0] != ?/
|
|
||||||
raise ArgumentError, "app is required" if app.nil?
|
|
||||||
|
|
||||||
path = path.chomp('/')
|
|
||||||
match = Regexp.new("^#{Regexp.quote(path).gsub('/', '/+')}(.*)", nil, 'n')
|
|
||||||
host = Regexp.new("^#{Regexp.quote(host)}$", true, 'n') unless host.nil? || host.is_a?(Regexp)
|
|
||||||
|
|
||||||
@mapping << [host, path, match, app]
|
|
||||||
sort!
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
rPath = env["PATH_INFO"].to_s
|
|
||||||
script_name = env['SCRIPT_NAME']
|
|
||||||
hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
|
|
||||||
@mapping.each do |host, path, match, app|
|
|
||||||
next unless host.nil? || hHost =~ host
|
|
||||||
next unless rPath =~ match && rest = $1
|
|
||||||
next unless rest.empty? || rest[0] == ?/
|
|
||||||
|
|
||||||
rest = "/" if rest.empty?
|
|
||||||
|
|
||||||
return app.call(
|
|
||||||
env.merge(
|
|
||||||
'SCRIPT_NAME' => (script_name + path),
|
|
||||||
'PATH_INFO' => rest))
|
|
||||||
end
|
|
||||||
[404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{rPath}"]]
|
|
||||||
end
|
|
||||||
end # Router
|
|
||||||
end # Padrino
|
|
|
@ -1,70 +0,0 @@
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# Run the Padrino apps as a self-hosted server using:
|
|
||||||
# thin, mongrel, webrick in that order.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# Padrino.run! # with these defaults => host: "localhost", port: "3000", adapter: the first found
|
|
||||||
# Padrino.run!("localhost", "4000", "mongrel") # use => host: "0.0.0.0", port: "3000", adapter: "mongrel"
|
|
||||||
#
|
|
||||||
def self.run!(options={})
|
|
||||||
Padrino.load!
|
|
||||||
Server.start(Padrino.application, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# This module build a Padrino server
|
|
||||||
#
|
|
||||||
class Server < Rack::Server
|
|
||||||
# Server Handlers
|
|
||||||
Handlers = [:thin, :mongrel, :webrick]
|
|
||||||
|
|
||||||
def self.start(app, opts={})
|
|
||||||
options = {}.merge(opts) # We use a standard hash instead of Thor::CoreExt::HashWithIndifferentAccess
|
|
||||||
options.symbolize_keys!
|
|
||||||
options[:Host] = options.delete(:host) || '0.0.0.0'
|
|
||||||
options[:Port] = options.delete(:port) || 3000
|
|
||||||
options[:AccessLog] = []
|
|
||||||
if options[:daemonize]
|
|
||||||
options[:pid] = options[:pid].blank? ? File.expand_path('tmp/pids/server.pid') : opts[:pid]
|
|
||||||
FileUtils.mkdir_p(File.dirname(options[:pid]))
|
|
||||||
end
|
|
||||||
options[:server] = detect_rack_handler if options[:server].blank?
|
|
||||||
new(options, app).start
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(options, app)
|
|
||||||
@options, @app = options, app
|
|
||||||
end
|
|
||||||
|
|
||||||
def start
|
|
||||||
puts "=> Padrino/#{Padrino.version} has taken the stage #{Padrino.env} at http://#{options[:Host]}:#{options[:Port]}"
|
|
||||||
[:INT, :TERM].each { |sig| trap(sig) { exit } }
|
|
||||||
super
|
|
||||||
ensure
|
|
||||||
puts "<= Padrino has ended his set (crowd applauds)" unless options[:daemonize]
|
|
||||||
end
|
|
||||||
|
|
||||||
def app
|
|
||||||
@app
|
|
||||||
end
|
|
||||||
alias :wrapped_app :app
|
|
||||||
|
|
||||||
def options
|
|
||||||
@options
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def self.detect_rack_handler
|
|
||||||
Handlers.each do |handler|
|
|
||||||
begin
|
|
||||||
return handler if Rack::Handler.get(handler.to_s.downcase)
|
|
||||||
rescue LoadError
|
|
||||||
rescue NameError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
fail "Server handler (#{Handlers.join(', ')}) not found."
|
|
||||||
end
|
|
||||||
end # Server
|
|
||||||
end # Padrino
|
|
|
@ -1,135 +0,0 @@
|
||||||
##
|
|
||||||
# This file loads certain extensions required by Padrino from ActiveSupport.
|
|
||||||
#
|
|
||||||
require 'active_support/core_ext/kernel' # silence_warnings
|
|
||||||
require 'active_support/core_ext/module/aliasing' # alias_method_chain
|
|
||||||
require 'active_support/core_ext/class/attribute_accessors' # cattr_reader
|
|
||||||
require 'active_support/core_ext/hash/keys' # symbolize_keys
|
|
||||||
require 'active_support/core_ext/hash/reverse_merge' # reverse_merge
|
|
||||||
require 'active_support/core_ext/hash/slice' # slice
|
|
||||||
require 'active_support/core_ext/object/blank' # present?
|
|
||||||
require 'active_support/core_ext/array/extract_options' # extract_options
|
|
||||||
require 'active_support/inflector/methods' # constantize
|
|
||||||
require 'active_support/inflector/inflections' # pluralize
|
|
||||||
require 'active_support/inflections' # load default inflections
|
|
||||||
|
|
||||||
##
|
|
||||||
# This is a small version of active_support/core_ext/string/inflections.rb
|
|
||||||
# to prevent to load a lot of dependencies including I18n gem
|
|
||||||
#
|
|
||||||
# Issue: https://github.com/rails/rails/issues/1526
|
|
||||||
#
|
|
||||||
class String
|
|
||||||
# Returns the plural form of the word in the string.
|
|
||||||
#
|
|
||||||
# "post".pluralize # => "posts"
|
|
||||||
# "octopus".pluralize # => "octopi"
|
|
||||||
# "sheep".pluralize # => "sheep"
|
|
||||||
# "words".pluralize # => "words"
|
|
||||||
# "the blue mailman".pluralize # => "the blue mailmen"
|
|
||||||
# "CamelOctopus".pluralize # => "CamelOctopi"
|
|
||||||
def pluralize
|
|
||||||
ActiveSupport::Inflector.pluralize(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
# +constantize+ tries to find a declared constant with the name specified
|
|
||||||
# in the string. It raises a NameError when the name is not in CamelCase
|
|
||||||
# or is not initialized.
|
|
||||||
#
|
|
||||||
# Examples
|
|
||||||
# "Module".constantize # => Module
|
|
||||||
# "Class".constantize # => Class
|
|
||||||
def constantize
|
|
||||||
ActiveSupport::Inflector.constantize(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
|
|
||||||
# is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
|
|
||||||
#
|
|
||||||
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
|
|
||||||
#
|
|
||||||
# "active_record".camelize # => "ActiveRecord"
|
|
||||||
# "active_record".camelize(:lower) # => "activeRecord"
|
|
||||||
# "active_record/errors".camelize # => "ActiveRecord::Errors"
|
|
||||||
# "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
|
|
||||||
def camelize(first_letter = :upper)
|
|
||||||
case first_letter
|
|
||||||
when :upper then ActiveSupport::Inflector.camelize(self, true)
|
|
||||||
when :lower then ActiveSupport::Inflector.camelize(self, false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
alias_method :camelcase, :camelize
|
|
||||||
|
|
||||||
# The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
|
|
||||||
#
|
|
||||||
# +underscore+ will also change '::' to '/' to convert namespaces to paths.
|
|
||||||
#
|
|
||||||
# "ActiveRecord".underscore # => "active_record"
|
|
||||||
# "ActiveRecord::Errors".underscore # => active_record/errors
|
|
||||||
def underscore
|
|
||||||
ActiveSupport::Inflector.underscore(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Create a class name from a plural table name like Rails does for table names to models.
|
|
||||||
# Note that this returns a string and not a class. (To convert to an actual class
|
|
||||||
# follow +classify+ with +constantize+.)
|
|
||||||
#
|
|
||||||
# "egg_and_hams".classify # => "EggAndHam"
|
|
||||||
# "posts".classify # => "Post"
|
|
||||||
#
|
|
||||||
# Singular names are not handled correctly.
|
|
||||||
#
|
|
||||||
# "business".classify # => "Busines"
|
|
||||||
def classify
|
|
||||||
ActiveSupport::Inflector.classify(self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module ObjectSpace
|
|
||||||
class << self
|
|
||||||
# Returns all the classes in the object space.
|
|
||||||
def classes
|
|
||||||
ObjectSpace.each_object(Module).select do |klass|
|
|
||||||
Class.class_eval { klass } rescue false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# FileSet helper method for iterating and interacting with files inside a directory
|
|
||||||
#
|
|
||||||
class FileSet
|
|
||||||
# Iterates over every file in the glob pattern and yields to a block
|
|
||||||
# Returns the list of files matching the glob pattern
|
|
||||||
# FileSet.glob('padrino-core/application/*.rb', __FILE__) { |file| load file }
|
|
||||||
def self.glob(glob_pattern, file_path=nil, &block)
|
|
||||||
glob_pattern = File.join(File.dirname(file_path), glob_pattern) if file_path
|
|
||||||
file_list = Dir.glob(glob_pattern).sort
|
|
||||||
file_list.each { |file| block.call(file) }
|
|
||||||
file_list
|
|
||||||
end
|
|
||||||
|
|
||||||
# Requires each file matched in the glob pattern into the application
|
|
||||||
# FileSet.glob_require('padrino-core/application/*.rb', __FILE__)
|
|
||||||
def self.glob_require(glob_pattern, file_path=nil)
|
|
||||||
self.glob(glob_pattern, file_path) { |f| require f }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# YAML Engine Parsing Fix
|
|
||||||
# https://github.com/padrino/padrino-framework/issues/424
|
|
||||||
#
|
|
||||||
require 'yaml' unless defined?(YAML)
|
|
||||||
YAML::ENGINE.yamler = "syck" if defined?(YAML::ENGINE)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Loads our locale configuration files
|
|
||||||
#
|
|
||||||
I18n.load_path += Dir["#{File.dirname(__FILE__)}/locale/*.yml"] if defined?(I18n)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Used to know if this file has already been required
|
|
||||||
#
|
|
||||||
module SupportLite; end
|
|
|
@ -1,23 +0,0 @@
|
||||||
module Padrino
|
|
||||||
|
|
||||||
##
|
|
||||||
# This module it's used for bootstrap with padrino rake
|
|
||||||
# thirdy party tasks, in your gem/plugin/extension you
|
|
||||||
# need only do this:
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# Padrino::Tasks.files << yourtask.rb
|
|
||||||
# Padrino::Tasks.files.concat(Dir["/path/to/all/my/tasks/*.rb"])
|
|
||||||
# Padrino::Tasks.files.unshift("yourtask.rb")
|
|
||||||
#
|
|
||||||
module Tasks
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns a list of files to handle with padrino rake
|
|
||||||
#
|
|
||||||
def self.files
|
|
||||||
@files ||= []
|
|
||||||
end
|
|
||||||
end # Tasks
|
|
||||||
end # Padrino
|
|
|
@ -1,15 +0,0 @@
|
||||||
##
|
|
||||||
# Manages current Padrino version for use in gem generation.
|
|
||||||
#
|
|
||||||
# We put this in a separate file so you can get padrino version
|
|
||||||
# without include full padrino core.
|
|
||||||
#
|
|
||||||
module Padrino
|
|
||||||
VERSION = '0.10.0' unless defined?(Padrino::VERSION)
|
|
||||||
##
|
|
||||||
# Return the current Padrino version
|
|
||||||
#
|
|
||||||
def self.version
|
|
||||||
VERSION
|
|
||||||
end
|
|
||||||
end # Padrino
|
|
|
@ -1,38 +0,0 @@
|
||||||
#!/usr/bin/env gem build
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
require File.expand_path("../lib/padrino-core/version.rb", __FILE__)
|
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
|
||||||
s.name = "padrino-core"
|
|
||||||
s.rubyforge_project = "padrino-core"
|
|
||||||
s.authors = ["Padrino Team", "Nathan Esquenazi", "Davide D'Agostino", "Arthur Chiu"]
|
|
||||||
s.email = "padrinorb@gmail.com"
|
|
||||||
s.summary = "The required Padrino core gem"
|
|
||||||
s.homepage = "http://www.padrinorb.com"
|
|
||||||
s.description = "The Padrino core gem required for use of this framework"
|
|
||||||
s.required_rubygems_version = ">= 1.3.6"
|
|
||||||
s.version = Padrino.version
|
|
||||||
s.date = Time.now.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
s.extra_rdoc_files = Dir["*.rdoc"]
|
|
||||||
s.files = `git ls-files`.split("\n")
|
|
||||||
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
||||||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
||||||
s.require_paths = ["lib"]
|
|
||||||
s.rdoc_options = ["--charset=UTF-8"]
|
|
||||||
|
|
||||||
# TODO remove after a couple versions
|
|
||||||
s.post_install_message = "\e[32m" + ("*" * 20)
|
|
||||||
s.post_install_message << "\n UPGRADE NOTES\n\n\e[31m When upgrading, please 'enable :sessions' for each application"
|
|
||||||
s.post_install_message << " as shown here:\e[0m http://bit.ly/kODKMx\n"
|
|
||||||
s.post_install_message << "\e[31m When upgrading, please 'register Padrino::Rendering' for each application"
|
|
||||||
s.post_install_message << " as shown here:\e[0m https://gist.github.com/1d36a35794dbbd664ea4"
|
|
||||||
s.post_install_message << "\n\e[32m" + ("*" * 20) + "\n\e[0m"
|
|
||||||
|
|
||||||
s.add_dependency("tilt", "~> 1.3.0")
|
|
||||||
s.add_dependency("sinatra", "~> 1.2.6")
|
|
||||||
s.add_dependency("http_router", "~> 0.8.10")
|
|
||||||
s.add_dependency("thor", "~> 0.14.3")
|
|
||||||
s.add_dependency("activesupport", "~> 3.0.0")
|
|
||||||
end
|
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
:test: bacon
|
|
||||||
:mock: mocha
|
|
||||||
:orm: datamapper
|
|
||||||
:renderer: erb
|
|
||||||
:script: jquery
|
|
|
@ -1,7 +0,0 @@
|
||||||
.DS_Store
|
|
||||||
log/**/*
|
|
||||||
tmp/**/*
|
|
||||||
vendor/gems/gems
|
|
||||||
vendor/gems/specifications
|
|
||||||
vendor/gems/doc
|
|
||||||
vendor/gems/environment.rb
|
|
|
@ -1,27 +0,0 @@
|
||||||
PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
|
|
||||||
|
|
||||||
module LibDemo
|
|
||||||
def self.give_me_a_random
|
|
||||||
@rand ||= rand(100)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Complex1Demo < Padrino::Application
|
|
||||||
set :reload, true
|
|
||||||
get("/old"){ "Old Sinatra Way" }
|
|
||||||
end
|
|
||||||
|
|
||||||
class Complex2Demo < Padrino::Application
|
|
||||||
set :reload, true
|
|
||||||
get("/old"){ "Old Sinatra Way" }
|
|
||||||
get("/"){ "The magick number is: 12!" } # Change only the number!!!
|
|
||||||
end
|
|
||||||
|
|
||||||
Complex1Demo.controllers do
|
|
||||||
get("/"){ "Given random #{LibDemo.give_me_a_random}" }
|
|
||||||
end
|
|
||||||
|
|
||||||
Complex2Demo.controllers do
|
|
||||||
end
|
|
||||||
|
|
||||||
Padrino.load!
|
|
|
@ -1,33 +0,0 @@
|
||||||
PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
|
|
||||||
# Remove this comment if you want do some like this: ruby PADRINO_ENV=test app.rb
|
|
||||||
#
|
|
||||||
# require 'rubygems'
|
|
||||||
# require 'padrino-core'
|
|
||||||
#
|
|
||||||
|
|
||||||
class SimpleDemo < Padrino::Application
|
|
||||||
set :reload, true
|
|
||||||
before { true }
|
|
||||||
after { true }
|
|
||||||
error(404) { "404" }
|
|
||||||
end
|
|
||||||
|
|
||||||
SimpleDemo.controllers do
|
|
||||||
get "/" do
|
|
||||||
'The magick number is: 72!' # Change only the number!!!
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/rand" do
|
|
||||||
rand(2 ** 256).to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
## If you want use this as a standalone app uncomment:
|
|
||||||
#
|
|
||||||
# Padrino.mount("SimpleDemo").to("/")
|
|
||||||
# Padrino.run! unless Padrino.loaded? # If you enable reloader prevent to re-run the app
|
|
||||||
#
|
|
||||||
# Then run it from your console: ruby -I"lib" test/fixtures/apps/simple.rb
|
|
||||||
#
|
|
||||||
|
|
||||||
Padrino.load!
|
|
|
@ -1,9 +0,0 @@
|
||||||
# This file will be safe loaded three times.
|
|
||||||
# The first one fail because B and C constant are not defined
|
|
||||||
# The second one file because B requires C constant so will not be loaded
|
|
||||||
# The third one B and C are defined
|
|
||||||
|
|
||||||
# But here we need some of b.rb
|
|
||||||
A_result = [B, C]
|
|
||||||
|
|
||||||
A = "A"
|
|
|
@ -1,4 +0,0 @@
|
||||||
# But here we need some of c.rb and a.rb
|
|
||||||
B_result = C
|
|
||||||
|
|
||||||
B = "B"
|
|
|
@ -1 +0,0 @@
|
||||||
C = "C"
|
|
|
@ -1,13 +0,0 @@
|
||||||
class E
|
|
||||||
def self.fields
|
|
||||||
@fields ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.inherited(subclass)
|
|
||||||
subclass.fields.replace fields.dup
|
|
||||||
end
|
|
||||||
|
|
||||||
G
|
|
||||||
|
|
||||||
fields << "name"
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
class F < E
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
class G
|
|
||||||
end
|
|
|
@ -1,4 +0,0 @@
|
||||||
D = 0 unless defined?(D)
|
|
||||||
D += 1
|
|
||||||
|
|
||||||
raise "SomeThing"
|
|
|
@ -1,101 +0,0 @@
|
||||||
ENV['PADRINO_ENV'] = 'test'
|
|
||||||
PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
|
|
||||||
|
|
||||||
require File.expand_path('../../../load_paths', __FILE__)
|
|
||||||
require 'padrino-core'
|
|
||||||
require 'test/unit'
|
|
||||||
require 'rack/test'
|
|
||||||
require 'rack'
|
|
||||||
require 'shoulda'
|
|
||||||
require 'phocus'
|
|
||||||
|
|
||||||
# Rubies < 1.9 don't handle hashes in the properly order so to prevent
|
|
||||||
# this issue for now we remove extra values from mimetypes.
|
|
||||||
Rack::Mime::MIME_TYPES.delete(".xsl") # In this way application/xml respond only to .xml
|
|
||||||
|
|
||||||
module Kernel
|
|
||||||
# Silences the output by redirecting to stringIO
|
|
||||||
# silence_logger { ...commands... } => "...output..."
|
|
||||||
def silence_logger(&block)
|
|
||||||
$stdout = log_buffer = StringIO.new
|
|
||||||
block.call
|
|
||||||
$stdout = STDOUT
|
|
||||||
log_buffer.string
|
|
||||||
end
|
|
||||||
alias :silence_stdout :silence_logger
|
|
||||||
|
|
||||||
def silence_warnings
|
|
||||||
old_verbose, $VERBOSE = $VERBOSE, nil
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
$VERBOSE = old_verbose
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Class
|
|
||||||
# Allow assertions in request context
|
|
||||||
include Test::Unit::Assertions
|
|
||||||
end
|
|
||||||
|
|
||||||
class Test::Unit::TestCase
|
|
||||||
include Rack::Test::Methods
|
|
||||||
|
|
||||||
# Sets up a Sinatra::Base subclass defined with the block
|
|
||||||
# given. Used in setup or individual spec methods to establish
|
|
||||||
# the application.
|
|
||||||
def mock_app(base=Padrino::Application, &block)
|
|
||||||
@app = Sinatra.new(base, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def app
|
|
||||||
Rack::Lint.new(@app)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Asserts that a file matches the pattern
|
|
||||||
def assert_match_in_file(pattern, file)
|
|
||||||
assert File.exist?(file), "File '#{file}' does not exist!"
|
|
||||||
assert_match pattern, File.read(file)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Delegate other missing methods to response.
|
|
||||||
def method_missing(name, *args, &block)
|
|
||||||
if response && response.respond_to?(name)
|
|
||||||
response.send(name, *args, &block)
|
|
||||||
else
|
|
||||||
super(name, *args, &block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
alias :response :last_response
|
|
||||||
|
|
||||||
def create_template(name, content, options={})
|
|
||||||
FileUtils.mkdir_p(File.dirname(__FILE__) + "/views")
|
|
||||||
FileUtils.mkdir_p(File.dirname(__FILE__) + "/views/layouts")
|
|
||||||
path = "/views/#{name}"
|
|
||||||
path += ".#{options.delete(:locale)}" if options[:locale].present?
|
|
||||||
path += ".#{options[:format]}" if options[:format].present?
|
|
||||||
path += ".erb" unless options[:format].to_s =~ /haml|rss|atom/
|
|
||||||
path += ".builder" if options[:format].to_s =~ /rss|atom/
|
|
||||||
file = File.dirname(__FILE__) + path
|
|
||||||
File.open(file, 'w') { |io| io.write content }
|
|
||||||
file
|
|
||||||
end
|
|
||||||
alias :create_view :create_template
|
|
||||||
alias :create_layout :create_template
|
|
||||||
|
|
||||||
def remove_views
|
|
||||||
FileUtils.rm_rf(File.dirname(__FILE__) + "/views")
|
|
||||||
end
|
|
||||||
|
|
||||||
def with_template(name, content, options={})
|
|
||||||
# Build a temp layout
|
|
||||||
template = create_template(name, content, options)
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
# Remove temp layout
|
|
||||||
File.unlink(template) rescue nil
|
|
||||||
remove_views
|
|
||||||
end
|
|
||||||
alias :with_view :with_template
|
|
||||||
alias :with_layout :with_template
|
|
||||||
end
|
|
|
@ -1,83 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
|
|
||||||
class PadrinoTestApp < Padrino::Application; end
|
|
||||||
class PadrinoTestApp2 < Padrino::Application; end
|
|
||||||
|
|
||||||
class TestApplication < Test::Unit::TestCase
|
|
||||||
def setup
|
|
||||||
Padrino.clear!
|
|
||||||
end
|
|
||||||
|
|
||||||
def teardown
|
|
||||||
remove_views
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for application functionality' do
|
|
||||||
|
|
||||||
should 'check default options' do
|
|
||||||
assert File.identical?(__FILE__, PadrinoTestApp.app_file)
|
|
||||||
assert_equal :padrino_test_app, PadrinoTestApp.app_name
|
|
||||||
assert_equal :test, PadrinoTestApp.environment
|
|
||||||
assert_equal Padrino.root("views"), PadrinoTestApp.views
|
|
||||||
assert PadrinoTestApp.raise_errors
|
|
||||||
assert !PadrinoTestApp.logging
|
|
||||||
assert !PadrinoTestApp.sessions
|
|
||||||
assert !PadrinoTestApp.dump_errors
|
|
||||||
assert !PadrinoTestApp.show_exceptions
|
|
||||||
assert PadrinoTestApp.raise_errors
|
|
||||||
assert !Padrino.configure_apps
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'check padrino specific options' do
|
|
||||||
assert !PadrinoTestApp.instance_variable_get(:@_configured)
|
|
||||||
PadrinoTestApp.send(:setup_application!)
|
|
||||||
assert_equal :padrino_test_app, PadrinoTestApp.app_name
|
|
||||||
assert_equal 'StandardFormBuilder', PadrinoTestApp.default_builder
|
|
||||||
assert PadrinoTestApp.instance_variable_get(:@_configured)
|
|
||||||
assert !PadrinoTestApp.reload?
|
|
||||||
assert !PadrinoTestApp.flash
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'set global project settings' do
|
|
||||||
Padrino.configure_apps { enable :sessions; set :foo, "bar" }
|
|
||||||
PadrinoTestApp.send(:default_configuration!)
|
|
||||||
PadrinoTestApp2.send(:default_configuration!)
|
|
||||||
assert PadrinoTestApp.sessions, "should have sessions enabled"
|
|
||||||
assert_equal "bar", PadrinoTestApp.settings.foo, "should have foo assigned"
|
|
||||||
assert_equal PadrinoTestApp.session_secret, PadrinoTestApp2.session_secret
|
|
||||||
end
|
|
||||||
|
|
||||||
should "have shared sessions accessible in project" do
|
|
||||||
Padrino.configure_apps { enable :sessions; set :session_secret, 'secret' }
|
|
||||||
Padrino.mount("PadrinoTestApp").to("/write")
|
|
||||||
Padrino.mount("PadrinoTestApp2").to("/read")
|
|
||||||
PadrinoTestApp.tap { |app| app.send(:default_configuration!)
|
|
||||||
app.get("/") { session[:foo] = "shared" } }
|
|
||||||
PadrinoTestApp2.tap { |app| app.send(:default_configuration!)
|
|
||||||
app.get("/") { session[:foo] } }
|
|
||||||
browser = Rack::Test::Session.new(Rack::MockSession.new(Padrino.application))
|
|
||||||
browser.get '/write'
|
|
||||||
browser.get '/read'
|
|
||||||
assert_equal 'shared', browser.last_response.body
|
|
||||||
end
|
|
||||||
|
|
||||||
# compare to: test_routing: allow global provides
|
|
||||||
should "set content_type to :html if none can be determined" do
|
|
||||||
mock_app do
|
|
||||||
provides :xml
|
|
||||||
|
|
||||||
get("/foo"){ "Foo in #{content_type}" }
|
|
||||||
get("/bar"){ "Foo in #{content_type}" }
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
|
||||||
assert_equal 'Foo in xml', body
|
|
||||||
get '/foo'
|
|
||||||
assert_equal 'Foo in xml', body
|
|
||||||
|
|
||||||
get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
|
||||||
assert_equal "Foo in html", body
|
|
||||||
end # content_type to :html
|
|
||||||
end # application functionality
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,79 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
|
|
||||||
class TestCore < Test::Unit::TestCase
|
|
||||||
def setup
|
|
||||||
Padrino.clear!
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for core functionality' do
|
|
||||||
|
|
||||||
should 'check some global methods' do
|
|
||||||
assert_respond_to Padrino, :root
|
|
||||||
assert_respond_to Padrino, :env
|
|
||||||
assert_respond_to Padrino, :application
|
|
||||||
assert_respond_to Padrino, :set_encoding
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
should 'set correct utf-8 encoding' do
|
|
||||||
Padrino.set_encoding
|
|
||||||
if RUBY_VERSION <'1.9'
|
|
||||||
assert_equal 'UTF8', $KCODE
|
|
||||||
else
|
|
||||||
assert_equal Encoding.default_external, Encoding::UTF_8
|
|
||||||
assert_equal Encoding.default_internal, nil # Encoding::UTF_8
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'have load paths' do
|
|
||||||
assert_equal [Padrino.root('lib'), Padrino.root('models'), Padrino.root('shared')], Padrino.load_paths
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'raise application error if I instantiate a new padrino application without mounted apps' do
|
|
||||||
assert_raise(Padrino::ApplicationLoadError) { Padrino.application.new }
|
|
||||||
end
|
|
||||||
|
|
||||||
should "check before/after padrino load hooks" do
|
|
||||||
Padrino.before_load { @_foo = 1 }
|
|
||||||
Padrino.after_load { @_foo += 1 }
|
|
||||||
Padrino.load!
|
|
||||||
assert_equal 1, Padrino.before_load.size
|
|
||||||
assert_equal 1, Padrino.after_load.size
|
|
||||||
assert_equal 2, @_foo
|
|
||||||
end
|
|
||||||
|
|
||||||
should "add middlewares in front if specified" do
|
|
||||||
test = Class.new {
|
|
||||||
def initialize(app)
|
|
||||||
@app = app
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
status, headers, body = @app.call(env)
|
|
||||||
headers["Middleware-Called"] = "yes"
|
|
||||||
return status, headers, body
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
class Foo < Padrino::Application; end
|
|
||||||
|
|
||||||
Padrino.use(test)
|
|
||||||
Padrino.mount(Foo).to("/")
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/")
|
|
||||||
assert_equal "yes", res["Middleware-Called"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,44 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
|
|
||||||
class TestDependencies < Test::Unit::TestCase
|
|
||||||
context 'when we require a dependency that have another dependency' do
|
|
||||||
|
|
||||||
should 'raise an error without reloading it twice' do
|
|
||||||
silence_warnings do
|
|
||||||
assert_raise(RuntimeError) do
|
|
||||||
Padrino.require_dependencies(
|
|
||||||
Padrino.root("fixtures/dependencies/a.rb"),
|
|
||||||
Padrino.root("fixtures/dependencies/b.rb"),
|
|
||||||
Padrino.root("fixtures/dependencies/c.rb"),
|
|
||||||
Padrino.root("fixtures/dependencies/d.rb")
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert_equal 1, D
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve dependency problems' do
|
|
||||||
silence_warnings do
|
|
||||||
Padrino.require_dependencies(
|
|
||||||
Padrino.root("fixtures/dependencies/a.rb"),
|
|
||||||
Padrino.root("fixtures/dependencies/b.rb"),
|
|
||||||
Padrino.root("fixtures/dependencies/c.rb")
|
|
||||||
)
|
|
||||||
end
|
|
||||||
assert_equal ["B", "C"], A_result
|
|
||||||
assert_equal "C", B_result
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'remove partially loaded constants' do
|
|
||||||
silence_warnings do
|
|
||||||
Padrino.require_dependencies(
|
|
||||||
Padrino.root("fixtures/dependencies/circular/e.rb"),
|
|
||||||
Padrino.root("fixtures/dependencies/circular/f.rb"),
|
|
||||||
Padrino.root("fixtures/dependencies/circular/g.rb")
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal ["name"], F.fields
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,266 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
|
|
||||||
class TestFilters < Test::Unit::TestCase
|
|
||||||
should "filters by accept header" do
|
|
||||||
mock_app do
|
|
||||||
get '/foo', :provides => [:xml, :js] do
|
|
||||||
request.env['HTTP_ACCEPT']
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
|
||||||
assert ok?
|
|
||||||
assert_equal 'application/xml', body
|
|
||||||
assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
|
|
||||||
|
|
||||||
get '/foo.xml'
|
|
||||||
assert ok?
|
|
||||||
assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
|
|
||||||
|
|
||||||
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
|
|
||||||
assert ok?
|
|
||||||
assert_equal 'application/javascript', body
|
|
||||||
assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
|
|
||||||
|
|
||||||
get '/foo.js'
|
|
||||||
assert ok?
|
|
||||||
assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
|
|
||||||
|
|
||||||
get '/foo', {}, { "HTTP_ACCEPT" => 'text/html' }
|
|
||||||
assert_equal 406, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should "allow passing & halting in before filters" do
|
|
||||||
mock_app do
|
|
||||||
controller do
|
|
||||||
before { env['QUERY_STRING'] == 'secret' or pass }
|
|
||||||
get :index do
|
|
||||||
"secret index"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
controller do
|
|
||||||
before { env['QUERY_STRING'] == 'halt' and halt 401, 'go away!' }
|
|
||||||
get :index do
|
|
||||||
"index"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/?secret"
|
|
||||||
assert_equal "secret index", body
|
|
||||||
|
|
||||||
get "/?halt"
|
|
||||||
assert_equal "go away!", body
|
|
||||||
assert_equal 401, status
|
|
||||||
|
|
||||||
get "/"
|
|
||||||
assert_equal "index", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'scope filters in the given controller' do
|
|
||||||
mock_app do
|
|
||||||
before { @global = 'global' }
|
|
||||||
after { @global = nil }
|
|
||||||
|
|
||||||
controller :foo do
|
|
||||||
before { @foo = :foo }
|
|
||||||
after { @foo = nil }
|
|
||||||
get("/") { [@foo, @bar, @global].compact.join(" ") }
|
|
||||||
end
|
|
||||||
|
|
||||||
get("/") { [@foo, @bar, @global].compact.join(" ") }
|
|
||||||
|
|
||||||
controller :bar do
|
|
||||||
before { @bar = :bar }
|
|
||||||
after { @bar = nil }
|
|
||||||
get("/") { [@foo, @bar, @global].compact.join(" ") }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "bar global", body
|
|
||||||
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "foo global", body
|
|
||||||
|
|
||||||
get "/"
|
|
||||||
assert_equal "global", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'be able to access params in a before filter' do
|
|
||||||
username_from_before_filter = nil
|
|
||||||
|
|
||||||
mock_app do
|
|
||||||
before do
|
|
||||||
username_from_before_filter = params[:username]
|
|
||||||
end
|
|
||||||
|
|
||||||
get :users, :with => :username do
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/users/josh'
|
|
||||||
assert_equal 'josh', username_from_before_filter
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to access params normally when a before filter is specified" do
|
|
||||||
mock_app do
|
|
||||||
before { }
|
|
||||||
get :index do
|
|
||||||
params.inspect
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/?test=what'
|
|
||||||
assert_equal '{"test"=>"what"}', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter based on a path" do
|
|
||||||
mock_app do
|
|
||||||
before('/') { @test = "#{@test}before"}
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :main do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/'
|
|
||||||
assert_equal 'before', body
|
|
||||||
get '/main'
|
|
||||||
assert_equal '', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter based on a symbol" do
|
|
||||||
mock_app do
|
|
||||||
before(:index) { @test = 'before'}
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :main do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/'
|
|
||||||
assert_equal 'before', body
|
|
||||||
get '/main'
|
|
||||||
assert_equal '', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter based on a symbol for a controller" do
|
|
||||||
mock_app do
|
|
||||||
controller :foo do
|
|
||||||
before(:test) { @test = 'foo'}
|
|
||||||
get :test do
|
|
||||||
@test.to_s + " response"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
controller :bar do
|
|
||||||
before(:test) { @test = 'bar'}
|
|
||||||
get :test do
|
|
||||||
@test.to_s + " response"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/foo/test'
|
|
||||||
assert_equal 'foo response', body
|
|
||||||
get '/bar/test'
|
|
||||||
assert_equal 'bar response', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter based on a symbol or path" do
|
|
||||||
mock_app do
|
|
||||||
before(:index, '/main') { @test = 'before'}
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :main do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/'
|
|
||||||
assert_equal 'before', body
|
|
||||||
get '/main'
|
|
||||||
assert_equal 'before', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter based on a symbol or regexp" do
|
|
||||||
mock_app do
|
|
||||||
before(:index, /main/) { @test = 'before'}
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :main do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :profile do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/'
|
|
||||||
assert_equal 'before', body
|
|
||||||
get '/main'
|
|
||||||
assert_equal 'before', body
|
|
||||||
get '/profile'
|
|
||||||
assert_equal '', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter excluding based on a symbol" do
|
|
||||||
mock_app do
|
|
||||||
before(:except => :index) { @test = 'before'}
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :main do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/'
|
|
||||||
assert_equal '', body
|
|
||||||
get '/main'
|
|
||||||
assert_equal 'before', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter based on a request param" do
|
|
||||||
mock_app do
|
|
||||||
before(:agent => /IE/) { @test = 'before'}
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/'
|
|
||||||
assert_equal '', body
|
|
||||||
get "/", {}, {'HTTP_USER_AGENT' => 'This is IE'}
|
|
||||||
assert_equal 'before', body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to filter based on a symbol or path in multiple controller" do
|
|
||||||
mock_app do
|
|
||||||
controllers :foo do
|
|
||||||
before(:index, '/foo/main') { @test = 'before' }
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :main do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
controllers :bar do
|
|
||||||
before(:index, '/bar/main') { @test = 'also before' }
|
|
||||||
get :index do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
get :main do
|
|
||||||
@test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/foo'
|
|
||||||
assert_equal 'before', body
|
|
||||||
get '/bar'
|
|
||||||
assert_equal 'also before', body
|
|
||||||
get '/foo/main'
|
|
||||||
assert_equal 'before', body
|
|
||||||
get '/bar/main'
|
|
||||||
assert_equal 'also before', body
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,91 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
|
|
||||||
class TestPadrinoLogger < Test::Unit::TestCase
|
|
||||||
|
|
||||||
def setup
|
|
||||||
Padrino::Logger::Config[:test][:stream] = :null # The default
|
|
||||||
Padrino::Logger.setup!
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup_logger(options={})
|
|
||||||
@log = StringIO.new
|
|
||||||
@logger = Padrino::Logger.new(options.merge(:stream => @log))
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for logger functionality' do
|
|
||||||
|
|
||||||
context 'check stream config' do
|
|
||||||
|
|
||||||
should 'use stdout if stream is nil' do
|
|
||||||
Padrino::Logger::Config[:test][:stream] = nil
|
|
||||||
Padrino::Logger.setup!
|
|
||||||
assert_equal $stdout, Padrino.logger.log
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'use StringIO as default for test' do
|
|
||||||
assert_instance_of StringIO, Padrino.logger.log
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'use a custom stream' do
|
|
||||||
my_stream = StringIO.new
|
|
||||||
Padrino::Logger::Config[:test][:stream] = my_stream
|
|
||||||
Padrino::Logger.setup!
|
|
||||||
assert_equal my_stream, Padrino.logger.log
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'log something' do
|
|
||||||
setup_logger(:log_level => :error)
|
|
||||||
@logger.error "You log this error?"
|
|
||||||
assert_match(/You log this error?/, @log.string)
|
|
||||||
@logger.debug "You don't log this error!"
|
|
||||||
assert_no_match(/You don't log this error!/, @log.string)
|
|
||||||
@logger << "Yep this can be logged"
|
|
||||||
assert_match(/Yep this can be logged/, @log.string)
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'respond to #write for Rack::CommonLogger' do
|
|
||||||
setup_logger(:log_level => :error)
|
|
||||||
@logger.error "Error message"
|
|
||||||
assert_match /Error message/, @log.string
|
|
||||||
@logger << "logged anyways"
|
|
||||||
assert_match /logged anyways/, @log.string
|
|
||||||
@logger.write "log via alias"
|
|
||||||
assert_match /log via alias/, @log.string
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'log an application' do
|
|
||||||
mock_app do
|
|
||||||
enable :logging
|
|
||||||
get("/"){ "Foo" }
|
|
||||||
end
|
|
||||||
get "/"
|
|
||||||
assert_equal "Foo", body
|
|
||||||
assert_match /GET/, Padrino.logger.log.string
|
|
||||||
end
|
|
||||||
|
|
||||||
context "static asset logging" do
|
|
||||||
should 'not log static assets by default' do
|
|
||||||
mock_app do
|
|
||||||
enable :logging
|
|
||||||
get("/images/something.png"){ env["sinatra.static_file"] = '/public/images/something.png'; "Foo" }
|
|
||||||
end
|
|
||||||
get "/images/something.png"
|
|
||||||
assert_equal "Foo", body
|
|
||||||
assert_match "", Padrino.logger.log.string
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'allow turning on static assets logging' do
|
|
||||||
Padrino.logger.instance_eval{ @log_static = true }
|
|
||||||
mock_app do
|
|
||||||
enable :logging
|
|
||||||
get("/images/something.png"){ env["sinatra.static_file"] = '/public/images/something.png'; "Foo" }
|
|
||||||
end
|
|
||||||
get "/images/something.png"
|
|
||||||
assert_equal "Foo", body
|
|
||||||
assert_match /GET/, Padrino.logger.log.string
|
|
||||||
Padrino.logger.instance_eval{ @log_static = false }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,176 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
|
|
||||||
class TestMounter < Test::Unit::TestCase
|
|
||||||
|
|
||||||
def setup
|
|
||||||
$VERBOSE, @_verbose_was = nil, $VERBOSE
|
|
||||||
Padrino.clear!
|
|
||||||
end
|
|
||||||
|
|
||||||
def teardown
|
|
||||||
$VERBOSE = @_verbose_was
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for mounter functionality' do
|
|
||||||
|
|
||||||
should 'check methods' do
|
|
||||||
mounter = Padrino::Mounter.new("test", :app_file => "/path/to/test.rb")
|
|
||||||
mounter.to("/test")
|
|
||||||
assert_kind_of Padrino::Mounter, mounter
|
|
||||||
assert_respond_to Padrino::Mounter, :new
|
|
||||||
assert_respond_to mounter, :to
|
|
||||||
assert_respond_to mounter, :map_onto
|
|
||||||
assert_equal "test", mounter.name
|
|
||||||
assert_equal "Test", mounter.app_class
|
|
||||||
assert_equal "/path/to/test.rb", mounter.app_file
|
|
||||||
assert_equal "/test", mounter.uri_root
|
|
||||||
assert_equal File.dirname(mounter.app_file), mounter.app_root
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'check locate_app_file with __FILE__' do
|
|
||||||
mounter = Padrino::Mounter.new("test", :app_file => __FILE__)
|
|
||||||
mounter.to("/test")
|
|
||||||
assert_equal "test", mounter.name
|
|
||||||
assert_equal "Test", mounter.app_class
|
|
||||||
assert_equal __FILE__, mounter.app_file
|
|
||||||
assert_equal "/test", mounter.uri_root
|
|
||||||
assert_equal File.dirname(mounter.app_file), mounter.app_root
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'mount an app' do
|
|
||||||
class ::AnApp < Padrino::Application; end
|
|
||||||
Padrino.mount("an_app").to("/")
|
|
||||||
assert_equal AnApp, Padrino.mounted_apps.first.app_obj
|
|
||||||
assert_equal ["an_app"], Padrino.mounted_apps.map(&:name)
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'correctly mount an app in a namespace' do
|
|
||||||
module ::SomeNamespace
|
|
||||||
class AnApp < Padrino::Application; end
|
|
||||||
end
|
|
||||||
Padrino.mount("some_namespace/an_app").to("/")
|
|
||||||
assert_equal SomeNamespace::AnApp, Padrino.mounted_apps.first.app_obj
|
|
||||||
assert_equal ["some_namespace/an_app"], Padrino.mounted_apps.map(&:name)
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'mount a primary app to root uri' do
|
|
||||||
mounter = Padrino.mount("test", :app_file => __FILE__).to("/")
|
|
||||||
assert_equal "test", mounter.name
|
|
||||||
assert_equal "Test", mounter.app_class
|
|
||||||
assert_equal Test, mounter.app_obj
|
|
||||||
assert_equal __FILE__, mounter.app_file
|
|
||||||
assert_equal "/", mounter.uri_root
|
|
||||||
assert_equal File.dirname(mounter.app_file), mounter.app_root
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'mount a primary app to sub_uri' do
|
|
||||||
mounter = Padrino.mount("test", :app_file => __FILE__).to('/me')
|
|
||||||
assert_equal "test", mounter.name
|
|
||||||
assert_equal "Test", mounter.app_class
|
|
||||||
assert_equal Test, mounter.app_obj
|
|
||||||
assert_equal __FILE__, mounter.app_file
|
|
||||||
assert_equal "/me", mounter.uri_root
|
|
||||||
assert_equal File.dirname(mounter.app_file), mounter.app_root
|
|
||||||
end
|
|
||||||
|
|
||||||
should "raise error when app has no located file" do
|
|
||||||
assert_raise(Padrino::Mounter::MounterException) { Padrino.mount("tester_app").to('/test') }
|
|
||||||
assert_equal 0, Padrino.mounted_apps.size
|
|
||||||
end
|
|
||||||
|
|
||||||
should "raise error when app has no located object" do
|
|
||||||
assert_raise(Padrino::Mounter::MounterException) { Padrino.mount("tester_app", :app_file => "/path/to/file.rb").to('/test') }
|
|
||||||
assert_equal 0, Padrino.mounted_apps.size
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'mount multiple apps' do
|
|
||||||
class ::OneApp < Padrino::Application; end
|
|
||||||
class ::TwoApp < Padrino::Application; end
|
|
||||||
|
|
||||||
Padrino.mount("one_app").to("/one_app")
|
|
||||||
Padrino.mount("two_app").to("/two_app")
|
|
||||||
# And testing no duplicates
|
|
||||||
Padrino.mount("one_app").to("/one_app")
|
|
||||||
Padrino.mount("two_app").to("/two_app")
|
|
||||||
|
|
||||||
assert_equal OneApp, Padrino.mounted_apps[0].app_obj
|
|
||||||
assert_equal TwoApp, Padrino.mounted_apps[1].app_obj
|
|
||||||
assert_equal 2, Padrino.mounted_apps.size, "should not mount duplicate apps"
|
|
||||||
assert_equal ["one_app", "two_app"], Padrino.mounted_apps.map(&:name)
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'change mounted_root' do
|
|
||||||
Padrino.mounted_root = "fixtures"
|
|
||||||
assert_equal Padrino.root("fixtures", "test", "app.rb"), Padrino.mounted_root("test", "app.rb")
|
|
||||||
Padrino.mounted_root = "apps"
|
|
||||||
assert_equal Padrino.root("apps", "test", "app.rb"), Padrino.mounted_root("test", "app.rb")
|
|
||||||
Padrino.mounted_root = nil
|
|
||||||
assert_equal Padrino.root("test", "app.rb"), Padrino.mounted_root("test", "app.rb")
|
|
||||||
end
|
|
||||||
|
|
||||||
should "be able to access routes data for mounted apps" do
|
|
||||||
class ::OneApp < Padrino::Application
|
|
||||||
get("/test") { "test" }
|
|
||||||
get(:index, :provides => [:js, :json]) { "index" }
|
|
||||||
controllers :posts do
|
|
||||||
get(:index) { "index" }
|
|
||||||
get(:new, :provides => :js) { "new" }
|
|
||||||
get(:show, :provides => [:js, :html], :with => :id) { "show" }
|
|
||||||
post(:create, :provides => :js, :with => :id) { "create" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class ::TwoApp < Padrino::Application
|
|
||||||
controllers :users do
|
|
||||||
get(:index) { "users" }
|
|
||||||
get(:new) { "users new" }
|
|
||||||
post(:create) { "users create" }
|
|
||||||
put(:update) { "users update" }
|
|
||||||
delete(:destroy) { "users delete" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Padrino.mount("one_app").to("/")
|
|
||||||
Padrino.mount("two_app").to("/two_app")
|
|
||||||
|
|
||||||
assert_equal 11, Padrino.mounted_apps[0].routes.size
|
|
||||||
assert_equal 7, Padrino.mounted_apps[1].routes.size
|
|
||||||
assert_equal 5, Padrino.mounted_apps[0].named_routes.size
|
|
||||||
assert_equal 5, Padrino.mounted_apps[1].named_routes.size
|
|
||||||
|
|
||||||
first_route = Padrino.mounted_apps[0].named_routes[3]
|
|
||||||
assert_equal "posts_show", first_route.identifier.to_s
|
|
||||||
assert_equal "(:posts, :show)", first_route.name
|
|
||||||
assert_equal "GET", first_route.verb
|
|
||||||
assert_equal "/posts/show/:id(.:format)", first_route.path
|
|
||||||
another_route = Padrino.mounted_apps[1].named_routes[2]
|
|
||||||
assert_equal "users_create", another_route.identifier.to_s
|
|
||||||
assert_equal "(:users, :create)", another_route.name
|
|
||||||
assert_equal "POST", another_route.verb
|
|
||||||
assert_equal "/two_app/users/create", another_route.path
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'correctly instantiate a new padrino application' do
|
|
||||||
mock_app do
|
|
||||||
get("/demo_1"){ "Im Demo 1" }
|
|
||||||
get("/demo_2"){ "Im Demo 2" }
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/demo_1'
|
|
||||||
assert_equal "Im Demo 1", body
|
|
||||||
get '/demo_2'
|
|
||||||
assert_equal "Im Demo 2", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "not clobber the public setting when mounting an app" do
|
|
||||||
class ::PublicApp < Padrino::Application
|
|
||||||
set :root, "/root"
|
|
||||||
set :public, File.expand_path(File.dirname(__FILE__))
|
|
||||||
end
|
|
||||||
|
|
||||||
Padrino.mount("public_app").to("/public")
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/public/test_mounter.rb")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal File.read(__FILE__), res.body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,66 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/complex')
|
|
||||||
|
|
||||||
class TestComplexReloader < Test::Unit::TestCase
|
|
||||||
|
|
||||||
context 'for complex reload functionality' do
|
|
||||||
|
|
||||||
should 'correctly instantiate Complex(1-2)Demo fixture' do
|
|
||||||
Padrino.clear!
|
|
||||||
Padrino.mount("complex_1_demo").to("/complex_1_demo")
|
|
||||||
Padrino.mount("complex_2_demo").to("/complex_2_demo")
|
|
||||||
assert_equal ["/complex_1_demo", "/complex_2_demo"], Padrino.mounted_apps.map(&:uri_root)
|
|
||||||
assert_equal ["complex_1_demo", "complex_2_demo"], Padrino.mounted_apps.map(&:name)
|
|
||||||
assert Complex1Demo.reload?
|
|
||||||
assert Complex2Demo.reload?
|
|
||||||
assert_match %r{fixtures/apps/complex.rb}, Complex1Demo.app_file
|
|
||||||
assert_match %r{fixtures/apps/complex.rb}, Complex2Demo.app_file
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'correctly reload Complex(1-2)Demo fixture' do
|
|
||||||
assert_match %r{fixtures/apps/complex.rb}, Complex1Demo.app_file
|
|
||||||
@app = Padrino.application
|
|
||||||
|
|
||||||
get "/"
|
|
||||||
assert_equal 404, status
|
|
||||||
|
|
||||||
get "/complex_1_demo"
|
|
||||||
assert_equal "Given random #{LibDemo.give_me_a_random}", body
|
|
||||||
|
|
||||||
get "/complex_2_demo"
|
|
||||||
assert_equal 200, status
|
|
||||||
|
|
||||||
get "/complex_1_demo/old"
|
|
||||||
assert_equal 200, status
|
|
||||||
|
|
||||||
get "/complex_2_demo/old"
|
|
||||||
assert_equal 200, status
|
|
||||||
|
|
||||||
new_phrase = "The magick number is: #{rand(2**255)}!"
|
|
||||||
buffer = File.read(Complex1Demo.app_file)
|
|
||||||
new_buffer = buffer.gsub(/The magick number is: \d+!/, new_phrase)
|
|
||||||
begin
|
|
||||||
File.open(Complex1Demo.app_file, "w") { |f| f.write(new_buffer) }
|
|
||||||
sleep 1.2 # We need at least a cooldown of 1 sec.
|
|
||||||
get "/complex_2_demo"
|
|
||||||
assert_equal new_phrase, body
|
|
||||||
|
|
||||||
# Re-Check that we didn't forget any route
|
|
||||||
get "/complex_1_demo"
|
|
||||||
assert_equal "Given random #{LibDemo.give_me_a_random}", body
|
|
||||||
|
|
||||||
get "/complex_2_demo"
|
|
||||||
assert_equal 200, status
|
|
||||||
|
|
||||||
get "/complex_1_demo/old"
|
|
||||||
assert_equal 200, status
|
|
||||||
|
|
||||||
get "/complex_2_demo/old"
|
|
||||||
assert_equal 200, status
|
|
||||||
ensure
|
|
||||||
# Now we need to prevent to commit a new changed file so we revert it
|
|
||||||
File.open(Complex1Demo.app_file, "w") { |f| f.write(buffer) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,97 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/simple')
|
|
||||||
|
|
||||||
class TestSimpleReloader < Test::Unit::TestCase
|
|
||||||
|
|
||||||
context 'for simple reset functionality' do
|
|
||||||
|
|
||||||
should 'reset routes' do
|
|
||||||
mock_app do
|
|
||||||
(1..10).each do |i|
|
|
||||||
get("/#{i}") { "Foo #{i}" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
(1..10).each do |i|
|
|
||||||
get "/#{i}"
|
|
||||||
assert_equal "Foo #{i}", body
|
|
||||||
end
|
|
||||||
@app.reset_routes!
|
|
||||||
(1..10).each do |i|
|
|
||||||
get "/#{i}"
|
|
||||||
assert_equal 404, status
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'keep sinatra routes on development' do
|
|
||||||
mock_app do
|
|
||||||
set :environment, :development
|
|
||||||
get("/"){ "ok" }
|
|
||||||
end
|
|
||||||
assert_equal :development, @app.environment
|
|
||||||
get "/"
|
|
||||||
assert_equal 200, status
|
|
||||||
get "/__sinatra__/404.png"
|
|
||||||
assert_equal 200, status
|
|
||||||
assert_match /image\/png/, response["Content-Type"]
|
|
||||||
@app.reset_routes!
|
|
||||||
get "/"
|
|
||||||
assert_equal 404, status
|
|
||||||
get "/__sinatra__/404.png"
|
|
||||||
assert_equal 200, status
|
|
||||||
assert_match /image\/png/, response["Content-Type"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for simple reload functionality' do
|
|
||||||
|
|
||||||
should 'correctly instantiate SimpleDemo fixture' do
|
|
||||||
Padrino.clear!
|
|
||||||
Padrino.mount("simple_demo").to("/")
|
|
||||||
assert_equal ["simple_demo"], Padrino.mounted_apps.map(&:name)
|
|
||||||
assert SimpleDemo.reload?
|
|
||||||
assert_match %r{fixtures/apps/simple.rb}, SimpleDemo.app_file
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'correctly reload SimpleDemo fixture' do
|
|
||||||
@app = SimpleDemo
|
|
||||||
get "/"
|
|
||||||
assert ok?
|
|
||||||
new_phrase = "The magick number is: #{rand(2**255)}!"
|
|
||||||
buffer = File.read(SimpleDemo.app_file)
|
|
||||||
new_buffer = buffer.gsub(/The magick number is: \d+!/, new_phrase)
|
|
||||||
File.open(SimpleDemo.app_file, "w") { |f| f.write(new_buffer) }
|
|
||||||
sleep 1.2 # We need at least a cooldown of 1 sec.
|
|
||||||
get "/"
|
|
||||||
assert_equal new_phrase, body
|
|
||||||
|
|
||||||
# Now we need to prevent to commit a new changed file so we revert it
|
|
||||||
File.open(SimpleDemo.app_file, "w") { |f| f.write(buffer) }
|
|
||||||
Padrino.reload!
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'correctly reset SimpleDemo fixture' do
|
|
||||||
@app = SimpleDemo
|
|
||||||
@app.reload!
|
|
||||||
get "/rand"
|
|
||||||
assert ok?
|
|
||||||
last_body = body
|
|
||||||
assert_equal 2, @app.filters[:before].size # one is ours the other is default_filter for content type
|
|
||||||
assert_equal 1, @app.errors.size
|
|
||||||
assert_equal 1, @app.filters[:after].size
|
|
||||||
assert_equal 1, @app.middleware.size # [Padrino::Reloader::Rack]
|
|
||||||
assert_equal 4, @app.routes.size # GET+HEAD of "/" + GET+HEAD of "/rand" = 4
|
|
||||||
assert_equal 2, @app.extensions.size # [Padrino::Routing, Padrino::Rendering]
|
|
||||||
assert_equal 0, @app.templates.size
|
|
||||||
@app.reload!
|
|
||||||
get "/rand"
|
|
||||||
assert_not_equal last_body, body
|
|
||||||
assert_equal 2, @app.filters[:before].size # one is ours the other is default_filter for content type
|
|
||||||
assert_equal 1, @app.errors.size
|
|
||||||
assert_equal 1, @app.filters[:after].size
|
|
||||||
assert_equal 1, @app.middleware.size
|
|
||||||
assert_equal 4, @app.routes.size # GET+HEAD of "/" = 2
|
|
||||||
assert_equal 2, @app.extensions.size # [Padrino::Routing, Padrino::Rendering]
|
|
||||||
assert_equal 0, @app.templates.size
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,437 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
require 'i18n'
|
|
||||||
|
|
||||||
class TestRendering < Test::Unit::TestCase
|
|
||||||
def setup
|
|
||||||
Padrino::Application.send(:register, Padrino::Rendering)
|
|
||||||
end
|
|
||||||
|
|
||||||
def teardown
|
|
||||||
remove_views
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for application layout functionality' do
|
|
||||||
|
|
||||||
should 'get no layout' do
|
|
||||||
mock_app do
|
|
||||||
get("/"){ "no layout" }
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/"
|
|
||||||
assert_equal "no layout", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'be compatible with sinatra layout' do
|
|
||||||
mock_app do
|
|
||||||
layout do
|
|
||||||
"this is a <%= yield %>"
|
|
||||||
end
|
|
||||||
|
|
||||||
get("/"){ render :erb, "sinatra layout" }
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/"
|
|
||||||
assert_equal "this is a sinatra layout", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'use rails way layout' do
|
|
||||||
with_layout :application, "this is a <%= yield %>" do
|
|
||||||
mock_app do
|
|
||||||
get("/"){ render :erb, "rails way layout" }
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/"
|
|
||||||
assert_equal "this is a rails way layout", body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'use rails way for a custom layout' do
|
|
||||||
with_layout "layouts/custom", "this is a <%= yield %>" do
|
|
||||||
mock_app do
|
|
||||||
layout :custom
|
|
||||||
get("/"){ render :erb, "rails way custom layout" }
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/"
|
|
||||||
assert_equal "this is a rails way custom layout", body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'not use layout' do
|
|
||||||
with_layout :application, "this is a <%= yield %>" do
|
|
||||||
with_view :index, "index" do
|
|
||||||
mock_app do
|
|
||||||
get("/with/layout"){ render :index }
|
|
||||||
get("/without/layout"){ render :index, :layout => false }
|
|
||||||
end
|
|
||||||
get "/with/layout"
|
|
||||||
assert_equal "this is a index", body
|
|
||||||
get "/without/layout"
|
|
||||||
assert_equal "index", body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'not use layout with js format' do
|
|
||||||
create_layout :application, "this is an <%= yield %>"
|
|
||||||
create_view :foo, "erb file"
|
|
||||||
create_view :foo, "js file", :format => :js
|
|
||||||
mock_app do
|
|
||||||
get('/layout_test', :provides => [:html, :js]){ render :foo }
|
|
||||||
end
|
|
||||||
get "/layout_test"
|
|
||||||
assert_equal "this is an erb file", body
|
|
||||||
get "/layout_test.js"
|
|
||||||
assert_equal "js file", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'use correct layout for each format' do
|
|
||||||
create_layout :application, "this is an <%= yield %>"
|
|
||||||
create_layout :application, "document start <%= yield %> end", :format => :xml
|
|
||||||
create_view :foo, "erb file"
|
|
||||||
create_view :foo, "xml file", :format => :xml
|
|
||||||
mock_app do
|
|
||||||
get('/layout_test', :provides => [:html, :xml]){ render :foo }
|
|
||||||
end
|
|
||||||
get "/layout_test"
|
|
||||||
assert_equal "this is an erb file", body
|
|
||||||
get "/layout_test.xml"
|
|
||||||
assert_equal "document start xml file end", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'by default use html file when no other is given' do
|
|
||||||
create_layout :foo, "html file", :format => :html
|
|
||||||
|
|
||||||
mock_app do
|
|
||||||
get('/content_type_test', :provides => [:html, :xml]) { render :foo }
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/content_type_test"
|
|
||||||
assert_equal "html file", body
|
|
||||||
get "/content_type_test.xml"
|
|
||||||
assert_equal "html file", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'not use html file when DEFAULT_RENDERING_OPTIONS[:strict_format] == true' do
|
|
||||||
create_layout :foo, "html file", :format => :html
|
|
||||||
|
|
||||||
mock_app do
|
|
||||||
get('/default_rendering_test', :provides => [:html, :xml]) { render :foo }
|
|
||||||
end
|
|
||||||
|
|
||||||
@save = Padrino::Rendering::DEFAULT_RENDERING_OPTIONS
|
|
||||||
Padrino::Rendering::DEFAULT_RENDERING_OPTIONS[:strict_format] = true
|
|
||||||
|
|
||||||
get "/default_rendering_test"
|
|
||||||
assert_equal "html file", body
|
|
||||||
assert_raise Padrino::Rendering::TemplateNotFound do
|
|
||||||
get "/default_rendering_test.xml"
|
|
||||||
end
|
|
||||||
|
|
||||||
Padrino::Rendering::DEFAULT_RENDERING_OPTIONS.merge(@save)
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'use correct layout with each controller' do
|
|
||||||
create_layout :foo, "foo layout at <%= yield %>"
|
|
||||||
create_layout :bar, "bar layout at <%= yield %>"
|
|
||||||
create_layout :application, "default layout at <%= yield %>"
|
|
||||||
mock_app do
|
|
||||||
get("/"){ render :erb, "application" }
|
|
||||||
controller :foo do
|
|
||||||
layout :foo
|
|
||||||
get("/"){ render :erb, "foo" }
|
|
||||||
end
|
|
||||||
controller :bar do
|
|
||||||
layout :bar
|
|
||||||
get("/"){ render :erb, "bar" }
|
|
||||||
end
|
|
||||||
controller :none do
|
|
||||||
get("/") { render :erb, "none" }
|
|
||||||
get("/with_foo_layout") { render :erb, "none with layout", :layout => :foo }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "foo layout at foo", body
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "bar layout at bar", body
|
|
||||||
get "/none"
|
|
||||||
assert_equal "default layout at none", body
|
|
||||||
get "/none/with_foo_layout"
|
|
||||||
assert_equal "foo layout at none with layout", body
|
|
||||||
get "/"
|
|
||||||
assert_equal "default layout at application", body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'solve layout in layouts paths' do
|
|
||||||
create_layout :foo, "foo layout <%= yield %>"
|
|
||||||
create_layout :"layouts/bar", "bar layout <%= yield %>"
|
|
||||||
mock_app do
|
|
||||||
get("/") { render :erb, "none" }
|
|
||||||
get("/foo") { render :erb, "foo", :layout => :foo }
|
|
||||||
get("/bar") { render :erb, "bar", :layout => :bar }
|
|
||||||
end
|
|
||||||
get "/"
|
|
||||||
assert_equal "none", body
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "foo layout foo", body
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "bar layout bar", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'render correctly if layout was not found or not exist' do
|
|
||||||
create_layout :application, "application layout for <%= yield %>"
|
|
||||||
create_view :foo, "index", :format => :html
|
|
||||||
create_view :foo, "xml.rss", :format => :rss
|
|
||||||
mock_app do
|
|
||||||
get("/foo", :provides => [:html, :rss]) { render('foo') }
|
|
||||||
get("/baz", :provides => :js) { render(:erb, 'baz') }
|
|
||||||
get("/bar") { render :haml, "haml" }
|
|
||||||
end
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "application layout for index", body
|
|
||||||
get "/foo.rss"
|
|
||||||
assert_equal "<rss/>", body.chomp
|
|
||||||
get "/baz.js"
|
|
||||||
assert_equal "baz", body
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "haml", body.chomp
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for application render functionality' do
|
|
||||||
|
|
||||||
should 'be compatible with sinatra render' do
|
|
||||||
mock_app do
|
|
||||||
get("/"){ render :erb, "<%= 1+2 %>" }
|
|
||||||
end
|
|
||||||
get "/"
|
|
||||||
assert_equal "3", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "support passing locals into render" do
|
|
||||||
create_layout :application, "layout <%= yield %>"
|
|
||||||
create_view :index, "<%= foo %>"
|
|
||||||
mock_app do
|
|
||||||
get("/") { render "index", { :layout => true }, { :foo => "bar" } }
|
|
||||||
end
|
|
||||||
get "/"
|
|
||||||
assert_equal "layout bar", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "support passing locals into sinatra render" do
|
|
||||||
create_layout :application, "layout <%= yield %>"
|
|
||||||
create_view :index, "<%= foo %>"
|
|
||||||
mock_app do
|
|
||||||
get("/") { render :erb, :index, { :layout => true }, { :foo => "bar" } }
|
|
||||||
end
|
|
||||||
get "/"
|
|
||||||
assert_equal "layout bar", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "support passing locals into special nil engine render" do
|
|
||||||
create_layout :application, "layout <%= yield %>"
|
|
||||||
create_view :index, "<%= foo %>"
|
|
||||||
mock_app do
|
|
||||||
get("/") { render nil, :index, { :layout => true }, { :foo => "bar" } }
|
|
||||||
end
|
|
||||||
get "/"
|
|
||||||
assert_equal "layout bar", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'be compatible with sinatra views' do
|
|
||||||
with_view :index, "<%= 1+2 %>" do
|
|
||||||
mock_app do
|
|
||||||
get("/foo") { render :erb, :index }
|
|
||||||
get("/bar") { erb :index }
|
|
||||||
get("/dir") { "3" }
|
|
||||||
get("/inj") { erb "<%= 2+1 %>" }
|
|
||||||
get("/rnj") { render :erb, "<%= 2+1 %>" }
|
|
||||||
end
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "3", body
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "3", body
|
|
||||||
get "/dir"
|
|
||||||
assert_equal "3", body
|
|
||||||
get "/inj"
|
|
||||||
assert_equal "3", body
|
|
||||||
get "/rnj"
|
|
||||||
assert_equal "3", body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve template engine' do
|
|
||||||
with_view :index, "<%= 1+2 %>" do
|
|
||||||
mock_app do
|
|
||||||
get("/foo") { render :index }
|
|
||||||
get("/bar") { render "/index" }
|
|
||||||
end
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "3", body
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "3", body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve template content type' do
|
|
||||||
create_view :foo, "Im Js", :format => :js
|
|
||||||
create_view :foo, "Im Erb"
|
|
||||||
mock_app do
|
|
||||||
get("/foo", :provides => :js) { render :foo }
|
|
||||||
get("/bar.js") { render :foo }
|
|
||||||
end
|
|
||||||
get "/foo.js"
|
|
||||||
assert_equal "Im Js", body
|
|
||||||
# TODO: implement this!
|
|
||||||
# get "/bar.js"
|
|
||||||
# assert_equal "Im Js", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve with explicit template format' do
|
|
||||||
create_view :foo, "Im Js", :format => :js
|
|
||||||
create_view :foo, "Im Haml", :format => :haml
|
|
||||||
create_view :foo, "Im Xml", :format => :xml
|
|
||||||
mock_app do
|
|
||||||
get("/foo_normal", :provides => :js) { render 'foo' }
|
|
||||||
get("/foo_haml", :provides => :js) { render 'foo.haml' }
|
|
||||||
get("/foo_xml", :provides => :js) { render 'foo.xml' }
|
|
||||||
end
|
|
||||||
get "/foo_normal.js"
|
|
||||||
assert_equal "Im Js", body
|
|
||||||
get "/foo_haml.js"
|
|
||||||
assert_equal "Im Haml\n", body
|
|
||||||
get "/foo_xml.js"
|
|
||||||
assert_equal "Im Xml", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve without explict template format' do
|
|
||||||
create_view :foo, "Im Html"
|
|
||||||
create_view :foo, "xml.rss", :format => :rss
|
|
||||||
mock_app do
|
|
||||||
get(:index, :map => "/", :provides => [:html, :rss]){ render 'foo' }
|
|
||||||
end
|
|
||||||
get "/", {}, { 'HTTP_ACCEPT' => 'text/html;q=0.9' }
|
|
||||||
assert_equal "Im Html", body
|
|
||||||
get ".rss"
|
|
||||||
assert_equal "<rss/>\n", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should "ignore files ending in tilde and not render them" do
|
|
||||||
create_view :foo, "Im Wrong", :format => 'haml~'
|
|
||||||
create_view :foo, "Im Haml", :format => :haml
|
|
||||||
create_view :bar, "Im Haml backup", :format => 'haml~'
|
|
||||||
mock_app do
|
|
||||||
get('/foo') { render 'foo' }
|
|
||||||
get('/bar') { render 'bar' }
|
|
||||||
end
|
|
||||||
get '/foo'
|
|
||||||
assert_equal "Im Haml\n", body
|
|
||||||
assert_raises(Padrino::Rendering::TemplateNotFound) { get '/bar' }
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve template locale' do
|
|
||||||
create_view :foo, "Im English", :locale => :en
|
|
||||||
create_view :foo, "Im Italian", :locale => :it
|
|
||||||
mock_app do
|
|
||||||
get("/foo") { render :foo }
|
|
||||||
end
|
|
||||||
I18n.locale = :en
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "Im English", body
|
|
||||||
I18n.locale = :it
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "Im Italian", body
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve template content_type and locale' do
|
|
||||||
create_view :foo, "Im Js", :format => :js
|
|
||||||
create_view :foo, "Im Erb"
|
|
||||||
create_view :foo, "Im English Erb", :locale => :en
|
|
||||||
create_view :foo, "Im Italian Erb", :locale => :it
|
|
||||||
create_view :foo, "Im English Js", :format => :js, :locale => :en
|
|
||||||
create_view :foo, "Im Italian Js", :format => :js, :locale => :it
|
|
||||||
mock_app do
|
|
||||||
get("/foo", :provides => [:html, :js]) { render :foo }
|
|
||||||
end
|
|
||||||
I18n.locale = :none
|
|
||||||
get "/foo.js"
|
|
||||||
assert_equal "Im Js", body
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "Im Erb", body
|
|
||||||
I18n.locale = :en
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "Im English Erb", body
|
|
||||||
I18n.locale = :it
|
|
||||||
get "/foo"
|
|
||||||
assert_equal "Im Italian Erb", body
|
|
||||||
I18n.locale = :en
|
|
||||||
get "/foo.js"
|
|
||||||
assert_equal "Im English Js", body
|
|
||||||
I18n.locale = :it
|
|
||||||
get "/foo.js"
|
|
||||||
assert_equal "Im Italian Js", body
|
|
||||||
I18n.locale = :en
|
|
||||||
get "/foo.pk"
|
|
||||||
assert_equal 405, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'resolve template content_type and locale with layout' do
|
|
||||||
create_layout :foo, "Hello <%= yield %> in a Js layout", :format => :js
|
|
||||||
create_layout :foo, "Hello <%= yield %> in a Js-En layout", :format => :js, :locale => :en
|
|
||||||
create_layout :foo, "Hello <%= yield %> in a Js-It layout", :format => :js, :locale => :it
|
|
||||||
create_layout :foo, "Hello <%= yield %> in a Erb-En layout", :locale => :en
|
|
||||||
create_layout :foo, "Hello <%= yield %> in a Erb-It layout", :locale => :it
|
|
||||||
create_layout :foo, "Hello <%= yield %> in a Erb layout"
|
|
||||||
create_view :bar, "Im Js", :format => :js
|
|
||||||
create_view :bar, "Im Erb"
|
|
||||||
create_view :bar, "Im English Erb", :locale => :en
|
|
||||||
create_view :bar, "Im Italian Erb", :locale => :it
|
|
||||||
create_view :bar, "Im English Js", :format => :js, :locale => :en
|
|
||||||
create_view :bar, "Im Italian Js", :format => :js, :locale => :it
|
|
||||||
create_view :bar, "Im a json", :format => :json
|
|
||||||
mock_app do
|
|
||||||
layout :foo
|
|
||||||
get("/bar", :provides => [:html, :js, :json]) { render :bar }
|
|
||||||
end
|
|
||||||
I18n.locale = :none
|
|
||||||
get "/bar.js"
|
|
||||||
assert_equal "Hello Im Js in a Js layout", body
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "Hello Im Erb in a Erb layout", body
|
|
||||||
I18n.locale = :en
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "Hello Im English Erb in a Erb-En layout", body
|
|
||||||
I18n.locale = :it
|
|
||||||
get "/bar"
|
|
||||||
assert_equal "Hello Im Italian Erb in a Erb-It layout", body
|
|
||||||
I18n.locale = :en
|
|
||||||
get "/bar.js"
|
|
||||||
assert_equal "Hello Im English Js in a Js-En layout", body
|
|
||||||
I18n.locale = :it
|
|
||||||
get "/bar.js"
|
|
||||||
assert_equal "Hello Im Italian Js in a Js-It layout", body
|
|
||||||
I18n.locale = :en
|
|
||||||
get "/bar.json"
|
|
||||||
assert_equal "Im a json", body
|
|
||||||
get "/bar.pk"
|
|
||||||
assert_equal 405, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should 'renders erb with blocks' do
|
|
||||||
mock_app do
|
|
||||||
def container
|
|
||||||
@_out_buf << "THIS."
|
|
||||||
yield
|
|
||||||
@_out_buf << "SPARTA!"
|
|
||||||
end
|
|
||||||
def is; "IS."; end
|
|
||||||
get '/' do
|
|
||||||
render :erb, '<% container do %> <%= is %> <% end %>'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
get '/'
|
|
||||||
assert ok?
|
|
||||||
assert_equal 'THIS. IS. SPARTA!', body
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,146 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/fixtures/apps/simple')
|
|
||||||
|
|
||||||
class TestRouter < Test::Unit::TestCase
|
|
||||||
|
|
||||||
def setup
|
|
||||||
Padrino.clear!
|
|
||||||
end
|
|
||||||
|
|
||||||
should "dispatch paths correctly" do
|
|
||||||
app = lambda { |env|
|
|
||||||
[200, {
|
|
||||||
'X-ScriptName' => env['SCRIPT_NAME'],
|
|
||||||
'X-PathInfo' => env['PATH_INFO'],
|
|
||||||
'Content-Type' => 'text/plain'
|
|
||||||
}, [""]]
|
|
||||||
}
|
|
||||||
map = Padrino::Router.new(
|
|
||||||
{ :path => '/bar', :to => app },
|
|
||||||
{ :path => '/foo', :to => app },
|
|
||||||
{ :path => '/foo/bar', :to => app }
|
|
||||||
)
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/qux")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/foo")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/foo", res["X-ScriptName"]
|
|
||||||
assert_equal "/", res["X-PathInfo"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/foo/")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/foo", res["X-ScriptName"]
|
|
||||||
assert_equal "/", res["X-PathInfo"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/foo/bar")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/foo/bar", res["X-ScriptName"]
|
|
||||||
assert_equal "/", res["X-PathInfo"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/foo/bar/")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/foo/bar", res["X-ScriptName"]
|
|
||||||
assert_equal "/", res["X-PathInfo"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/foo///bar//quux")
|
|
||||||
assert_equal 200, res.status
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/foo/bar", res["X-ScriptName"]
|
|
||||||
assert_equal "//quux", res["X-PathInfo"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/bleh/foo", res["X-ScriptName"]
|
|
||||||
assert_equal "/quux", res["X-PathInfo"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org')
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/bar", res["X-ScriptName"]
|
|
||||||
assert_equal "/", res["X-PathInfo"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/bar/", 'HTTP_HOST' => 'foo.org')
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "/bar", res["X-ScriptName"]
|
|
||||||
assert_equal "/", res["X-PathInfo"]
|
|
||||||
end
|
|
||||||
|
|
||||||
should "dispatches hosts correctly" do
|
|
||||||
map = Padrino::Router.new(
|
|
||||||
{ :host => "foo.org", :to => lambda { |env|
|
|
||||||
[200,
|
|
||||||
{ "Content-Type" => "text/plain",
|
|
||||||
"X-Position" => "foo.org",
|
|
||||||
"X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
|
||||||
}, [""]]}},
|
|
||||||
{ :host => "subdomain.foo.org", :to => lambda { |env|
|
|
||||||
[200,
|
|
||||||
{ "Content-Type" => "text/plain",
|
|
||||||
"X-Position" => "subdomain.foo.org",
|
|
||||||
"X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
|
||||||
}, [""]]}},
|
|
||||||
{ :host => /.*\.bar.org/, :to => lambda { |env|
|
|
||||||
[200,
|
|
||||||
{ "Content-Type" => "text/plain",
|
|
||||||
"X-Position" => "bar.org",
|
|
||||||
"X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
|
|
||||||
}, [""]]}}
|
|
||||||
)
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "bar.org")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "at.bar.org")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "bar.org", res["X-Position"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "foo.org")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "foo.org", res["X-Position"]
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "subdomain.foo.org", "SERVER_NAME" => "foo.org")
|
|
||||||
assert res.ok?
|
|
||||||
assert_equal "subdomain.foo.org", res["X-Position"]
|
|
||||||
end
|
|
||||||
|
|
||||||
should "works with padrino core applications" do
|
|
||||||
Padrino.mount("simple_demo").host("padrino.org")
|
|
||||||
assert_equal ["simple_demo"], Padrino.mounted_apps.map(&:name)
|
|
||||||
assert_equal ["padrino.org"], Padrino.mounted_apps.map(&:app_host)
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/", "HTTP_HOST" => "bar.org")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/", "HTTP_HOST" => "padrino.org")
|
|
||||||
assert res.ok?
|
|
||||||
end
|
|
||||||
|
|
||||||
should "works with padrino applications" do
|
|
||||||
Padrino.mount("simple_demo").to("/foo").host(/.*\.padrino.org/)
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/", "HTTP_HOST" => "bar.org")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/", "HTTP_HOST" => "padrino.org")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/none", "HTTP_HOST" => "foo.padrino.org")
|
|
||||||
assert res.not_found?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/foo", "HTTP_HOST" => "bar.padrino.org")
|
|
||||||
assert res.ok?
|
|
||||||
|
|
||||||
res = Rack::MockRequest.new(Padrino.application).get("/foo/", "HTTP_HOST" => "bar.padrino.org")
|
|
||||||
assert res.ok?
|
|
||||||
end
|
|
||||||
end
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +0,0 @@
|
||||||
README.rdoc
|
|
||||||
lib/**/*.rb
|
|
||||||
bin/*
|
|
||||||
features/**/*.feature
|
|
||||||
LICENSE
|
|
|
@ -1,21 +0,0 @@
|
||||||
## MAC OS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
## TEXTMATE
|
|
||||||
*.tmproj
|
|
||||||
tmtags
|
|
||||||
|
|
||||||
## EMACS
|
|
||||||
*~
|
|
||||||
\#*
|
|
||||||
.\#*
|
|
||||||
|
|
||||||
## VIM
|
|
||||||
*.swp
|
|
||||||
|
|
||||||
## PROJECT::GENERAL
|
|
||||||
coverage
|
|
||||||
rdoc
|
|
||||||
pkg
|
|
||||||
|
|
||||||
## PROJECT::SPECIFIC
|
|
|
@ -1,20 +0,0 @@
|
||||||
Copyright (c) 2011 Padrino
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,239 +0,0 @@
|
||||||
= Application Extensions and Helpers (padrino-helpers)
|
|
||||||
|
|
||||||
=== Overview
|
|
||||||
|
|
||||||
This component provides a great deal of view helpers related to html markup generation.
|
|
||||||
There are helpers for generating tags, forms, links, images, and more. Most of the basic
|
|
||||||
methods should be very familiar to anyone who has used rails view helpers.
|
|
||||||
|
|
||||||
=== Output Helpers
|
|
||||||
|
|
||||||
Output helpers are a collection of important methods for managing, capturing and displaying output
|
|
||||||
in various ways and is used frequently to support higher-level helper functions. There are
|
|
||||||
three output helpers worth mentioning: <tt>content_for</tt>, <tt>capture_html</tt>, and <tt>concat_content</tt>
|
|
||||||
|
|
||||||
The content_for functionality supports capturing content and then rendering this into a different place
|
|
||||||
such as within a layout. One such popular example is including assets onto the layout from a template:
|
|
||||||
|
|
||||||
# app/views/site/index.erb
|
|
||||||
...
|
|
||||||
<% content_for :assets do %>
|
|
||||||
<%= stylesheet_link_tag 'index', 'custom' %>
|
|
||||||
<% end %>
|
|
||||||
...
|
|
||||||
|
|
||||||
Added to a template, this will capture the includes from the block and allow them to be yielded into the layout:
|
|
||||||
|
|
||||||
# app/views/layout.erb
|
|
||||||
...
|
|
||||||
<head>
|
|
||||||
<title>Example</title>
|
|
||||||
<%= stylesheet_link_tag 'style' %>
|
|
||||||
<%= yield_content :assets %>
|
|
||||||
</head>
|
|
||||||
...
|
|
||||||
|
|
||||||
This will automatically insert the contents of the block (in this case a stylesheet include) into the
|
|
||||||
location the content is yielded within the layout.
|
|
||||||
|
|
||||||
The capture_html and the concat_content methods allow content to be manipulated and stored for use in building
|
|
||||||
additional helpers accepting blocks or displaying information in a template. One example is the use of
|
|
||||||
these in constructing a simplified 'form_tag' helper which accepts a block.
|
|
||||||
|
|
||||||
# form_tag '/register' do ... end
|
|
||||||
def form_tag(url, options={}, &block)
|
|
||||||
# ... truncated ...
|
|
||||||
inner_form_html = capture_html(&block)
|
|
||||||
concat_content '<form>' + inner_form_html + '</form>'
|
|
||||||
end
|
|
||||||
|
|
||||||
This will capture the template body passed into the form_tag block and then append the content
|
|
||||||
to the template through the use of <tt>concat_content</tt>. Note have been built to work for both haml and erb
|
|
||||||
templates using the same syntax.
|
|
||||||
|
|
||||||
For more information on using output helpers, check out the guide for
|
|
||||||
{Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers].
|
|
||||||
|
|
||||||
=== Tag Helpers
|
|
||||||
|
|
||||||
Tag helpers are the basic building blocks used to construct html 'tags' within a view template. There
|
|
||||||
are three major functions for this category: <tt>tag</tt>, <tt>content_tag</tt> and <tt>input_tag</tt>.
|
|
||||||
|
|
||||||
The tag and content_tag are for building arbitrary html tags with a name and specified options. If
|
|
||||||
the tag contains 'content' within then <tt>content_tag</tt> is used. For example:
|
|
||||||
|
|
||||||
tag(:br, :style => ‘clear:both’) => <br style="clear:both" />
|
|
||||||
content_tag(:p, "demo", :class => ‘light’) => <p class="light">demo</p>
|
|
||||||
|
|
||||||
The input_tag is used to build tags that are related to accepting input from the user:
|
|
||||||
|
|
||||||
input_tag :text, :class => "demo" => <input type='text' class='demo' />
|
|
||||||
input_tag :password, :value => "secret", :class => "demo"
|
|
||||||
|
|
||||||
Note that all of these accept html options and result in returning a string containing html tags.
|
|
||||||
|
|
||||||
For more information on using tag helpers, check out the guide for
|
|
||||||
{Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers].
|
|
||||||
|
|
||||||
=== Asset Helpers
|
|
||||||
|
|
||||||
Asset helpers are intended to help insert useful html onto a view template such as 'flash' notices,
|
|
||||||
hyperlinks, mail_to links, images, stylesheets and javascript. An example of their uses would be on a
|
|
||||||
simple view template:
|
|
||||||
|
|
||||||
# app/views/example.haml
|
|
||||||
...
|
|
||||||
%head
|
|
||||||
= stylesheet_link_tag 'layout'
|
|
||||||
= javascript_include_tag 'application'
|
|
||||||
%body
|
|
||||||
...
|
|
||||||
= flash_tag :notice
|
|
||||||
%p= link_to 'Blog', '/blog', :class => 'example'
|
|
||||||
%p Mail me at #{mail_to 'fake@faker.com', "Fake Email Link", :cc => "test@demo.com"}
|
|
||||||
%p= image_tag 'padrino.png', :width => '35', :class => 'logo'
|
|
||||||
|
|
||||||
For more information on using asset helpers, check out the guide for
|
|
||||||
{Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers].
|
|
||||||
|
|
||||||
=== Form Helpers
|
|
||||||
|
|
||||||
Form helpers are the 'standard' form tag helpers you would come to expect when building forms. A simple
|
|
||||||
example of constructing a non-object form would be:
|
|
||||||
|
|
||||||
- form_tag '/destroy', :class => 'destroy-form', :method => 'delete' do
|
|
||||||
= flash_tag(:notice)
|
|
||||||
- field_set_tag do
|
|
||||||
%p
|
|
||||||
= label_tag :username, :class => 'first'
|
|
||||||
= text_field_tag :username, :value => params[:username]
|
|
||||||
%p
|
|
||||||
= label_tag :password, :class => 'first'
|
|
||||||
= password_field_tag :password, :value => params[:password]
|
|
||||||
%p
|
|
||||||
= label_tag :strategy
|
|
||||||
= select_tag :strategy, :options => ['delete', 'destroy'], :selected => 'delete'
|
|
||||||
%p
|
|
||||||
= check_box_tag :confirm_delete
|
|
||||||
- field_set_tag(:class => 'buttons') do
|
|
||||||
= submit_tag "Remove"
|
|
||||||
|
|
||||||
For more information on using form helpers, check out the guide for
|
|
||||||
{Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers].
|
|
||||||
|
|
||||||
=== FormBuilders
|
|
||||||
|
|
||||||
Form builders are full-featured objects allowing the construction of complex object-based forms
|
|
||||||
using a simple, intuitive syntax.
|
|
||||||
|
|
||||||
A form_for using these basic fields might look like:
|
|
||||||
|
|
||||||
- form_for @user, '/register', :id => 'register' do |f|
|
|
||||||
= f.error_messages
|
|
||||||
%p
|
|
||||||
= f.label :username, :caption => "Nickname"
|
|
||||||
= f.text_field :username
|
|
||||||
%p
|
|
||||||
= f.label :email
|
|
||||||
= f.text_field :email
|
|
||||||
%p
|
|
||||||
= f.label :password
|
|
||||||
= f.password_field :password
|
|
||||||
%p
|
|
||||||
= f.label :is_admin, :caption => "Admin User?"
|
|
||||||
= f.check_box :is_admin
|
|
||||||
%p
|
|
||||||
= f.label :color, :caption => "Favorite Color?"
|
|
||||||
= f.select :color, :options => ['red', 'black']
|
|
||||||
%p
|
|
||||||
- fields_for @user.location do |location|
|
|
||||||
= location.text_field :street
|
|
||||||
= location.text_field :city
|
|
||||||
%p
|
|
||||||
= f.submit "Create", :class => 'button'
|
|
||||||
|
|
||||||
Forms can also accept nested attributes using `fields_for` within the form builder in recent releases. Check out the guide for {Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers] to learn more about nested forms.
|
|
||||||
|
|
||||||
There is also an additional StandardFormBuilder which builds on the abstract fields that can be used within a form_for.
|
|
||||||
|
|
||||||
A form_for using these standard fields might be:
|
|
||||||
|
|
||||||
- form_for @user, '/register', :id => 'register' do |f|
|
|
||||||
= f.error_messages
|
|
||||||
= f.text_field_block :name, :caption => "Full name"
|
|
||||||
= f.text_field_block :email
|
|
||||||
= f.check_box_block :remember_me
|
|
||||||
= f.select_block :fav_color, :options => ['red', 'blue']
|
|
||||||
= f.password_field_block :password
|
|
||||||
= f.submit_block "Create", :class => 'button'
|
|
||||||
|
|
||||||
and would generate this html (with each input contained in a paragraph and containing a label):
|
|
||||||
|
|
||||||
<form id="register" action="/register" method="post">
|
|
||||||
<p><label for="user_name">Full name: </label><input type="text" id="user_name" name="user[name]"></p>
|
|
||||||
...omitted...
|
|
||||||
<p><input type="submit" value="Create" class="button"></p>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
You can also easily build your own FormBuilder which allows for customized fields and behavior.
|
|
||||||
|
|
||||||
For more information on using the Padrino form builders, check out the guide for
|
|
||||||
{Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers].
|
|
||||||
|
|
||||||
=== Format Helpers
|
|
||||||
|
|
||||||
Format helpers are several useful utilities for manipulating the format of text to achieve a goal.
|
|
||||||
The four format helpers are <tt>escape_html</tt>, <tt>relative_time_ago</tt>, <tt>time_in_words</tt>,
|
|
||||||
and <tt>js_escape_html</tt>.
|
|
||||||
|
|
||||||
The escape_html and js_escape_html function are for taking an html string and escaping certain characters.
|
|
||||||
<tt>escape_html</tt> will escape ampersands, brackets and quotes to their HTML/XML entities. This is useful
|
|
||||||
to sanitize user content before displaying this on a template. <tt>js_escape_html</tt> is used for
|
|
||||||
passing javascript information from a js template to a javascript function.
|
|
||||||
|
|
||||||
escape_html('<hello>&<goodbye>') # => <hello>&<goodbye>
|
|
||||||
|
|
||||||
There is also an alias for escape_html called <tt>h</tt> for even easier usage within templates.
|
|
||||||
|
|
||||||
Format helpers also includes a number of useful text manipulation functions such as <tt>simple_format</tt>,
|
|
||||||
<tt>pluralize</tt>, <tt>word_wrap</tt>, <tt>truncate</tt> and <tt>truncate_words</tt>.
|
|
||||||
|
|
||||||
simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
|
|
||||||
pluralize(2, 'person') => '2 people'
|
|
||||||
word_wrap('Once upon a time', :line_width => 8) => "Once upon\na time"
|
|
||||||
truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."
|
|
||||||
truncate_words("Once upon a time in a world far far away", :length => 4) => "Once upon a time..."
|
|
||||||
|
|
||||||
These helpers can be invoked from any route or view within your application.
|
|
||||||
|
|
||||||
For more information on using the format helpers, check out the guide for
|
|
||||||
{Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers].
|
|
||||||
|
|
||||||
=== Render Helpers
|
|
||||||
|
|
||||||
This component provides a number of rendering helpers making the process of displaying templates a bit easier.
|
|
||||||
This plugin also has support for useful additions such as partials (with support for :collection) for the templating system.
|
|
||||||
|
|
||||||
Using render plugin helpers is extremely simple. If you want to render an erb template in your view path:
|
|
||||||
|
|
||||||
render :erb, 'path/to/erb/template'
|
|
||||||
|
|
||||||
or using haml templates works just as well:
|
|
||||||
|
|
||||||
render :haml, 'path/to/haml/template'
|
|
||||||
|
|
||||||
There is also a method which renders the first view matching the path and removes the need to define an engine:
|
|
||||||
|
|
||||||
render 'path/to/any/template'
|
|
||||||
|
|
||||||
Finally, we have the all-important partials support for rendering mini-templates onto a page:
|
|
||||||
|
|
||||||
partial 'photo/_item', :object => @photo, :locals => { :foo => 'bar' }
|
|
||||||
partial 'photo/_item', :collection => @photos
|
|
||||||
|
|
||||||
For more information on using the render and partial helpers, check out the guide for
|
|
||||||
{Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers].
|
|
||||||
|
|
||||||
== Copyright
|
|
||||||
|
|
||||||
Copyright (c) 2011 Padrino. See LICENSE for details.
|
|
|
@ -1,5 +0,0 @@
|
||||||
# coding:utf-8
|
|
||||||
RAKE_ROOT = __FILE__
|
|
||||||
|
|
||||||
require 'rubygems'
|
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/../gem_rake_helper')
|
|
|
@ -1,51 +0,0 @@
|
||||||
require 'padrino-core/support_lite' unless defined?(SupportLite)
|
|
||||||
require 'cgi'
|
|
||||||
require 'i18n'
|
|
||||||
require 'enumerator'
|
|
||||||
require 'active_support/core_ext/string/conversions' # to_date
|
|
||||||
require 'active_support/core_ext/float/rounding' # round
|
|
||||||
require 'active_support/option_merger' # with_options
|
|
||||||
require 'active_support/core_ext/object/with_options' # with_options
|
|
||||||
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"]
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
##
|
|
||||||
# This component provides a great deal of view helpers related to html markup generation.
|
|
||||||
# There are helpers for generating tags, forms, links, images, and more.
|
|
||||||
# Most of the basic methods should be very familiar to anyone who has used rails view helpers.
|
|
||||||
#
|
|
||||||
module Helpers
|
|
||||||
##
|
|
||||||
# Register these helpers:
|
|
||||||
#
|
|
||||||
# Padrino::Helpers::OutputHelpers
|
|
||||||
# Padrino::Helpers::TagHelpers
|
|
||||||
# Padrino::Helpers::AssetTagHelpers
|
|
||||||
# Padrino::Helpers::FormHelpers
|
|
||||||
# Padrino::Helpers::FormatHelpers
|
|
||||||
# Padrino::Helpers::RenderHelpers
|
|
||||||
# Padrino::Helpers::NumberHelpers
|
|
||||||
#
|
|
||||||
# for Padrino::Application
|
|
||||||
#
|
|
||||||
class << self
|
|
||||||
def registered(app)
|
|
||||||
app.set :default_builder, 'StandardFormBuilder'
|
|
||||||
app.helpers Padrino::Helpers::OutputHelpers
|
|
||||||
app.helpers Padrino::Helpers::TagHelpers
|
|
||||||
app.helpers Padrino::Helpers::AssetTagHelpers
|
|
||||||
app.helpers Padrino::Helpers::FormHelpers
|
|
||||||
app.helpers Padrino::Helpers::FormatHelpers
|
|
||||||
app.helpers Padrino::Helpers::RenderHelpers
|
|
||||||
app.helpers Padrino::Helpers::NumberHelpers
|
|
||||||
app.helpers Padrino::Helpers::TranslationHelpers
|
|
||||||
end
|
|
||||||
alias :included :registered
|
|
||||||
end
|
|
||||||
end # Helpers
|
|
||||||
end # Padrino
|
|
|
@ -1,288 +0,0 @@
|
||||||
module Padrino
|
|
||||||
module Helpers
|
|
||||||
module AssetTagHelpers
|
|
||||||
##
|
|
||||||
# Creates a div to display the flash of given type if it exists
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
# # Generates: <div class="notice">flash-notice</div>
|
|
||||||
# flash_tag(:notice, :id => 'flash-notice')
|
|
||||||
#
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates a link element with given name, url and options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# link_to('click me', '/dashboard', :class => 'linky')
|
|
||||||
# link_to('click me', '/dashboard', :remote => true)
|
|
||||||
# link_to('click me', '/dashboard', :method => :delete)
|
|
||||||
# link_to('click me', :class => 'blocky') do ... end
|
|
||||||
#
|
|
||||||
# Note that you can pass :+if+ or :+unless+ conditions, but if you provide :current as
|
|
||||||
# condition padrino return true/false if the request.path_info match the given url
|
|
||||||
#
|
|
||||||
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);'
|
|
||||||
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);')
|
|
||||||
return name unless parse_conditions(url, options)
|
|
||||||
options.reverse_merge!(:href => url)
|
|
||||||
content_tag(:a, name, options)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates a form containing a single button that submits to the url.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # Generates:
|
|
||||||
# # <form class="form" action="/admin/accounts/destroy/2" method="post">
|
|
||||||
# # <input type="hidden" value="delete" name="_method" />
|
|
||||||
# # <input type="submit" value="Delete" />
|
|
||||||
# # </form>
|
|
||||||
# button_to 'Delete', url(:accounts_destroy, :id => account), :method => :delete, :class => :form
|
|
||||||
#
|
|
||||||
def button_to(*args, &block)
|
|
||||||
name, url = args[0], args[1]
|
|
||||||
options = args.extract_options!
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates a link tag that browsers and news readers can use to auto-detect an RSS or ATOM feed.
|
|
||||||
#
|
|
||||||
# === Options
|
|
||||||
#
|
|
||||||
# :rel:: Specify the relation of this link, defaults to "alternate"
|
|
||||||
# :type:: Override the auto-generated mime type
|
|
||||||
# :title:: Specify the title of the link, defaults to the type
|
|
||||||
#
|
|
||||||
# === Examples
|
|
||||||
#
|
|
||||||
# # Generates: <link type="application/atom+xml" rel="alternate" href="/blog/posts.atom" title="ATOM" />
|
|
||||||
# feed_tag :atom, url(:blog, :posts, :format => :atom), :title => "ATOM"
|
|
||||||
# # Generates: <link type="application/rss+xml" rel="alternate" href="/blog/posts.rss" title="rss" />
|
|
||||||
# feed_tag :rss, url(:blog, :posts, :format => :rss)
|
|
||||||
#
|
|
||||||
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))
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates a mail link element with given name and caption
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # Generates: <a href="mailto:me@demo.com">me@demo.com</a>
|
|
||||||
# mail_to "me@demo.com"
|
|
||||||
# # Generates: <a href="mailto:me@demo.com">My Email</a>
|
|
||||||
# mail_to "me@demo.com", "My Email"
|
|
||||||
#
|
|
||||||
def mail_to(email, caption=nil, mail_options={})
|
|
||||||
html_options = mail_options.slice!(:cc, :bcc, :subject, :body)
|
|
||||||
mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@')
|
|
||||||
mail_href = "mailto:#{email}"; mail_href << "?#{mail_query}" if mail_query.present?
|
|
||||||
link_to((caption || email), mail_href, html_options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates a meta element with the content and given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # Generates: <meta name="keywords" content="weblog,news">
|
|
||||||
# meta_tag "weblog,news", :name => "keywords"
|
|
||||||
#
|
|
||||||
# # Generates: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
||||||
# meta_tag "text/html; charset=UTF-8", 'http-equiv' => "Content-Type"
|
|
||||||
#
|
|
||||||
def meta_tag(content, options={})
|
|
||||||
options.reverse_merge!("content" => content)
|
|
||||||
tag(:meta, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Generates a favicon link. looks inside images folder
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# favicon_tag 'favicon.png'
|
|
||||||
# favicon_tag 'icons/favicon.png'
|
|
||||||
# # or override some options
|
|
||||||
# favicon_tag 'favicon.png', :type => 'image/ico'
|
|
||||||
#
|
|
||||||
def favicon_tag(source,options={})
|
|
||||||
type = File.extname(source).gsub('.','')
|
|
||||||
options = options.dup.reverse_merge!(:href => image_path(source), :rel => 'icon', :type => "image/#{type}")
|
|
||||||
tag(:link, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates an image element with given url and options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# image_tag('icons/avatar.png')
|
|
||||||
#
|
|
||||||
def image_tag(url, options={})
|
|
||||||
options.reverse_merge!(:src => image_path(url))
|
|
||||||
tag(:img, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns an html script tag for each of the sources provided.
|
|
||||||
# You can pass in the filename without extension or a symbol and we search it in your +appname.public+
|
|
||||||
# like app/public/stylesheets for inclusion. You can provide also a full path.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# stylesheet_link_tag 'style', 'application', 'layout'
|
|
||||||
#
|
|
||||||
def stylesheet_link_tag(*sources)
|
|
||||||
options = sources.extract_options!.symbolize_keys
|
|
||||||
options.reverse_merge!(:media => 'screen', :rel => 'stylesheet', :type => 'text/css')
|
|
||||||
sources.flatten.map { |source|
|
|
||||||
tag(:link, options.reverse_merge(:href => asset_path(:css, source)))
|
|
||||||
}.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns an html script tag for each of the sources provided.
|
|
||||||
# You can pass in the filename without extension or a symbol and we search it in your +appname.public+
|
|
||||||
# like app/public/javascript for inclusion. You can provide also a full path.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# javascript_include_tag 'application', :extjs
|
|
||||||
#
|
|
||||||
def javascript_include_tag(*sources)
|
|
||||||
options = sources.extract_options!.symbolize_keys
|
|
||||||
options.reverse_merge!(:type => 'text/javascript', :content => "")
|
|
||||||
sources.flatten.map { |source|
|
|
||||||
tag(:script, options.reverse_merge(:src => asset_path(:js, source)))
|
|
||||||
}.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the path to the image, either relative or absolute. We search it in your +appname.public+
|
|
||||||
# like app/public/images for inclusion. You can provide also a full path.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # Generates: /images/foo.jpg?1269008689
|
|
||||||
# image_path("foo.jpg")
|
|
||||||
#
|
|
||||||
def image_path(src)
|
|
||||||
asset_path(:images, src)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the path to the specified asset (css or javascript)
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # Generates: /javascripts/application.js?1269008689
|
|
||||||
# asset_path :js, :application
|
|
||||||
#
|
|
||||||
# # Generates: /stylesheets/application.css?1269008689
|
|
||||||
# asset_path :css, :application
|
|
||||||
#
|
|
||||||
# # Generates: /images/example.jpg?1269008689
|
|
||||||
# asset_path :images, 'example.jpg'
|
|
||||||
#
|
|
||||||
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
|
|
||||||
source = source.to_s.gsub(/\s/, '%20')
|
|
||||||
ignore_extension = (asset_folder.to_s == kind.to_s) # don't append 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}#{timestamp}"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the uri root of the application.
|
|
||||||
#
|
|
||||||
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
|
|
||||||
#
|
|
||||||
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}"
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Parses link_to options for given correct conditions
|
|
||||||
#
|
|
||||||
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
|
|
||||||
#
|
|
||||||
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
|
|
||||||
end
|
|
||||||
end # AssetTagHelpers
|
|
||||||
end # Helpers
|
|
||||||
end # Padrino
|
|
|
@ -1,220 +0,0 @@
|
||||||
module Padrino
|
|
||||||
module Helpers
|
|
||||||
module FormBuilder #:nodoc:
|
|
||||||
class AbstractFormBuilder #:nodoc:
|
|
||||||
attr_accessor :template, :object
|
|
||||||
|
|
||||||
def initialize(template, object, options={})
|
|
||||||
@template = template
|
|
||||||
@object = build_object(object)
|
|
||||||
@options = options
|
|
||||||
raise "FormBuilder template must be initialized!" unless template
|
|
||||||
raise "FormBuilder object must be not be nil value. If there's no object, use a symbol instead! (i.e :user)" unless object
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.error_messages
|
|
||||||
def error_messages(*params)
|
|
||||||
params.unshift object
|
|
||||||
@template.error_messages_for(*params)
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.error_message_on(field)
|
|
||||||
def error_message_on(field, options={})
|
|
||||||
@template.error_message_on(object, field, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.label :username, :caption => "Nickname"
|
|
||||||
def label(field, options={})
|
|
||||||
options.reverse_merge!(:caption => "#{field_human_name(field)}: ")
|
|
||||||
@template.label_tag(field_id(field), options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.hidden_field :session_id, :value => "45"
|
|
||||||
def hidden_field(field, options={})
|
|
||||||
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
|
||||||
@template.hidden_field_tag field_name(field), options
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.text_field :username, :value => "(blank)", :id => 'username'
|
|
||||||
def text_field(field, options={})
|
|
||||||
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
|
||||||
options.merge!(:class => field_error(field, options))
|
|
||||||
@template.text_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))
|
|
||||||
options.merge!(:class => field_error(field, options))
|
|
||||||
@template.text_area_tag field_name(field), options
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.password_field :password, :id => 'password'
|
|
||||||
def password_field(field, options={})
|
|
||||||
options.reverse_merge!(:value => field_value(field), :id => field_id(field))
|
|
||||||
options.merge!(:class => field_error(field, options))
|
|
||||||
@template.password_field_tag field_name(field), options
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.select :color, :options => ['red', 'green'], :include_blank => true
|
|
||||||
# f.select :color, :collection => @colors, :fields => [:name, :id]
|
|
||||||
def select(field, options={})
|
|
||||||
options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
|
|
||||||
options.merge!(:class => field_error(field, options))
|
|
||||||
@template.select_tag field_name(field), options
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.check_box :remember_me, :value => 'true', :uncheck_value => '0'
|
|
||||||
def check_box(field, options={})
|
|
||||||
unchecked_value = options.delete(:uncheck_value) || '0'
|
|
||||||
options.reverse_merge!(:id => field_id(field), :value => '1')
|
|
||||||
options.reverse_merge!(:checked => true) if values_matches_field?(field, options[:value])
|
|
||||||
html = @template.hidden_field_tag(options[:name] || field_name(field), :value => unchecked_value, :id => nil)
|
|
||||||
html << @template.check_box_tag(field_name(field), options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.radio_button :gender, :value => 'male'
|
|
||||||
def radio_button(field, options={})
|
|
||||||
options.reverse_merge!(:id => field_id(field, options[:value]))
|
|
||||||
options.reverse_merge!(:checked => true) if values_matches_field?(field, options[:value])
|
|
||||||
@template.radio_button_tag field_name(field), options
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.file_field :photo, :class => 'avatar'
|
|
||||||
def file_field(field, options={})
|
|
||||||
options.reverse_merge!(:id => field_id(field))
|
|
||||||
options.merge!(:class => field_error(field, options))
|
|
||||||
@template.file_field_tag field_name(field), options
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.submit "Update", :class => 'large'
|
|
||||||
def submit(caption="Submit", options={})
|
|
||||||
@template.submit_tag caption, options
|
|
||||||
end
|
|
||||||
|
|
||||||
# f.image_submit "buttons/submit.png", :class => 'large'
|
|
||||||
def image_submit(source, options={})
|
|
||||||
@template.image_submit_tag source, options
|
|
||||||
end
|
|
||||||
|
|
||||||
# Supports nested fields for a child model within a form
|
|
||||||
# f.fields_for :addresses
|
|
||||||
# f.fields_for :addresses, address
|
|
||||||
# f.fields_for :addresses, @addresses
|
|
||||||
def fields_for(child_association, instance_or_collection=nil, &block)
|
|
||||||
default_collection = self.object.send(child_association)
|
|
||||||
include_index = default_collection.respond_to?(:each)
|
|
||||||
nested_options = { :parent => self, :association => child_association }
|
|
||||||
nested_objects = instance_or_collection ? Array(instance_or_collection) : Array(default_collection)
|
|
||||||
result = nested_objects.each_with_index.map do |child_instance, index|
|
|
||||||
nested_options[:index] = include_index ? index : nil
|
|
||||||
@template.fields_for(child_instance, { :nested => nested_options }, &block)
|
|
||||||
end.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
# Returns the known field types for a formbuilder
|
|
||||||
def self.field_types
|
|
||||||
[:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns true if the value matches the value in the field
|
|
||||||
# field_has_value?(:gender, 'male')
|
|
||||||
def values_matches_field?(field, value)
|
|
||||||
value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Add a :invalid css class to the field if it contain an error
|
|
||||||
def field_error(field, options)
|
|
||||||
error = @object.errors[field] rescue nil
|
|
||||||
error.blank? ? options[:class] : [options[:class], :invalid].flatten.compact.join(" ")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the human name of the field. Look that use builtin I18n.
|
|
||||||
def field_human_name(field)
|
|
||||||
I18n.translate("#{object_model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the name for the given field
|
|
||||||
# field_name(:username) => "user[username]"
|
|
||||||
# field_name(:number) => "user[telephone_attributes][number]"
|
|
||||||
# field_name(:street) => "user[addresses_attributes][0][street]"
|
|
||||||
def field_name(field=nil)
|
|
||||||
result = []
|
|
||||||
if root_form?
|
|
||||||
result << object_model_name
|
|
||||||
elsif nested_form?
|
|
||||||
parent_form = @options[:nested][:parent]
|
|
||||||
attributes_name = "#{@options[:nested][:association]}_attributes"
|
|
||||||
nested_index = @options[:nested][:index]
|
|
||||||
fragment = [parent_form.field_name, "[#{attributes_name}", "]"]
|
|
||||||
fragment.insert(2, "][#{nested_index}") if nested_index
|
|
||||||
result << fragment
|
|
||||||
end
|
|
||||||
result << "[#{field}]" unless field.blank?
|
|
||||||
result.flatten.join
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the id for the given field
|
|
||||||
# field_id(:username) => "user_username"
|
|
||||||
# field_id(:gender, :male) => "user_gender_male"
|
|
||||||
# field_name(:number) => "user_telephone_attributes_number"
|
|
||||||
# field_name(:street) => "user_addresses_attributes_0_street"
|
|
||||||
def field_id(field=nil, value=nil)
|
|
||||||
result = []
|
|
||||||
if root_form?
|
|
||||||
result << object_model_name
|
|
||||||
elsif nested_form?
|
|
||||||
parent_form = @options[:nested][:parent]
|
|
||||||
attributes_name = "#{@options[:nested][:association]}_attributes"
|
|
||||||
nested_index = @options[:nested][:index]
|
|
||||||
fragment = [parent_form.field_id, "_#{attributes_name}"]
|
|
||||||
fragment.push("_#{nested_index}") if nested_index
|
|
||||||
result << fragment
|
|
||||||
end
|
|
||||||
result << "_#{field}" unless field.blank?
|
|
||||||
result << "_#{value}" unless value.blank?
|
|
||||||
result.flatten.join
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the child object if it exists
|
|
||||||
def nested_object_id
|
|
||||||
nested_form? && object.respond_to?(:new_record?) && !object.new_record? && object.id
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns true if this form object is nested in a parent form
|
|
||||||
def nested_form?
|
|
||||||
@options[:nested] && @options[:nested][:parent] && @options[:nested][:parent].respond_to?(:object)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the value for the object's field
|
|
||||||
# field_value(:username) => "Joey"
|
|
||||||
def field_value(field)
|
|
||||||
@object && @object.respond_to?(field) ? @object.send(field) : ""
|
|
||||||
end
|
|
||||||
|
|
||||||
# explicit_object is either a symbol or a record
|
|
||||||
# Returns a new record of the type specified in the object
|
|
||||||
def build_object(object_or_symbol)
|
|
||||||
object_or_symbol.is_a?(Symbol) ? @template.instance_variable_get("@#{object_or_symbol}") || object_class(object_or_symbol).new : object_or_symbol
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the object's models name
|
|
||||||
# => user_assignment
|
|
||||||
def object_model_name(explicit_object=object)
|
|
||||||
explicit_object.is_a?(Symbol) ? explicit_object : explicit_object.class.to_s.underscore.gsub(/\//, '_')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the class type for the given object
|
|
||||||
def object_class(explicit_object)
|
|
||||||
explicit_object.is_a?(Symbol) ? explicit_object.to_s.camelize.constantize : explicit_object.class
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns true if this form is the top-level (not nested)
|
|
||||||
def root_form?
|
|
||||||
!nested_form?
|
|
||||||
end
|
|
||||||
end # AbstractFormBuilder
|
|
||||||
end # FormBuilder
|
|
||||||
end # Helpers
|
|
||||||
end # Padrino
|
|
|
@ -1,43 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/abstract_form_builder') unless defined?(AbstractFormBuilder)
|
|
||||||
|
|
||||||
module Padrino
|
|
||||||
module Helpers
|
|
||||||
module FormBuilder #:nodoc:
|
|
||||||
class StandardFormBuilder < AbstractFormBuilder #:nodoc:
|
|
||||||
|
|
||||||
##
|
|
||||||
# StandardFormBuilder
|
|
||||||
#
|
|
||||||
# text_field_block(:username, { :class => 'long' }, { :class => 'wide-label' })
|
|
||||||
# text_area_block(:summary, { :class => 'long' }, { :class => 'wide-label' })
|
|
||||||
# password_field_block(:password, { :class => 'long' }, { :class => 'wide-label' })
|
|
||||||
# file_field_block(:photo, { :class => 'long' }, { :class => 'wide-label' })
|
|
||||||
# check_box_block(:remember_me, { :class => 'long' }, { :class => 'wide-label' })
|
|
||||||
# select_block(:color, :options => ['green', 'black'])
|
|
||||||
#
|
|
||||||
(self.field_types - [ :hidden_field, :radio_button ]).each do |field_type|
|
|
||||||
class_eval <<-EOF
|
|
||||||
def #{field_type}_block(field, options={}, label_options={})
|
|
||||||
label_options.reverse_merge!(:caption => options.delete(:caption)) if options[:caption]
|
|
||||||
field_html = label(field, label_options)
|
|
||||||
field_html << #{field_type}(field, options)
|
|
||||||
@template.content_tag(:p, field_html)
|
|
||||||
end
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
|
|
||||||
# submit_block("Update")
|
|
||||||
def submit_block(caption, options={})
|
|
||||||
submit_html = self.submit(caption, options)
|
|
||||||
@template.content_tag(:p, submit_html)
|
|
||||||
end
|
|
||||||
|
|
||||||
# image_submit_block("submit.png")
|
|
||||||
def image_submit_block(source, options={})
|
|
||||||
submit_html = self.image_submit(source, options)
|
|
||||||
@template.content_tag(:p, submit_html)
|
|
||||||
end
|
|
||||||
end # StandardFormBuilder
|
|
||||||
end # FormBuilder
|
|
||||||
end # Helpers
|
|
||||||
end # Padrino
|
|
|
@ -1,446 +0,0 @@
|
||||||
module Padrino
|
|
||||||
module Helpers
|
|
||||||
module FormHelpers
|
|
||||||
##
|
|
||||||
# Constructs a form for object using given or default form_builder
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# form_for :user, '/register' do |f| ... end
|
|
||||||
# form_for @user, '/register', :id => 'register' do |f| ... end
|
|
||||||
#
|
|
||||||
def form_for(object, url, settings={}, &block)
|
|
||||||
form_html = capture_html(builder_instance(object, settings), &block)
|
|
||||||
form_tag(url, settings) { form_html }
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs form fields for an object using given or default form_builder
|
|
||||||
# Used within an existing form to allow alternate objects within one form
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# fields_for @user.assignment do |assignment| ... end
|
|
||||||
# fields_for :assignment do |assigment| ... end
|
|
||||||
#
|
|
||||||
def fields_for(object, settings={}, &block)
|
|
||||||
instance = builder_instance(object, settings)
|
|
||||||
fields_html = capture_html(instance, &block)
|
|
||||||
fields_html << instance.hidden_field(:id) if instance.send(:nested_object_id)
|
|
||||||
concat_content fields_html
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a form without object based on options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# form_tag '/register' do ... end
|
|
||||||
#
|
|
||||||
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"
|
|
||||||
inner_form_html = hidden_form_method_field(desired_method)
|
|
||||||
inner_form_html += capture_html(&block)
|
|
||||||
concat_content content_tag(:form, inner_form_html, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the hidden method field for 'put' and 'delete' forms
|
|
||||||
# Only 'get' and 'post' are allowed within browsers;
|
|
||||||
# 'put' and 'delete' are just specified using hidden fields with form action still 'put'.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # Generate: <input name="_method" value="delete" />
|
|
||||||
# hidden_form_method_field('delete')
|
|
||||||
#
|
|
||||||
def hidden_form_method_field(desired_method)
|
|
||||||
return '' if desired_method.blank? || desired_method.to_s =~ /get|post/i
|
|
||||||
hidden_field_tag(:_method, :value => desired_method)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a field_set to group fields with given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# field_set_tag("Office", :class => 'office-set')
|
|
||||||
#
|
|
||||||
def field_set_tag(*args, &block)
|
|
||||||
options = args.extract_options!
|
|
||||||
legend_text = args[0].is_a?(String) ? args.first : nil
|
|
||||||
legend_html = legend_text.blank? ? '' : content_tag(:legend, legend_text)
|
|
||||||
field_set_content = legend_html + capture_html(&block)
|
|
||||||
concat_content content_tag(:fieldset, field_set_content, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs list html for the errors for a given symbol
|
|
||||||
#
|
|
||||||
# ==== Options
|
|
||||||
#
|
|
||||||
# :header_tag:: Used for the header of the error div (default: "h2").
|
|
||||||
# :id:: The id of the error div (default: "errorExplanation").
|
|
||||||
# :class:: The class of the error div (default: "errorExplanation").
|
|
||||||
# :object:: The object (or array of objects) for which to display errors,
|
|
||||||
# if you need to escape the instance variable convention.
|
|
||||||
# :object_name:: The object name to use in the header, or any text that you prefer.
|
|
||||||
# If +:object_name+ is not set, the name of the first object will be used.
|
|
||||||
# :header_message:: The message in the header of the error div. Pass +nil+
|
|
||||||
# or an empty string to avoid the header message altogether. (Default: "X errors
|
|
||||||
# prohibited this object from being saved").
|
|
||||||
# :message:: The explanation message after the header message and before
|
|
||||||
# the error list. Pass +nil+ or an empty string to avoid the explanation message
|
|
||||||
# altogether. (Default: "There were problems with the following fields:").
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# error_messages_for :user
|
|
||||||
#
|
|
||||||
def error_messages_for(*objects)
|
|
||||||
options = objects.extract_options!.symbolize_keys
|
|
||||||
objects = objects.map {|object_name| object_name.is_a?(Symbol) ? instance_variable_get("@#{object_name}") : object_name }.compact
|
|
||||||
count = objects.inject(0) {|sum, object| sum + object.errors.size }
|
|
||||||
|
|
||||||
unless count.zero?
|
|
||||||
html = {}
|
|
||||||
[:id, :class, :style].each do |key|
|
|
||||||
if options.include?(key)
|
|
||||||
value = options[key]
|
|
||||||
html[key] = value unless value.blank?
|
|
||||||
else
|
|
||||||
html[key] = 'field-errors' unless key == :style
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
options[:object_name] ||= objects.first.class
|
|
||||||
|
|
||||||
I18n.with_options :locale => options[:locale], :scope => [:models, :errors, :template] do |locale|
|
|
||||||
header_message = if options.include?(:header_message)
|
|
||||||
options[:header_message]
|
|
||||||
else
|
|
||||||
object_name = options[:object_name].to_s.underscore.gsub(/\//, ' ')
|
|
||||||
object_name = I18n.t(:name, :default => object_name.humanize, :scope => [:models, object_name], :count => 1)
|
|
||||||
locale.t :header, :count => count, :model => object_name
|
|
||||||
end
|
|
||||||
message = options.include?(:message) ? options[:message] : locale.t(:body)
|
|
||||||
error_messages = objects.map { |object|
|
|
||||||
object_name = options[:object_name].to_s.underscore.gsub(/\//, ' ')
|
|
||||||
object.errors.map { |f, msg|
|
|
||||||
field = I18n.t(f, :default => f.to_s.humanize, :scope => [:models, object_name, :attributes])
|
|
||||||
content_tag(:li, "%s %s" % [field, msg])
|
|
||||||
}
|
|
||||||
}.join
|
|
||||||
|
|
||||||
contents = ''
|
|
||||||
contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
|
|
||||||
contents << content_tag(:p, message) unless message.blank?
|
|
||||||
contents << content_tag(:ul, error_messages)
|
|
||||||
|
|
||||||
content_tag(:div, contents, html)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
|
|
||||||
#
|
|
||||||
# ==== Options
|
|
||||||
#
|
|
||||||
# :tag:: The tag that enclose your error. (Default 'div')
|
|
||||||
# :prepend:: Text to add before error.
|
|
||||||
# :append:: Text to add after error.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # => <span class="error">can't be blank</div>
|
|
||||||
# error_message_on :post, :title
|
|
||||||
# error_message_on @post, :title
|
|
||||||
#
|
|
||||||
# # => <div class="custom" style="border:1px solid red">can't be blank</div>
|
|
||||||
# error_message_on :post, :title, :tag => :id, :class => :custom, :style => "border:1px solid red"
|
|
||||||
#
|
|
||||||
# # => <div class="error">This title can't be blank (or it won't work)</div>
|
|
||||||
# error_message_on :post, :title, :prepend => "This title", :append => "(or it won't work)"
|
|
||||||
#
|
|
||||||
def error_message_on(object, field, options={})
|
|
||||||
object = object.is_a?(Symbol) ? instance_variable_get("@#{object}") : object
|
|
||||||
error = object.errors[field] rescue nil
|
|
||||||
if error
|
|
||||||
options.reverse_merge!(:tag => :span, :class => :error)
|
|
||||||
tag = options.delete(:tag)
|
|
||||||
# Array(error).first is necessary because some orm give us an array others directly a value
|
|
||||||
error = [options.delete(:prepend), Array(error).first, options.delete(:append)].compact.join(" ")
|
|
||||||
content_tag(tag, error, options)
|
|
||||||
else
|
|
||||||
''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a label tag from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# label_tag :username, :class => 'long-label'
|
|
||||||
# label_tag :username, :class => 'long-label' do ... end
|
|
||||||
#
|
|
||||||
def label_tag(name, options={}, &block)
|
|
||||||
options.reverse_merge!(:caption => "#{name.to_s.humanize}: ", :for => name)
|
|
||||||
caption_text = options.delete(:caption)
|
|
||||||
caption_text << "<span class='required'>*</span> " if options.delete(:required)
|
|
||||||
if block_given? # label with inner content
|
|
||||||
label_content = caption_text + capture_html(&block)
|
|
||||||
concat_content(content_tag(:label, label_content, options))
|
|
||||||
else # regular label
|
|
||||||
content_tag(:label, caption_text, options)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a hidden field input from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# hidden_field_tag :session_key, :value => "__secret__"
|
|
||||||
#
|
|
||||||
def hidden_field_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name)
|
|
||||||
input_tag(:hidden, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a text field input from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# text_field_tag :username, :class => 'long'
|
|
||||||
#
|
|
||||||
def text_field_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name)
|
|
||||||
input_tag(:text, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a text area input from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# text_area_tag :username, :class => 'long', :value => "Demo?"
|
|
||||||
#
|
|
||||||
def text_area_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name, :rows => "", :cols => "")
|
|
||||||
content_tag(:textarea, options.delete(:value).to_s, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a password field input from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# password_field_tag :password, :class => 'long'
|
|
||||||
#
|
|
||||||
def password_field_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name)
|
|
||||||
input_tag(:password, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a select from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# options = [['caption', 'value'], ['Green', 'green1'], ['Blue', 'blue1'], ['Black', "black1"]]
|
|
||||||
# options = ['option', 'red', 'yellow' ]
|
|
||||||
# select_tag(:favorite_color, :options => ['red', 'yellow'], :selected => 'green1')
|
|
||||||
# select_tag(:country, :collection => @countries, :fields => [:name, :code], :include_blank => 'None')
|
|
||||||
#
|
|
||||||
# # Optgroups can be generated using :grouped_options => (Hash or nested Array)
|
|
||||||
# grouped_options = [['Friends',['Yoda',['Obiwan',1]]],['Enemies',['Palpatine',['Darth Vader',3]]]]
|
|
||||||
# grouped_options = {'Friends' => ['Yoda',['Obiwan',1]],'Enemies' => ['Palpatine',['Darth Vader',3]]}
|
|
||||||
# select_tag(:color, :grouped_options => [['warm',['red','yellow']],['cool',['blue', 'purple']]])
|
|
||||||
#
|
|
||||||
# # Optgroups can be generated using :grouped_options => (Hash or nested Array)
|
|
||||||
# grouped_options = [['Friends',['Yoda',['Obiwan',1]]],['Enemies',['Palpatine',['Darth Vader',3]]]]
|
|
||||||
# grouped_options = {'Friends' => ['Yoda',['Obiwan',1]],'Enemies' => ['Palpatine',['Darth Vader',3]]}
|
|
||||||
# select_tag(:color, :grouped_options => [['warm',['red','yellow']],['cool',['blue', 'purple']]])
|
|
||||||
#
|
|
||||||
def select_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name)
|
|
||||||
collection, fields = options.delete(:collection), options.delete(:fields)
|
|
||||||
options[:options] = options_from_collection(collection, fields) if collection
|
|
||||||
prompt = options.delete(:include_blank)
|
|
||||||
select_options_html = if options[:options]
|
|
||||||
options_for_select(options.delete(:options), options.delete(:selected))
|
|
||||||
elsif options[:grouped_options]
|
|
||||||
grouped_options_for_select(options.delete(:grouped_options), options.delete(:selected), prompt)
|
|
||||||
end
|
|
||||||
select_options_html = select_options_html.unshift(blank_option(prompt)) if select_options_html.is_a?(Array)
|
|
||||||
options.merge!(:name => "#{options[:name]}[]") if options[:multiple]
|
|
||||||
content_tag(:select, select_options_html, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a check_box from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# check_box_tag :remember_me, :value => 'Yes'
|
|
||||||
#
|
|
||||||
def check_box_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name, :value => '1')
|
|
||||||
input_tag(:checkbox, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a radio_button from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# radio_button_tag :remember_me, :value => 'true'
|
|
||||||
#
|
|
||||||
def radio_button_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name)
|
|
||||||
input_tag(:radio, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a file field input from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# file_field_tag :photo, :class => 'long'
|
|
||||||
#
|
|
||||||
def file_field_tag(name, options={})
|
|
||||||
options.reverse_merge!(:name => name)
|
|
||||||
input_tag(:file, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a submit button from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# submit_tag "Create", :class => 'success'
|
|
||||||
#
|
|
||||||
def submit_tag(caption="Submit", options={})
|
|
||||||
options.reverse_merge!(:value => caption)
|
|
||||||
input_tag(:submit, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Constructs a button input from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# button_tag "Cancel", :class => 'clear'
|
|
||||||
#
|
|
||||||
def button_tag(caption, options = {})
|
|
||||||
options.reverse_merge!(:value => caption)
|
|
||||||
input_tag(:button, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Constructs a submit button from the given options
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# submit_tag "Create", :class => 'success'
|
|
||||||
#
|
|
||||||
def image_submit_tag(source, options={})
|
|
||||||
options.reverse_merge!(:src => image_path(source))
|
|
||||||
input_tag(:image, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns an array of option items for a select field based on the given collection
|
|
||||||
# fields is an array containing the fields to display from each item in the collection
|
|
||||||
#
|
|
||||||
def options_from_collection(collection, fields)
|
|
||||||
collection.map { |item| [ item.send(fields.first), item.send(fields.last) ] }
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the options tags for a select based on the given option items
|
|
||||||
#
|
|
||||||
def options_for_select(option_items, selected_value=nil)
|
|
||||||
return '' if option_items.blank?
|
|
||||||
option_items.map do |caption, value|
|
|
||||||
value ||= caption
|
|
||||||
content_tag(:option, caption, :value => value, :selected => option_is_selected?(value, caption, selected_value))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the optgroups with options tags for a select based on the given :grouped_options items
|
|
||||||
#
|
|
||||||
def grouped_options_for_select(collection,selected=nil,prompt=false)
|
|
||||||
if collection.is_a?(Hash)
|
|
||||||
collection.map do |key, value|
|
|
||||||
content_tag :optgroup, :label => key do
|
|
||||||
options_for_select(value, selected)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elsif collection.is_a?(Array)
|
|
||||||
collection.map do |optgroup|
|
|
||||||
content_tag :optgroup, :label => optgroup.first do
|
|
||||||
options_for_select(optgroup.last, selected)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the blank option serving as a prompt if passed
|
|
||||||
#
|
|
||||||
def blank_option(prompt)
|
|
||||||
return unless prompt
|
|
||||||
case prompt
|
|
||||||
when String then content_tag(:option, prompt, :value => '')
|
|
||||||
when Array then content_tag(:option, prompt.first, :value => prompt.last)
|
|
||||||
else content_tag(:option, '', :value => '')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
##
|
|
||||||
# Returns the FormBuilder class to use based on all available setting sources
|
|
||||||
# If explicitly defined, returns that, otherwise returns defaults.
|
|
||||||
#
|
|
||||||
# configured_form_builder_class(nil) => StandardFormBuilder
|
|
||||||
#
|
|
||||||
def configured_form_builder_class(explicit_builder=nil)
|
|
||||||
default_builder = self.respond_to?(:settings) && self.settings.default_builder
|
|
||||||
configured_builder = explicit_builder || default_builder || 'StandardFormBuilder'
|
|
||||||
configured_builder = "Padrino::Helpers::FormBuilder::#{configured_builder}".constantize if configured_builder.is_a?(String)
|
|
||||||
configured_builder
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns an initialized builder instance for the given object and settings
|
|
||||||
#
|
|
||||||
# builder_instance(@account, :nested => { ... }) => <FormBuilder>
|
|
||||||
#
|
|
||||||
def builder_instance(object, settings={})
|
|
||||||
builder_class = configured_form_builder_class(settings.delete(:builder))
|
|
||||||
builder_class.new(self, object, settings)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns whether the option should be selected or not
|
|
||||||
#
|
|
||||||
def option_is_selected?(value, caption, selected_values)
|
|
||||||
Array(selected_values).any? do |selected|
|
|
||||||
[value.to_s, caption.to_s].include?(selected.to_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end # FormHelpers
|
|
||||||
end # Helpers
|
|
||||||
end # Padrino
|
|
|
@ -1,260 +0,0 @@
|
||||||
module Padrino
|
|
||||||
module Helpers
|
|
||||||
module FormatHelpers
|
|
||||||
##
|
|
||||||
# Returns escaped text to protect against malicious content
|
|
||||||
#
|
|
||||||
def escape_html(text)
|
|
||||||
Rack::Utils.escape_html(text)
|
|
||||||
end
|
|
||||||
alias h escape_html
|
|
||||||
alias sanitize_html escape_html
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns escaped text to protect against malicious content
|
|
||||||
# Returns blank if the text is empty
|
|
||||||
#
|
|
||||||
def h!(text, blank_text = ' ')
|
|
||||||
return blank_text if text.nil? || text.empty?
|
|
||||||
h text
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Strips all HTML tags from the html
|
|
||||||
#
|
|
||||||
def strip_tags(html)
|
|
||||||
html.gsub(/<\/?[^>]*>/, "") if html
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns text transformed into HTML using simple formatting rules. Two or more consecutive newlines(\n\n) are considered
|
|
||||||
# as a paragraph and wrapped in <p> or your own tags. One newline (\n) is considered as a linebreak and a <br /> tag is appended.
|
|
||||||
# This method does not remove the newlines from the text.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
|
|
||||||
# simple_format("hello\nworld", :tag => :div, :class => :foo) # => "<div class="foo">hello<br/>world</div>"
|
|
||||||
#
|
|
||||||
def simple_format(text, options={})
|
|
||||||
t = options.delete(:tag) || :p
|
|
||||||
start_tag = tag(t, options.merge(:open => 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
|
|
||||||
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
|
|
||||||
text.insert 0, start_tag
|
|
||||||
text << "</#{t}>"
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Attempts to pluralize the singular word unless count is 1. If plural is supplied, it will use that when count is > 1,
|
|
||||||
# otherwise it will use the Inflector to determine the plural form
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# pluralize(2, 'person') => '2 people'
|
|
||||||
#
|
|
||||||
def pluralize(count, singular, plural = nil)
|
|
||||||
"#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Truncates a given text after a given :length if text is longer than :length (defaults to 30).
|
|
||||||
# The last characters will be replaced with the :omission (defaults to "…") for a total length not exceeding :length.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."
|
|
||||||
#
|
|
||||||
def truncate(text, options={})
|
|
||||||
options.reverse_merge!(:length => 30, :omission => "...")
|
|
||||||
if text
|
|
||||||
len = options[:length] - options[:omission].length
|
|
||||||
chars = text
|
|
||||||
(chars.length > options[:length] ? chars[0...len] + options[:omission] : text).to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Truncates words of a given text after a given :length if number of words in text is more than :length (defaults to 30).
|
|
||||||
# The last words will be replaced with the :omission (defaults to "…") for a total number of words not exceeding :length.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# truncate_words("Once upon a time in a world far far away", :length => 8) => "Once upon a time in a world far..."
|
|
||||||
#
|
|
||||||
def truncate_words(text, options={})
|
|
||||||
options.reverse_merge!(:length => 30, :omission => "...")
|
|
||||||
if text
|
|
||||||
words = text.split()
|
|
||||||
words[0..(options[:length]-1)].join(' ') + (words.length > options[:length] ? options[:omission] : '')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Wraps the text into lines no longer than line_width width.
|
|
||||||
# This method breaks on the first whitespace character that does not exceed line_width (which is 80 by default).
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# word_wrap('Once upon a time', :line_width => 8) => "Once upon\na time"
|
|
||||||
#
|
|
||||||
def word_wrap(text, *args)
|
|
||||||
options = args.extract_options!
|
|
||||||
unless args.blank?
|
|
||||||
options[:line_width] = args[0] || 80
|
|
||||||
end
|
|
||||||
options.reverse_merge!(:line_width => 80)
|
|
||||||
|
|
||||||
text.split("\n").map do |line|
|
|
||||||
line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line
|
|
||||||
end * "\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Highlights one or more words everywhere in text by inserting it into a :highlighter string.
|
|
||||||
#
|
|
||||||
# The highlighter can be customized by passing :+highlighter+ as a single-quoted string
|
|
||||||
# with \1 where the phrase is to be inserted (defaults to ’<strong class="highlight">\1</strong>’)
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# # => Lorem ipsum <strong class="highlight">dolor</strong> sit amet
|
|
||||||
# highlight('Lorem ipsum dolor sit amet', 'dolor')
|
|
||||||
#
|
|
||||||
# # => Lorem ipsum <span class="custom">dolor</span> sit amet
|
|
||||||
# highlight('Lorem ipsum dolor sit amet', 'dolor', :highlighter => '<span class="custom">\1</span>')
|
|
||||||
#
|
|
||||||
def highlight(text, words, *args)
|
|
||||||
options = args.extract_options!
|
|
||||||
options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
|
|
||||||
|
|
||||||
if text.blank? || words.blank?
|
|
||||||
text
|
|
||||||
else
|
|
||||||
match = Array(words).map { |p| Regexp.escape(p) }.join('|')
|
|
||||||
text.gsub(/(#{match})(?!(?:[^<]*?)(?:["'])[^<>]*>)/i, options[:highlighter])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Reports the approximate distance in time between two Time or Date objects or integers as seconds.
|
|
||||||
# Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs
|
|
||||||
# Distances are reported based on the following table:
|
|
||||||
#
|
|
||||||
# 0 <-> 29 secs # => less than a minute
|
|
||||||
# 30 secs <-> 1 min, 29 secs # => 1 minute
|
|
||||||
# 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
|
|
||||||
# 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
|
|
||||||
# 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
|
|
||||||
# 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day
|
|
||||||
# 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
|
|
||||||
# 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
|
|
||||||
# 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
|
|
||||||
# 1 yr <-> 1 yr, 3 months # => about 1 year
|
|
||||||
# 1 yr, 3 months <-> 1 yr, 9 months # => over 1 year
|
|
||||||
# 1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years
|
|
||||||
# 2 yrs <-> max time or date # => (same rules as 1 yr)
|
|
||||||
#
|
|
||||||
# With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds:
|
|
||||||
# 0-4 secs # => less than 5 seconds
|
|
||||||
# 5-9 secs # => less than 10 seconds
|
|
||||||
# 10-19 secs # => less than 20 seconds
|
|
||||||
# 20-39 secs # => half a minute
|
|
||||||
# 40-59 secs # => less than a minute
|
|
||||||
# 60-89 secs # => 1 minute
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# from_time = Time.now
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
|
|
||||||
# distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
|
|
||||||
# distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute
|
|
||||||
# distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute
|
|
||||||
# distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years
|
|
||||||
# distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years
|
|
||||||
#
|
|
||||||
# to_time = Time.now + 6.years + 19.days
|
|
||||||
# distance_of_time_in_words(from_time, to_time, true) # => about 6 years
|
|
||||||
# distance_of_time_in_words(to_time, from_time, true) # => about 6 years
|
|
||||||
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
|
|
||||||
#
|
|
||||||
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
|
|
||||||
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
|
||||||
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
|
||||||
distance_in_minutes = (((to_time.to_i - from_time.to_i).abs)/60).round
|
|
||||||
distance_in_seconds = ((to_time.to_i - from_time.to_i).abs).round
|
|
||||||
|
|
||||||
I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
|
|
||||||
case distance_in_minutes
|
|
||||||
when 0..1
|
|
||||||
return distance_in_minutes == 0 ?
|
|
||||||
locale.t(:less_than_x_minutes, :count => 1) :
|
|
||||||
locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds
|
|
||||||
|
|
||||||
case distance_in_seconds
|
|
||||||
when 0..4 then locale.t :less_than_x_seconds, :count => 5
|
|
||||||
when 5..9 then locale.t :less_than_x_seconds, :count => 10
|
|
||||||
when 10..19 then locale.t :less_than_x_seconds, :count => 20
|
|
||||||
when 20..39 then locale.t :half_a_minute
|
|
||||||
when 40..59 then locale.t :less_than_x_minutes, :count => 1
|
|
||||||
else locale.t :x_minutes, :count => 1
|
|
||||||
end
|
|
||||||
|
|
||||||
when 2..44 then locale.t :x_minutes, :count => distance_in_minutes
|
|
||||||
when 45..89 then locale.t :about_x_hours, :count => 1
|
|
||||||
when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
|
|
||||||
when 1440..2529 then locale.t :x_days, :count => 1
|
|
||||||
when 2530..43199 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round
|
|
||||||
when 43200..86399 then locale.t :about_x_months, :count => 1
|
|
||||||
when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
|
|
||||||
else
|
|
||||||
distance_in_years = distance_in_minutes / 525600
|
|
||||||
minute_offset_for_leap_year = (distance_in_years / 4) * 1440
|
|
||||||
remainder = ((distance_in_minutes - minute_offset_for_leap_year) % 525600)
|
|
||||||
if remainder < 131400
|
|
||||||
locale.t(:about_x_years, :count => distance_in_years)
|
|
||||||
elsif remainder < 394200
|
|
||||||
locale.t(:over_x_years, :count => distance_in_years)
|
|
||||||
else
|
|
||||||
locale.t(:almost_x_years, :count => distance_in_years + 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
|
|
||||||
#
|
|
||||||
# ==== Examples
|
|
||||||
#
|
|
||||||
# time_ago_in_words(3.minutes.from_now) # => 3 minutes
|
|
||||||
# time_ago_in_words(Time.now - 15.hours) # => 15 hours
|
|
||||||
# time_ago_in_words(Time.now) # => less than a minute
|
|
||||||
#
|
|
||||||
# from_time = Time.now - 3.days - 14.minutes - 25.seconds # => 3 days
|
|
||||||
#
|
|
||||||
def time_ago_in_words(from_time, include_seconds = false)
|
|
||||||
distance_of_time_in_words(from_time, Time.now, include_seconds)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Used in xxxx.js.erb files to escape html so that it can be passed to javascript from Padrino
|
|
||||||
#
|
|
||||||
# js_escape_html("<h1>Hey</h1>")
|
|
||||||
#
|
|
||||||
def js_escape_html(html_content)
|
|
||||||
return '' unless html_content
|
|
||||||
javascript_mapping = { '\\' => '\\\\', '</' => '<\/', "\r\n" => '\n', "\n" => '\n', "\r" => '\n', '"' => '\\"', "'" => "\\'" }
|
|
||||||
html_content.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { javascript_mapping[$1] }
|
|
||||||
end
|
|
||||||
end # FormatHelpers
|
|
||||||
end # Helpers
|
|
||||||
end # Padrino
|
|
|
@ -1,103 +0,0 @@
|
||||||
cz:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: ","
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: " "
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%n %u"
|
|
||||||
unit: "Kč"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator: ","
|
|
||||||
# delimiter: " "
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "půl minutou"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "asi před sekundou"
|
|
||||||
other: "asi před %{count} sekundami"
|
|
||||||
x_seconds:
|
|
||||||
one: "sekundou"
|
|
||||||
other: "%{count} sekundami"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "před necelou minutou"
|
|
||||||
other: "před ani ne %{count} minutami"
|
|
||||||
x_minutes:
|
|
||||||
one: "minutou"
|
|
||||||
other: "%{count} minutami"
|
|
||||||
about_x_hours:
|
|
||||||
one: "asi hodinou"
|
|
||||||
other: "asi %{count} hodinami"
|
|
||||||
x_days:
|
|
||||||
one: "24 hodinami"
|
|
||||||
other: "%{count} dny"
|
|
||||||
about_x_months:
|
|
||||||
one: "asi měsícem"
|
|
||||||
other: "asi %{count} měsíci"
|
|
||||||
x_months:
|
|
||||||
one: "měsícem"
|
|
||||||
other: "%{count} měsíci"
|
|
||||||
about_x_years:
|
|
||||||
one: "asi rokem"
|
|
||||||
other: "asi %{count} roky"
|
|
||||||
over_x_years:
|
|
||||||
one: "více než před rokem"
|
|
||||||
other: "více než %{count} roky"
|
|
||||||
almost_x_years:
|
|
||||||
one: "skoro rokem"
|
|
||||||
other: "almost %{count} roků"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "Při ukládání %{model} došlo k chybě a nebylo jej možné uložit"
|
|
||||||
other: "Při ukládání %{model} došlo ke %{count} chybám a nebylo možné jej uložit"
|
|
||||||
body: "Následující pole obsahují chybně vyplněné údaje:"
|
|
|
@ -1,91 +0,0 @@
|
||||||
da:
|
|
||||||
number:
|
|
||||||
format:
|
|
||||||
separator: ","
|
|
||||||
delimiter: "."
|
|
||||||
precision: 3
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
format: "%u %n"
|
|
||||||
unit: "DKK"
|
|
||||||
separator: ","
|
|
||||||
delimiter: "."
|
|
||||||
precision: 2
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "et halvt minut"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "mindre end et sekund"
|
|
||||||
other: "mindre end %{count} sekunder"
|
|
||||||
x_seconds:
|
|
||||||
one: "et sekund"
|
|
||||||
other: "%{count} sekunder"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "mindre end et minut"
|
|
||||||
other: "mindre end %{count} minutter"
|
|
||||||
x_minutes:
|
|
||||||
one: "et minut"
|
|
||||||
other: "%{count} minutter"
|
|
||||||
about_x_hours:
|
|
||||||
one: "cirka en time"
|
|
||||||
other: "cirka %{count} timer"
|
|
||||||
x_days:
|
|
||||||
one: "en dag"
|
|
||||||
other: "%{count} dage"
|
|
||||||
about_x_months:
|
|
||||||
one: "cirka en måned"
|
|
||||||
other: "cirka %{count} måneder"
|
|
||||||
x_months:
|
|
||||||
one: "en måned"
|
|
||||||
other: "%{count} måneder"
|
|
||||||
about_x_years:
|
|
||||||
one: "cirka et år"
|
|
||||||
other: "cirka %{count} år"
|
|
||||||
over_x_years:
|
|
||||||
one: "mere end et år"
|
|
||||||
other: "mere end %{count} år"
|
|
||||||
almost_x_years:
|
|
||||||
one: "næsten et år"
|
|
||||||
other: "næsten %{count} years"
|
|
||||||
prompts:
|
|
||||||
second: "Sekund"
|
|
||||||
minute: "Minut"
|
|
||||||
hour: "Time"
|
|
||||||
day: "Dag"
|
|
||||||
month: "Måned"
|
|
||||||
year: "År"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "En fejl forhindrede %{model} i at blive gemt"
|
|
||||||
other: "%{count} fejl forhindrede denne %{model} i at blive gemt"
|
|
||||||
body: "Der var problemer med følgende felter:"
|
|
|
@ -1,78 +0,0 @@
|
||||||
de:
|
|
||||||
number:
|
|
||||||
format:
|
|
||||||
precision: 2
|
|
||||||
separator: ','
|
|
||||||
delimiter: '.'
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
unit: '€'
|
|
||||||
format: '%n%u'
|
|
||||||
separator:
|
|
||||||
delimiter:
|
|
||||||
precision:
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: 'eine halbe Minute'
|
|
||||||
less_than_x_seconds:
|
|
||||||
zero: 'weniger als 1 Sekunde'
|
|
||||||
one: 'weniger als 1 Sekunde'
|
|
||||||
other: 'weniger als %{count} Sekunden'
|
|
||||||
x_seconds:
|
|
||||||
one: '1 Sekunde'
|
|
||||||
other: '%{count} Sekunden'
|
|
||||||
less_than_x_minutes:
|
|
||||||
zero: 'weniger als 1 Minute'
|
|
||||||
one: 'weniger als 1 Minute'
|
|
||||||
other: 'weniger als %{count} Minuten'
|
|
||||||
x_minutes:
|
|
||||||
one: '1 Minute'
|
|
||||||
other: '%{count} Minuten'
|
|
||||||
about_x_hours:
|
|
||||||
one: 'etwa 1 Stunde'
|
|
||||||
other: 'etwa %{count} Stunden'
|
|
||||||
x_days:
|
|
||||||
one: '1 Tag'
|
|
||||||
other: '%{count} Tage'
|
|
||||||
about_x_months:
|
|
||||||
one: 'etwa 1 Monat'
|
|
||||||
other: 'etwa %{count} Monate'
|
|
||||||
x_months:
|
|
||||||
one: '1 Monat'
|
|
||||||
other: '%{count} Monate'
|
|
||||||
about_x_years:
|
|
||||||
one: 'etwa 1 Jahr'
|
|
||||||
other: 'etwa %{count} Jahre'
|
|
||||||
over_x_years:
|
|
||||||
one: 'mehr als 1 Jahr'
|
|
||||||
other: 'mehr als %{count} Jahre'
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 Fehler verhindert, dass Objekt %{model} gesichert werden kann"
|
|
||||||
other: "%{count} Fehler verhindern, dass Objekt %{model} gesichert werden kann"
|
|
||||||
body: "Es existieren Probleme mit den folgenden Feldern:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
en:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: "."
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: ","
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%u%n"
|
|
||||||
unit: "$"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: "."
|
|
||||||
delimiter: ","
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "half a minute"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "less than 1 second"
|
|
||||||
other: "less than %{count} seconds"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 second"
|
|
||||||
other: "%{count} seconds"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "less than a minute"
|
|
||||||
other: "less than %{count} minutes"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 minute"
|
|
||||||
other: "%{count} minutes"
|
|
||||||
about_x_hours:
|
|
||||||
one: "about 1 hour"
|
|
||||||
other: "about %{count} hours"
|
|
||||||
x_days:
|
|
||||||
one: "1 day"
|
|
||||||
other: "%{count} days"
|
|
||||||
about_x_months:
|
|
||||||
one: "about 1 month"
|
|
||||||
other: "about %{count} months"
|
|
||||||
x_months:
|
|
||||||
one: "1 month"
|
|
||||||
other: "%{count} months"
|
|
||||||
about_x_years:
|
|
||||||
one: "about 1 year"
|
|
||||||
other: "about %{count} years"
|
|
||||||
over_x_years:
|
|
||||||
one: "over 1 year"
|
|
||||||
other: "over %{count} years"
|
|
||||||
almost_x_years:
|
|
||||||
one: "almost 1 year"
|
|
||||||
other: "almost %{count} years"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 error prohibited this %{model} from being saved"
|
|
||||||
other: "%{count} errors prohibited this %{model} from being saved"
|
|
||||||
body: "There were problems with the following fields:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
es:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: "."
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: ","
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%u%n"
|
|
||||||
unit: "$"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: "."
|
|
||||||
delimiter: ","
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "medio minuto"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "menos de un segundo"
|
|
||||||
other: "menos de %{count} segundos"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 segundo"
|
|
||||||
other: "%{count} segundos"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "menos de un minuto"
|
|
||||||
other: "menos de %{count} minutos"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 minuto"
|
|
||||||
other: "%{count} minutos"
|
|
||||||
about_x_hours:
|
|
||||||
one: "hace 1 hora"
|
|
||||||
other: "hace %{count} horas"
|
|
||||||
x_days:
|
|
||||||
one: "1 día"
|
|
||||||
other: "%{count} días"
|
|
||||||
about_x_months:
|
|
||||||
one: "hace 1 mes"
|
|
||||||
other: "hace %{count} meses"
|
|
||||||
x_months:
|
|
||||||
one: "1 mes"
|
|
||||||
other: "%{count} meses"
|
|
||||||
about_x_years:
|
|
||||||
one: "hace 1 año"
|
|
||||||
other: "hace %{count} años"
|
|
||||||
over_x_years:
|
|
||||||
one: "hace más de 1 año"
|
|
||||||
other: "hace más de %{count} años"
|
|
||||||
almost_x_years:
|
|
||||||
one: "casi 1 año"
|
|
||||||
other: "casi %{count} años"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 error impidió que %{model} se guardara"
|
|
||||||
other: "%{count} erroress impidieron que %{model} se guardara"
|
|
||||||
body: "Hay problemas con los siguientes campos:"
|
|
|
@ -1,79 +0,0 @@
|
||||||
fr:
|
|
||||||
number:
|
|
||||||
format:
|
|
||||||
precision: 2
|
|
||||||
separator: ','
|
|
||||||
delimiter: '.'
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
unit: '€'
|
|
||||||
format: '%n%u'
|
|
||||||
separator:
|
|
||||||
delimiter:
|
|
||||||
precision:
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "une demi minute"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "infèrieur à une seconde"
|
|
||||||
other: "infèrieur à %{count} secondes"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 seconde"
|
|
||||||
other: "%{count} secondes"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "infèrieur à 1 minute"
|
|
||||||
other: "infèrieur à %{count} minutes"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 minute"
|
|
||||||
other: "%{count} minutes"
|
|
||||||
about_x_hours:
|
|
||||||
one: "environ 1 heure"
|
|
||||||
other: "environ %{count} heures"
|
|
||||||
x_days:
|
|
||||||
one: "1 jour"
|
|
||||||
other: "%{count} jours"
|
|
||||||
about_x_months:
|
|
||||||
one: "environ 1 mois"
|
|
||||||
other: "environ %{count} mois"
|
|
||||||
x_months:
|
|
||||||
one: "1 mois"
|
|
||||||
other: "%{count} mois"
|
|
||||||
about_x_years:
|
|
||||||
one: "environ 1 ans"
|
|
||||||
other: "environ %{count} ans"
|
|
||||||
over_x_years:
|
|
||||||
one: "plus d'un an"
|
|
||||||
other: "plus de %{count} ans"
|
|
||||||
almost_x_years:
|
|
||||||
one: "près d'un ans"
|
|
||||||
other: "près de %{count} years"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 erreur a empêché ce %{model} d'être sauvé"
|
|
||||||
other: "%{count} erreurs ont empêché ce %{model} d'être sauvé"
|
|
||||||
body: "Il y avait des problèmes avec les champs suivants:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
hu:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: ","
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: "."
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%n %u"
|
|
||||||
unit: "Ft"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: ","
|
|
||||||
delimiter: "."
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "byte"
|
|
||||||
other: "byte"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "fél perc"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "kevesebb, mint egy másodperc"
|
|
||||||
other: "kevesebb, mint %{count} másodperc"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 másodperc"
|
|
||||||
other: "%{count} másodperc"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "kevesebb, mint egy perc"
|
|
||||||
other: "kevesebb, mint %{count} perc"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 perc"
|
|
||||||
other: "%{count} perc"
|
|
||||||
about_x_hours:
|
|
||||||
one: "nagyjából 1 óra"
|
|
||||||
other: "nagyjából %{count} óra"
|
|
||||||
x_days:
|
|
||||||
one: "1 nap"
|
|
||||||
other: "%{count} nap"
|
|
||||||
about_x_months:
|
|
||||||
one: "nagyjából 1 hónap"
|
|
||||||
other: "nagyjából %{count} hónap"
|
|
||||||
x_months:
|
|
||||||
one: "1 hónap"
|
|
||||||
other: "%{count} hónap"
|
|
||||||
about_x_years:
|
|
||||||
one: "nagyjából 1 év"
|
|
||||||
other: "nagyjából %{count} év"
|
|
||||||
over_x_years:
|
|
||||||
one: "több, mint 1 év"
|
|
||||||
other: "több, mint %{count} év"
|
|
||||||
almost_x_years:
|
|
||||||
one: "majdnem 1 év"
|
|
||||||
other: "majdnem %{count} év"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 hiba akadályozza a(z) %{model} mentését"
|
|
||||||
other: "%{count} hiba akadályozza a(z) %{model} mentését"
|
|
||||||
body: "A következő mezőkkel van baj:"
|
|
|
@ -1,85 +0,0 @@
|
||||||
it:
|
|
||||||
number:
|
|
||||||
format:
|
|
||||||
separator: ","
|
|
||||||
delimiter: "."
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
format: "%n %u"
|
|
||||||
unit: "€"
|
|
||||||
separator: "."
|
|
||||||
delimiter: ","
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "mezzo minuto"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "meno di un secondo"
|
|
||||||
other: "meno di %{count} secondi"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 secondo"
|
|
||||||
other: "%{count} secondi"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "meno di un minuto"
|
|
||||||
other: "meno di %{count} minuti"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 minuto"
|
|
||||||
other: "%{count} minuti"
|
|
||||||
about_x_hours:
|
|
||||||
one: "circa un'ora"
|
|
||||||
other: "circa %{count} ore"
|
|
||||||
x_days:
|
|
||||||
one: "1 giorno"
|
|
||||||
other: "%{count} giorni"
|
|
||||||
about_x_months:
|
|
||||||
one: "circa un mese"
|
|
||||||
other: "circa %{count} mesi"
|
|
||||||
x_months:
|
|
||||||
one: "1 mese"
|
|
||||||
other: "%{count} mesi"
|
|
||||||
about_x_years:
|
|
||||||
one: "circa un anno"
|
|
||||||
other: "circa %{count} anni"
|
|
||||||
over_x_years:
|
|
||||||
one: "oltre un anno"
|
|
||||||
other: "oltre %{count} anni"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "Non posso salvare questo %{model}: 1 errore"
|
|
||||||
other: "Non posso salvare questo %{model}: %{count} errori."
|
|
||||||
body: "Per favore ricontrolla i seguenti campi:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
ja:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: "."
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: ","
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%u%n"
|
|
||||||
unit: "¥"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: "."
|
|
||||||
delimiter: ","
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "30秒"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "1 秒以内"
|
|
||||||
other: "%{count} 秒以内"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 秒"
|
|
||||||
other: "%{count} 秒"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "1分以内"
|
|
||||||
other: "%{count} 分以内"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 分"
|
|
||||||
other: "%{count} 分"
|
|
||||||
about_x_hours:
|
|
||||||
one: "およそ 1 時間"
|
|
||||||
other: "およそ %{count} 時間"
|
|
||||||
x_days:
|
|
||||||
one: "1 日"
|
|
||||||
other: "%{count} 日"
|
|
||||||
about_x_months:
|
|
||||||
one: "およそ 1 ヶ月"
|
|
||||||
other: "およそ %{count} ヶ月"
|
|
||||||
x_months:
|
|
||||||
one: "1 ヶ月"
|
|
||||||
other: "%{count} ヶ月"
|
|
||||||
about_x_years:
|
|
||||||
one: "およそ 1 年"
|
|
||||||
other: "およそ %{count} 年"
|
|
||||||
over_x_years:
|
|
||||||
one: "1 年以上"
|
|
||||||
other: "%{count} 年以上"
|
|
||||||
almost_x_years:
|
|
||||||
one: "ほぼ 1 年"
|
|
||||||
other: "ほぼ %{count} 年"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 つのエラーにより、 %{model} をセーブできませんでした"
|
|
||||||
other: "%{count} つのエラーにより、 %{model} をセーブできませんでした"
|
|
||||||
body: "以下のフィールドにエラーが存在します:"
|
|
|
@ -1,78 +0,0 @@
|
||||||
nl:
|
|
||||||
number:
|
|
||||||
format:
|
|
||||||
precision: 2
|
|
||||||
separator: ','
|
|
||||||
delimiter: '.'
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
unit: '€'
|
|
||||||
format: '%u %n'
|
|
||||||
separator:
|
|
||||||
delimiter:
|
|
||||||
precision:
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "byte"
|
|
||||||
other: "bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: 'een halve minuut'
|
|
||||||
less_than_x_seconds:
|
|
||||||
zero: 'minder dan 1 seconde'
|
|
||||||
one: 'minder dan 1 seconde'
|
|
||||||
other: 'minder dan %{count} seconden'
|
|
||||||
x_seconds:
|
|
||||||
one: '1 seconde'
|
|
||||||
other: '%{count} seconden'
|
|
||||||
less_than_x_minutes:
|
|
||||||
zero: 'minder dan 1 minuut'
|
|
||||||
one: 'minder dan 1 minuut'
|
|
||||||
other: 'minder dan %{count} minuten'
|
|
||||||
x_minutes:
|
|
||||||
one: '1 minuut'
|
|
||||||
other: '%{count} minuten'
|
|
||||||
about_x_hours:
|
|
||||||
one: 'ongeveer 1 uur'
|
|
||||||
other: 'ongeveer %{count} uur'
|
|
||||||
x_days:
|
|
||||||
one: '1 dag'
|
|
||||||
other: '%{count} dagen'
|
|
||||||
about_x_months:
|
|
||||||
one: 'ongeveer 1 dag'
|
|
||||||
other: 'ongeveer %{count} dagen'
|
|
||||||
x_months:
|
|
||||||
one: '1 maand'
|
|
||||||
other: '%{count} maanden'
|
|
||||||
about_x_years:
|
|
||||||
one: 'ongeveer 1 jaar'
|
|
||||||
other: 'ongeveer %{count} jaar'
|
|
||||||
over_x_years:
|
|
||||||
one: 'meer dan 1 jaar'
|
|
||||||
other: 'meer dan %{count} jaar'
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 fout verhindert het opslaan van dit %{model} object"
|
|
||||||
other: "%{count} fouten verhinderen het opslaan van dit %{model} object"
|
|
||||||
body: "Controleer alstublieft de volgende velden:"
|
|
|
@ -1,91 +0,0 @@
|
||||||
"no":
|
|
||||||
number:
|
|
||||||
format:
|
|
||||||
separator: ","
|
|
||||||
delimiter: "."
|
|
||||||
precision: 3
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
format: "%u %n"
|
|
||||||
unit: "NOK"
|
|
||||||
separator: ","
|
|
||||||
delimiter: "."
|
|
||||||
precision: 2
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "et halvt minutt"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "mindre enn et sekund"
|
|
||||||
other: "mindre enn %{count} sekunder"
|
|
||||||
x_seconds:
|
|
||||||
one: "ett sekund"
|
|
||||||
other: "%{count} sekunder"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "mindre enn et minutt"
|
|
||||||
other: "mindre enn %{count} minutter"
|
|
||||||
x_minutes:
|
|
||||||
one: "ett minutt"
|
|
||||||
other: "%{count} minutter"
|
|
||||||
about_x_hours:
|
|
||||||
one: "cirka en time"
|
|
||||||
other: "cirka %{count} timer"
|
|
||||||
x_days:
|
|
||||||
one: "en dag"
|
|
||||||
other: "%{count} dager"
|
|
||||||
about_x_months:
|
|
||||||
one: "cirka en måned"
|
|
||||||
other: "cirka %{count} måneder"
|
|
||||||
x_months:
|
|
||||||
one: "en måned"
|
|
||||||
other: "%{count} måneder"
|
|
||||||
about_x_years:
|
|
||||||
one: "cirka et år"
|
|
||||||
other: "cirka %{count} år"
|
|
||||||
over_x_years:
|
|
||||||
one: "mer enn ett år"
|
|
||||||
other: "mer enn %{count} år"
|
|
||||||
almost_x_years:
|
|
||||||
one: "nesten et år"
|
|
||||||
other: "nesten %{count} år"
|
|
||||||
prompts:
|
|
||||||
second: "Sekund"
|
|
||||||
minute: "Minutt"
|
|
||||||
hour: "Time"
|
|
||||||
day: "Dag"
|
|
||||||
month: "Måned"
|
|
||||||
year: "År"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "En feil forhindrer %{model} å bli lagret"
|
|
||||||
other: "%{count} feil forhindrer denne %{model} i å bli lagret"
|
|
||||||
body: "Det er problemer med følgende felter:"
|
|
|
@ -1,95 +0,0 @@
|
||||||
pl:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
separator: ","
|
|
||||||
delimiter: " "
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
format: "%n %u"
|
|
||||||
unit: "PLN"
|
|
||||||
separator: ","
|
|
||||||
delimiter: " "
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "bajt"
|
|
||||||
other: "bajty"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "pół minuty"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "mniej niż sekundę"
|
|
||||||
few: "mniej niż %{count} sekundy"
|
|
||||||
other: "mniej niż %{count} sekund"
|
|
||||||
x_seconds:
|
|
||||||
one: "sekundę"
|
|
||||||
few: "%{count} sekundy"
|
|
||||||
other: "%{count} sekund"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "mniej niż minutę"
|
|
||||||
few: "mniej niż %{count} minuty"
|
|
||||||
other: "mniej niż %{count} minut"
|
|
||||||
x_minutes:
|
|
||||||
one: "minutę"
|
|
||||||
few: "%{count} minuty"
|
|
||||||
other: "%{count} minut"
|
|
||||||
about_x_hours:
|
|
||||||
one: "około godziny"
|
|
||||||
other: "około %{count} godzin"
|
|
||||||
x_days:
|
|
||||||
one: "1 dzień"
|
|
||||||
other: "%{count} dni"
|
|
||||||
about_x_months:
|
|
||||||
one: "około miesiąca"
|
|
||||||
other: "około %{count} miesięcy"
|
|
||||||
x_months:
|
|
||||||
one: "1 miesiąc"
|
|
||||||
few: "%{count} miesiące"
|
|
||||||
other: "%{count} miesięcy"
|
|
||||||
about_x_years:
|
|
||||||
one: "około roku"
|
|
||||||
other: "około %{count} lat"
|
|
||||||
almost_x_years:
|
|
||||||
one: "prawie rok"
|
|
||||||
few: "prawie %{count} lata"
|
|
||||||
other: "prawie %{count} lat"
|
|
||||||
over_x_years:
|
|
||||||
one: "ponad rok"
|
|
||||||
few: "ponad %{count} lata"
|
|
||||||
other: "ponad %{count} lat"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "%{model} nie został zachowany z powodu jednego błędu"
|
|
||||||
other: "%{model} nie został zachowany z powodu %{count} błędów"
|
|
||||||
body: "Błędy dotyczą następujących pól:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
pt_br:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: ","
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: "."
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%u%n"
|
|
||||||
unit: "R$"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: "."
|
|
||||||
delimiter: ","
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "meio minuto"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "menos de 1 segundo"
|
|
||||||
other: "menos de %{count} segundos"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 segundo"
|
|
||||||
other: "%{count} segundos"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "menos de 1 minuto"
|
|
||||||
other: "menos de %{count} minutos"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 minuto"
|
|
||||||
other: "%{count} minutos"
|
|
||||||
about_x_hours:
|
|
||||||
one: "cerca de 1 hora"
|
|
||||||
other: "cerca de %{count} horas"
|
|
||||||
x_days:
|
|
||||||
one: "1 dia"
|
|
||||||
other: "%{count} dias"
|
|
||||||
about_x_months:
|
|
||||||
one: "cerca de 1 mês"
|
|
||||||
other: "cerca de %{count} meses"
|
|
||||||
x_months:
|
|
||||||
one: "1 mês"
|
|
||||||
other: "%{count} meses"
|
|
||||||
about_x_years:
|
|
||||||
one: "cerca de 1 ano"
|
|
||||||
other: "cerca de %{count} anos"
|
|
||||||
over_x_years:
|
|
||||||
one: "mais de 1 ano"
|
|
||||||
other: "mais de %{count} anos"
|
|
||||||
almost_x_years:
|
|
||||||
one: "quase 1 ano"
|
|
||||||
other: "quase %{count} anos"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "Não posso salvar %{model}: 1 erro"
|
|
||||||
other: "Não posso salvar %{model}: %{count} erros."
|
|
||||||
body: "Por favor, verifique novamente os seguintes campos:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
ru:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: ","
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: ""
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%n %u"
|
|
||||||
unit: "руб"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: ","
|
|
||||||
delimiter: " "
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Байт"
|
|
||||||
other: "Байт"
|
|
||||||
kb: "Кб"
|
|
||||||
mb: "Мб"
|
|
||||||
gb: "Гб"
|
|
||||||
tb: "Тб"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "пол минуты"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "менее секунды"
|
|
||||||
other: "менее %{count} секунд"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 секунда"
|
|
||||||
other: "%{count} секунд"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "менее минуты"
|
|
||||||
other: "менее %{count} минут"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 минута"
|
|
||||||
other: "%{count} минут"
|
|
||||||
about_x_hours:
|
|
||||||
one: "около часа"
|
|
||||||
other: "около %{count} часов"
|
|
||||||
x_days:
|
|
||||||
one: "1 день"
|
|
||||||
other: "%{count} дней"
|
|
||||||
about_x_months:
|
|
||||||
one: "около месяца"
|
|
||||||
other: "около %{count} месяцев"
|
|
||||||
x_months:
|
|
||||||
one: "1 месяц"
|
|
||||||
other: "%{count} месяцев"
|
|
||||||
about_x_years:
|
|
||||||
one: "около года"
|
|
||||||
other: "около %{count} лет"
|
|
||||||
over_x_years:
|
|
||||||
one: "более года"
|
|
||||||
other: "более %{count} лет"
|
|
||||||
almost_x_years:
|
|
||||||
one: "почти год"
|
|
||||||
other: "почти %{count} года"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "Данные «%{model}» не могут быть сохранены из-за 1 ошибки"
|
|
||||||
other: "Данные «%{model}» не могут быть сохранены из-за %{count} ошибок"
|
|
||||||
body: "Допущены ошибки в следующих полях:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
tr:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: "."
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: ","
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%n%u"
|
|
||||||
unit: "TL"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: "."
|
|
||||||
delimiter: ","
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "30 saniye"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "1 saniyeden az"
|
|
||||||
other: "%{count} saniyeden az"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 saniye"
|
|
||||||
other: "%{count} saniye"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "bir dakikadan az"
|
|
||||||
other: "%{count} dakikadan az"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 dakika"
|
|
||||||
other: "%{count} dakika"
|
|
||||||
about_x_hours:
|
|
||||||
one: "yaklaşık 1 saat"
|
|
||||||
other: "yaklaşık %{count} saat"
|
|
||||||
x_days:
|
|
||||||
one: "1 gün"
|
|
||||||
other: "%{count} gün"
|
|
||||||
about_x_months:
|
|
||||||
one: "yaklaşık 1 ay"
|
|
||||||
other: "yaklaşık %{count} ay"
|
|
||||||
x_months:
|
|
||||||
one: "1 ay"
|
|
||||||
other: "%{count} ay"
|
|
||||||
about_x_years:
|
|
||||||
one: "yaklaşık 1 yıl"
|
|
||||||
other: "yaklaşık %{count} yıl"
|
|
||||||
over_x_years:
|
|
||||||
one: "1 yıldan fazla"
|
|
||||||
other: "%{count} yıldan fazla"
|
|
||||||
almost_x_years:
|
|
||||||
one: "neredeyse 1 yıl"
|
|
||||||
other: "neredeyse %{count} yıl"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "1 hata oluştu; %{model} kaydedilemedi"
|
|
||||||
other: "%{count} hata oluştu; %{model} kaydedilemedi"
|
|
||||||
body: "Hata oluşan alanlar:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
uk:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: ","
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: ""
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%n %u"
|
|
||||||
unit: "грн"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: ","
|
|
||||||
delimiter: " "
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Байт"
|
|
||||||
other: "Байт"
|
|
||||||
kb: "Кб"
|
|
||||||
mb: "Мб"
|
|
||||||
gb: "Гб"
|
|
||||||
tb: "Тб"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "півхвилини"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "менше секунди"
|
|
||||||
other: "менше %{count} секунд"
|
|
||||||
x_seconds:
|
|
||||||
one: "1 секунда"
|
|
||||||
other: "%{count} секунд"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "менше хвилини"
|
|
||||||
other: "менше %{count} хвилин"
|
|
||||||
x_minutes:
|
|
||||||
one: "1 хвилина"
|
|
||||||
other: "%{count} хвилин"
|
|
||||||
about_x_hours:
|
|
||||||
one: "близько години"
|
|
||||||
other: "близько %{count} годин"
|
|
||||||
x_days:
|
|
||||||
one: "1 день"
|
|
||||||
other: "%{count} днів"
|
|
||||||
about_x_months:
|
|
||||||
one: "близько місяця"
|
|
||||||
other: "близько %{count} місяців"
|
|
||||||
x_months:
|
|
||||||
one: "1 місяць"
|
|
||||||
other: "%{count} месяців"
|
|
||||||
about_x_years:
|
|
||||||
one: "близько року"
|
|
||||||
other: "близько %{count} років"
|
|
||||||
over_x_years:
|
|
||||||
one: "більше року"
|
|
||||||
other: "більше %{count} років"
|
|
||||||
almost_x_years:
|
|
||||||
one: "майже рік"
|
|
||||||
other: "майжу %{count} роки"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "Дані «%{model}» не можуть бути збережені через 1 помилки"
|
|
||||||
other: "Дані «%{model}» не можуть бути збережені через %{count} помилок"
|
|
||||||
body: "Допущені помилки в наступних полях:"
|
|
|
@ -1,103 +0,0 @@
|
||||||
zh_cn:
|
|
||||||
number:
|
|
||||||
# Used in number_with_delimiter()
|
|
||||||
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
|
|
||||||
format:
|
|
||||||
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
|
|
||||||
separator: "."
|
|
||||||
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
|
|
||||||
delimiter: ","
|
|
||||||
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
|
|
||||||
precision: 3
|
|
||||||
|
|
||||||
# Used in number_to_currency()
|
|
||||||
currency:
|
|
||||||
format:
|
|
||||||
# Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
|
|
||||||
format: "%u %n"
|
|
||||||
unit: "元"
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
separator: "."
|
|
||||||
delimiter: ","
|
|
||||||
precision: 2
|
|
||||||
|
|
||||||
# Used in number_to_percentage()
|
|
||||||
percentage:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_precision()
|
|
||||||
precision:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
# precision:
|
|
||||||
|
|
||||||
# Used in number_to_human_size()
|
|
||||||
human:
|
|
||||||
format:
|
|
||||||
# These three are to override number.format and are optional
|
|
||||||
# separator:
|
|
||||||
delimiter: ""
|
|
||||||
precision: 1
|
|
||||||
storage_units:
|
|
||||||
# Storage units output formatting.
|
|
||||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
|
||||||
format: "%n %u"
|
|
||||||
units:
|
|
||||||
byte:
|
|
||||||
one: "Byte"
|
|
||||||
other: "Bytes"
|
|
||||||
kb: "KB"
|
|
||||||
mb: "MB"
|
|
||||||
gb: "GB"
|
|
||||||
tb: "TB"
|
|
||||||
|
|
||||||
# Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
|
|
||||||
datetime:
|
|
||||||
distance_in_words:
|
|
||||||
half_a_minute: "半分钟"
|
|
||||||
less_than_x_seconds:
|
|
||||||
one: "不到一秒"
|
|
||||||
other: "不到 %{count} 秒"
|
|
||||||
x_seconds:
|
|
||||||
one: "一秒"
|
|
||||||
other: "%{count} 秒"
|
|
||||||
less_than_x_minutes:
|
|
||||||
one: "不到一分钟"
|
|
||||||
other: "不到 %{count} 分钟"
|
|
||||||
x_minutes:
|
|
||||||
one: "一分钟"
|
|
||||||
other: "%{count} 分钟"
|
|
||||||
about_x_hours:
|
|
||||||
one: "大约一小时"
|
|
||||||
other: "大约 %{count} 小时"
|
|
||||||
x_days:
|
|
||||||
one: "一天"
|
|
||||||
other: "%{count} 天"
|
|
||||||
about_x_months:
|
|
||||||
one: "大约一个月"
|
|
||||||
other: "大约 %{count} 个月"
|
|
||||||
x_months:
|
|
||||||
one: "一个月"
|
|
||||||
other: "%{count} 个月"
|
|
||||||
about_x_years:
|
|
||||||
one: "大约一年"
|
|
||||||
other: "大约 %{count} 年"
|
|
||||||
over_x_years:
|
|
||||||
one: "一年多"
|
|
||||||
other: "%{count} 年多"
|
|
||||||
almost_x_years:
|
|
||||||
one: "接近一年"
|
|
||||||
other: "接近 %{count} 年"
|
|
||||||
models:
|
|
||||||
errors:
|
|
||||||
template:
|
|
||||||
header:
|
|
||||||
one: "有1 个错误发生使得「%{model}」无法被储存。 "
|
|
||||||
other: "有%{count} 个错误发生使得「%{model}」无法被储存。 "
|
|
||||||
body: "以下栏位发生问题:
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue