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.

@@ -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/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ *.swp
6
+ *.swo
@@ -0,0 +1,7 @@
1
+ lang: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - rbx-18mode
7
+ - jruby-19mode
data/Gemfile CHANGED
@@ -1,4 +1,23 @@
1
- source "http://rubygems.org"
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
@@ -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("spec") do |t|
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
@@ -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
- request.path_info.sub(/\/#{I18n.locale}/, "/#{lang}") if settings.locales.include?(lang)
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
- I18n.locale = settings.locales[0]
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
- route.instance_variable_set(:@original_path, "/:lang#{route.original_path}") unless route.original_path =~/:lang/
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] = I18n.locale
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, :layout unless app.respond_to?(: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 { |k,v| body += "\n#{k.inspect} => #{v.inspect}" }
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.error 404 do
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
@@ -1,5 +1,5 @@
1
1
  module Padrino
2
2
  module Contrib
3
- VERSION = '0.1.13'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
@@ -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
@@ -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 'rspec' unless defined?(RSpec)
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 %>
@@ -0,0 +1,2 @@
1
+ Exceptions layout
2
+ <%= yield %>
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
- hash: 1
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.rdoc
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
- none: false
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- hash: 3
68
- segments:
69
- - 0
70
- version: "0"
71
- required_rubygems_version: !ruby/object:Gem::Requirement
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: 1.8.15
69
+ rubygems_version: 2.0.7
84
70
  signing_key:
85
- specification_version: 3
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
- has_rdoc:
79
+ - spec/views/exception_notifier/errors.erb
80
+ - spec/views/exception_notifier/layouts/layout.erb
@@ -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