loaf 0.3.0 → 0.4.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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -8
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +23 -2
  5. data/Appraisals +18 -0
  6. data/CHANGELOG.md +12 -0
  7. data/Gemfile +16 -1
  8. data/README.md +69 -52
  9. data/Rakefile +5 -3
  10. data/bin/setup +7 -0
  11. data/gemfiles/rails3.2.gemfile +21 -0
  12. data/gemfiles/rails4.0.gemfile +22 -0
  13. data/gemfiles/rails4.1.gemfile +21 -0
  14. data/gemfiles/rails4.2.gemfile +21 -0
  15. data/lib/loaf.rb +24 -1
  16. data/lib/loaf/configuration.rb +15 -22
  17. data/lib/loaf/controller_extensions.rb +25 -12
  18. data/lib/loaf/crumb.rb +13 -1
  19. data/lib/loaf/crumb_formatter.rb +14 -13
  20. data/lib/loaf/options_validator.rb +10 -2
  21. data/lib/loaf/translation.rb +15 -8
  22. data/lib/loaf/version.rb +1 -8
  23. data/lib/loaf/view_extensions.rb +42 -15
  24. data/loaf.gemspec +10 -17
  25. data/spec/integration/configuration_spec.rb +7 -8
  26. data/spec/integration/crumbs_routing_spec.rb +31 -28
  27. data/spec/rails_app/app/controllers/application_controller.rb +0 -2
  28. data/spec/rails_app/app/controllers/posts_controller.rb +13 -2
  29. data/spec/rails_app/app/views/layouts/_breadcrumbs.html.erb +2 -0
  30. data/spec/rails_app/app/views/posts/index.html.erb +0 -2
  31. data/spec/rails_app/app/views/posts/new.html.erb +3 -0
  32. data/spec/rails_app/app/views/posts/show.html.erb +1 -0
  33. data/spec/rails_app/config/environments/development.rb +2 -0
  34. data/spec/rails_app/config/environments/production.rb +2 -0
  35. data/spec/rails_app/config/environments/test.rb +2 -3
  36. data/spec/rails_app/config/routes.rb +0 -2
  37. data/spec/rails_app/{app/mailers → log}/.gitkeep +0 -0
  38. data/spec/spec_helper.rb +42 -4
  39. data/spec/support/dummy_view.rb +7 -0
  40. data/spec/unit/controller_extensions_spec.rb +63 -0
  41. data/spec/unit/crumb_formatter_spec.rb +38 -0
  42. data/spec/unit/options_validator_spec.rb +17 -0
  43. data/spec/unit/translation_spec.rb +22 -0
  44. data/spec/unit/view_extensions/breadcrumb_spec.rb +24 -0
  45. data/spec/unit/view_extensions/breadcrumbs_spec.rb +128 -0
  46. data/spec/unit/view_extensions/has_breadcrumbs_spec.rb +12 -0
  47. data/tasks/console.rake +10 -0
  48. data/tasks/coverage.rake +11 -0
  49. data/tasks/spec.rake +29 -0
  50. metadata +50 -100
  51. data/.rvmrc +0 -28
  52. data/Gemfile.lock +0 -132
  53. data/spec/integration/nested_crumbs_spec.rb +0 -5
  54. data/spec/loaf/controller_extensions_spec.rb +0 -55
  55. data/spec/loaf/crumb_formatter_spec.rb +0 -33
  56. data/spec/loaf/options_validator_spec.rb +0 -29
  57. data/spec/loaf/translation_spec.rb +0 -23
  58. data/spec/loaf/view_extensions_spec.rb +0 -114
  59. data/spec/loaf_spec.rb +0 -5
  60. data/spec/rails_app/app/assets/images/rails.png +0 -0
  61. data/spec/rails_app/app/assets/javascripts/application.js +0 -9
  62. data/spec/rails_app/app/assets/stylesheets/application.css +0 -7
  63. data/spec/rails_app/app/helpers/application_helper.rb +0 -2
  64. data/spec/rails_app/app/models/.gitkeep +0 -0
