Merge remote-tracking branch 'origin/v3-stable'
Conflicts: CHANGELOG.md middleman-core/lib/middleman-core/core_extensions/rendering.rb middleman-core/lib/middleman-core/extensions.rb middleman-core/lib/middleman-core/version.rb middleman-core/lib/middleman-more/core_extensions/compass.rb middleman-core/lib/middleman-more/core_extensions/default_helpers.rb middleman-core/middleman-core.gemspec
This commit is contained in:
commit
7b46fd6524
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -3,13 +3,24 @@ master
|
||||||
|
|
||||||
* Asciidoc information now available with the `asciidoc` local, which is a normal hash.
|
* Asciidoc information now available with the `asciidoc` local, which is a normal hash.
|
||||||
* Remove `page` template local. Use `current_resource` instead.
|
* Remove `page` template local. Use `current_resource` instead.
|
||||||
* Dropped support for `page` & `proxy` blocks.
|
* Dropped support for providing a block to `page` & `proxy`.
|
||||||
* Dropped support for instance variables inside templates.
|
* Dropped support for instance variables inside templates.
|
||||||
* Moved all rendering into `TemplateRenderer` and `FileRenderer`
|
* Moved all rendering into `TemplateRenderer` and `FileRenderer`
|
||||||
* Placed all template evaluation inside the `TemplateContext` class
|
* Placed all template evaluation inside the `TemplateContext` class
|
||||||
* Remove deprecated `request` instance
|
* Remove deprecated `request` instance
|
||||||
* Remove old module-style extension support
|
* Remove old module-style extension support
|
||||||
* Placed all `config.rb` evaluation inside the `ConfigContext` class
|
* Placed all `config.rb` evaluation inside the `ConfigContext` class
|
||||||
|
* Update Padrino to 0.12.0. Introduces BREAKING CHANGE for Haml. Helpers which take blocks used to require `-` instead of `=` to work correctly. Now, all helpers which output content should use `=`. See: http://www.padrinorb.com/blog/upgrading-padrino-from-0-11-x-to-0-12-0-guide
|
||||||
|
* Depend on Erubis and remove support for specifying another ERb engine.
|
||||||
|
* Removed the ability to set the `sass_cache_path`.
|
||||||
|
|
||||||
|
3.2.2
|
||||||
|
===
|
||||||
|
|
||||||
|
* Specify the full path to the NEWLINE constant
|
||||||
|
* Refactor some internals which were dependent on certain order of operations
|
||||||
|
* Updated i18n dep
|
||||||
|
* Updated Uglifier dep
|
||||||
|
|
||||||
3.2.1
|
3.2.1
|
||||||
===
|
===
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -22,7 +22,7 @@ gem 'asciidoctor', :require => false
|
||||||
|
|
||||||
platforms :ruby do
|
platforms :ruby do
|
||||||
gem 'therubyracer'
|
gem 'therubyracer'
|
||||||
gem 'redcarpet', '~> 3.0'
|
gem 'redcarpet', '~> 3.1'
|
||||||
gem 'pry', :require => false, :group => :development
|
gem 'pry', :require => false, :group => :development
|
||||||
gem 'pry-debugger', :require => false, :group => :development
|
gem 'pry-debugger', :require => false, :group => :development
|
||||||
end
|
end
|
||||||
|
|
|
@ -64,6 +64,8 @@ module Middleman::Cli
|
||||||
opts[:glob] = options['glob'] if options.has_key?('glob')
|
opts[:glob] = options['glob'] if options.has_key?('glob')
|
||||||
opts[:clean] = options['clean']
|
opts[:clean] = options['clean']
|
||||||
|
|
||||||
|
self.class.shared_instance.run_hook :before_build, self
|
||||||
|
|
||||||
action BuildAction.new(self, opts)
|
action BuildAction.new(self, opts)
|
||||||
|
|
||||||
self.class.shared_instance.run_hook :after_build, self
|
self.class.shared_instance.run_hook :after_build, self
|
||||||
|
|
|
@ -34,7 +34,7 @@ module Middleman::Cli
|
||||||
config[:environment] = opts[:environment].to_sym
|
config[:environment] = opts[:environment].to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
logger(opts[:debug] ? 0 : 1, opts[:instrumenting] || false)
|
::Middleman::Logger.singleton(opts[:debug] ? 0 : 1, opts[:instrumenting] || false)
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: get file watcher / reload! working in console
|
# TODO: get file watcher / reload! working in console
|
||||||
|
|
|
@ -43,7 +43,7 @@ module Middleman::Cli
|
||||||
:desc => 'Skip Git ignores and keeps'
|
:desc => 'Skip Git ignores and keeps'
|
||||||
# The init task
|
# The init task
|
||||||
# @param [String] name
|
# @param [String] name
|
||||||
def init(name)
|
def init(name = '.')
|
||||||
key = options[:template].to_sym
|
key = options[:template].to_sym
|
||||||
unless ::Middleman::Templates.registered.has_key?(key)
|
unless ::Middleman::Templates.registered.has_key?(key)
|
||||||
raise Thor::Error.new "Unknown project template '#{key}'"
|
raise Thor::Error.new "Unknown project template '#{key}'"
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
# page "/admin/*"
|
# page "/admin/*"
|
||||||
# end
|
# end
|
||||||
|
|
||||||
# Proxy pages (http://middlemanapp.com/dynamic-pages/)
|
# Proxy pages (http://middlemanapp.com/basics/dynamic-pages/)
|
||||||
# proxy "/this-page-has-no-template.html", "/template-file.html", :locals => {
|
# proxy "/this-page-has-no-template.html", "/template-file.html", :locals => {
|
||||||
# :which_fake_page => "Rendering a fake page with a local variable" }
|
# :which_fake_page => "Rendering a fake page with a local variable" }
|
||||||
|
|
||||||
|
|
|
@ -15,19 +15,29 @@ Feature: Middleman CLI
|
||||||
| source/javascripts/all.js |
|
| source/javascripts/all.js |
|
||||||
| source/stylesheets/all.css |
|
| source/stylesheets/all.css |
|
||||||
| source/stylesheets/normalize.css |
|
| source/stylesheets/normalize.css |
|
||||||
|
|
||||||
|
Scenario: Create a new project in the current directory
|
||||||
|
Given a directory named "MY_PROJECT"
|
||||||
|
When I cd to "MY_PROJECT"
|
||||||
|
And I run `middleman init`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the following files should exist:
|
||||||
|
| Gemfile |
|
||||||
|
| config.rb |
|
||||||
|
| source/index.html.erb |
|
||||||
|
|
||||||
Scenario: Create a new project (alias i)
|
Scenario: Create a new project (alias i)
|
||||||
When I run `middleman i MY_PROJECT`
|
When I run `middleman i MY_PROJECT`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
|
||||||
Scenario: Create a new project (alias new)
|
Scenario: Create a new project (alias new)
|
||||||
When I run `middleman new MY_PROJECT`
|
When I run `middleman new MY_PROJECT`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
|
||||||
Scenario: Create a new project (alias n)
|
Scenario: Create a new project (alias n)
|
||||||
When I run `middleman n MY_PROJECT`
|
When I run `middleman n MY_PROJECT`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
|
||||||
Scenario: Create a new project with Rack
|
Scenario: Create a new project with Rack
|
||||||
When I run `middleman init MY_PROJECT --rack`
|
When I run `middleman init MY_PROJECT --rack`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
@ -36,7 +46,7 @@ Feature: Middleman CLI
|
||||||
| config.rb |
|
| config.rb |
|
||||||
| config.ru |
|
| config.ru |
|
||||||
| Gemfile |
|
| Gemfile |
|
||||||
|
|
||||||
Scenario: Create a new HTML5 project
|
Scenario: Create a new HTML5 project
|
||||||
When I run `middleman init MY_PROJECT --template=html5`
|
When I run `middleman init MY_PROJECT --template=html5`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
@ -54,7 +64,7 @@ Feature: Middleman CLI
|
||||||
| layouts/layout.erb |
|
| layouts/layout.erb |
|
||||||
| humans.txt |
|
| humans.txt |
|
||||||
| js/main.js |
|
| js/main.js |
|
||||||
|
|
||||||
Scenario: Create a new HTML5 project with Rack
|
Scenario: Create a new HTML5 project with Rack
|
||||||
When I run `middleman init MY_PROJECT --rack --template=html5`
|
When I run `middleman init MY_PROJECT --rack --template=html5`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
@ -63,7 +73,7 @@ Feature: Middleman CLI
|
||||||
| config.rb |
|
| config.rb |
|
||||||
| config.ru |
|
| config.ru |
|
||||||
| Gemfile |
|
| Gemfile |
|
||||||
|
|
||||||
Scenario: Create a new Mobile HTML5 project
|
Scenario: Create a new Mobile HTML5 project
|
||||||
When I run `middleman init MY_PROJECT --template=mobile`
|
When I run `middleman init MY_PROJECT --template=mobile`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
@ -79,7 +89,7 @@ Feature: Middleman CLI
|
||||||
| index.html |
|
| index.html |
|
||||||
| humans.txt |
|
| humans.txt |
|
||||||
| js/libs/respond.min.js |
|
| js/libs/respond.min.js |
|
||||||
|
|
||||||
Scenario: Create a new Mobile HTML5 project with Rack
|
Scenario: Create a new Mobile HTML5 project with Rack
|
||||||
When I run `middleman init MY_PROJECT --rack --template=mobile`
|
When I run `middleman init MY_PROJECT --rack --template=mobile`
|
||||||
Then a directory named "MY_PROJECT" should exist
|
Then a directory named "MY_PROJECT" should exist
|
||||||
|
|
|
@ -28,3 +28,11 @@ Feature: Layouts dir
|
||||||
When I go to "/index.html"
|
When I go to "/index.html"
|
||||||
Then I should see "contents of the layout"
|
Then I should see "contents of the layout"
|
||||||
|
|
||||||
|
Scenario: Prefer a layout in the layouts_dir to one with the same name in the root
|
||||||
|
Given a fixture app "layouts-dir-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
And the Server is running
|
||||||
|
When I go to "/ambiguous.html"
|
||||||
|
Then I should see "contents of the layout in layouts_dir"
|
||||||
|
|
|
@ -86,8 +86,8 @@ Feature: Markdown (Redcarpet) support
|
||||||
Then I should see "![dust mite](http://dust.mite/image.png)"
|
Then I should see "![dust mite](http://dust.mite/image.png)"
|
||||||
And I should not see "<img"
|
And I should not see "<img"
|
||||||
When I go to "/with_toc_data.html"
|
When I go to "/with_toc_data.html"
|
||||||
Then I should see 'id="toc_0"'
|
Then I should see 'id="first-header"'
|
||||||
And I should see 'id="toc_1"'
|
And I should see 'id="second-header"'
|
||||||
When I go to "/hard_wrap.html"
|
When I go to "/hard_wrap.html"
|
||||||
Then I should see "br"
|
Then I should see "br"
|
||||||
When I go to "/link.html"
|
When I go to "/link.html"
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
Feature: SASS .sass-cache custom location
|
|
||||||
|
|
||||||
Scenario: Using the default location for .sass-cache folder
|
|
||||||
Given the Server is running at "sass-cache-path-default-app"
|
|
||||||
|
|
||||||
When I go to "/stylesheets/plain.css"
|
|
||||||
Then I should see "color: blue;"
|
|
||||||
|
|
||||||
# TODO::
|
|
||||||
# Not sure how to test this location, as the directory is stored outside of the app root
|
|
||||||
# during testing, but inside app root in "production"
|
|
||||||
|
|
||||||
# Then a directory named ".sass-cache" should exist
|
|
||||||
|
|
||||||
|
|
||||||
Scenario: Using a custom location for .sass-cache folder
|
|
||||||
Given the Server is running at "sass-cache-path-custom-app"
|
|
||||||
|
|
||||||
When I go to "/stylesheets/plain.css"
|
|
||||||
Then I should see "html, body, div, span, applet, object, iframe,"
|
|
||||||
|
|
||||||
Then a directory named "/tmp/middleman-core-custom-sass_cache_path" should exist
|
|
|
@ -5,6 +5,5 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
- capture_html :from_template do
|
= capture_html :from_template do
|
||||||
%h1= "I am the yielded content haml"
|
%h1= "I am the yielded content haml"
|
||||||
|
|
||||||
%p I am in the template
|
%p I am in the template
|
|
@ -1,4 +1,4 @@
|
||||||
- content_for :from_template do
|
= content_for :from_template do
|
||||||
= "I am the yielded content haml <s>with html tags</s>"
|
= "I am the yielded content haml <s>with html tags</s>"
|
||||||
|
|
||||||
%p I am in the template
|
%p I am in the template
|
|
@ -1,2 +1 @@
|
||||||
<%= yield %>
|
<%= yield %> Override.
|
||||||
Override.
|
|
|
@ -1,2 +1 @@
|
||||||
<%= yield %>
|
<%= yield %> Override.
|
||||||
Override.
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
layout: other
|
||||||
|
---
|
||||||
|
|
||||||
|
Hello
|
|
@ -0,0 +1,3 @@
|
||||||
|
contents of the layout in layouts_dir
|
||||||
|
|
||||||
|
<%= yield %>
|
3
middleman-core/fixtures/layouts-dir-app/source/other.erb
Normal file
3
middleman-core/fixtures/layouts-dir-app/source/other.erb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
contents of the layout in the root
|
||||||
|
|
||||||
|
<%= yield %>
|
|
@ -1,2 +1,2 @@
|
||||||
- link_to "/" do
|
= link_to "/" do
|
||||||
%s haml with html tags
|
%s haml with html tags
|
|
@ -1,2 +1,2 @@
|
||||||
- link_to "/" do
|
= link_to "/" do
|
||||||
s slim with html tags
|
s slim with html tags
|
|
@ -1,3 +1,3 @@
|
||||||
- wrap_layout :outer_haml do
|
= wrap_layout :outer_haml do
|
||||||
Inner
|
Inner
|
||||||
= yield
|
= yield
|
|
@ -1,3 +1,3 @@
|
||||||
- wrap_layout :outer_slim do
|
= wrap_layout :outer_slim do
|
||||||
h3 Inner
|
h3 Inner
|
||||||
== yield
|
== yield
|
|
@ -1,3 +1,3 @@
|
||||||
- wrap_layout :master_haml do
|
= wrap_layout :master_haml do
|
||||||
Outer
|
Outer
|
||||||
= yield
|
= yield
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
- wrap_layout :master_slim do
|
= wrap_layout :master_slim do
|
||||||
h2 Outer
|
h2 Outer
|
||||||
== yield
|
== yield
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
set :sass_cache_path, File.join('/tmp', "#{File.basename(Dir.pwd)}-custom-sass_cache_path")
|
|
|
@ -1,4 +0,0 @@
|
||||||
@import "compass/reset"
|
|
||||||
|
|
||||||
red
|
|
||||||
color: blue
|
|
|
@ -1,3 +0,0 @@
|
||||||
|
|
||||||
# Using default setting
|
|
||||||
# set :sass_cache_path, File.join(Dir.pwd, '.sass-cache')
|
|
|
@ -1,4 +0,0 @@
|
||||||
@import "compass/reset"
|
|
||||||
|
|
||||||
red
|
|
||||||
color: blue
|
|
|
@ -3,7 +3,7 @@ require 'i18n'
|
||||||
|
|
||||||
# Don't fail on invalid locale, that's not what our current
|
# Don't fail on invalid locale, that's not what our current
|
||||||
# users expect.
|
# users expect.
|
||||||
::I18n.config.enforce_available_locales = false
|
::I18n.enforce_available_locales = false
|
||||||
|
|
||||||
# Use ActiveSupport JSON
|
# Use ActiveSupport JSON
|
||||||
require 'active_support/json'
|
require 'active_support/json'
|
||||||
|
@ -41,6 +41,9 @@ module Middleman
|
||||||
# Ready (all loading and parsing of extensions complete) hook
|
# Ready (all loading and parsing of extensions complete) hook
|
||||||
define_hook :ready
|
define_hook :ready
|
||||||
|
|
||||||
|
# Runs before the build is started
|
||||||
|
define_hook :before_build
|
||||||
|
|
||||||
# Runs after the build is finished
|
# Runs after the build is finished
|
||||||
define_hook :after_build
|
define_hook :after_build
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ module Middleman
|
||||||
# Bind app hooks to local methods
|
# Bind app hooks to local methods
|
||||||
bind_before_configuration
|
bind_before_configuration
|
||||||
bind_after_configuration
|
bind_after_configuration
|
||||||
|
bind_before_build
|
||||||
bind_after_build
|
bind_after_build
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -136,6 +137,19 @@ module Middleman
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bind_before_build
|
||||||
|
ext = self
|
||||||
|
if ext.respond_to?(:before_build)
|
||||||
|
@klass.before_build do |builder|
|
||||||
|
if ext.method(:before_build).arity === 1
|
||||||
|
ext.before_build(builder)
|
||||||
|
else
|
||||||
|
ext.before_build
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def bind_after_build
|
def bind_after_build
|
||||||
ext = self
|
ext = self
|
||||||
if ext.respond_to?(:after_build)
|
if ext.respond_to?(:after_build)
|
||||||
|
|
|
@ -76,4 +76,4 @@ module Middleman
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'middleman-core/extension'
|
require 'middleman-core/extension'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
if !defined?(::Padrino::Helpers)
|
if !defined?(::Padrino::Helpers)
|
||||||
require 'vendored-middleman-deps/padrino-core-0.11.4/lib/padrino-core/support_lite'
|
require 'vendored-middleman-deps/padrino-core-0.12.0/lib/padrino-core/support_lite'
|
||||||
require 'vendored-middleman-deps/padrino-helpers-0.11.4/lib/padrino-helpers'
|
require 'vendored-middleman-deps/padrino-helpers-0.12.0/lib/padrino-helpers'
|
||||||
end
|
end
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
|
|
|
@ -7,30 +7,28 @@ module Middleman
|
||||||
|
|
||||||
# once registered
|
# once registered
|
||||||
def registered(app)
|
def registered(app)
|
||||||
# Setup a default ERb engine
|
|
||||||
app.config.define_setting :erb_engine, :erb, 'The engine to use for rendering ERb templates'
|
|
||||||
app.config.define_setting :erb_engine_prefix, ::Tilt, 'The parent module for ERb template engines'
|
|
||||||
|
|
||||||
app.before_configuration do
|
app.before_configuration do
|
||||||
template_extensions :erb => :html
|
template_extensions :erb => :html
|
||||||
end
|
end
|
||||||
|
|
||||||
# After config
|
# After config
|
||||||
app.after_configuration do
|
app.after_configuration do
|
||||||
# Find the user's prefered engine
|
::Tilt.prefer(Template, :erb)
|
||||||
# Convert symbols to classes
|
|
||||||
if config[:erb_engine].is_a? Symbol
|
|
||||||
engine = engine.to_s
|
|
||||||
engine = engine == 'erb' ? 'ERB' : engine.camelize
|
|
||||||
config[:erb_engine] = config[:erb_engine_prefix].const_get("#{engine}Template")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Tell Tilt to use the preferred engine
|
|
||||||
::Tilt.prefer(config[:erb_engine])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alias :included :registered
|
alias :included :registered
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Template < ::Tilt::ErubisTemplate
|
||||||
|
##
|
||||||
|
# In preamble we need a flag `__in_erb_template` and SafeBuffer for padrino apps.
|
||||||
|
#
|
||||||
|
def precompiled_preamble(locals)
|
||||||
|
original = super
|
||||||
|
"__in_erb_template = true\n" << original
|
||||||
|
#.rpartition("\n").first << "#{@outvar} = _buf = ActiveSupport::SafeBuffer.new\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
# Require gem
|
# Require gem
|
||||||
require 'haml'
|
require 'haml'
|
||||||
|
|
||||||
|
module SafeTemplate
|
||||||
|
def render(*)
|
||||||
|
super.html_safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Tilt::HamlTemplate
|
||||||
|
include SafeTemplate
|
||||||
|
end
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
module Renderers
|
module Renderers
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,6 @@ module Middleman
|
||||||
# Default sass options
|
# Default sass options
|
||||||
app.config.define_setting :sass, {}, 'Sass engine options'
|
app.config.define_setting :sass, {}, 'Sass engine options'
|
||||||
|
|
||||||
# Location of SASS .sass-cache directory.
|
|
||||||
# @return [String]
|
|
||||||
app.config.define_setting :sass_cache_path, File.join(app.root_path, '.sass-cache'), 'Location of sass cache' # runtime compile of path
|
|
||||||
|
|
||||||
app.before_configuration do
|
app.before_configuration do
|
||||||
template_extensions :scss => :css,
|
template_extensions :scss => :css,
|
||||||
:sass => :css
|
:sass => :css
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
# Load gem
|
# Load gem
|
||||||
require 'slim'
|
require 'slim'
|
||||||
|
|
||||||
|
module SafeTemplate
|
||||||
|
def render(*)
|
||||||
|
super.html_safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Slim::Template
|
||||||
|
include SafeTemplate
|
||||||
|
|
||||||
|
def precompiled_preamble(locals)
|
||||||
|
"__in_slim_template = true\n" << super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
module Renderers
|
module Renderers
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class Middleman::CoreExtensions::Compass < ::Middleman::Extension
|
||||||
::Compass.configuration do |compass_config|
|
::Compass.configuration do |compass_config|
|
||||||
compass_config.project_path = app.source_dir
|
compass_config.project_path = app.source_dir
|
||||||
compass_config.environment = :development
|
compass_config.environment = :development
|
||||||
compass_config.cache_path = app.config[:sass_cache_path]
|
compass_config.cache = false
|
||||||
compass_config.sass_dir = app.config[:css_dir]
|
compass_config.sass_dir = app.config[:css_dir]
|
||||||
compass_config.css_dir = app.config[:css_dir]
|
compass_config.css_dir = app.config[:css_dir]
|
||||||
compass_config.javascripts_dir = app.config[:js_dir]
|
compass_config.javascripts_dir = app.config[:js_dir]
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
if !defined?(::Padrino::Helpers)
|
if !defined?(::Padrino::Helpers)
|
||||||
require 'vendored-middleman-deps/padrino-core-0.11.4/lib/padrino-core/support_lite'
|
require 'vendored-middleman-deps/padrino-core-0.12.0/lib/padrino-core/support_lite'
|
||||||
require 'vendored-middleman-deps/padrino-helpers-0.11.4/lib/padrino-helpers'
|
require 'vendored-middleman-deps/padrino-helpers-0.12.0/lib/padrino-helpers'
|
||||||
|
|
||||||
|
# Don't fail on invalid locale, that's not what our current
|
||||||
|
# users expect.
|
||||||
|
::I18n.enforce_available_locales = false
|
||||||
end
|
end
|
||||||
|
|
||||||
class Padrino::Helpers::OutputHelpers::ErbHandler
|
class Padrino::Helpers::OutputHelpers::ErbHandler
|
||||||
# Force Erb capture not to use safebuffer
|
# Force Erb capture not to use safebuffer
|
||||||
def capture_from_template(*args, &block)
|
def capture_from_template(*args, &block)
|
||||||
self.output_buffer, _buf_was = '', self.output_buffer
|
self.output_buffer, _buf_was = '', self.output_buffer
|
||||||
captured_block = block.call(*args)
|
raw = block.call(*args)
|
||||||
ret = eval('@_out_buf', block.binding)
|
captured = template.instance_variable_get(:@_out_buf)
|
||||||
self.output_buffer = _buf_was
|
self.output_buffer = _buf_was
|
||||||
[ ret, captured_block ]
|
engine_matches?(block) ? captured : raw
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,6 +53,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
||||||
attributes = tag_attributes(options)
|
attributes = tag_attributes(options)
|
||||||
output = ActiveSupport::SafeBuffer.new
|
output = ActiveSupport::SafeBuffer.new
|
||||||
output.safe_concat "<#{name}#{attributes}>"
|
output.safe_concat "<#{name}#{attributes}>"
|
||||||
|
|
||||||
if content.respond_to?(:each) && !content.is_a?(String)
|
if content.respond_to?(:each) && !content.is_a?(String)
|
||||||
content.each { |c| output.safe_concat c; output.safe_concat ::Padrino::Helpers::TagHelpers::NEWLINE }
|
content.each { |c| output.safe_concat c; output.safe_concat ::Padrino::Helpers::TagHelpers::NEWLINE }
|
||||||
else
|
else
|
||||||
|
@ -249,4 +254,4 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Middleman::CoreExtensions::DefaultHelpers.register
|
Middleman::CoreExtensions::DefaultHelpers.register
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
begin
|
|
||||||
require 'slim'
|
|
||||||
|
|
||||||
if defined? Padrino::Rendering
|
|
||||||
Padrino::Rendering.engine_configurations[:slim] =
|
|
||||||
{:generator => Temple::Generators::RailsOutputBuffer,
|
|
||||||
:buffer => "@_out_buf", :use_html_safe => true}
|
|
||||||
|
|
||||||
class Slim::Template
|
|
||||||
include Padrino::Rendering::SafeTemplate
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue LoadError
|
|
||||||
end
|
|
|
@ -1,341 +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.
|
|
||||||
#
|
|
||||||
|
|
||||||
# The modification times for every file in a project.
|
|
||||||
MTIMES = {}
|
|
||||||
# The list of files loaded as part of a project.
|
|
||||||
LOADED_FILES = {}
|
|
||||||
# The list of object constants and classes loaded as part of the project.
|
|
||||||
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 ||= Set.new
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Specified constants can be configured to be reloaded on every request.
|
|
||||||
# Default included constants are: [none]
|
|
||||||
#
|
|
||||||
def include_constants
|
|
||||||
@_include_constants ||= Set.new
|
|
||||||
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!
|
|
||||||
clear_modification_times
|
|
||||||
clear_loaded_classes
|
|
||||||
clear_loaded_files_and_features
|
|
||||||
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]
|
|
||||||
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 do |klass|
|
|
||||||
klass._orig_klass_name.split('::')[0]
|
|
||||||
end
|
|
||||||
|
|
||||||
klasses = klasses | Padrino.mounted_apps.map { |app| app.app_class }
|
|
||||||
Padrino::Reloader.exclude_constants.merge(klasses)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# A safe Kernel::require which issues the necessary hooks depending on results
|
|
||||||
#
|
|
||||||
def safe_load(file, options={})
|
|
||||||
began_at = Time.now
|
|
||||||
force = options[:force]
|
|
||||||
file = figure_path(file)
|
|
||||||
reload = should_reload?(file)
|
|
||||||
m_time = modification_time(file)
|
|
||||||
|
|
||||||
return if !force && m_time && !reload
|
|
||||||
|
|
||||||
remove_loaded_file_classes(file)
|
|
||||||
remove_loaded_file_features(file)
|
|
||||||
|
|
||||||
# Duplicate objects and loaded features before load file
|
|
||||||
klasses = ObjectSpace.classes
|
|
||||||
files = Set.new($LOADED_FEATURES.dup)
|
|
||||||
|
|
||||||
reload_deps_of_file(file)
|
|
||||||
|
|
||||||
# And finally load the specified file
|
|
||||||
begin
|
|
||||||
logger.devel :loading, began_at, file if !reload
|
|
||||||
logger.debug :reload, began_at, file if reload
|
|
||||||
|
|
||||||
$LOADED_FEATURES.delete(file) if files.include?(file)
|
|
||||||
Padrino::Utils.silence_output
|
|
||||||
loaded = false
|
|
||||||
require(file)
|
|
||||||
loaded = true
|
|
||||||
update_modification_time(file)
|
|
||||||
rescue SyntaxError => e
|
|
||||||
logger.error "Cannot require #{file} due to a syntax error: #{e.message}"
|
|
||||||
ensure
|
|
||||||
Padrino::Utils.unsilence_output
|
|
||||||
new_constants = ObjectSpace.new_classes(klasses)
|
|
||||||
if loaded
|
|
||||||
process_loaded_file(:file => file,
|
|
||||||
:constants => new_constants,
|
|
||||||
:files => files)
|
|
||||||
else
|
|
||||||
logger.devel "Failed to load #{file}; removing partially defined constants"
|
|
||||||
unload_constants(new_constants)
|
|
||||||
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.any? { |c| const._orig_klass_name.index(c) == 0 } &&
|
|
||||||
!include_constants.any? { |c| const._orig_klass_name.index(c) == 0 }
|
|
||||||
begin
|
|
||||||
parts = const.to_s.sub(/^::(Object)?/, 'Object::').split('::')
|
|
||||||
object = parts.pop
|
|
||||||
base = parts.empty? ? Object : Inflector.constantize(parts * '::')
|
|
||||||
base.send :remove_const, object
|
|
||||||
logger.devel "Removed constant: #{const} from #{base}"
|
|
||||||
rescue NameError; end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
###
|
|
||||||
# Clear instance variables that keep track of # loaded features/files/mtimes.
|
|
||||||
#
|
|
||||||
def clear_modification_times
|
|
||||||
MTIMES.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_loaded_classes
|
|
||||||
LOADED_CLASSES.each do |file, klasses|
|
|
||||||
klasses.each { |klass| remove_constant(klass) }
|
|
||||||
LOADED_CLASSES.delete(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_loaded_files_and_features
|
|
||||||
LOADED_FILES.each do |file, dependencies|
|
|
||||||
dependencies.each { |dependency| $LOADED_FEATURES.delete(dependency) }
|
|
||||||
$LOADED_FEATURES.delete(file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Macro for mtime query.
|
|
||||||
#
|
|
||||||
def modification_time(file)
|
|
||||||
MTIMES[file]
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Macro for mtime update.
|
|
||||||
#
|
|
||||||
def update_modification_time(file)
|
|
||||||
MTIMES[file] = File.mtime(file)
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Tracks loaded file features/classes/constants:
|
|
||||||
#
|
|
||||||
def process_loaded_file(*args)
|
|
||||||
options = args.extract_options!
|
|
||||||
new_constants = options[:constants]
|
|
||||||
files = options[:files]
|
|
||||||
file = options[:file]
|
|
||||||
|
|
||||||
# Store the file details
|
|
||||||
LOADED_CLASSES[file] = new_constants
|
|
||||||
LOADED_FILES[file] = Set.new($LOADED_FEATURES) - files - [file]
|
|
||||||
|
|
||||||
# Track only features in our Padrino.root
|
|
||||||
LOADED_FILES[file].delete_if { |feature| !in_root?(feature) }
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Unloads all constants in new_constants.
|
|
||||||
#
|
|
||||||
def unload_constants(new_constants)
|
|
||||||
new_constants.each { |klass| remove_constant(klass) }
|
|
||||||
end
|
|
||||||
|
|
||||||
###
|
|
||||||
# Safe load dependencies of a file.
|
|
||||||
#
|
|
||||||
def reload_deps_of_file(file)
|
|
||||||
if features = LOADED_FILES.delete(file)
|
|
||||||
features.each { |feature| safe_load(feature, :force => true) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Check if file was changed or if force a reload.
|
|
||||||
#
|
|
||||||
def should_reload?(file)
|
|
||||||
MTIMES[file] && File.mtime(file) > MTIMES[file]
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Removes all classes declared in the specified file.
|
|
||||||
#
|
|
||||||
def remove_loaded_file_classes(file)
|
|
||||||
if klasses = LOADED_CLASSES.delete(file)
|
|
||||||
klasses.each { |klass| remove_constant(klass) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Remove all loaded fatures with our file.
|
|
||||||
#
|
|
||||||
def remove_loaded_file_features(file)
|
|
||||||
if features = LOADED_FILES[file]
|
|
||||||
features.each { |feature| $LOADED_FEATURES.delete(feature) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Return the mounted_apps providing the app location.
|
|
||||||
# Can be an array because in one app.rb we can define multiple Padrino::Application.
|
|
||||||
#
|
|
||||||
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).index(Padrino.root) == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Searches Ruby files in your +Padrino.load_paths+ , Padrino::Application.load_paths
|
|
||||||
# and monitors them for any changes.
|
|
||||||
#
|
|
||||||
def rotation
|
|
||||||
files_for_rotation.uniq.map do |file|
|
|
||||||
file = File.expand_path(file)
|
|
||||||
next if Padrino::Reloader.exclude.any? { |base| file.index(base) == 0 } || !File.exist?(file)
|
|
||||||
yield file, File.mtime(file)
|
|
||||||
end.compact
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Creates an array of paths for use in #rotation.
|
|
||||||
#
|
|
||||||
def files_for_rotation
|
|
||||||
files = Padrino.load_paths.map { |path| Dir["#{path}/**/*.rb"] }.flatten
|
|
||||||
files = files | Padrino.mounted_apps.map { |app| app.app_file }
|
|
||||||
files = files | Padrino.mounted_apps.map { |app| app.app_obj.dependencies }.flatten
|
|
||||||
end
|
|
||||||
end # self
|
|
||||||
|
|
||||||
##
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Invoked in order to perform the reload as part of the request stack.
|
|
||||||
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
|
|
||||||
end
|
|
|
@ -1,80 +0,0 @@
|
||||||
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
|
||||||
|
|
||||||
describe "Application" do
|
|
||||||
before { Padrino.clear! }
|
|
||||||
after { remove_views }
|
|
||||||
|
|
||||||
context 'CSRF protection' do
|
|
||||||
context "with CSRF protection on" do
|
|
||||||
before do
|
|
||||||
mock_app do
|
|
||||||
enable :sessions
|
|
||||||
enable :protect_from_csrf
|
|
||||||
post('/'){ 'HI' }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "not allow requests without tokens" do
|
|
||||||
post "/"
|
|
||||||
assert_equal 403, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should "allow requests with correct tokens" do
|
|
||||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}
|
|
||||||
assert_equal 200, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should "not allow requests with incorrect tokens" do
|
|
||||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
|
|
||||||
assert_equal 403, status
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "without CSRF protection on" do
|
|
||||||
before do
|
|
||||||
mock_app do
|
|
||||||
enable :sessions
|
|
||||||
disable :protect_from_csrf
|
|
||||||
post('/'){ 'HI' }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "allows requests without tokens" do
|
|
||||||
post "/"
|
|
||||||
assert_equal 200, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should "allow requests with correct tokens" do
|
|
||||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "a"}
|
|
||||||
assert_equal 200, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should "allow requests with incorrect tokens" do
|
|
||||||
post "/", {"authenticity_token" => "a"}, 'rack.session' => {:csrf => "b"}
|
|
||||||
assert_equal 200, status
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with optional CSRF protection" do
|
|
||||||
before do
|
|
||||||
mock_app do
|
|
||||||
enable :sessions
|
|
||||||
enable :protect_from_csrf
|
|
||||||
set :allow_disabled_csrf, true
|
|
||||||
post('/on') { 'HI' }
|
|
||||||
post('/off', :csrf_protection => false) { 'HI' }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "allow access to routes with csrf_protection off" do
|
|
||||||
post "/off"
|
|
||||||
assert_equal 200, status
|
|
||||||
end
|
|
||||||
|
|
||||||
should "not allow access to routes with csrf_protection on" do
|
|
||||||
post "/on"
|
|
||||||
assert_equal 403, status
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -14,14 +14,19 @@ require 'padrino-core/server'
|
||||||
require 'padrino-core/tasks'
|
require 'padrino-core/tasks'
|
||||||
require 'padrino-core/module'
|
require 'padrino-core/module'
|
||||||
|
|
||||||
|
if ENV["PADRINO_ENV"]
|
||||||
PADRINO_ENV = ENV["PADRINO_ENV"] ||= ENV["RACK_ENV"] ||= "development" unless defined?(PADRINO_ENV)
|
warn 'Environment variable PADRINO_ENV is deprecated. Please, use RACK_ENV.'
|
||||||
|
ENV["RACK_ENV"] ||= ENV["PADRINO_ENV"]
|
||||||
|
end
|
||||||
|
RACK_ENV = ENV["RACK_ENV"] ||= "development" unless defined?(RACK_ENV)
|
||||||
PADRINO_ROOT = ENV["PADRINO_ROOT"] ||= File.dirname(Padrino.first_caller) unless defined?(PADRINO_ROOT)
|
PADRINO_ROOT = ENV["PADRINO_ROOT"] ||= File.dirname(Padrino.first_caller) unless defined?(PADRINO_ROOT)
|
||||||
|
|
||||||
module Padrino
|
module Padrino
|
||||||
class ApplicationLoadError < RuntimeError # @private
|
class ApplicationLoadError < RuntimeError # @private
|
||||||
end
|
end
|
||||||
|
|
||||||
|
extend Loader
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
##
|
##
|
||||||
# Helper method for file references.
|
# Helper method for file references.
|
||||||
|
@ -42,13 +47,13 @@ module Padrino
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Helper method that return {PADRINO_ENV}.
|
# Helper method that return {RACK_ENV}.
|
||||||
#
|
#
|
||||||
# @return [Symbol]
|
# @return [Symbol]
|
||||||
# The Padrino Environment.
|
# The Padrino Environment.
|
||||||
#
|
#
|
||||||
def env
|
def env
|
||||||
@_env ||= PADRINO_ENV.to_s.downcase.to_sym
|
@_env ||= RACK_ENV.to_s.downcase.to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -61,18 +66,10 @@ module Padrino
|
||||||
# No applications were mounted.
|
# No applications were mounted.
|
||||||
#
|
#
|
||||||
def application
|
def application
|
||||||
raise ApplicationLoadError, "At least one app must be mounted!" unless Padrino.mounted_apps && Padrino.mounted_apps.any?
|
raise ApplicationLoadError, "At least one app must be mounted!" unless Padrino.mounted_apps.present?
|
||||||
router = Padrino::Router.new
|
router = Padrino::Router.new
|
||||||
Padrino.mounted_apps.each { |app| app.map_onto(router) }
|
Padrino.mounted_apps.each { |app| app.map_onto(router) }
|
||||||
|
middleware.present? ? add_middleware(router) : router
|
||||||
if middleware.present?
|
|
||||||
builder = Rack::Builder.new
|
|
||||||
middleware.each { |c,a,b| builder.use(c, *a, &b) }
|
|
||||||
builder.run(router)
|
|
||||||
builder.to_app
|
|
||||||
else
|
|
||||||
router
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -90,21 +87,14 @@ module Padrino
|
||||||
#
|
#
|
||||||
def configure_apps(&block)
|
def configure_apps(&block)
|
||||||
return unless block_given?
|
return unless block_given?
|
||||||
@@_global_configurations ||= []
|
global_configurations << block
|
||||||
@@_global_configurations << block
|
|
||||||
@_global_configuration = lambda do |app|
|
|
||||||
@@_global_configurations.each do |configuration|
|
|
||||||
app.class_eval(&configuration)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns project-wide configuration settings defined in
|
# Stores global configuration blocks.
|
||||||
# {configure_apps} block.
|
|
||||||
#
|
#
|
||||||
def apps_configuration
|
def global_configurations
|
||||||
@_global_configuration
|
@_global_configurations ||= []
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -119,15 +109,21 @@ module Padrino
|
||||||
# @return [NilClass]
|
# @return [NilClass]
|
||||||
#
|
#
|
||||||
def set_encoding
|
def set_encoding
|
||||||
if RUBY_VERSION < '1.9'
|
Encoding.default_external = Encoding::UTF_8
|
||||||
$KCODE='u'
|
Encoding.default_internal = Encoding::UTF_8
|
||||||
else
|
|
||||||
Encoding.default_external = Encoding::UTF_8
|
|
||||||
Encoding.default_internal = Encoding::UTF_8
|
|
||||||
end
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Creates Rack stack with the router added to the middleware chain.
|
||||||
|
#
|
||||||
|
def add_middleware(router)
|
||||||
|
builder = Rack::Builder.new
|
||||||
|
middleware.each{ |mw,args,block| builder.use(mw, *args, &block) }
|
||||||
|
builder.run(router)
|
||||||
|
builder.to_app
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# A Rack::Builder object that allows to add middlewares in front of all
|
# A Rack::Builder object that allows to add middlewares in front of all
|
||||||
# Padrino applications.
|
# Padrino applications.
|
||||||
|
@ -161,8 +157,8 @@ module Padrino
|
||||||
# @yield []
|
# @yield []
|
||||||
# The given block will be passed to the initialized middleware.
|
# The given block will be passed to the initialized middleware.
|
||||||
#
|
#
|
||||||
def use(m, *args, &block)
|
def use(mw, *args, &block)
|
||||||
middleware << [m, args, block]
|
middleware << [mw, args, block]
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
|
@ -1,12 +1,10 @@
|
||||||
require 'padrino-core/application/flash'
|
require 'padrino-core/application/flash'
|
||||||
require 'padrino-core/application/rendering'
|
require 'padrino-core/application/rendering'
|
||||||
require 'padrino-core/application/routing'
|
require 'padrino-core/application/routing'
|
||||||
require 'padrino-core/application/showexceptions'
|
require 'padrino-core/application/show_exceptions'
|
||||||
|
require 'padrino-core/application/authenticity_token'
|
||||||
|
|
||||||
module Padrino
|
module Padrino
|
||||||
class ApplicationSetupError < RuntimeError
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Subclasses of this become independent Padrino applications
|
# Subclasses of this become independent Padrino applications
|
||||||
# (stemming from Sinatra::Application).
|
# (stemming from Sinatra::Application).
|
||||||
|
@ -26,20 +24,24 @@ module Padrino
|
||||||
Padrino.logger
|
Padrino.logger
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: Remove this hack after getting rid of thread-unsafe http_router:
|
||||||
|
alias_method :original_call, :call
|
||||||
|
def call(*args)
|
||||||
|
settings.init_mutex.synchronize do
|
||||||
|
instance_eval{ undef :call }
|
||||||
|
class_eval{ alias_method :call, :original_call }
|
||||||
|
instance_eval{ undef :original_call }
|
||||||
|
super(*args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def inherited(base)
|
def inherited(base)
|
||||||
begun_at = Time.now
|
begun_at = Time.now
|
||||||
CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
|
CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
|
||||||
base.default_configuration!
|
base.default_configuration!
|
||||||
base.prerequisites.concat([
|
|
||||||
File.join(base.root, '/models.rb'),
|
|
||||||
File.join(base.root, '/models/**/*.rb'),
|
|
||||||
File.join(base.root, '/lib.rb'),
|
|
||||||
File.join(base.root, '/lib/**/*.rb')
|
|
||||||
]).uniq!
|
|
||||||
Padrino.require_dependencies(base.prerequisites)
|
|
||||||
logger.devel :setup, begun_at, base
|
logger.devel :setup, begun_at, base
|
||||||
super(base) # Loading the subclass inherited method
|
super(base)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -54,10 +56,10 @@ module Padrino
|
||||||
# MyApp.reload!
|
# MyApp.reload!
|
||||||
#
|
#
|
||||||
def reload!
|
def reload!
|
||||||
logger.devel "Reloading #{settings}"
|
logger.devel "Reloading application #{settings}"
|
||||||
reset!
|
reset!
|
||||||
reset_router!
|
reset_router!
|
||||||
Padrino.require_dependencies(settings.app_file, :force => true) # Reload the app file
|
Padrino.require_dependencies(settings.app_file, :force => true)
|
||||||
require_dependencies
|
require_dependencies
|
||||||
default_filters!
|
default_filters!
|
||||||
default_routes!
|
default_routes!
|
||||||
|
@ -90,6 +92,26 @@ module Padrino
|
||||||
router.routes
|
router.routes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns an absolute path of view in application views folder.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Admin.view_path 'users/index' #=> "/home/user/test/admin/views/users/index"
|
||||||
|
#
|
||||||
|
def view_path(view)
|
||||||
|
File.expand_path(view, views)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns an absolute path of application layout.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Admin.layout_path :application #=> "/home/user/test/admin/views/layouts/application"
|
||||||
|
#
|
||||||
|
def layout_path(layout)
|
||||||
|
view_path("layouts/#{layout}")
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Setup the application by registering initializers, load paths and logger.
|
# Setup the application by registering initializers, load paths and logger.
|
||||||
# Invoked automatically when an application is first instantiated.
|
# Invoked automatically when an application is first instantiated.
|
||||||
|
@ -103,11 +125,11 @@ module Padrino
|
||||||
settings.default_routes!
|
settings.default_routes!
|
||||||
settings.default_errors!
|
settings.default_errors!
|
||||||
if defined?(I18n)
|
if defined?(I18n)
|
||||||
|
Reloader.special_files += settings.locale_path
|
||||||
I18n.load_path << settings.locale_path
|
I18n.load_path << settings.locale_path
|
||||||
I18n.reload!
|
I18n.reload!
|
||||||
end
|
end
|
||||||
@_configured = true
|
@_configured = true
|
||||||
@_configured
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -127,7 +149,13 @@ module Padrino
|
||||||
# directory that need to be added to +$LOAD_PATHS+ from this application
|
# directory that need to be added to +$LOAD_PATHS+ from this application
|
||||||
#
|
#
|
||||||
def load_paths
|
def load_paths
|
||||||
@_load_paths ||= %w[models lib mailers controllers helpers].map { |path| File.join(settings.root, path) }
|
@_load_paths ||= [
|
||||||
|
'models',
|
||||||
|
'lib',
|
||||||
|
'mailers',
|
||||||
|
'controllers',
|
||||||
|
'helpers',
|
||||||
|
].map { |path| File.join(settings.root, path) }
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -143,8 +171,14 @@ module Padrino
|
||||||
#
|
#
|
||||||
def dependencies
|
def dependencies
|
||||||
[
|
[
|
||||||
'urls.rb', 'config/urls.rb', 'mailers/*.rb', 'mailers.rb',
|
'urls.rb',
|
||||||
'controllers/**/*.rb', 'controllers.rb', 'helpers/**/*.rb', 'helpers.rb'
|
'config/urls.rb',
|
||||||
|
'mailers/*.rb',
|
||||||
|
'mailers.rb',
|
||||||
|
'controllers/**/*.rb',
|
||||||
|
'controllers.rb',
|
||||||
|
'helpers/**/*.rb',
|
||||||
|
'helpers.rb',
|
||||||
].map { |file| Dir[File.join(settings.root, file)] }.flatten
|
].map { |file| Dir[File.join(settings.root, file)] }.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -167,38 +201,67 @@ module Padrino
|
||||||
@_prerequisites ||= []
|
@_prerequisites ||= []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def default(option, *args, &block)
|
||||||
|
set(option, *args, &block) unless respond_to?(option)
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
##
|
##
|
||||||
# Defines default settings for Padrino application.
|
# Defines default settings for Padrino application.
|
||||||
#
|
#
|
||||||
def default_configuration!
|
def default_configuration!
|
||||||
# Overwriting Sinatra defaults
|
set :app_file, File.expand_path(caller_files.first || $0)
|
||||||
set :app_file, File.expand_path(caller_files.first || $0) # Assume app file is first caller
|
set :app_name, settings.to_s.underscore.to_sym
|
||||||
|
|
||||||
set :environment, Padrino.env
|
set :environment, Padrino.env
|
||||||
set :reload, Proc.new { development? }
|
set :reload, Proc.new { development? }
|
||||||
set :logging, Proc.new { development? }
|
set :logging, Proc.new { development? }
|
||||||
|
|
||||||
set :method_override, true
|
set :method_override, true
|
||||||
set :sessions, false
|
|
||||||
set :public_folder, Proc.new { Padrino.root('public', uri_root) }
|
|
||||||
set :views, Proc.new { File.join(root, 'views') }
|
|
||||||
set :images_path, Proc.new { File.join(public_folder, 'images') }
|
|
||||||
set :protection, true
|
|
||||||
|
|
||||||
set :haml, { :ugly => (Padrino.env == :production) } if defined?(Haml)
|
|
||||||
|
|
||||||
# Padrino specific
|
|
||||||
set :uri_root, '/'
|
|
||||||
set :app_name, settings.to_s.underscore.to_sym
|
|
||||||
set :default_builder, 'StandardFormBuilder'
|
set :default_builder, 'StandardFormBuilder'
|
||||||
|
|
||||||
|
# TODO: Remove this hack after getting rid of thread-unsafe http_router:
|
||||||
|
set :init_mutex, Mutex.new
|
||||||
|
|
||||||
|
# TODO: Remove this line after sinatra version up.
|
||||||
|
set :add_charset, %w[javascript xml xhtml+xml].map {|t| "application/#{t}" }
|
||||||
|
|
||||||
|
default_paths!
|
||||||
|
default_security!
|
||||||
|
global_configuration!
|
||||||
|
setup_prerequisites!
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_prerequisites!
|
||||||
|
prerequisites.concat(default_prerequisites).uniq!
|
||||||
|
Padrino.require_dependencies(prerequisites)
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_paths!
|
||||||
|
set :locale_path, Proc.new { Dir.glob File.join(root, 'locale/**/*.{rb,yml}') }
|
||||||
|
set :views, Proc.new { File.join(root, 'views') }
|
||||||
|
|
||||||
|
set :uri_root, '/'
|
||||||
|
set :public_folder, Proc.new { Padrino.root('public', uri_root) }
|
||||||
|
set :images_path, Proc.new { File.join(public_folder, 'images') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_security!
|
||||||
|
set :protection, :except => :path_traversal
|
||||||
set :authentication, false
|
set :authentication, false
|
||||||
|
set :sessions, false
|
||||||
set :locale_path, Proc.new { Dir[File.join(settings.root, '/locale/**/*.{rb,yml}')] }
|
|
||||||
|
|
||||||
# Authenticity token
|
|
||||||
set :protect_from_csrf, false
|
set :protect_from_csrf, false
|
||||||
set :allow_disabled_csrf, false
|
set :allow_disabled_csrf, false
|
||||||
# Load the Global Configurations
|
end
|
||||||
class_eval(&Padrino.apps_configuration) if Padrino.apps_configuration
|
|
||||||
|
##
|
||||||
|
# Applies global padrino configuration blocks to current application.
|
||||||
|
#
|
||||||
|
def global_configuration!
|
||||||
|
Padrino.global_configurations.each do |configuration|
|
||||||
|
class_eval(&configuration)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -220,9 +283,7 @@ module Padrino
|
||||||
#
|
#
|
||||||
def default_filters!
|
def default_filters!
|
||||||
before do
|
before do
|
||||||
unless @_content_type
|
response['Content-Type'] = 'text/html;charset=utf-8' unless @_content_type
|
||||||
response['Content-Type'] = 'text/html;charset=utf-8'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -249,7 +310,20 @@ module Padrino
|
||||||
Padrino.require_dependencies(dependencies, :force => true)
|
Padrino.require_dependencies(dependencies, :force => true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns globs of default paths of application prerequisites.
|
||||||
|
#
|
||||||
|
def default_prerequisites
|
||||||
|
[
|
||||||
|
'/models.rb',
|
||||||
|
'/models/**/*.rb',
|
||||||
|
'/lib.rb',
|
||||||
|
'/lib/**/*.rb',
|
||||||
|
].map{ |glob| File.join(settings.root, glob) }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Overrides the default middleware for Sinatra based on Padrino conventions.
|
# Overrides the default middleware for Sinatra based on Padrino conventions.
|
||||||
# Also initializes the application after setting up the middleware.
|
# Also initializes the application after setting up the middleware.
|
||||||
def setup_default_middleware(builder)
|
def setup_default_middleware(builder)
|
||||||
|
@ -267,9 +341,33 @@ module Padrino
|
||||||
|
|
||||||
# sets up csrf protection for the app:
|
# sets up csrf protection for the app:
|
||||||
def setup_csrf_protection(builder)
|
def setup_csrf_protection(builder)
|
||||||
if protect_from_csrf? && !sessions?
|
check_csrf_protection_dependency
|
||||||
raise(<<-ERROR)
|
|
||||||
`protect_from_csrf` is activated, but `sessions` are not. To enable csrf
|
if protect_from_csrf?
|
||||||
|
options = options_for_csrf_protection_setup
|
||||||
|
options.merge!(protect_from_csrf) if protect_from_csrf.kind_of?(Hash)
|
||||||
|
builder.use(options[:except] ? Padrino::AuthenticityToken : Rack::Protection::AuthenticityToken, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# returns the options used in the builder for csrf protection setup
|
||||||
|
def options_for_csrf_protection_setup
|
||||||
|
options = { :logger => logger }
|
||||||
|
|
||||||
|
if allow_disabled_csrf?
|
||||||
|
options.merge!({
|
||||||
|
:reaction => :report,
|
||||||
|
:report_key => 'protection.csrf.failed'
|
||||||
|
})
|
||||||
|
end
|
||||||
|
options
|
||||||
|
end
|
||||||
|
|
||||||
|
# throw an exception if the protect_from_csrf is active but sessions not.
|
||||||
|
def check_csrf_protection_dependency
|
||||||
|
if (protect_from_csrf? && !sessions?) && !defined?(Padrino::IGNORE_CSRF_SETUP_WARNING)
|
||||||
|
warn(<<-ERROR)
|
||||||
|
`protect_from_csrf` is activated, but `sessions` seem to be off. To enable csrf
|
||||||
protection, use:
|
protection, use:
|
||||||
|
|
||||||
enable :sessions
|
enable :sessions
|
||||||
|
@ -277,19 +375,12 @@ protection, use:
|
||||||
or deactivate protect_from_csrf:
|
or deactivate protect_from_csrf:
|
||||||
|
|
||||||
disable :protect_from_csrf
|
disable :protect_from_csrf
|
||||||
ERROR
|
|
||||||
end
|
|
||||||
|
|
||||||
if protect_from_csrf?
|
If you use a different session store, ignore this warning using:
|
||||||
if allow_disabled_csrf?
|
|
||||||
builder.use Rack::Protection::AuthenticityToken,
|
# in boot.rb:
|
||||||
:reaction => :report,
|
Padrino::IGNORE_CSRF_SETUP_WARNING = true
|
||||||
:report_key => 'protection.csrf.failed',
|
ERROR
|
||||||
:logger => logger
|
|
||||||
else
|
|
||||||
builder.use Rack::Protection::AuthenticityToken,
|
|
||||||
:logger => logger
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -0,0 +1,25 @@
|
||||||
|
module Padrino
|
||||||
|
class AuthenticityToken < Rack::Protection::AuthenticityToken
|
||||||
|
def initialize(app, options = {})
|
||||||
|
@app = app
|
||||||
|
@except = options[:except]
|
||||||
|
@except = Array(@except) unless @except.is_a?(Proc)
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
if except?(env)
|
||||||
|
@app.call(env)
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def except?(env)
|
||||||
|
return false unless @except
|
||||||
|
path_info = env['PATH_INFO']
|
||||||
|
@except.is_a?(Proc) ? @except.call(env) : @except.any?{|path|
|
||||||
|
path.is_a?(Regexp) ? path.match(path_info) : path == path_info }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -195,14 +195,16 @@ module Padrino
|
||||||
options[:layout] = @layout if options[:layout].nil? || options[:layout] == true
|
options[:layout] = @layout if options[:layout].nil? || options[:layout] == true
|
||||||
# Resolve layouts similar to in Rails
|
# Resolve layouts similar to in Rails
|
||||||
if options[:layout].nil? && !settings.templates.has_key?(:layout)
|
if options[:layout].nil? && !settings.templates.has_key?(:layout)
|
||||||
layout_path, layout_engine = *resolved_layout
|
layout_path = settings.fetch_layout_path(options[:layout])
|
||||||
|
is_included_extension = %w[.slim .erb .haml].include?(File.extname(layout_path.to_s))
|
||||||
|
layout_path, layout_engine = *(is_included_extension ? resolve_template(layout_path) : resolved_layout)
|
||||||
|
|
||||||
# We need to force layout false so sinatra don't try to render it
|
# We need to force layout false so sinatra don't try to render it
|
||||||
options[:layout] = layout_path || false
|
options[:layout] = layout_path || false
|
||||||
options[:layout] = false unless layout_engine == engine # TODO allow different layout engine
|
options[:layout] = false unless is_included_extension ? layout_engine : layout_engine == engine
|
||||||
options[:layout_engine] = layout_engine || engine if options[:layout]
|
options[:layout_engine] = layout_engine || engine if options[:layout]
|
||||||
elsif options[:layout].present?
|
elsif options[:layout].present?
|
||||||
options[:layout] = settings.fetch_layout_path(options[:layout] || @layout)
|
options[:layout], options[:layout_engine] = *resolve_template(settings.fetch_layout_path(options[:layout]), options)
|
||||||
end
|
end
|
||||||
# Default to original layout value if none found.
|
# Default to original layout value if none found.
|
||||||
options[:layout] ||= layout_was
|
options[:layout] ||= layout_was
|
||||||
|
@ -272,15 +274,21 @@ module Padrino
|
||||||
end
|
end
|
||||||
|
|
||||||
# Resolve view path and options.
|
# Resolve view path and options.
|
||||||
options.reverse_merge!(DEFAULT_RENDERING_OPTIONS)
|
options = DEFAULT_RENDERING_OPTIONS.merge(options)
|
||||||
view_path = options.delete(:views) || settings.views || "./views"
|
view_path = options.delete(:views) || settings.views || "./views"
|
||||||
target_extension = File.extname(template_path)[1..-1] || "none" # explicit template extension
|
target_extension = File.extname(template_path)[1..-1] || "none" # explicit template extension
|
||||||
template_path = template_path.chomp(".#{target_extension}")
|
template_path = template_path.chomp(".#{target_extension}")
|
||||||
|
template_glob =
|
||||||
|
if respond_to?(:request) && request.controller.present?
|
||||||
|
File.join("{,#{request.controller}}", template_path)
|
||||||
|
else
|
||||||
|
template_path
|
||||||
|
end
|
||||||
|
|
||||||
# Generate potential template candidates
|
# Generate potential template candidates
|
||||||
templates = Dir[File.join(view_path, template_path) + ".*"].map do |file|
|
templates = Dir[File.join(view_path, template_glob) + ".*"].map do |file|
|
||||||
template_engine = File.extname(file)[1..-1].to_sym # Retrieves engine extension
|
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 = file.squeeze('/').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 }
|
[template_file, template_engine] unless IGNORE_FILE_PATTERN.any? { |pattern| template_engine.to_s =~ pattern }
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,15 +40,18 @@ begin
|
||||||
def render(*args)
|
def render(*args)
|
||||||
app = args.first
|
app = args.first
|
||||||
app_class = app.class
|
app_class = app.class
|
||||||
@padrino_app = app.kind_of?(Padrino::Application) ||
|
@is_padrino_app = app.kind_of?(Padrino::Application) ||
|
||||||
(app_class.respond_to?(:erb) && app_class.erb[:engine_class] == Padrino::Erubis::SafeBufferTemplate)
|
(app_class.respond_to?(:erb) && app_class.erb[:engine_class] == Padrino::Erubis::SafeBufferTemplate)
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# In preamble we need a flag `__in_erb_template` and SafeBuffer for padrino apps.
|
||||||
|
#
|
||||||
def precompiled_preamble(locals)
|
def precompiled_preamble(locals)
|
||||||
buf = @padrino_app ? "ActiveSupport::SafeBuffer.new" : "''"
|
original = super
|
||||||
old_postamble = super.split("\n")[0..-2]
|
return original unless @is_padrino_app
|
||||||
[old_postamble, "#{@outvar} = _buf = (#{@outvar} || #{buf})"].join("\n")
|
"__in_erb_template = true\n" << original.rpartition("\n").first << "#{@outvar} = _buf = ActiveSupport::SafeBuffer.new\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -57,8 +60,9 @@ begin
|
||||||
Tilt.prefer(Padrino::Erubis::Template, :erb)
|
Tilt.prefer(Padrino::Erubis::Template, :erb)
|
||||||
|
|
||||||
if defined? Padrino::Rendering
|
if defined? Padrino::Rendering
|
||||||
Padrino::Rendering.engine_configurations[:erb] =
|
Padrino::Rendering.engine_configurations[:erb] = {
|
||||||
{:engine_class => Padrino::Erubis::SafeBufferTemplate}
|
:engine_class => Padrino::Erubis::SafeBufferTemplate,
|
||||||
|
}
|
||||||
end
|
end
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
end
|
end
|
|
@ -17,8 +17,9 @@ begin
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined? Padrino::Rendering
|
if defined? Padrino::Rendering
|
||||||
Padrino::Rendering.engine_configurations[:haml] =
|
Padrino::Rendering.engine_configurations[:haml] = {
|
||||||
{:escape_html => true}
|
:escape_html => true,
|
||||||
|
}
|
||||||
|
|
||||||
class Tilt::HamlTemplate
|
class Tilt::HamlTemplate
|
||||||
include Padrino::Rendering::SafeTemplate
|
include Padrino::Rendering::SafeTemplate
|
|
@ -0,0 +1,21 @@
|
||||||
|
begin
|
||||||
|
require 'slim'
|
||||||
|
|
||||||
|
if defined? Padrino::Rendering
|
||||||
|
Padrino::Rendering.engine_configurations[:slim] = {
|
||||||
|
:generator => Temple::Generators::RailsOutputBuffer,
|
||||||
|
:buffer => "@_out_buf",
|
||||||
|
:use_html_safe => true,
|
||||||
|
:disable_capture => true,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Slim::Template
|
||||||
|
include Padrino::Rendering::SafeTemplate
|
||||||
|
|
||||||
|
def precompiled_preamble(locals)
|
||||||
|
"__in_slim_template = true\n" << super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue LoadError
|
||||||
|
end
|
|
@ -15,6 +15,19 @@ class Sinatra::Request
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# This patches Sinatra to accept UTF-8 urls on JRuby 1.7.6
|
||||||
|
#
|
||||||
|
if RUBY_ENGINE == 'jruby' && defined?(JRUBY_VERSION) && JRUBY_VERSION > '1.7.4'
|
||||||
|
class Sinatra::Base
|
||||||
|
class << self
|
||||||
|
alias_method :old_generate_method, :generate_method
|
||||||
|
def generate_method(method_name, &block)
|
||||||
|
old_generate_method(method_name.to_sym, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class HttpRouter
|
class HttpRouter
|
||||||
def rewrite_partial_path_info(env, request); end
|
def rewrite_partial_path_info(env, request); end
|
||||||
|
@ -61,7 +74,7 @@ class HttpRouter
|
||||||
class Route
|
class Route
|
||||||
VALID_HTTP_VERBS.replace %w[GET POST PUT PATCH DELETE HEAD OPTIONS LINK UNLINK]
|
VALID_HTTP_VERBS.replace %w[GET POST PUT PATCH DELETE HEAD OPTIONS LINK UNLINK]
|
||||||
|
|
||||||
attr_accessor :use_layout, :controller, :action, :cache, :cache_key, :cache_expires_in, :parent
|
attr_accessor :use_layout, :controller, :action, :cache, :cache_key, :cache_expires, :parent
|
||||||
|
|
||||||
def before_filters(&block)
|
def before_filters(&block)
|
||||||
@_before_filters ||= []
|
@_before_filters ||= []
|
||||||
|
@ -172,6 +185,7 @@ class HttpRouter
|
||||||
env['router.request'] = request
|
env['router.request'] = request
|
||||||
env['router.params'] ||= {}
|
env['router.params'] ||= {}
|
||||||
#{"env['router.params'].merge!(Hash[#{param_names.inspect}.zip(request.params)])" if dynamic?}
|
#{"env['router.params'].merge!(Hash[#{param_names.inspect}.zip(request.params)])" if dynamic?}
|
||||||
|
env['router.params'] = env['router.params'].with_indifferent_access
|
||||||
@router.rewrite#{"_partial" if route.match_partially}_path_info(env, request)
|
@router.rewrite#{"_partial" if route.match_partially}_path_info(env, request)
|
||||||
response = @router.process_destination_path(#{path_ivar}, env)
|
response = @router.process_destination_path(#{path_ivar}, env)
|
||||||
return response unless router.pass_on_response(response)
|
return response unless router.pass_on_response(response)
|
||||||
|
@ -193,7 +207,7 @@ module Padrino
|
||||||
def apply?(request)
|
def apply?(request)
|
||||||
detect = @args.any? do |arg|
|
detect = @args.any? do |arg|
|
||||||
case arg
|
case arg
|
||||||
when Symbol then request.route_obj && (request.route_obj.name == arg or request.route_obj.name == [@scoped_controller, arg].flatten.join("_").to_sym)
|
when Symbol then request.route_obj && (request.route_obj.name == arg or request.route_obj.name == [@scoped_controller, arg].flatten.join(" ").to_sym)
|
||||||
else arg === request.path_info
|
else arg === request.path_info
|
||||||
end
|
end
|
||||||
end || @options.any? do |name, val|
|
end || @options.any? do |name, val|
|
||||||
|
@ -500,7 +514,13 @@ module Padrino
|
||||||
|
|
||||||
def compiled_router
|
def compiled_router
|
||||||
if @deferred_routes
|
if @deferred_routes
|
||||||
deferred_routes.each { |routes| routes.each { |(route, dest)| route.to(dest) } }
|
deferred_routes.each do |routes|
|
||||||
|
routes.each do |(route, dest)|
|
||||||
|
route.to(dest)
|
||||||
|
route.before_filters.flatten!
|
||||||
|
route.after_filters.flatten!
|
||||||
|
end
|
||||||
|
end
|
||||||
@deferred_routes = nil
|
@deferred_routes = nil
|
||||||
router.sort!
|
router.sort!
|
||||||
end
|
end
|
||||||
|
@ -557,10 +577,10 @@ module Padrino
|
||||||
def url(*args)
|
def url(*args)
|
||||||
params = args.extract_options! # parameters is hash at end
|
params = args.extract_options! # parameters is hash at end
|
||||||
names, params_array = args.partition{|a| a.is_a?(Symbol)}
|
names, params_array = args.partition{|a| a.is_a?(Symbol)}
|
||||||
name = names.join("_").to_sym # route name is concatenated with underscores
|
name = names[0, 2].join(" ").to_sym # route name is concatenated with underscores
|
||||||
if params.is_a?(Hash)
|
if params.is_a?(Hash)
|
||||||
params[:format] = params[:format].to_s unless params[:format].nil?
|
params[:format] = params[:format].to_s unless params[:format].nil?
|
||||||
params = value_to_param(params)
|
params = value_to_param(params.symbolize_keys)
|
||||||
end
|
end
|
||||||
url =
|
url =
|
||||||
if params_array.empty?
|
if params_array.empty?
|
||||||
|
@ -568,10 +588,7 @@ module Padrino
|
||||||
else
|
else
|
||||||
compiled_router.path(name, *(params_array << params))
|
compiled_router.path(name, *(params_array << params))
|
||||||
end
|
end
|
||||||
url[0,0] = conform_uri(uri_root) if defined?(uri_root)
|
rebase_url(url)
|
||||||
url[0,0] = conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
|
|
||||||
url = "/" if url.blank?
|
|
||||||
url
|
|
||||||
rescue HttpRouter::InvalidRouteException
|
rescue HttpRouter::InvalidRouteException
|
||||||
route_error = "route mapping for url(#{name.inspect}) could not be found!"
|
route_error = "route mapping for url(#{name.inspect}) could not be found!"
|
||||||
raise Padrino::Routing::UnrecognizedException.new(route_error)
|
raise Padrino::Routing::UnrecognizedException.new(route_error)
|
||||||
|
@ -586,6 +603,17 @@ module Padrino
|
||||||
route('HEAD', path, *args, &block)
|
route('HEAD', path, *args, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rebase_url(url)
|
||||||
|
if url.start_with?('/')
|
||||||
|
new_url = ''
|
||||||
|
new_url << conform_uri(uri_root) if defined?(uri_root)
|
||||||
|
new_url << conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
|
||||||
|
new_url << url
|
||||||
|
else
|
||||||
|
url.blank? ? '/' : url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
# Parse params from the url method
|
# Parse params from the url method
|
||||||
def value_to_param(value)
|
def value_to_param(value)
|
||||||
|
@ -702,8 +730,8 @@ module Padrino
|
||||||
invoke_hook(:padrino_route_added, route, verb, path, args, options, block)
|
invoke_hook(:padrino_route_added, route, verb, path, args, options, block)
|
||||||
|
|
||||||
# Add Application defaults.
|
# Add Application defaults.
|
||||||
route.before_filters.concat(@filters[:before])
|
route.before_filters << @filters[:before]
|
||||||
route.after_filters.concat(@filters[:after])
|
route.after_filters << @filters[:after]
|
||||||
if @_controller
|
if @_controller
|
||||||
route.use_layout = @layout
|
route.use_layout = @layout
|
||||||
route.controller = Array(@_controller)[0].to_s
|
route.controller = Array(@_controller)[0].to_s
|
||||||
|
@ -786,7 +814,7 @@ module Padrino
|
||||||
name = options.delete(:name) if name.nil? && options.key?(:name)
|
name = options.delete(:name) if name.nil? && options.key?(:name)
|
||||||
if name
|
if name
|
||||||
controller_name = controller.join("_")
|
controller_name = controller.join("_")
|
||||||
name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
|
name = "#{controller_name} #{name}".to_sym unless controller_name.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Merge in option defaults.
|
# Merge in option defaults.
|
||||||
|
@ -856,9 +884,10 @@ module Padrino
|
||||||
def provides(*types)
|
def provides(*types)
|
||||||
@_use_format = true
|
@_use_format = true
|
||||||
condition do
|
condition do
|
||||||
mime_types = types.map { |t| mime_type(t) }.compact
|
mime_types = types.map { |t| mime_type(t) }.compact
|
||||||
url_format = params[:format].to_sym if params[:format]
|
url_format = params[:format].to_sym if params[:format]
|
||||||
accepts = request.accept.map(&:to_str)
|
accepts = request.accept.map(&:to_str)
|
||||||
|
accepts.clear if accepts == ["*/*"]
|
||||||
|
|
||||||
# Per rfc2616-sec14:
|
# Per rfc2616-sec14:
|
||||||
# Assume */* if no ACCEPT header is given.
|
# Assume */* if no ACCEPT header is given.
|
||||||
|
@ -890,7 +919,12 @@ module Padrino
|
||||||
|
|
||||||
if matched_format
|
if matched_format
|
||||||
@_content_type = url_format || accept_format || :html
|
@_content_type = url_format || accept_format || :html
|
||||||
content_type(@_content_type, :charset => 'utf-8')
|
|
||||||
|
if @_content_type != :json
|
||||||
|
content_type(@_content_type, :charset => 'utf-8')
|
||||||
|
else
|
||||||
|
content_type(@_content_type)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
matched_format
|
matched_format
|
||||||
|
@ -924,17 +958,24 @@ module Padrino
|
||||||
# url(:show, :id => 1)
|
# url(:show, :id => 1)
|
||||||
# url(:show, :name => :test)
|
# url(:show, :name => :test)
|
||||||
# url(:show, 1)
|
# url(:show, 1)
|
||||||
# url("/foo")
|
# url("/foo", false, false)
|
||||||
#
|
#
|
||||||
# @see Padrino::Routing::ClassMethods#url
|
# @see Padrino::Routing::ClassMethods#url
|
||||||
#
|
#
|
||||||
def url(*args)
|
def url(*args)
|
||||||
# Delegate to Sinatra 1.2 for simple url("/foo")
|
if args.first.is_a?(String)
|
||||||
# http://www.sinatrarb.com/intro#Generating%20URLs
|
url_path = settings.rebase_url(args.shift)
|
||||||
return super if args.first.is_a?(String) && !args[1].is_a?(Hash)
|
if args.empty?
|
||||||
|
url_path
|
||||||
# Delegate to Padrino named route URL generation.
|
else
|
||||||
settings.url(*args)
|
# Delegate sinatra-style urls to Sinatra. Ex: url("/foo", false, false)
|
||||||
|
# http://www.sinatrarb.com/intro#Generating%20URLs
|
||||||
|
super url_path, *args
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# Delegate to Padrino named route URL generation.
|
||||||
|
settings.url(*args)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
alias :url_for :url
|
alias :url_for :url
|
||||||
|
|
||||||
|
@ -944,9 +985,15 @@ module Padrino
|
||||||
# @example
|
# @example
|
||||||
# absolute_url(:show, :id => 1) # => http://example.com/show?id=1
|
# absolute_url(:show, :id => 1) # => http://example.com/show?id=1
|
||||||
# absolute_url(:show, 24) # => https://example.com/admin/show/24
|
# absolute_url(:show, 24) # => https://example.com/admin/show/24
|
||||||
|
# absolute_url('/foo/bar') # => https://example.com/admin/foo/bar
|
||||||
|
# absolute_url('baz') # => https://example.com/admin/foo/baz
|
||||||
#
|
#
|
||||||
def absolute_url( *args )
|
def absolute_url(*args)
|
||||||
uri url(*args), true, false
|
url_path = args.shift
|
||||||
|
if url_path.is_a?(String) && !url_path.start_with?('/')
|
||||||
|
url_path = request.env['PATH_INFO'].rpartition('/').first << '/' << url_path
|
||||||
|
end
|
||||||
|
uri url(url_path, *args), true, false
|
||||||
end
|
end
|
||||||
|
|
||||||
def recognize_path(path)
|
def recognize_path(path)
|
||||||
|
@ -958,10 +1005,12 @@ module Padrino
|
||||||
#
|
#
|
||||||
def current_path(*path_params)
|
def current_path(*path_params)
|
||||||
if path_params.last.is_a?(Hash)
|
if path_params.last.is_a?(Hash)
|
||||||
path_params[-1] = params.merge(path_params[-1])
|
path_params[-1] = params.merge(path_params[-1].with_indifferent_access)
|
||||||
else
|
else
|
||||||
path_params << params
|
path_params << params
|
||||||
end
|
end
|
||||||
|
|
||||||
|
path_params[-1] = path_params[-1].symbolize_keys
|
||||||
@route.path(*path_params)
|
@route.path(*path_params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Padrino
|
||||||
%r{lib/padrino-.*$},
|
%r{lib/padrino-.*$},
|
||||||
%r{/padrino-.*/(lib|bin)},
|
%r{/padrino-.*/(lib|bin)},
|
||||||
%r{/bin/padrino$},
|
%r{/bin/padrino$},
|
||||||
%r{/sinatra(/(base|main|showexceptions))?\.rb$},
|
%r{/sinatra(/(base|main|show_?exceptions))?\.rb$},
|
||||||
%r{lib/tilt.*\.rb$},
|
%r{lib/tilt.*\.rb$},
|
||||||
%r{lib/rack.*\.rb$},
|
%r{lib/rack.*\.rb$},
|
||||||
%r{lib/mongrel.*\.rb$},
|
%r{lib/mongrel.*\.rb$},
|
|
@ -18,11 +18,19 @@ module Padrino
|
||||||
method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background."
|
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 :pid, :type => :string, :aliases => "-i", :desc => "File to store pid."
|
||||||
method_option :debug, :type => :boolean, :desc => "Set debugging flags."
|
method_option :debug, :type => :boolean, :desc => "Set debugging flags."
|
||||||
|
method_option :options, :type => :array, :aliases => "-O", :desc => "--options NAME=VALUE NAME2=VALUE2'. pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$0} --server_options"
|
||||||
|
method_option :server_options, :type => :boolean, :desc => "Tells the current server handler's options that can be used with --options"
|
||||||
|
|
||||||
def start
|
def start
|
||||||
prepare :start
|
prepare :start
|
||||||
require File.expand_path("../adapter", __FILE__)
|
require File.expand_path("../adapter", __FILE__)
|
||||||
require File.expand_path('config/boot.rb')
|
require File.expand_path('config/boot.rb')
|
||||||
Padrino::Cli::Adapter.start(options)
|
|
||||||
|
if options[:server_options]
|
||||||
|
puts server_options(options)
|
||||||
|
else
|
||||||
|
Padrino::Cli::Adapter.start(options)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "stop", "Stops the Padrino application (alternatively use 'st')."
|
desc "stop", "Stops the Padrino application (alternatively use 'st')."
|
||||||
|
@ -116,7 +124,7 @@ module Padrino
|
||||||
help(task.to_s)
|
help(task.to_s)
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
end
|
end
|
||||||
ENV["PADRINO_ENV"] ||= ENV["RACK_ENV"] ||= options.environment.to_s
|
ENV["RACK_ENV"] ||= options.environment.to_s
|
||||||
chdir(options.chdir)
|
chdir(options.chdir)
|
||||||
unless File.exist?('config/boot.rb')
|
unless File.exist?('config/boot.rb')
|
||||||
puts "=> Could not find boot file in: #{options.chdir}/config/boot.rb !!!"
|
puts "=> Could not find boot file in: #{options.chdir}/config/boot.rb !!!"
|
||||||
|
@ -124,6 +132,29 @@ module Padrino
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# https://github.com/rack/rack/blob/master/lib/rack/server.rb\#L100
|
||||||
|
def server_options(options)
|
||||||
|
begin
|
||||||
|
info = []
|
||||||
|
server = Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
|
||||||
|
if server && server.respond_to?(:valid_options)
|
||||||
|
info << ""
|
||||||
|
info << "Server-specific options for #{server.name}:"
|
||||||
|
|
||||||
|
has_options = false
|
||||||
|
server.valid_options.each do |name, description|
|
||||||
|
next if name.to_s.match(/^(Host|Port)[^a-zA-Z]/) # ignore handler's host and port options, we do our own.
|
||||||
|
info << " -O %-21s %s" % [name, description]
|
||||||
|
has_options = true
|
||||||
|
end
|
||||||
|
return "" if !has_options
|
||||||
|
end
|
||||||
|
info.join("\n")
|
||||||
|
rescue NameError
|
||||||
|
return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def self.banner(task=nil, *args)
|
def self.banner(task=nil, *args)
|
|
@ -16,6 +16,16 @@ task :environment do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Loads skeleton Padrino environment, no models, no application settings.
|
||||||
|
task :skeleton do
|
||||||
|
module Padrino::Reloader
|
||||||
|
def self.safe_load(file, options)
|
||||||
|
super unless file.include?('/models/')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
require File.expand_path('config/boot.rb', Rake.application.original_dir)
|
||||||
|
end
|
||||||
|
|
||||||
desc "Generate a secret key"
|
desc "Generate a secret key"
|
||||||
task :secret do
|
task :secret do
|
||||||
shell.say SecureRandom.hex(32)
|
shell.say SecureRandom.hex(32)
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
@ -1,5 +1,5 @@
|
||||||
module Padrino
|
module Padrino
|
||||||
class << self
|
module Loader
|
||||||
##
|
##
|
||||||
# Hooks to be called before a load/reload.
|
# Hooks to be called before a load/reload.
|
||||||
#
|
#
|
||||||
|
@ -40,17 +40,6 @@ module Padrino
|
||||||
@_after_load
|
@_after_load
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
|
||||||
# The used +$LOAD_PATHS+ from Padrino.
|
|
||||||
#
|
|
||||||
# @return [Array<String>]
|
|
||||||
# The load paths used by 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
|
# Requires necessary dependencies as well as application files from root
|
||||||
# lib and models.
|
# lib and models.
|
||||||
|
@ -60,21 +49,18 @@ module Padrino
|
||||||
#
|
#
|
||||||
def load!
|
def load!
|
||||||
return false if loaded?
|
return false if loaded?
|
||||||
t = Time.now
|
began_at = Time.now
|
||||||
|
|
||||||
@_called_from = first_caller
|
@_called_from = first_caller
|
||||||
Padrino.set_encoding
|
set_encoding
|
||||||
Padrino.set_load_paths(*load_paths)
|
set_load_paths(*load_paths)
|
||||||
Padrino::Logger.setup! # Initialize our logger
|
Logger.setup!
|
||||||
Padrino.require_dependencies("#{root}/config/database.rb", :nodeps => true) # Be sure to don't remove constants from dbs.
|
require_dependencies("#{root}/config/database.rb")
|
||||||
Padrino::Reloader.lock! # Now we can remove constant from here to down
|
Reloader.lock!
|
||||||
Padrino.before_load.each(&:call) # Run before hooks
|
before_load.each(&:call)
|
||||||
Padrino.dependency_paths.each { |path| Padrino.require_dependencies(path) }
|
require_dependencies(*dependency_paths)
|
||||||
Padrino.after_load.each(&:call) # Run after hooks
|
after_load.each(&:call)
|
||||||
Padrino::Reloader.run!
|
logger.devel "Loaded Padrino in #{Time.now - began_at} seconds"
|
||||||
Thread.current[:padrino_loaded] = true
|
Thread.current[:padrino_loaded] = true
|
||||||
|
|
||||||
Padrino.logger.devel "Loaded Padrino in #{Time.now - t} seconds"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -83,14 +69,14 @@ module Padrino
|
||||||
# @return [NilClass]
|
# @return [NilClass]
|
||||||
#
|
#
|
||||||
def clear!
|
def clear!
|
||||||
Padrino.clear_middleware!
|
clear_middleware!
|
||||||
Padrino.mounted_apps.clear
|
mounted_apps.clear
|
||||||
@_load_paths = nil
|
@_load_paths = nil
|
||||||
@_dependency_paths = nil
|
@_dependency_paths = nil
|
||||||
@_global_configuration = nil
|
@_global_configuration = nil
|
||||||
Padrino.before_load.clear
|
before_load.clear
|
||||||
Padrino.after_load.clear
|
after_load.clear
|
||||||
Padrino::Reloader.clear!
|
Reloader.clear!
|
||||||
Thread.current[:padrino_loaded] = nil
|
Thread.current[:padrino_loaded] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -98,10 +84,10 @@ module Padrino
|
||||||
# Method for reloading required applications and their files.
|
# Method for reloading required applications and their files.
|
||||||
#
|
#
|
||||||
def reload!
|
def reload!
|
||||||
return unless Padrino::Reloader.changed?
|
return unless Reloader.changed?
|
||||||
Padrino.before_load.each(&:call) # Run before hooks
|
before_load.each(&:call)
|
||||||
Padrino::Reloader.reload! # detects the modified files
|
Reloader.reload!
|
||||||
Padrino.after_load.each(&:call) # Run after hooks
|
after_load.each(&:call)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -147,38 +133,55 @@ module Padrino
|
||||||
# require_dependencies("#{Padrino.root}/lib/**/*.rb")
|
# require_dependencies("#{Padrino.root}/lib/**/*.rb")
|
||||||
#
|
#
|
||||||
def require_dependencies(*paths)
|
def require_dependencies(*paths)
|
||||||
options = paths.extract_options!
|
options = paths.extract_options!.merge( :cyclic => true )
|
||||||
|
files = paths.flatten.map{|path| Dir[path].sort_by{|v| v.count('/') }}.flatten.uniq
|
||||||
# Extract all files to load
|
|
||||||
files = paths.flatten.map { |path| Dir[path] }.flatten.uniq.sort
|
|
||||||
|
|
||||||
while files.present?
|
while files.present?
|
||||||
errors, failed = [], []
|
error, fatal, loaded = nil, nil, nil
|
||||||
|
|
||||||
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|
|
files.dup.each do |file|
|
||||||
begin
|
begin
|
||||||
Padrino::Reloader.safe_load(file, options.dup)
|
Reloader.safe_load(file, options)
|
||||||
files.delete(file)
|
files.delete(file)
|
||||||
|
loaded = true
|
||||||
rescue NameError, LoadError => e
|
rescue NameError, LoadError => e
|
||||||
Padrino.logger.devel "Problem while loading #{file}: #{e}"
|
logger.devel "Cyclic dependency reload for #{e.class}: #{e.message}"
|
||||||
errors << e
|
error = e
|
||||||
failed << file
|
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
raise e
|
fatal = e
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Stop processing if nothing loads or if everything has loaded
|
if fatal || !loaded
|
||||||
raise errors.last if files.size == size_at_start && files.present?
|
e = fatal || error
|
||||||
break if files.empty?
|
logger.error "#{e.class}: #{e.message}; #{e.backtrace.first}"
|
||||||
|
raise e
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Concat to +$LOAD_PATH+ the given paths.
|
||||||
|
#
|
||||||
|
# @param [Array<String>] paths
|
||||||
|
# The paths to concat.
|
||||||
|
#
|
||||||
|
def set_load_paths(*paths)
|
||||||
|
load_paths.concat(paths).uniq!
|
||||||
|
$LOAD_PATH.concat(paths).uniq!
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# The used +$LOAD_PATHS+ from Padrino.
|
||||||
|
#
|
||||||
|
# @return [Array<String>]
|
||||||
|
# The load paths used by Padrino.
|
||||||
|
#
|
||||||
|
def load_paths
|
||||||
|
@_load_paths ||= load_paths_was.dup
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns default list of path globs to load as dependencies.
|
# Returns default list of path globs to load as dependencies.
|
||||||
# Appends custom dependency patterns to the be loaded for Padrino.
|
# Appends custom dependency patterns to the be loaded for Padrino.
|
||||||
|
@ -190,35 +193,32 @@ module Padrino
|
||||||
# Padrino.dependency_paths << "#{Padrino.root}/uploaders/*.rb"
|
# Padrino.dependency_paths << "#{Padrino.root}/uploaders/*.rb"
|
||||||
#
|
#
|
||||||
def dependency_paths
|
def dependency_paths
|
||||||
@_dependency_paths ||= (dependency_paths_was + Array(module_paths))
|
@_dependency_paths ||= dependency_paths_was + module_paths
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Concat to +$LOAD_PATH+ the given paths.
|
|
||||||
#
|
|
||||||
# @param [Array<String>] paths
|
|
||||||
# The paths to concat.
|
|
||||||
#
|
|
||||||
def set_load_paths(*paths)
|
|
||||||
$:.concat(paths); load_paths.concat(paths)
|
|
||||||
$:.uniq!; load_paths.uniq!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def module_paths
|
def module_paths
|
||||||
Padrino.modules.map(&:dependency_paths).flatten!
|
modules.map(&:dependency_paths).flatten
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_paths_was
|
||||||
|
@_load_paths_was ||= [
|
||||||
|
"#{root}/lib",
|
||||||
|
"#{root}/models",
|
||||||
|
"#{root}/shared",
|
||||||
|
].freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def dependency_paths_was
|
def dependency_paths_was
|
||||||
[
|
@_dependency_paths_was ||= [
|
||||||
"#{root}/config/database.rb",
|
"#{root}/config/database.rb",
|
||||||
"#{root}/lib/**/*.rb",
|
"#{root}/lib/**/*.rb",
|
||||||
"#{root}/shared/lib/**/*.rb",
|
|
||||||
"#{root}/models/**/*.rb",
|
"#{root}/models/**/*.rb",
|
||||||
|
"#{root}/shared/lib/**/*.rb",
|
||||||
"#{root}/shared/models/**/*.rb",
|
"#{root}/shared/models/**/*.rb",
|
||||||
"#{root}/config/apps.rb"
|
"#{root}/config/apps.rb"
|
||||||
]
|
].freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -11,7 +11,7 @@ nl:
|
||||||
|
|
||||||
day_names: [zondag, maandag, dinsdag, woensdag, donderdag, vrijdag, zaterdag]
|
day_names: [zondag, maandag, dinsdag, woensdag, donderdag, vrijdag, zaterdag]
|
||||||
abbr_day_names: [zo, ma, di, wo, do, vr, za]
|
abbr_day_names: [zo, ma, di, wo, do, vr, za]
|
||||||
month_names: [~, januari, februari, maart, april, mei, juni, juli, augustus, september, oktober, november]
|
month_names: [~, januari, februari, maart, april, mei, juni, juli, augustus, september, oktober, november, december]
|
||||||
abbr_month_names: [~, jan, feb, maa, apr, mei, jun, jul, aug, sep, okt, nov, dec]
|
abbr_month_names: [~, jan, feb, maa, apr, mei, jun, jul, aug, sep, okt, nov, dec]
|
||||||
order:
|
order:
|
||||||
- day
|
- day
|
|
@ -4,9 +4,9 @@ zh_cn:
|
||||||
# Use the strftime parameters for formats.
|
# Use the strftime parameters for formats.
|
||||||
# When no format has been given, it uses default.
|
# When no format has been given, it uses default.
|
||||||
# You can provide other formats here if you like!
|
# You can provide other formats here if you like!
|
||||||
default: "%Y 年 %m 月 %d 日"
|
default: "%Y年%m月%d日"
|
||||||
short: "%b 月 %d 日"
|
short: "%b月%d日"
|
||||||
long: "公元 %Y 年 %B 月 %d 日"
|
long: "%Y年%B月%d日"
|
||||||
only_day: "%e"
|
only_day: "%e"
|
||||||
|
|
||||||
day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
|
day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
|
||||||
|
@ -20,9 +20,9 @@ zh_cn:
|
||||||
|
|
||||||
time:
|
time:
|
||||||
formats:
|
formats:
|
||||||
default: "%Y 年 %b 月 %d 日 %H:%M:%S %z"
|
default: "%Y年%b月%d日 %H:%M:%S %z"
|
||||||
short: "%d 月 %b 日 %H:%M"
|
short: "%b月%d日 %H:%M"
|
||||||
long: "%Y 年 %B 月 %d 日 %H 时 %M 分"
|
long: "%Y年%B%d日 %H时%M分"
|
||||||
am: "上午"
|
am: "上午"
|
||||||
pm: "下午"
|
pm: "下午"
|
||||||
|
|
|
@ -52,10 +52,10 @@ module Padrino
|
||||||
# :devel:: Development-related information that is unnecessary in debug mode
|
# :devel:: Development-related information that is unnecessary in debug mode
|
||||||
#
|
#
|
||||||
Levels = {
|
Levels = {
|
||||||
:fatal => 7,
|
:fatal => 4,
|
||||||
:error => 6,
|
:error => 3,
|
||||||
:warn => 4,
|
:warn => 2,
|
||||||
:info => 3,
|
:info => 1,
|
||||||
:debug => 0,
|
:debug => 0,
|
||||||
:devel => -1,
|
:devel => -1,
|
||||||
} unless defined?(Levels)
|
} unless defined?(Levels)
|
||||||
|
@ -194,13 +194,13 @@ module Padrino
|
||||||
#
|
#
|
||||||
def colorize(string, *colors)
|
def colorize(string, *colors)
|
||||||
colors.each do |c|
|
colors.each do |c|
|
||||||
string = string.send(c)
|
string = string.colorize(c)
|
||||||
end
|
end
|
||||||
string
|
string
|
||||||
end
|
end
|
||||||
|
|
||||||
def stylized_level(level)
|
def stylized_level(level)
|
||||||
style = ColoredLevels[level].map { |c| "\e[%dm" % String.colors[c] } * ''
|
style = ColoredLevels[level].map { |c| "\e[%dm" % String::Colorizer.colors[c] } * ''
|
||||||
[style, super, "\e[0m"] * ''
|
[style, super, "\e[0m"] * ''
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -280,7 +280,7 @@ module Padrino
|
||||||
|
|
||||||
stream = case config[:stream]
|
stream = case config[:stream]
|
||||||
when :to_file
|
when :to_file
|
||||||
FileUtils.mkdir_p(Padrino.root('log')) unless File.exists?(Padrino.root('log'))
|
FileUtils.mkdir_p(Padrino.root('log')) unless File.exist?(Padrino.root('log'))
|
||||||
File.new(Padrino.root('log', "#{Padrino.env}.log"), 'a+')
|
File.new(Padrino.root('log', "#{Padrino.env}.log"), 'a+')
|
||||||
when :null then StringIO.new
|
when :null then StringIO.new
|
||||||
when :stdout then $stdout
|
when :stdout then $stdout
|
|
@ -8,10 +8,11 @@ module Padrino
|
||||||
# Mounter.new("blog_app", :app_file => "/path/to/blog/app.rb").to("/blog")
|
# Mounter.new("blog_app", :app_file => "/path/to/blog/app.rb").to("/blog")
|
||||||
#
|
#
|
||||||
class Mounter
|
class Mounter
|
||||||
|
DEFAULT_CASCADE = [404, 405]
|
||||||
class MounterException < RuntimeError
|
class MounterException < RuntimeError
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_accessor :name, :uri_root, :app_file, :app_class, :app_root, :app_obj, :app_host
|
attr_accessor :name, :uri_root, :app_file, :app_class, :app_root, :app_obj, :app_host, :cascade
|
||||||
|
|
||||||
##
|
##
|
||||||
# @param [String, Padrino::Application] name
|
# @param [String, Padrino::Application] name
|
||||||
|
@ -31,8 +32,9 @@ module Padrino
|
||||||
@app_file = options[:app_file] || locate_app_file
|
@app_file = options[:app_file] || locate_app_file
|
||||||
@app_obj = options[:app_obj] || app_constant || locate_app_object
|
@app_obj = options[:app_obj] || app_constant || locate_app_object
|
||||||
ensure_app_file! || ensure_app_object!
|
ensure_app_file! || ensure_app_object!
|
||||||
@app_root = options[:app_root] || File.dirname(@app_file)
|
@app_root = options[:app_root] || (@app_obj.respond_to?(:root) && @app_obj.root || File.dirname(@app_file))
|
||||||
@uri_root = "/"
|
@uri_root = "/"
|
||||||
|
@cascade = options[:cascade] ? true == options[:cascade] ? DEFAULT_CASCADE.dup : Array(options[:cascade]) : []
|
||||||
Padrino::Reloader.exclude_constants << @app_class
|
Padrino::Reloader.exclude_constants << @app_class
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,11 +84,12 @@ module Padrino
|
||||||
def map_onto(router)
|
def map_onto(router)
|
||||||
app_data, app_obj = self, @app_obj
|
app_data, app_obj = self, @app_obj
|
||||||
app_obj.set :uri_root, app_data.uri_root
|
app_obj.set :uri_root, app_data.uri_root
|
||||||
app_obj.set :app_name, app_data.name
|
app_obj.set :app_name, app_data.app_obj.app_name.to_s
|
||||||
app_obj.set :app_file, app_data.app_file unless ::File.exist?(app_obj.app_file)
|
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 :root, app_data.app_root unless app_data.app_root.blank?
|
||||||
app_obj.set :public_folder, Padrino.root('public', app_data.uri_root) unless File.exists?(app_obj.public_folder)
|
app_obj.set :public_folder, Padrino.root('public', app_data.uri_root) unless File.exist?(app_obj.public_folder)
|
||||||
app_obj.set :static, File.exist?(app_obj.public_folder) if app_obj.nil?
|
app_obj.set :static, File.exist?(app_obj.public_folder) if app_obj.nil?
|
||||||
|
app_obj.set :cascade, app_data.cascade
|
||||||
app_obj.setup_application! # Initializes the app here with above settings.
|
app_obj.setup_application! # Initializes the app here with above settings.
|
||||||
router.map(:to => app_obj, :path => app_data.uri_root, :host => app_data.app_host)
|
router.map(:to => app_obj, :path => app_data.uri_root, :host => app_data.app_host)
|
||||||
end
|
end
|
||||||
|
@ -106,7 +109,9 @@ module Padrino
|
||||||
#
|
#
|
||||||
def named_routes
|
def named_routes
|
||||||
app_obj.routes.map { |route|
|
app_obj.routes.map { |route|
|
||||||
name_array = "(#{route.name.to_s.split("_").map { |piece| %Q[:#{piece}] }.join(", ")})"
|
route_name = route.name.to_s
|
||||||
|
route_name.sub!(/^#{route.controller} /, "") if route.controller
|
||||||
|
name_array = "(#{route.controller ? %Q[:#{route.controller}] + ", " : ""}:#{route_name})"
|
||||||
request_method = route.request_methods.first
|
request_method = route.request_methods.first
|
||||||
next if route.name.blank? || request_method == 'HEAD'
|
next if route.name.blank? || request_method == 'HEAD'
|
||||||
original_path = route.original_path.is_a?(Regexp) ? route.original_path.inspect : route.original_path
|
original_path = route.original_path.is_a?(Regexp) ? route.original_path.inspect : route.original_path
|
|
@ -0,0 +1,250 @@
|
||||||
|
require 'pathname'
|
||||||
|
require 'padrino-core/reloader/rack'
|
||||||
|
require 'padrino-core/reloader/storage'
|
||||||
|
|
||||||
|
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.
|
||||||
|
#
|
||||||
|
extend self
|
||||||
|
|
||||||
|
# The modification times for every file in a project.
|
||||||
|
MTIMES = {}
|
||||||
|
|
||||||
|
##
|
||||||
|
# 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 ||= Set.new %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 ||= Set.new
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Specified constants can be configured to be reloaded on every request.
|
||||||
|
# Default included constants are: [none]
|
||||||
|
#
|
||||||
|
def include_constants
|
||||||
|
@_include_constants ||= Set.new
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Reload apps and files with changes detected.
|
||||||
|
#
|
||||||
|
def reload!
|
||||||
|
rotation do |file|
|
||||||
|
next unless file_changed?(file)
|
||||||
|
reload_special(file) || reload_regular(file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Remove files and classes loaded with stat
|
||||||
|
#
|
||||||
|
def clear!
|
||||||
|
MTIMES.clear
|
||||||
|
Storage.clear!
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns true if any file changes are detected.
|
||||||
|
#
|
||||||
|
def changed?
|
||||||
|
rotation do |file|
|
||||||
|
break true if file_changed?(file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# We lock dependencies sets to prevent reloading of protected constants
|
||||||
|
#
|
||||||
|
def lock!
|
||||||
|
klasses = ObjectSpace.classes do |klass|
|
||||||
|
klass._orig_klass_name.split('::').first
|
||||||
|
end
|
||||||
|
klasses |= Padrino.mounted_apps.map(&:app_class)
|
||||||
|
exclude_constants.merge(klasses)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# A safe Kernel::require which issues the necessary hooks depending on results
|
||||||
|
#
|
||||||
|
def safe_load(file, options={})
|
||||||
|
began_at = Time.now
|
||||||
|
file = figure_path(file)
|
||||||
|
return unless options[:force] || file_changed?(file)
|
||||||
|
|
||||||
|
Storage.prepare(file) # might call #safe_load recursively
|
||||||
|
logger.devel(file_new?(file) ? :loading : :reload, began_at, file)
|
||||||
|
begin
|
||||||
|
with_silence{ require(file) }
|
||||||
|
Storage.commit(file)
|
||||||
|
update_modification_time(file)
|
||||||
|
rescue Exception => e
|
||||||
|
unless options[:cyclic]
|
||||||
|
logger.error "#{e.class}: #{e.message}; #{e.backtrace.first}"
|
||||||
|
logger.error "Failed to load #{file}; removing partially defined constants"
|
||||||
|
end
|
||||||
|
Storage.rollback(file)
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Removes the specified class and constant.
|
||||||
|
#
|
||||||
|
def remove_constant(const)
|
||||||
|
return if constant_excluded?(const)
|
||||||
|
base, _, object = const.to_s.rpartition('::')
|
||||||
|
base = base.empty? ? Object : base.constantize
|
||||||
|
base.send :remove_const, object
|
||||||
|
logger.devel "Removed constant #{const} from #{base}"
|
||||||
|
rescue NameError
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the list of special tracked files for Reloader.
|
||||||
|
#
|
||||||
|
def special_files
|
||||||
|
@special_files ||= Set.new
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Sets the list of special tracked files for Reloader.
|
||||||
|
#
|
||||||
|
def special_files=(files)
|
||||||
|
@special_files = Set.new(files)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns absolute path of the file.
|
||||||
|
#
|
||||||
|
def figure_path(file)
|
||||||
|
return file if Pathname.new(file).absolute?
|
||||||
|
$LOAD_PATH.each do |path|
|
||||||
|
found = File.join(path, file)
|
||||||
|
return File.expand_path(found) if File.file?(found)
|
||||||
|
end
|
||||||
|
file
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Reloads the file if it's special. For now it's only I18n locale files.
|
||||||
|
#
|
||||||
|
def reload_special(file)
|
||||||
|
return unless special_files.any?{ |f| File.identical?(f, file) }
|
||||||
|
if defined?(I18n)
|
||||||
|
began_at = Time.now
|
||||||
|
I18n.reload!
|
||||||
|
update_modification_time(file)
|
||||||
|
logger.devel :reload, began_at, file
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Reloads ruby file and applications dependent on it.
|
||||||
|
#
|
||||||
|
def reload_regular(file)
|
||||||
|
apps = mounted_apps_of(file)
|
||||||
|
if apps.present?
|
||||||
|
apps.each { |app| app.app_obj.reload! }
|
||||||
|
update_modification_time(file)
|
||||||
|
else
|
||||||
|
safe_load(file)
|
||||||
|
reloadable_apps.each do |app|
|
||||||
|
app.app_obj.reload! if app.app_obj.dependencies.include?(file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
###
|
||||||
|
# Macro for mtime update.
|
||||||
|
#
|
||||||
|
def update_modification_time(file)
|
||||||
|
MTIMES[file] = File.mtime(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
###
|
||||||
|
# Returns true if the file is new or it's modification time changed.
|
||||||
|
#
|
||||||
|
def file_changed?(file)
|
||||||
|
file_new?(file) || File.mtime(file) > MTIMES[file]
|
||||||
|
end
|
||||||
|
|
||||||
|
###
|
||||||
|
# Returns true if the file is new.
|
||||||
|
#
|
||||||
|
def file_new?(file)
|
||||||
|
MTIMES[file].nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Return the mounted_apps providing the app location.
|
||||||
|
# Can be an array because in one app.rb we can define multiple Padrino::Application.
|
||||||
|
#
|
||||||
|
def mounted_apps_of(file)
|
||||||
|
Padrino.mounted_apps.select { |app| File.identical?(file, app.app_file) }
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Searches Ruby files in your +Padrino.load_paths+ , Padrino::Application.load_paths
|
||||||
|
# and monitors them for any changes.
|
||||||
|
#
|
||||||
|
def rotation
|
||||||
|
files_for_rotation.each do |file|
|
||||||
|
file = File.expand_path(file)
|
||||||
|
next if Reloader.exclude.any? { |base| file.start_with?(base) } || !File.file?(file)
|
||||||
|
yield file
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Creates an array of paths for use in #rotation.
|
||||||
|
#
|
||||||
|
def files_for_rotation
|
||||||
|
files = Set.new
|
||||||
|
Padrino.load_paths.each{ |path| files += Dir.glob("#{path}/**/*.rb") }
|
||||||
|
reloadable_apps.each do |app|
|
||||||
|
files << app.app_file
|
||||||
|
files += app.app_obj.dependencies
|
||||||
|
end
|
||||||
|
files + special_files
|
||||||
|
end
|
||||||
|
|
||||||
|
def constant_excluded?(const)
|
||||||
|
(exclude_constants - include_constants).any?{ |c| const._orig_klass_name.start_with?(c) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def reloadable_apps
|
||||||
|
Padrino.mounted_apps.select{ |app| app.app_obj.respond_to?(:reload) && app.app_obj.reload? }
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Disables output, yields block, switches output back.
|
||||||
|
#
|
||||||
|
def with_silence
|
||||||
|
verbosity_level, $-v = $-v, nil
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
$-v = verbosity_level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,26 @@
|
||||||
|
module Padrino
|
||||||
|
module Reloader
|
||||||
|
##
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Invoked in order to perform the reload as part of the request stack.
|
||||||
|
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
|
||||||
|
end
|
|
@ -0,0 +1,55 @@
|
||||||
|
module Padrino
|
||||||
|
module Reloader
|
||||||
|
module Storage
|
||||||
|
extend self
|
||||||
|
|
||||||
|
def clear!
|
||||||
|
files.each_key do |file|
|
||||||
|
remove(file)
|
||||||
|
$LOADED_FEATURES.delete(file)
|
||||||
|
end
|
||||||
|
@files = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove(name)
|
||||||
|
file = files[name] || return
|
||||||
|
file[:constants].each{ |constant| Reloader.remove_constant(constant) }
|
||||||
|
file[:features].each{ |feature| $LOADED_FEATURES.delete(feature) }
|
||||||
|
files.delete(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare(name)
|
||||||
|
file = remove(name)
|
||||||
|
@old_entries ||= {}
|
||||||
|
@old_entries[name] = {
|
||||||
|
:constants => ObjectSpace.classes,
|
||||||
|
:features => old_features = Set.new($LOADED_FEATURES.dup)
|
||||||
|
}
|
||||||
|
features = file && file[:features] || []
|
||||||
|
features.each{ |feature| Reloader.safe_load(feature, :force => true) }
|
||||||
|
$LOADED_FEATURES.delete(name) if old_features.include?(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def commit(name)
|
||||||
|
entry = {
|
||||||
|
:constants => ObjectSpace.new_classes(@old_entries[name][:constants]),
|
||||||
|
:features => Set.new($LOADED_FEATURES) - @old_entries[name][:features] - [name]
|
||||||
|
}
|
||||||
|
files[name] = entry
|
||||||
|
@old_entries.delete(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def rollback(name)
|
||||||
|
new_constants = ObjectSpace.new_classes(@old_entries[name][:constants])
|
||||||
|
new_constants.each{ |klass| Reloader.remove_constant(klass) }
|
||||||
|
@old_entries.delete(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def files
|
||||||
|
@files ||= {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -62,14 +62,15 @@ module Padrino
|
||||||
host = Regexp.new("^#{Regexp.quote(host)}$", true, 'n') unless host.nil? || host.is_a?(Regexp)
|
host = Regexp.new("^#{Regexp.quote(host)}$", true, 'n') unless host.nil? || host.is_a?(Regexp)
|
||||||
|
|
||||||
@mapping << [host, path, match, app]
|
@mapping << [host, path, match, app]
|
||||||
sort!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# The call handler setup to route a request given the mappings specified.
|
# The call handler setup to route a request given the mappings specified.
|
||||||
def call(env)
|
def call(env)
|
||||||
|
began_at = Time.now
|
||||||
path_info = env["PATH_INFO"].to_s
|
path_info = env["PATH_INFO"].to_s
|
||||||
script_name = env['SCRIPT_NAME']
|
script_name = env['SCRIPT_NAME']
|
||||||
http_host = env['HTTP_HOST']
|
http_host = env['HTTP_HOST']
|
||||||
|
last_result = nil
|
||||||
|
|
||||||
@mapping.each do |host, path, match, app|
|
@mapping.each do |host, path, match, app|
|
||||||
next unless host.nil? || http_host =~ host
|
next unless host.nil? || http_host =~ host
|
||||||
|
@ -78,18 +79,16 @@ module Padrino
|
||||||
|
|
||||||
rest = "/" if rest.empty?
|
rest = "/" if rest.empty?
|
||||||
|
|
||||||
return app.call(
|
last_result = app.call(env.merge('SCRIPT_NAME' => script_name + path, 'PATH_INFO' => rest))
|
||||||
env.merge(
|
|
||||||
'SCRIPT_NAME' => (script_name + path),
|
cascade_setting = app.respond_to?(:cascade) ? app.cascade : true
|
||||||
'PATH_INFO' => rest))
|
cascade_statuses = cascade_setting.respond_to?(:include?) ? cascade_setting : Mounter::DEFAULT_CASCADE
|
||||||
|
break unless cascade_setting && cascade_statuses.include?(last_result[0])
|
||||||
|
end
|
||||||
|
last_result || begin
|
||||||
|
Padrino::Logger::Rack.new(nil,'/').send(:log, env, 404, {}, began_at) if logger.debug?
|
||||||
|
[404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path_info}"]]
|
||||||
end
|
end
|
||||||
[404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path_info}"]]
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def sort!
|
|
||||||
@mapping = @mapping.sort_by { |h, p, m, a| -p.size }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -31,6 +31,11 @@ module Padrino
|
||||||
FileUtils.mkdir_p(File.dirname(options[:pid]))
|
FileUtils.mkdir_p(File.dirname(options[:pid]))
|
||||||
end
|
end
|
||||||
options[:server] = detect_rack_handler if options[:server].blank?
|
options[:server] = detect_rack_handler if options[:server].blank?
|
||||||
|
if options[:options].is_a?(Array)
|
||||||
|
parsed_server_options = options.delete(:options).map { |opt| opt.split('=', 2) }.flatten
|
||||||
|
server_options = Hash[*parsed_server_options].symbolize_keys!
|
||||||
|
options.merge!(server_options)
|
||||||
|
end
|
||||||
new(options, app).start
|
new(options, app).start
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
# This file loads certain extensions required by Padrino from ActiveSupport.
|
# This file loads certain extensions required by Padrino from ActiveSupport.
|
||||||
#
|
#
|
||||||
require 'active_support/core_ext/module/aliasing' # alias_method_chain
|
require 'active_support/core_ext/module/aliasing' # alias_method_chain
|
||||||
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/reverse_merge' # reverse_merge
|
||||||
|
require 'active_support/core_ext/hash/keys' # symbolize_keys
|
||||||
|
require 'active_support/core_ext/hash/indifferent_access' # params[:foo]
|
||||||
require 'active_support/core_ext/hash/slice' # slice
|
require 'active_support/core_ext/hash/slice' # slice
|
||||||
require 'active_support/core_ext/object/blank' # present?
|
require 'active_support/core_ext/object/blank' # present?
|
||||||
require 'active_support/core_ext/array/extract_options' # extract_options
|
require 'active_support/core_ext/array/extract_options' # extract_options
|
||||||
|
@ -199,27 +200,41 @@ end
|
||||||
# puts help.red.bold
|
# puts help.red.bold
|
||||||
#
|
#
|
||||||
class String
|
class String
|
||||||
def self.colors
|
# colorize(:red)
|
||||||
@_colors ||= {
|
def colorize(color)
|
||||||
:clear => 0,
|
Colorizer.send(color, self)
|
||||||
:bold => 1,
|
|
||||||
:black => 30,
|
|
||||||
:red => 31,
|
|
||||||
:green => 32,
|
|
||||||
:yellow => 33,
|
|
||||||
:blue => 34,
|
|
||||||
:magenta => 35,
|
|
||||||
:cyan => 36,
|
|
||||||
:white => 37
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
colors.each do |color, value|
|
# Used to colorize strings for the shell
|
||||||
define_method(color) do
|
class Colorizer
|
||||||
["\e[", value.to_s, "m", self, "\e[", self.class.colors[:clear], "m"] * ''
|
# Returns colors integer mapping
|
||||||
|
def self.colors
|
||||||
|
@_colors ||= {
|
||||||
|
:clear => 0,
|
||||||
|
:bold => 1,
|
||||||
|
:black => 30,
|
||||||
|
:red => 31,
|
||||||
|
:green => 32,
|
||||||
|
:yellow => 33,
|
||||||
|
:blue => 34,
|
||||||
|
:magenta => 35,
|
||||||
|
:cyan => 36,
|
||||||
|
:white => 37
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Defines class level color methods
|
||||||
|
# i.e Colorizer.red("hello")
|
||||||
|
class << self
|
||||||
|
Colorizer.colors.each do |color, value|
|
||||||
|
define_method(color) do |target|
|
||||||
|
"\e[#{value}m" << target << "\e[0m"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Strip unnecessary indentation of the front of a string
|
||||||
def undent
|
def undent
|
||||||
gsub(/^.{#{slice(/^ +/).size}}/, '')
|
gsub(/^.{#{slice(/^ +/).size}}/, '')
|
||||||
end
|
end
|
||||||
|
@ -242,19 +257,3 @@ I18n.load_path += Dir["#{File.dirname(__FILE__)}/locale/*.yml"] if defined?(I18n
|
||||||
# Used to determine if this file has already been required
|
# Used to determine if this file has already been required
|
||||||
#
|
#
|
||||||
module SupportLite; end
|
module SupportLite; end
|
||||||
|
|
||||||
module Padrino
|
|
||||||
class Utils
|
|
||||||
###
|
|
||||||
# Silences output verbosity level so load
|
|
||||||
# errors are not visible when safe_load(file)
|
|
||||||
#
|
|
||||||
def self.silence_output
|
|
||||||
@verbosity_level, $-v = $-v, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.unsilence_output
|
|
||||||
$-v = @verbosity_level
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
module Padrino
|
module Padrino
|
||||||
# The version constant for the current version of Padrino.
|
# The version constant for the current version of Padrino.
|
||||||
VERSION = '0.11.4' unless defined?(Padrino::VERSION)
|
VERSION = '0.12.0' unless defined?(Padrino::VERSION)
|
||||||
|
|
||||||
#
|
#
|
||||||
# The current Padrino version.
|
# The current Padrino version.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue