padrino-contrib 0.1.13 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of padrino-contrib might be problematic. Click here for more details.
- checksums.yaml +15 -0
- data/.gitignore +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +20 -1
- data/README.md +38 -0
- data/Rakefile +1 -2
- data/lib/padrino-contrib.rb +1 -0
- data/lib/padrino-contrib/auto_locale.rb +60 -5
- data/lib/padrino-contrib/exception_notifier.rb +10 -3
- data/lib/padrino-contrib/helpers/breadcrumbs.rb +185 -0
- data/lib/padrino-contrib/version.rb +1 -1
- data/spec/auto_locale_spec.rb +126 -0
- data/spec/breadcrumb_helpers_spec.rb +133 -0
- data/spec/exception_notifier_spec.rb +102 -0
- data/spec/spec_helper.rb +21 -1
- data/spec/views/exception_notifier/errors.erb +1 -0
- data/spec/views/exception_notifier/layouts/layout.erb +2 -0
- metadata +34 -44
- data/README.rdoc +0 -32
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OGM1NTY5NDMyOWVkZDVhNGZkZjQxNTRkMzYzNDEzZDY1ODFmZWZiOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MzJkM2EyN2EwOWQ4NjAzNWMwMWM4MzI4N2U1OTA1NzE5Yzk2MWE4Nw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YjdmODEyZjQ3MmE5OGE4Y2ZmMGE2MGEyNTk3NTFhMTA4YTlkZWMxMzg4ZjYw
|
10
|
+
ZTQ0NDUwN2RjNjk5OGUzMzAxODg1NmU2NmRmYzYyOTA0MTU1ZTc3ZmFmNmRi
|
11
|
+
ZmNiYzA2OTQ0YTRhMjk3MGVkMjk0OTU3MjI0MWE5NTIzNDMzYWI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODk0ZDk5ZmE5OWQ2ODY2YjU5ZmFhYmM4MGFjZDFhYmQ4YWJlYjJjN2FmMGNm
|
14
|
+
YWM5NTFhNDg5YTM5YTZmNzYxNjIwYTI3ZTEzZjU0NTVmYzc2NWU2ODU1YjUx
|
15
|
+
MWE5ZDcxYWYyMTA2OTY0Mzk2MWJjOWIwZWEwODIzMzFjNmRjZDU=
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,4 +1,23 @@
|
|
1
|
-
source "
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in padrino-contrib.gemspec
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
gem 'i18n'
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem 'rake'
|
10
|
+
end
|
11
|
+
|
12
|
+
group :test, :development do
|
13
|
+
gem 'pry-debugger' unless ENV['TRAVIS']
|
14
|
+
end
|
15
|
+
|
16
|
+
group :test do
|
17
|
+
gem 'padrino-core'
|
18
|
+
gem 'padrino-helpers'
|
19
|
+
gem 'padrino-mailer'
|
20
|
+
gem 'rspec'
|
21
|
+
gem 'rack-test'
|
22
|
+
gem 'webrat'
|
23
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# padrino-contrib
|
2
|
+
|
3
|
+
## Contributed Plugins and Utilities
|
4
|
+
|
5
|
+
This package includes a variety of add-on components for Padrino Framework:
|
6
|
+
|
7
|
+
* breadcrumbs - Simple breadcrumb navigation helpers
|
8
|
+
* exception_notifier - Send errors through mail or/and to redmine
|
9
|
+
* auto_locale - Switch for you automatically the I18n.locale
|
10
|
+
* flash_session - Middleware that help you in passing your session in the URI, when it should be in the cookie.
|
11
|
+
* orm_ar_permalink - Generate permalink for a specified column on ActiveRecord
|
12
|
+
* orm_ar_permalink_i18n - Generate permalink for a specified multi language column(s) on ActiveRecord
|
13
|
+
* orm_ar_translate - Translate for you your ActiveRecord columns
|
14
|
+
* orm_mm_permalink - Generate permalink for a specified column on MongoMapper
|
15
|
+
* orm_mm_search - Full text search in MongoMapper in specified columns
|
16
|
+
* helpers_assets_compressor - Joins and compress your js/css with yui-compressor
|
17
|
+
|
18
|
+
## Use
|
19
|
+
|
20
|
+
In your Padrino project edit:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
# Gemfile
|
24
|
+
gem 'padrino-contrib'
|
25
|
+
|
26
|
+
# boot.rb
|
27
|
+
require 'padrino-contrib/exception_notifier'
|
28
|
+
# require 'padrino-contrib/orm/active_record/permalink'
|
29
|
+
# require 'padrino-contrib/orm/active_record/textile'
|
30
|
+
# require 'padrino-contrib/helpers/breadcrumbs'
|
31
|
+
|
32
|
+
Padrino.load! # Remember to add contribs before that line!
|
33
|
+
|
34
|
+
# app.rb
|
35
|
+
class MyApp < Padrino::Application
|
36
|
+
register Padrino::Contrib::ExceptionNotifier
|
37
|
+
end
|
38
|
+
```
|
data/Rakefile
CHANGED
@@ -21,8 +21,7 @@ end
|
|
21
21
|
task :release => :bump
|
22
22
|
|
23
23
|
desc "Run complete application spec suite"
|
24
|
-
RSpec::Core::RakeTask.new(
|
25
|
-
t.skip_bundler = true
|
24
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
26
25
|
t.pattern = './spec/**/*_spec.rb'
|
27
26
|
t.rspec_opts = %w(-fs --color --fail-fast)
|
28
27
|
end
|
data/lib/padrino-contrib.rb
CHANGED
@@ -9,6 +9,7 @@ module Padrino
|
|
9
9
|
autoload :AssetsCompressor, 'padrino-contrib/helpers/assets_compressor.rb'
|
10
10
|
autoload :JQuery, 'padrino-contrib/helpers/jquery.rb'
|
11
11
|
autoload :Flash, 'padrino-contrib/helpers/flash.rb'
|
12
|
+
autoload :Breadcrumbs, 'padrino-contrib/helpers/breadcrumbs.rb'
|
12
13
|
end # Helpers
|
13
14
|
end # Contrib
|
14
15
|
end # Padrino
|
@@ -9,6 +9,7 @@ module Padrino
|
|
9
9
|
# class MyApp < Padrino::Application
|
10
10
|
# register AutoLocale
|
11
11
|
# set :locales, [:en, :ru, :de] # First locale is the default locale
|
12
|
+
# set :locale_exclusive_paths, ['/js', '/css', '/img'] # asset uri paths which shouldn't be localized
|
12
13
|
# end
|
13
14
|
#
|
14
15
|
# # view.haml
|
@@ -22,7 +23,9 @@ module Padrino
|
|
22
23
|
# This reload the page changing the I18n.locale
|
23
24
|
#
|
24
25
|
def switch_to_lang(lang)
|
25
|
-
|
26
|
+
return unless settings.locales.include?(lang)
|
27
|
+
return url("/#{lang}", false) if request.path_info == '/'
|
28
|
+
url(request.path_info.sub(/\/#{I18n.locale}/, "/#{lang}"), false)
|
26
29
|
end
|
27
30
|
end # Helpers
|
28
31
|
|
@@ -30,17 +33,69 @@ module Padrino
|
|
30
33
|
app.helpers Padrino::Contrib::AutoLocale::Helpers
|
31
34
|
app.extend ClassMethods
|
32
35
|
app.set :locales, [:en]
|
36
|
+
app.set :locale_exclusive_paths, []
|
37
|
+
@@exclusive_paths = false
|
33
38
|
app.before do
|
39
|
+
# Gather excluded paths
|
40
|
+
unless @@exclusive_paths.is_a?(Array)
|
41
|
+
# auto include sinatra-assetpack configuration
|
42
|
+
if settings.respond_to?(:assets) and
|
43
|
+
settings.assets.respond_to?(:served) and
|
44
|
+
settings.assets.served.is_a?(Hash)
|
45
|
+
@@exclusive_paths = settings.locale_exclusive_paths + settings.assets.served.keys
|
46
|
+
else
|
47
|
+
@@exclusive_paths = settings.locale_exclusive_paths
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Default to the first locale
|
52
|
+
I18n.locale = settings.locales.first
|
53
|
+
|
54
|
+
# First check if the path starts with a known locale
|
34
55
|
if request.path_info =~ /^\/(#{settings.locales.join('|')})\b/
|
35
56
|
I18n.locale = $1.to_sym
|
57
|
+
|
58
|
+
# Then check if the path is excluded
|
59
|
+
elsif AutoLocale.excluded_path?(request.path_info, @@exclusive_paths)
|
60
|
+
next
|
61
|
+
|
62
|
+
# Root path "/" needs special treatment, as it doesn't contain any language parameter.
|
63
|
+
elsif request.path_info =~ /^\/?$/
|
64
|
+
# Try to guess the preferred language from the http header
|
65
|
+
for browser_locale in (request.env['HTTP_ACCEPT_LANGUAGE'] || '').split(",")
|
66
|
+
locale = browser_locale.split(";").first.downcase.sub('-', '_')
|
67
|
+
if settings.locales.include?(locale.to_sym)
|
68
|
+
I18n.locale = locale.to_sym
|
69
|
+
break
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# Then redirect from "/" to "/:lang" to match the new routing urls
|
73
|
+
redirect url("/#{I18n.locale.to_s}/", false)
|
74
|
+
|
75
|
+
# Return 404 not found for everything else
|
36
76
|
else
|
37
|
-
|
38
|
-
not_found if request.path_info !~ /^\/?$/
|
77
|
+
not_found
|
39
78
|
end
|
40
79
|
end
|
41
80
|
|
42
81
|
def self.padrino_route_added(route, verb, path, args, options, block)
|
43
|
-
|
82
|
+
##
|
83
|
+
# TODO: Regex original_path needs to be served as well.
|
84
|
+
#
|
85
|
+
return unless route.original_path.is_a?(String)
|
86
|
+
excluded_paths = block.binding.eval('settings').locale_exclusive_paths
|
87
|
+
return if AutoLocale.excluded_path?(route.original_path, excluded_paths)
|
88
|
+
route.path = "/:lang#{route.original_path}" unless route.original_path =~ /:lang/
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.excluded_path?(path, excluded_paths)
|
92
|
+
excluded_paths.detect do |excluded_path|
|
93
|
+
if excluded_path.is_a?(Regexp)
|
94
|
+
!!excluded_path.match(path)
|
95
|
+
elsif excluded_path.is_a?(String)
|
96
|
+
path.start_with?(excluded_path.end_with?("/") ? excluded_path : "#{excluded_path}/")
|
97
|
+
end
|
98
|
+
end
|
44
99
|
end
|
45
100
|
end
|
46
101
|
|
@@ -50,7 +105,7 @@ module Padrino
|
|
50
105
|
#
|
51
106
|
def url(*args)
|
52
107
|
params = args.extract_options!
|
53
|
-
params[:lang]
|
108
|
+
params[:lang] ||= I18n.locale
|
54
109
|
args << params
|
55
110
|
super(*args)
|
56
111
|
end
|
@@ -23,16 +23,23 @@ module Padrino
|
|
23
23
|
app.set :exceptions_subject, "Exception" unless app.respond_to?(:exceptions_subject)
|
24
24
|
app.set :exceptions_to, "errors@localhost.local" unless app.respond_to?(:exceptions_to)
|
25
25
|
app.set :exceptions_from, "foo@bar.local" unless app.respond_to?(:exceptions_from)
|
26
|
-
app.set :exceptions_layout, :
|
26
|
+
app.set :exceptions_layout, :application unless app.respond_to?(:exceptions_layout)
|
27
27
|
app.set :exceptions_views, app.views unless app.respond_to?(:exceptions_views)
|
28
28
|
app.set :redmine, {} unless app.respond_to?(:redmine)
|
29
|
+
app.set :exceptions_params_filter, ['password', 'password_confirmation'] unless app.respond_to?(:exceptions_params_filter)
|
29
30
|
app.error 500 do
|
30
31
|
boom = env['sinatra.error']
|
31
32
|
body = ["#{boom.class} - #{boom.message}:", *boom.backtrace].join("\n ")
|
32
33
|
body += "\n\n---Env:\n"
|
33
34
|
env.each { |k,v| body += "\n#{k}: #{v}" }
|
34
35
|
body += "\n\n---Params:\n"
|
35
|
-
params.each
|
36
|
+
params.each do |k,v|
|
37
|
+
if settings.exceptions_params_filter.include?(k)
|
38
|
+
body += "\n#{k.inspect} => [FILTERED]"
|
39
|
+
else
|
40
|
+
body += "\n#{k.inspect} => #{v.inspect}"
|
41
|
+
end
|
42
|
+
end
|
36
43
|
logger.error body
|
37
44
|
settings.redmine.each { |k,v| body += "\n#{k.to_s.capitalize}: #{v}" }
|
38
45
|
app.email do
|
@@ -45,7 +52,7 @@ module Padrino
|
|
45
52
|
content_type 'text/html', :charset => "utf-8"
|
46
53
|
render settings.exceptions_page, :layout => settings.exceptions_layout, :views => settings.exceptions_views
|
47
54
|
end
|
48
|
-
app.
|
55
|
+
app.not_found do
|
49
56
|
response.status = 404
|
50
57
|
content_type 'text/html', :charset => "utf-8"
|
51
58
|
render settings.exceptions_page, :layout => settings.exceptions_layout, :views => settings.exceptions_views
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module Padrino
|
2
|
+
module Contrib
|
3
|
+
module Helpers
|
4
|
+
class Breadcrumb
|
5
|
+
attr_accessor :home, :items
|
6
|
+
|
7
|
+
DEFAULT_URL = "/"
|
8
|
+
DEFAULT_CAPTION ="Home Page"
|
9
|
+
|
10
|
+
##
|
11
|
+
# Initialize breadcrumbs with default value.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# before do
|
15
|
+
# @breadcrumbs = breadcrumbs.new
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
def initialize
|
19
|
+
reset!
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Set the custom home (Parent) link.
|
24
|
+
#
|
25
|
+
# @param [String] url
|
26
|
+
# The url href.
|
27
|
+
#
|
28
|
+
# @param [String] caption
|
29
|
+
# The text caption.
|
30
|
+
#
|
31
|
+
# @param [Hash] options
|
32
|
+
# The HTML options to include in li.
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# breadcrumbs.set_home "/HomeFoo", "Foo Home", :id => "home-breadcrumb"
|
36
|
+
#
|
37
|
+
def set_home(url, caption, options = {})
|
38
|
+
self.home = {
|
39
|
+
:url => url.to_s,
|
40
|
+
:caption => caption.to_s.humanize.html_safe,
|
41
|
+
:name => :home,
|
42
|
+
:options => options
|
43
|
+
}
|
44
|
+
reset
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Reset breadcrumbs to default or personal home.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# breadcrumbs.reset
|
52
|
+
#
|
53
|
+
def reset
|
54
|
+
self.items = []
|
55
|
+
self.items << home
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Reset breadcrumbs to default home.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# breadcrumbs.reset!
|
63
|
+
#
|
64
|
+
def reset!
|
65
|
+
self.home = {
|
66
|
+
:name => :home,
|
67
|
+
:url => DEFAULT_URL,
|
68
|
+
:caption => DEFAULT_CAPTION,
|
69
|
+
:options => {}
|
70
|
+
}
|
71
|
+
reset
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Add a new breadcrumbs.
|
76
|
+
#
|
77
|
+
# @param [String] name
|
78
|
+
# The name of resource.
|
79
|
+
# @param [Symbol] name
|
80
|
+
# The name of resource.
|
81
|
+
#
|
82
|
+
# @param [String] url
|
83
|
+
# The url href.
|
84
|
+
#
|
85
|
+
# @param [String] caption
|
86
|
+
# The text caption.
|
87
|
+
#
|
88
|
+
# @param [Hash] options
|
89
|
+
# The HTML options to include in li.
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# breadcrumbs.add "foo", "/foo", "Foo Link", :id => "foo-id"
|
93
|
+
# breadcrumbs.add :foo, "/foo", "Foo Link", :class => "foo-class"
|
94
|
+
#
|
95
|
+
def add(name, url, caption, options = {})
|
96
|
+
items << {
|
97
|
+
:name => name.to_sym,
|
98
|
+
:url => url.to_s,
|
99
|
+
:caption => caption.to_s.humanize.html_safe,
|
100
|
+
:options => options
|
101
|
+
}
|
102
|
+
end
|
103
|
+
alias :<< :add
|
104
|
+
|
105
|
+
##
|
106
|
+
# Remove a breadcrumb.
|
107
|
+
#
|
108
|
+
# @param [String] name
|
109
|
+
# The name of resource to delete from breadcrumbs list.
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# breadcrumbs.del "foo"
|
113
|
+
# breadcrumbs.del :foo
|
114
|
+
#
|
115
|
+
def del(name)
|
116
|
+
items.delete_if { |item| item[:name] == name.to_sym }
|
117
|
+
end
|
118
|
+
end # Breadcrumb
|
119
|
+
|
120
|
+
module Breadcrumbs
|
121
|
+
##
|
122
|
+
# Render breadcrumbs to view.
|
123
|
+
#
|
124
|
+
# @param [Breadcrumbs] breadcrumbs
|
125
|
+
# The breadcrumbs to render into view.
|
126
|
+
#
|
127
|
+
# @param [Boolean] bootstrap
|
128
|
+
# If true, render separation (useful with Twitter Bootstrap).
|
129
|
+
#
|
130
|
+
# @param [String] active
|
131
|
+
# CSS class style set to active breadcrumb.
|
132
|
+
#
|
133
|
+
# @param [Hash] options
|
134
|
+
# The HTML options to include in ul.
|
135
|
+
#
|
136
|
+
# @return [String] Unordered list with breadcrumbs
|
137
|
+
#
|
138
|
+
# @example
|
139
|
+
# = breadcrumbs @breacrumbs
|
140
|
+
# # Generates:
|
141
|
+
# # <ul>
|
142
|
+
# # <li><a href="/foo">Foo Link</a></li>
|
143
|
+
# # <li class="active"><a href="/bar">Bar Link</a></li>
|
144
|
+
# # </ul>
|
145
|
+
#
|
146
|
+
def breadcrumbs(breadcrumbs, bootstrap = false, active = "active", options = {})
|
147
|
+
content = ActiveSupport::SafeBuffer.new
|
148
|
+
breadcrumbs.items[0..-2].each do |item|
|
149
|
+
content << render_item(item, bootstrap)
|
150
|
+
end
|
151
|
+
last = breadcrumbs.items.last
|
152
|
+
last_options = last[:options]
|
153
|
+
last = link_to(last[:caption], last[:url])
|
154
|
+
|
155
|
+
classes = [options[:class], last_options[:class]].map { |class_name| class_name.to_s.split(/\s/) }
|
156
|
+
classes[0] << "breadcrumb"
|
157
|
+
classes[1] << active if active
|
158
|
+
options[:class], last_options[:class] = classes.map { |class_name| class_name * " " }
|
159
|
+
|
160
|
+
content << content_tag(:li, last, last_options)
|
161
|
+
content_tag(:ul, content, options)
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
##
|
166
|
+
# Private method to return list item.
|
167
|
+
#
|
168
|
+
# @param [Hash] item
|
169
|
+
# The breadcrumb item.
|
170
|
+
#
|
171
|
+
# @param [Boolean] bootstrap
|
172
|
+
# If true, render separation (useful with Twitter Bootstrap).
|
173
|
+
#
|
174
|
+
# @return [String] List item with breadcrumb
|
175
|
+
#
|
176
|
+
def render_item(item, bootstrap)
|
177
|
+
content = ActiveSupport::SafeBuffer.new
|
178
|
+
content << link_to(item[:caption], item[:url])
|
179
|
+
content << content_tag(:span, "/", :class => "divider") if bootstrap
|
180
|
+
content_tag(:li, content, item[:options])
|
181
|
+
end
|
182
|
+
end # Breadcrumbs
|
183
|
+
end # Helpers
|
184
|
+
end # Contrib
|
185
|
+
end # Padrino
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Padrino::Contrib::AutoLocale do
|
4
|
+
before :all do
|
5
|
+
mock_app {
|
6
|
+
register Padrino::Contrib::AutoLocale
|
7
|
+
set :locales, [ :es, :en, :ru ]
|
8
|
+
|
9
|
+
get('/') { 'root' }
|
10
|
+
get('/bar') { 'bar' }
|
11
|
+
get(:foo) { 'foo' }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
after(:each) { I18n.locale = I18n.default_locale }
|
15
|
+
|
16
|
+
describe 'when requesting a localized path' do
|
17
|
+
it 'sets I18n.locale to the requested locale' do
|
18
|
+
expect { get '/ru' }.to change { I18n.locale }.to :ru
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns 404 if requesting an unsupported locale' do
|
22
|
+
get '/ja'
|
23
|
+
expect(last_response).to be_not_found
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when requesting the root path '/'" do
|
28
|
+
it 'redirects to the default locale' do
|
29
|
+
get '/'
|
30
|
+
expect(last_response).to be_redirect
|
31
|
+
follow_redirect!
|
32
|
+
expect(last_request.path_info).to eq "/#{@app.locales.first}/"
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'sets I18n.locale to the first locale' do
|
36
|
+
expect { get '/' }.to change { I18n.locale }.to @app.locales.first
|
37
|
+
end
|
38
|
+
|
39
|
+
it "doesn't choke when the HTTP_ACCEPT_LANGUAGE header is not present" do
|
40
|
+
expect do
|
41
|
+
get '/', { }, 'HTTP_ACCEPT_LANGUAGE' => nil
|
42
|
+
end.not_to raise_exception NoMethodError
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'when setting locale_exclusive_paths' do
|
47
|
+
before :each do
|
48
|
+
mock_app {
|
49
|
+
register Padrino::Contrib::AutoLocale
|
50
|
+
set :locales, [ :es, :en ]
|
51
|
+
set :locale_exclusive_paths, [ '/unlocalized' ]
|
52
|
+
get('/bar') { 'bar' }
|
53
|
+
get('/unlocalized/path') { 'unlocalized path' }
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns 404 if the path is not excluded' do
|
58
|
+
get '/bar'
|
59
|
+
expect(last_response).to be_not_found
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when the path is excluded' do
|
63
|
+
it 'does not prepend :lang to the route' do
|
64
|
+
expect(@app.routes.last.original_path).not_to match /:lang/
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'lets the request through' do
|
68
|
+
get '/unlocalized/path'
|
69
|
+
expect(last_response).to be_ok
|
70
|
+
expect(last_response.body).to eq 'unlocalized path'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'sets I18n.locale to the first locale' do
|
74
|
+
expect { get '/unlocalized/path' }.to change { I18n.locale }.to @app.locales.first
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'allows excluding the root path "/"' do
|
79
|
+
@app.locale_exclusive_paths << /^\/?$/
|
80
|
+
@app.get('/') { 'root path' }
|
81
|
+
get '/'
|
82
|
+
expect(last_response).not_to be_redirect
|
83
|
+
expect(last_response.body).to eq 'root path'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'overloaded #url' do
|
88
|
+
before(:each) { get '/en' }
|
89
|
+
|
90
|
+
it 'prepends the current lang' do
|
91
|
+
expect(@app.url(:foo)).to eq '/en/foo'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'allows overriding lang' do
|
95
|
+
expect(@app.url(:foo, :lang => 'ru')).to eq '/ru/foo'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#switch_to_lang' do
|
100
|
+
before :all do
|
101
|
+
mock_app {
|
102
|
+
register Padrino::Contrib::AutoLocale
|
103
|
+
set :locales, [ :es, :en ]
|
104
|
+
set :locale_exclusive_paths, [ /^\/?$/, '/unlocalized' ]
|
105
|
+
|
106
|
+
get('/(:lang)') { switch_to_lang(:en) }
|
107
|
+
get('/unlocalized/path') { switch_to_lang(:en) }
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'returns the current localized path switched to the requested lang' do
|
112
|
+
get '/es'
|
113
|
+
expect(last_response.body).to eq '/en'
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'switches the unlocalized root path to the requested lang' do
|
117
|
+
get '/'
|
118
|
+
expect(last_response.body).to eq '/en'
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'returns the same path if the path is not localized' do
|
122
|
+
get '/unlocalized/path'
|
123
|
+
expect(last_response.body).to eq '/unlocalized/path'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "BreadcrumbHelpers" do
|
4
|
+
include Padrino::Helpers::OutputHelpers
|
5
|
+
include Padrino::Helpers::TagHelpers
|
6
|
+
include Padrino::Helpers::AssetTagHelpers
|
7
|
+
include Padrino::Contrib::Helpers::Breadcrumbs
|
8
|
+
|
9
|
+
let(:breadcrumb){ Padrino::Helpers::Breadcrumb.new }
|
10
|
+
after(:each) { breadcrumb.reset! }
|
11
|
+
|
12
|
+
describe "for Breadcrumbs#breadcrumbs method" do
|
13
|
+
it 'should support breadcrumbs which is Padrino::Helpers::Breadcrumbs instance.' do
|
14
|
+
breadcrumb.add "foo", "/foo", "foo link"
|
15
|
+
expect(breadcrumbs(breadcrumb)).to have_selector(:a, :content => "Foo link", :href => "/foo")
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should support bootstrap' do
|
19
|
+
breadcrumb.add "foo", "/foo", "foo link"
|
20
|
+
expect(breadcrumbs(breadcrumb, true)).to have_selector(:span, :content => "/", :class => "divider")
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should support active' do
|
24
|
+
breadcrumb.add "foo", "/foo", "foo link"
|
25
|
+
expect(breadcrumbs(breadcrumb, nil, "custom-active")).to have_selector(:li, :class => "custom-active")
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should support options' do
|
29
|
+
actual_html = breadcrumbs(breadcrumb, nil, nil, :id => "breadcrumbs-id", :class => "breadcrumbs-class")
|
30
|
+
expect(actual_html).to have_selector(:ul, :class => "breadcrumbs-class breadcrumb", :id => "breadcrumbs-id")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "for #add method" do
|
35
|
+
it 'should support name of string and symbol type' do
|
36
|
+
breadcrumb.add "foo", "/foo", "Foo Link"
|
37
|
+
breadcrumb.add :bar, "/bar", "Bar Link"
|
38
|
+
|
39
|
+
actual_html = breadcrumbs(breadcrumb)
|
40
|
+
expect(actual_html).to have_selector(:a, :content => "Foo link", :href => "/foo")
|
41
|
+
expect(actual_html).to have_selector(:a, :content => "Bar link", :href => "/bar")
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should support url' do
|
45
|
+
breadcrumb.add :foo, "/foo", "Foo Link"
|
46
|
+
expect(breadcrumbs(breadcrumb)).to have_selector(:a, :href => "/foo")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should support caption' do
|
50
|
+
breadcrumb.add :foo, "/foo", "Foo Link"
|
51
|
+
expect(breadcrumbs(breadcrumb)).to have_selector(:a, :content => "Foo link")
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should support options' do
|
55
|
+
breadcrumb.add :foo, "/foo", "Foo Link", :id => "foo-id", :class => "foo-class"
|
56
|
+
breadcrumb.add :bar, "/bar", "Bar Link", :id => "bar-id", :class => "bar-class"
|
57
|
+
|
58
|
+
actual_html = breadcrumbs(breadcrumb)
|
59
|
+
expect(actual_html).to have_selector(:li, :class => "foo-class", :id => "foo-id")
|
60
|
+
expect(actual_html).to have_selector(:li, :class => "bar-class active", :id => "bar-id")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "for #del method" do
|
65
|
+
it 'should support name of string type' do
|
66
|
+
breadcrumb.add "foo", "/foo", "Foo Link"
|
67
|
+
breadcrumb.add :bar, "/bar", "Bar Link"
|
68
|
+
|
69
|
+
breadcrumb.del "foo"
|
70
|
+
breadcrumb.del "bar"
|
71
|
+
|
72
|
+
actual_html = breadcrumbs(breadcrumb)
|
73
|
+
expect(actual_html).not_to have_selector(:a, :content => "Foo link", :href => "/foo")
|
74
|
+
expect(actual_html).not_to have_selector(:a, :content => "Bar link", :href => "/bar")
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should support name of symbol type' do
|
78
|
+
breadcrumb.add "foo", "/foo", "Foo Link"
|
79
|
+
breadcrumb.add :bar, "/bar", "Bar Link"
|
80
|
+
|
81
|
+
breadcrumb.del :foo
|
82
|
+
breadcrumb.del :bar
|
83
|
+
|
84
|
+
actual_html = breadcrumbs(breadcrumb)
|
85
|
+
expect(actual_html).not_to have_selector(:a, :content => "Foo link", :href => "/foo")
|
86
|
+
expect(actual_html).not_to have_selector(:a, :content => "Bar link", :href => "/bar")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "for #set_home method" do
|
91
|
+
it 'should modified home item elements.' do
|
92
|
+
breadcrumb.set_home("/custom", "Custom Home Page")
|
93
|
+
expect(breadcrumbs(breadcrumb)).to have_selector(:a, :content => "Custom home page", :href => "/custom")
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should support options' do
|
97
|
+
breadcrumb.set_home("/custom", "Custom Home Page", :id => "home-id")
|
98
|
+
|
99
|
+
actual_html = breadcrumbs(breadcrumb)
|
100
|
+
expect(actual_html).to have_selector(:li, :id => "home-id")
|
101
|
+
expect(actual_html).to have_selector(:a, :content => "Custom home page", :href => "/custom")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "for #reset method" do
|
106
|
+
it 'should be #items which contains only home item.' do
|
107
|
+
breadcrumb.set_home("/custom", "Custom Home Page")
|
108
|
+
breadcrumb.add "foo", "/foo", "Foo Link"
|
109
|
+
breadcrumb.add :bar, "/bar", "Bar Link"
|
110
|
+
|
111
|
+
breadcrumb.reset
|
112
|
+
|
113
|
+
actual_html = breadcrumbs(breadcrumb)
|
114
|
+
expect(actual_html).to have_selector(:a, :content => "Custom home page", :href => "/custom")
|
115
|
+
expect(actual_html).not_to have_selector(:a, :content => "Foo link", :href => "/foo")
|
116
|
+
expect(actual_html).not_to have_selector(:a, :content => "Bar link", :href => "/bar")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "for #reset! method" do
|
121
|
+
it 'should be #items which contains only default home item.' do
|
122
|
+
breadcrumb.add "foo", "/foo", "foo link"
|
123
|
+
breadcrumb.add :bar, "/bar", "Bar Link"
|
124
|
+
|
125
|
+
breadcrumb.reset!
|
126
|
+
|
127
|
+
actual_html = breadcrumbs(breadcrumb)
|
128
|
+
expect(actual_html).to have_selector(:a, :content => "Home Page", :href => "/")
|
129
|
+
expect(actual_html).not_to have_selector(:a, :content => "Foo link", :href => "/foo")
|
130
|
+
expect(actual_html).not_to have_selector(:a, :content => "Bar link", :href => "/bar")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mail'
|
3
|
+
|
4
|
+
describe Padrino::Contrib::ExceptionNotifier do
|
5
|
+
before :each do
|
6
|
+
mock_app {
|
7
|
+
register Padrino::Helpers
|
8
|
+
register Padrino::Mailer
|
9
|
+
set :delivery_method, :test => { } # Resembles a more realistic SMTP configuration
|
10
|
+
register Padrino::Contrib::ExceptionNotifier
|
11
|
+
set :exceptions_views, Padrino.root('views/exception_notifier')
|
12
|
+
set :exceptions_page, 'errors.erb'
|
13
|
+
set :exceptions_layout, "layout.erb"
|
14
|
+
|
15
|
+
get(:boom) { 420 / 0 }
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def last_email
|
20
|
+
Mail::TestMailer.deliveries.last
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when an exception is raised' do
|
24
|
+
it 'sends a notification email' do
|
25
|
+
expect { get '/boom' }.to change { Mail::TestMailer.deliveries }
|
26
|
+
expect(last_email.subject).to eq '[Exception] ZeroDivisionError - divided by 0'
|
27
|
+
expect(last_email.to).to eq [ 'errors@localhost.local' ]
|
28
|
+
expect(last_email.from).to eq [ 'foo@bar.local' ]
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'allows customizing the email subject' do
|
32
|
+
@app.set :exceptions_subject, 'Custom subject'
|
33
|
+
get '/boom'
|
34
|
+
expect(last_email.subject).to eq '[Custom subject] ZeroDivisionError - divided by 0'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'allows customizing the recipients' do
|
38
|
+
@app.set :exceptions_to, 'Foo <foo@example.com>, bar@example.com'
|
39
|
+
get '/boom'
|
40
|
+
expect(last_email.to).to eq [ 'foo@example.com', 'bar@example.com' ]
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'allows customizing the sender' do
|
44
|
+
@app.set :exceptions_from, 'Foo <foo@example.com>'
|
45
|
+
get '/boom'
|
46
|
+
expect(last_email.from).to eq [ 'foo@example.com' ]
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'sends the request params' do
|
50
|
+
get '/boom', :foo => 'bar'
|
51
|
+
expect(last_email.body).to match /"foo" => "bar"/
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'filters out password and password_confirmation params' do
|
55
|
+
get '/boom', :password => 'super_secret', :password_confirmation => 'super_secret'
|
56
|
+
expect(last_email.body).to match /"password" => \[FILTERED\]/
|
57
|
+
expect(last_email.body).to match /"password_confirmation" => \[FILTERED\]/
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'allows customizing filtered params' do
|
61
|
+
@app.set :exceptions_params_filter, [ 'foo' ]
|
62
|
+
get '/boom', :foo => 'bar'
|
63
|
+
expect(last_email.body).to match /"foo" => \[FILTERED\]/
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'renders an error page' do
|
67
|
+
get '/boom'
|
68
|
+
expect(last_response.status).to eq 500
|
69
|
+
expect(last_response.body).to eq "Exceptions layout\n500"
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'allows customizing the error layout' do
|
73
|
+
@app.set :exceptions_layout, nil
|
74
|
+
get '/boom'
|
75
|
+
expect(last_response.body).to eq '500'
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'requires a view to be configured for the error page' do
|
79
|
+
@app.instance_eval { undef :exceptions_page }
|
80
|
+
expect { get '/boom' }.to raise_exception NoMethodError
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when a 404 is returned' do
|
85
|
+
it 'renders an error page' do
|
86
|
+
get '/not_found'
|
87
|
+
expect(last_response.status).to eq 404
|
88
|
+
expect(last_response.body).to eq "Exceptions layout\n404"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'allows customizing the error layout' do
|
92
|
+
@app.set :exceptions_layout, nil
|
93
|
+
get '/not_found'
|
94
|
+
expect(last_response.body).to eq '404'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'requires a view to be configured for the error page' do
|
98
|
+
@app.instance_eval { undef :exceptions_page }
|
99
|
+
expect { get '/not_found' }.to raise_exception NoMethodError
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
PADRINO_ENV = 'test'
|
2
|
+
PADRINO_ROOT = File.dirname(__FILE__) unless defined?(PADRINO_ROOT)
|
1
3
|
require 'rubygems' unless defined?(Gem)
|
2
|
-
require '
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.require(:default, PADRINO_ENV)
|
6
|
+
|
3
7
|
require 'padrino-contrib'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.include Rack::Test::Methods
|
11
|
+
config.include Webrat::Matchers
|
12
|
+
|
13
|
+
# Sets up a Sinatra::Base subclass defined with the block
|
14
|
+
# given. Used in setup or individual spec methods to establish
|
15
|
+
# the application.
|
16
|
+
def mock_app(base=Padrino::Application, &block)
|
17
|
+
@app = Sinatra.new(base, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def app
|
21
|
+
@app
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= response.status %>
|
metadata
CHANGED
@@ -1,44 +1,35 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: padrino-contrib
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 13
|
10
|
-
version: 0.1.13
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Davide D'Agostino
|
14
8
|
- Nathan Esquenazi
|
15
9
|
- Arthur Chiu
|
16
10
|
autorequire:
|
17
11
|
bindir: bin
|
18
12
|
cert_chain: []
|
19
|
-
|
20
|
-
date: 2012-02-14 00:00:00 Z
|
13
|
+
date: 2014-08-14 00:00:00.000000000 Z
|
21
14
|
dependencies: []
|
22
|
-
|
23
15
|
description: Contributed plugins and utilities for the Padrino Ruby Web Framework
|
24
16
|
email: padrinorb@gmail.com
|
25
17
|
executables: []
|
26
|
-
|
27
18
|
extensions: []
|
28
|
-
|
29
19
|
extra_rdoc_files: []
|
30
|
-
|
31
|
-
files:
|
20
|
+
files:
|
32
21
|
- .gitignore
|
22
|
+
- .travis.yml
|
33
23
|
- Gemfile
|
34
24
|
- LICENSE
|
35
|
-
- README.
|
25
|
+
- README.md
|
36
26
|
- Rakefile
|
37
27
|
- lib/padrino-contrib.rb
|
38
28
|
- lib/padrino-contrib/auto_locale.rb
|
39
29
|
- lib/padrino-contrib/exception_notifier.rb
|
40
30
|
- lib/padrino-contrib/flash_session.rb
|
41
31
|
- lib/padrino-contrib/helpers/assets_compressor.rb
|
32
|
+
- lib/padrino-contrib/helpers/breadcrumbs.rb
|
42
33
|
- lib/padrino-contrib/helpers/flash.rb
|
43
34
|
- lib/padrino-contrib/helpers/jquery.rb
|
44
35
|
- lib/padrino-contrib/orm/active_record/permalink.rb
|
@@ -49,42 +40,41 @@ files:
|
|
49
40
|
- lib/padrino-contrib/orm/mongo_mapper/search.rb
|
50
41
|
- lib/padrino-contrib/version.rb
|
51
42
|
- padrino-contrib.gemspec
|
43
|
+
- spec/auto_locale_spec.rb
|
52
44
|
- spec/autoload_spec.rb
|
45
|
+
- spec/breadcrumb_helpers_spec.rb
|
46
|
+
- spec/exception_notifier_spec.rb
|
53
47
|
- spec/spec_helper.rb
|
48
|
+
- spec/views/exception_notifier/errors.erb
|
49
|
+
- spec/views/exception_notifier/layouts/layout.erb
|
54
50
|
homepage: http://www.padrinorb.com
|
55
51
|
licenses: []
|
56
|
-
|
52
|
+
metadata: {}
|
57
53
|
post_install_message:
|
58
54
|
rdoc_options: []
|
59
|
-
|
60
|
-
require_paths:
|
55
|
+
require_paths:
|
61
56
|
- lib
|
62
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
none: false
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
hash: 3
|
77
|
-
segments:
|
78
|
-
- 0
|
79
|
-
version: "0"
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
80
67
|
requirements: []
|
81
|
-
|
82
68
|
rubyforge_project: padrino-contrib
|
83
|
-
rubygems_version:
|
69
|
+
rubygems_version: 2.0.7
|
84
70
|
signing_key:
|
85
|
-
specification_version:
|
71
|
+
specification_version: 4
|
86
72
|
summary: Contributed plugins and utilities for Padrino Framework
|
87
|
-
test_files:
|
73
|
+
test_files:
|
74
|
+
- spec/auto_locale_spec.rb
|
88
75
|
- spec/autoload_spec.rb
|
76
|
+
- spec/breadcrumb_helpers_spec.rb
|
77
|
+
- spec/exception_notifier_spec.rb
|
89
78
|
- spec/spec_helper.rb
|
90
|
-
|
79
|
+
- spec/views/exception_notifier/errors.erb
|
80
|
+
- spec/views/exception_notifier/layouts/layout.erb
|
data/README.rdoc
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
= Contributed Plugins and Utilities
|
2
|
-
|
3
|
-
This package includes a variety of add-on components for Padrino Framework:
|
4
|
-
|
5
|
-
* exception_notifier - Send errors through mail or/and to redmine
|
6
|
-
* auto_locale - Switch for you automatically the I18n.locale
|
7
|
-
* flash_session - Middleware that help you in passing your session in the URI, when it should be in the cookie.
|
8
|
-
* orm_ar_permalink - Generate permalink for a specified column on ActiveRecord
|
9
|
-
* orm_ar_permalink_i18n - Generate permalink for a specified multi language column(s) on ActiveRecord
|
10
|
-
* orm_ar_translate - Translate for you your ActiveRecord columns
|
11
|
-
* orm_mm_permalink - Generate permalink for a specified column on MongoMapper
|
12
|
-
* orm_mm_search - Full text search in MongoMapper in specified columns
|
13
|
-
* helpers_assets_compressor - Joins and compress your js/css with yui-compressor
|
14
|
-
|
15
|
-
=== Use
|
16
|
-
|
17
|
-
In your Padrino project edit:
|
18
|
-
|
19
|
-
# Gemfile
|
20
|
-
gem 'padrino-contrib'
|
21
|
-
|
22
|
-
# boot.rb
|
23
|
-
require 'padrino-contrib/exception_notifier'
|
24
|
-
# require 'padrino-contrib/orm/active_record/permalink'
|
25
|
-
# require 'padrino-contrib/orm/active_record/textile'
|
26
|
-
|
27
|
-
Padrino.load! # Remember to add contribs before that line!
|
28
|
-
|
29
|
-
# app.rb
|
30
|
-
class MyApp < Padrino::Application
|
31
|
-
register Padrino::Contrib::ExceptionNotifier
|
32
|
-
end
|