@@ -1,5 +1,3 @@
1
1
  class ApplicationController < ActionController::Base
2
2
  protect_from_forgery
3
-
4
- add_breadcrumb 'Home', 'root_path'
5
3
  end
@@ -1,12 +1,23 @@
1
+ class Post < Struct.new(:id); end
2
+
1
3
  class PostsController < ApplicationController
2
4
 
3
- add_breadcrumb 'All Posts', :posts_path
5
+ breadcrumb 'Home', :root_path, only: :index
4
6
 
5
7
  def index
8
+ breadcrumb 'All Posts', posts_path
9
+ end
10
+
11
+ def show
12
+ @post = ::Post.new(1)
6
13
  end
7
14
 
8
15
  def new
9
- add_breadcrumb 'New Post', 'new_post_path'
16
+ breadcrumb 'New Post', new_post_path
10
17
  end
11
18
 
19
+ def create
20
+ breadcrumb 'New Post', new_post_path, force: true
21
+ render action: :new
22
+ end
12
23
  end
@@ -1,3 +1,4 @@
1
+ <% if breadcrumbs? %>
1
2
  <ul id='breadcrumbs'>
2
3
  <% breadcrumbs do |name, url, styles| %>
3
4
  <li class="<%= styles %>">
@@ -6,3 +7,4 @@
6
7
  </li>
7
8
  <% end %>
8
9
  </ul>
10
+ <% end %>
@@ -1,3 +1 @@
1
- <% add_breadcrumb 'View Post', :posts_path %>
2
-
3
1
  <h1>Posts:index</h1>
@@ -1 +1,4 @@
1
1
  <h1>Posts:new</h1>
2
+ <%= form_tag posts_path, :method => "POST" do %>
3
+ <% submit_tag "Create"%>
4
+ <% end %>
@@ -0,0 +1 @@
1
+ <% breadcrumb 'Show Post in view', post_path(@post.id) %>
@@ -27,4 +27,6 @@ RailsApp::Application.configure do
27
27
 
28
28
  # Expands the lines which load the assets
29
29
  config.assets.debug = true
30
+
31
+ config.eager_load = false
30
32
  end
@@ -57,4 +57,6 @@ RailsApp::Application.configure do
57
57
 
58
58
  # Send deprecation notices to registered listeners
59
59
  config.active_support.deprecation = :notify
60
+
61
+ config.eager_load = true
60
62
  end
@@ -11,9 +11,6 @@ RailsApp::Application.configure do
11
11
  config.serve_static_assets = true
12
12
  config.static_cache_control = "public, max-age=3600"
13
13
 
14
- # Log error messages when you accidentally call methods on nil
15
- config.whiny_nils = true
16
-
17
14
  # Show full error reports and disable caching
18
15
  config.consider_all_requests_local = true
19
16
  config.action_controller.perform_caching = false
@@ -39,4 +36,6 @@ RailsApp::Application.configure do
39
36
 
40
37
  # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets
41
38
  config.assets.allow_debugging = true
39
+
40
+ config.eager_load = false
42
41
  end
@@ -1,9 +1,7 @@
1
1
  RailsApp::Application.routes.draw do
2
-
3
2
  root :to => 'home#index'
4
3
 
5
4
  resources :posts do
6
5
  resources :comments
7
6
  end
8
-
9
7
  end
@@ -1,15 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS'])
4
+ require 'simplecov'
5
+ require 'coveralls'
6
+
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ Coveralls::SimpleCov::Formatter
10
+ ]
11
+
12
+ SimpleCov.start do
13
+ command_name 'spec'
14
+ add_filter 'spec'
15
+ end
16
+ end
17
+
1
18
  # Configure Rails Environment
2
19
  ENV["RAILS_ENV"] = "test"
3
20
 
4
21
  require File.expand_path("../rails_app/config/environment.rb", __FILE__)
5
22
  require 'rspec/rails'
6
23
 
7
- Rails.backtrace_cleaner.remove_silencers!
24
+ require 'loaf'
8
25
 
9
- # Load support files
10
26
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
27
 
12
28
  RSpec.configure do |config|
