padrino-contrib 0.1.13 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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