13
- config.use_transactional_fixtures = true
14
- config.mock_with :rspec
29
+ config.expect_with :rspec do |expectations|
30
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
31
+ end
32
+
33
+ config.mock_with :rspec do |mocks|
34
+ mocks.verify_partial_doubles = true
35
+ end
36
+
37
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
38
+ config.disable_monkey_patching!
39
+
40
+ # This setting enables warnings. It's recommended, but in some cases may
41
+ # be too noisy due to issues in dependencies.
42
+ config.warnings = true
43
+
44
+ if config.files_to_run.one?
45
+ config.default_formatter = 'doc'
46
+ end
47
+
48
+ config.profile_examples = 2
49
+
50
+ config.order = :random
51
+
52
+ Kernel.srand config.seed
15
53
  end
@@ -0,0 +1,7 @@
1
+ class DummyView < ActionView::Base
2
+ include Loaf::ViewExtensions
3
+ attr_reader :_breadcrumbs
4
+
5
+ def url_for(*); end
6
+ def current_page?(*); end
7
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ class DummyController < ActionController::Base
6
+ def self.before_filter(options, &block)
7
+ yield self.new
8
+ end
9
+ include Loaf::ControllerExtensions
10
+ end
11
+
12
+ RSpec.describe Loaf::ControllerExtensions do
13
+
14
+ context 'when classes extend controller_extensions' do
15
+ it { expect(DummyController).to respond_to(:add_breadcrumb) }
16
+ it { expect(DummyController).to respond_to(:breadcrumb) }
17
+ it { expect(DummyController.new).to respond_to(:add_breadcrumb) }
18
+ it { expect(DummyController.new).to respond_to(:breadcrumb) }
19
+ it { expect(DummyController.new).to respond_to(:add_breadcrumbs) }
20
+ it { expect(DummyController.new).to respond_to(:clear_breadcrumbs) }
21
+ end
22
+
23
+ context 'class methods' do
24
+ it 'invokes before_filter' do
25
+ allow(DummyController).to receive(:before_filter)
26
+ DummyController.breadcrumb('name', 'url_path')
27
+ expect(DummyController).to have_received(:before_filter)
28
+ end
29
+
30
+ it 'delegates to instance' do
31
+ name = 'List objects'
32
+ url = :object_path
33
+ options = {force: true}
34
+ instance = double(:controller_instance).as_null_object
35
+
36
+ allow(DummyController).to receive(:new).and_return(instance)
37
+ DummyController.breadcrumb(name, url, options)
38
+ expect(instance).to have_received(:breadcrumb).with(name, url, options)
39
+ end
40
+ end
41
+
42
+ context 'instance methods' do
43
+ it 'instantiates breadcrumbs container' do
44
+ name = 'List objects'
45
+ url = :object_path
46
+ instance = DummyController.new
47
+
48
+ allow(Loaf::Crumb).to receive(:new)
49
+ instance.breadcrumb(name, url)
50
+ expect(Loaf::Crumb).to have_received(:new).with(name, url, {})
51
+ end
52
+
53
+ it 'adds breadcrumb to collection' do
54
+ name = 'List objects'
55
+ url = :object_path
56
+ instance = DummyController.new
57
+
58
+ expect {
59
+ instance.breadcrumb(name, url)
60
+ }.to change { instance._breadcrumbs.size }.by(1)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Loaf::CrumbFormatter, '.format_name' do
6
+ let(:formatter) {
7
+ Class.new do
8
+ extend Loaf::CrumbFormatter
9
+
10
+ def self.truncate(name, options)
11
+ name
12
+ end
13
+ end
14
+ }
15
+
16
+ it 'returns name error if breadcrumb name is nil' do
17
+ expect(formatter.format_name('')).to eql('')
18
+ end
19
+
20
+ it "doesn't capitalize by default" do
21
+ name = 'some random name'
22
+ formatted = formatter.format_name(name)
23
+ expect(formatted).to eql(name)
24
+ end
25
+
26
+ it 'capitalizes crumb name with capitalize option' do
27
+ name = 'some random name'
28
+ formatted = formatter.format_name(name, capitalize: true)
29
+ expect(formatted).to eql('Some random name')
30
+ end
31
+
32
+ it 'shortens crumb to provided length' do
33
+ name = 'very long name that is more that 30 characters long'
34
+ allow(formatter).to receive(:truncate).with(name, length: 30).
35
+ and_return(name[0..30])
36
+ expect(formatter.format_name(name, crumb_length: 30)).to eql(name[0..30])
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Loaf::OptionsValidator, '.valid?' do
6
+ let(:klass) { Class.extend Loaf::OptionsValidator }
7
+
8
+ it 'validates succesfully known option' do
9
+ expect(klass.valid?(crumb_length: 10)).to eq(true)
10
+ end
11
+
12
+ it 'validates unknown option with an error' do
13
+ expect {
14
+ klass.valid?(invalid_param: true)
15
+ }.to raise_error(Loaf::InvalidOptions)
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Loaf::Translation do
6
+
7
+ before { I18n.backend = I18n::Backend::Simple.new }
8
+
9
+ it 'translates breadcrumb title' do
10
+ I18n.backend.store_translations 'en', breadcrumbs: { home: 'Home'}
11
+ expect(described_class.breadcrumb_title('breadcrumbs.home')).to eql('Home')
12
+ end
13
+
14
+ it 'translates breadcrumb name with default scope' do
15
+ I18n.backend.store_translations 'en', breadcrumbs: {home: 'Home'}
16
+ expect(described_class.breadcrumb_title('home')).to eql('Home')
17
+ end
18
+
19
+ it 'translates breadcrumb name using default option' do
20
+ expect(described_class.breadcrumb_title('home', default: 'breadcrumb default name')).to eql('breadcrumb default name')
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Loaf::ViewExtensions, '.breadcrumb' do
6
+
7
+ it { expect(DummyView.new).to respond_to(:add_breadcrumb) }
8
+
9
+ it 'creates crumb instance' do
10
+ instance = DummyView.new
11
+ name = 'Home'
12
+ url = :home_path
13
+ allow(Loaf::Crumb).to receive(:new).with(name, url, {})
14
+ instance.breadcrumb name, url
15
+ expect(Loaf::Crumb).to have_received(:new).with(name, url, {})
16
+ end
17
+
18
+ it 'adds crumb to breadcrumbs storage' do
19
+ instance = DummyView.new
20
+ expect {
21
+ instance.breadcrumb 'Home', :home_path
22
+ }.to change { instance._breadcrumbs.size }.by(1)
23
+ end
24
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Loaf::ViewExtensions, '.breadcrumbs' do
6
+ it "yields to block all breadcrumbs" do
7
+ instance = DummyView.new
8
+ instance.breadcrumb('home', :home_path)
9
+ instance.breadcrumb('posts', :posts_path)
10
+
11
+ yielded = []
12
+ block = lambda { |name, url, styles| yielded << [name, url, styles]}
13
+ expect {
14
+ instance.breadcrumbs(&block)
15
+ }.to change { yielded.size }.from(0).to(2)
16
+ end
17
+
18
+ it "resolves breadcrumb paths" do
19
+ instance = DummyView.new
20
+ instance.breadcrumb('home', :home_path)
21
+ instance.breadcrumb('posts', :posts_path)
22
+
23
+ allow(instance).to receive(:url_for).with(:home_path).and_return('/home')
24
+ allow(instance).to receive(:url_for).with(:posts_path).and_return('/posts')
25
+ yielded = []
26
+ block = lambda { |name, url, styles| yielded << [name, url, styles]}
27
+ instance.breadcrumbs(&block)
28
+ expect(yielded).to eq([
29
+ ['home', '/home', ''],
30
+ ['posts', '/posts', '']
31
+ ])
32
+ end
33
+
34
+ it "checks current path and provides styles" do
35
+ instance = DummyView.new
36
+ instance.breadcrumb('home', :home_path)
37
+ instance.breadcrumb('posts', :posts_path)
38
+
39
+ allow(instance).to receive(:url_for).with(:home_path).and_return('/home')
40
+ allow(instance).to receive(:url_for).with(:posts_path).and_return('/posts')
41
+ allow(instance).to receive(:current_page?).with('/home').and_return(false)
42
+ allow(instance).to receive(:current_page?).with('/posts').and_return(true)
43
+
44
+ yielded = []
45
+ block = lambda { |name, url, styles| yielded << [name, url, styles]}
46
+ instance.breadcrumbs(&block)
47
+ expect(yielded).to eq([
48
+ ['home', '/home', ''],
49
+ ['posts', '/posts', 'selected']
50
+ ])
51
+ end
52
+
53
+ it "allows to force current path" do
54
+ instance = DummyView.new
55
+ instance.breadcrumb('home', :home_path)
56
+ instance.breadcrumb('posts', :posts_path, force: true)
57
+
58
+ allow(instance).to receive(:url_for).with(:home_path).and_return('/home')
59
+ allow(instance).to receive(:url_for).with(:posts_path).and_return('/posts')
60
+ allow(instance).to receive(:current_page?).and_return(false)
61
+
62
+ yielded = []
63
+ block = lambda { |name, url, styles| yielded << [name, url, styles]}
64
+ instance.breadcrumbs(&block)
65
+ expect(yielded).to eq([
66
+ ['home', '/home', ''],
67
+ ['posts', '/posts', 'selected']
68
+ ])
69
+ end
70
+
71
+ it "returns enumerator without block" do
72
+ instance = DummyView.new
73
+ instance.breadcrumb('home', :home_path)
74
+ instance.breadcrumb('posts', :posts_path)
75
+
76
+ allow(instance).to receive(:url_for).with(:home_path).and_return('/home')
77
+ allow(instance).to receive(:url_for).with(:posts_path).and_return('/posts')
78
+
79
+ result = instance.breadcrumbs
80
+ expect(result).to be_a(Enumerable)
81
+ expect(result.take(2)).to eq([
82
+ ['home', '/home', ''],
83
+ ['posts', '/posts', '']
84
+ ])
85
+ end
86
+
87
+ it 'validates passed options' do
88
+ instance = DummyView.new
89
+ block = lambda { |name, url, styles| }
90
+ expect {
91
+ instance.breadcrumbs(unknown: true, &block)
92
+ }.to raise_error(Loaf::InvalidOptions)
93
+ end
94
+
95
+ it 'uses global configuration for crumb formatting' do
96
+ allow(Loaf.configuration).to receive(:crumb_length).and_return(10)
97
+ instance = DummyView.new
98
+ instance.breadcrumb('home-sweet-home', :home_path)
99
+ instance.breadcrumb('posts-for-everybody', :posts_path)
100
+
101
+ allow(instance).to receive(:url_for).with(:home_path).and_return('/home')
102
+ allow(instance).to receive(:url_for).with(:posts_path).and_return('/posts')
103
+ yielded = []
104
+ block = lambda { |name, url, styles| yielded << [name, url, styles]}
105
+ instance.breadcrumbs(&block)
106
+ expect(yielded).to eq([
107
+ ['home-sw...', '/home', ''],
108
+ ['posts-f...', '/posts', '']
109
+ ])
110
+ end
111
+
112
+ it "allows to overwrite global configuration" do
113
+ allow(Loaf.configuration).to receive(:crumb_length).and_return(10)
114
+ instance = DummyView.new
115
+ instance.breadcrumb('home-sweet-home', :home_path)
116
+ instance.breadcrumb('posts-for-everybody', :posts_path)
117
+
118
+ allow(instance).to receive(:url_for).with(:home_path).and_return('/home')
119
+ allow(instance).to receive(:url_for).with(:posts_path).and_return('/posts')
120
+ yielded = []
121
+ block = lambda { |name, url, styles| yielded << [name, url, styles]}
122
+ instance.breadcrumbs(crumb_length: 15, &block)
123
+ expect(yielded).to eq([
124
+ ['home-sweet-home', '/home', ''],
125
+ ['posts-for-ev...', '/posts', '']
126
+ ])
127
+ end
128
+ end