loaf 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -3
  3. data/.rspec +1 -0
  4. data/.travis.yml +30 -12
  5. data/Appraisals +27 -9
  6. data/CHANGELOG.md +59 -11
  7. data/Gemfile +11 -11
  8. data/Gemfile.lock +182 -0
  9. data/README.md +120 -56
  10. data/assets/loaf_logo.png +0 -0
  11. data/bin/appraisal +16 -0
  12. data/bin/rake +16 -0
  13. data/gemfiles/rails3.2.gemfile +15 -13
  14. data/gemfiles/rails4.0.gemfile +13 -12
  15. data/gemfiles/rails4.1.gemfile +14 -13
  16. data/gemfiles/rails4.2.gemfile +14 -13
  17. data/gemfiles/rails5.0.gemfile +22 -0
  18. data/gemfiles/rails5.1.gemfile +22 -0
  19. data/lib/loaf.rb +2 -22
  20. data/lib/loaf/breadcrumb.rb +30 -0
  21. data/lib/loaf/configuration.rb +7 -8
  22. data/lib/loaf/controller_extensions.rb +13 -28
  23. data/lib/loaf/crumb.rb +5 -4
  24. data/lib/loaf/crumb_formatter.rb +3 -1
  25. data/lib/loaf/errors.rb +1 -3
  26. data/lib/loaf/options_validator.rb +2 -2
  27. data/lib/loaf/railtie.rb +19 -13
  28. data/lib/loaf/translation.rb +1 -1
  29. data/lib/loaf/version.rb +1 -3
  30. data/lib/loaf/view_extensions.rb +69 -18
  31. data/loaf.gemspec +20 -13
  32. data/spec/integration/{crumbs_routing_spec.rb → breadcrumb_trail_spec.rb} +19 -12
  33. data/spec/rails_app/app/controllers/application_controller.rb +2 -0
  34. data/spec/rails_app/app/controllers/posts_controller.rb +1 -4
  35. data/spec/rails_app/app/views/layouts/_breadcrumbs.html.erb +7 -5
  36. data/spec/rails_app/app/views/layouts/application.html.erb +0 -2
  37. data/spec/rails_app/config/environments/test.rb +1 -1
  38. data/spec/rails_app/config/secrets.yml +22 -0
  39. data/spec/spec_helper.rb +3 -3
  40. data/spec/support/dummy_controller.rb +9 -0
  41. data/spec/support/dummy_view.rb +42 -2
  42. data/spec/unit/configuration_spec.rb +35 -0
  43. data/spec/unit/controller_extensions_spec.rb +5 -14
  44. data/spec/unit/generators/install_generator_spec.rb +2 -1
  45. data/spec/unit/view_extensions/breadcrumb_trail_spec.rb +232 -0
  46. metadata +65 -31
  47. data/.ruby-version +0 -1
  48. data/init.rb +0 -3
  49. data/lib/loaf/builder.rb +0 -38
  50. data/spec/rails_app/.gitignore +0 -5
  51. data/spec/rails_app/lib/assets/.gitkeep +0 -0
  52. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  53. data/spec/rails_app/script/rails +0 -6
  54. data/spec/unit/view_extensions/breadcrumbs_spec.rb +0 -128
data/loaf.gemspec CHANGED
@@ -3,19 +3,26 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'loaf/version'
5
5
 
6
- Gem::Specification.new do |s|
7
- s.name = 'loaf'
8
- s.version = Loaf::VERSION.dup
9
- s.authors = ['Piotr Murach']
10
- s.email = [""]
11
- s.homepage = 'https://github.com/peter-murach/loaf'
12
- s.summary = %q{Loaf manages and displays breadcrumb trails in your Rails application.}
13
- s.description = %q{Loaf manages and displays breadcrumb trails in your Rails app. It aims to handle breadcrumb data through easy dsl and expose it through view helpers without any assumptions about markup.}
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'loaf'
8
+ spec.version = Loaf::VERSION.dup
9
+ spec.authors = ['Piotr Murach']
10
+ spec.email = [""]
11
+ spec.homepage = 'https://github.com/piotrmurach/loaf'
12
+ spec.summary = %q{Loaf manages and displays breadcrumb trails in your Rails application.}
13
+ spec.description = %q{Loaf manages and displays breadcrumb trails in your Rails app. It aims to handle breadcrumb data through easy dsl and expose it through view helpers without any assumptions about markup.}
14
14
 
15
- s.files = `git ls-files`.split("\n")
16
- s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
17
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
- s.require_paths = ["lib"]
15
+ spec.files = `git ls-files`.split("\n")
16
+ spec.test_files = `git ls-files -- {spec,features}/*`.split("\n")
17
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
19
 
20
- s.add_dependency 'rails', '>= 3.1'
20
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
21
+ spec.metadata['source_code_uri'] = 'https://github.com/piotrmurach/loaf'
22
+ spec.metadata['changelog_uri'] = 'https://github.com/piotrmurach/loaf/blob/master/CHANGELOG.md'
23
+
24
+ spec.add_dependency 'rails', '>= 3.2'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.5'
27
+ spec.add_development_dependency 'rake'
21
28
  end
@@ -1,25 +1,30 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'spec_helper'
4
-
5
- RSpec.describe "crumbs routing" do
3
+ RSpec.describe "breadcrumbs trail" do
6
4
  include ActionView::TestCase::Behavior
7
5
 
8
- it "doens't show empty breadcrumbs" do
6
+ it "shows root breadcrumb" do
9
7
  visit root_path
10
- expect(page).to_not have_content("breadcrumbs")
8
+
9
+ within '#breadcrumbs .selected' do
10
+ expect(page.html).to include('<a href="/">Home</a>')
11
+ end
11
12
  end
12
13
 
13
14
  it "inherits controller breadcrumb and adds index action breadcrumb" do
14
15
  visit posts_path
16
+
15
17
  within '#breadcrumbs' do
16
18
  expect(page.html).to include('<a href="/">Home</a>')
17
- expect(page.html).to include('<a href="/posts">All Posts</a>')
19
+ within '.selected' do
20
+ expect(page.html).to include('<a href="/posts">All Posts</a>')
21
+ end
18
22
  end
19
23
  end
20
24
 
21
25
  it 'filters out controller breadcrumb and adds new action breadcrumb' do
22
26
  visit new_post_path
27
+
23
28
  within '#breadcrumbs' do
24
29
  expect(page).to_not have_content('Home')
25
30
  expect(page).to have_content('New Post')
@@ -28,25 +33,27 @@ RSpec.describe "crumbs routing" do
28
33
 
29
34
  it "adds breadcrumb in view with path variable" do
30
35
  visit post_path(1)
31
- within '#breadcrumbs' do
36
+
37
+ within '#breadcrumbs .selected' do
32
38
  expect(page.html).to include('<a href="/posts/1">Show Post in view</a>')
33
39
  end
34
40
  end
35
41
 
36
42
  it 'is current when forced' do
37
43
  visit new_post_path
38
- click_button "Create"
39
44
 
40
- expect(page.current_path).to eq(posts_path)
45
+ expect(page.current_path).to eq(new_post_path)
41
46
  within '#breadcrumbs' do
42
- expect(page).to have_content('New Post')
43
- expect(page).to have_selector('.selected')
47
+ expect(page).to have_selector('li.selected', count: 2)
48
+ expect(page.html).to include('<a href="/posts">All</a>')
49
+ expect(page.html).to include('<a href="/posts/new">New Post</a>')
44
50
  end
45
51
  end
46
52
 
47
53
  it "allows for procs in name and url" do
48
54
  visit post_comments_path(1)
49
- within '#breadcrumbs' do
55
+
56
+ within '#breadcrumbs .selected' do
50
57
  expect(page.html).to include('<a href="/posts/1/comments">Post comments</a>')
51
58
  end
52
59
  end
@@ -1,3 +1,5 @@
1
1
  class ApplicationController < ActionController::Base
2
2
  protect_from_forgery
3
+
4
+ breadcrumb 'Home', :root_path, only: :index
3
5
  end
@@ -1,9 +1,6 @@
1
1
  class Post < Struct.new(:id); end
2
2
 
3
3
  class PostsController < ApplicationController
4
-
5
- breadcrumb 'Home', :root_path, only: :index
6
-
7
4
  def index
8
5
  breadcrumb 'all_posts', posts_path
9
6
  end
@@ -13,11 +10,11 @@ class PostsController < ApplicationController
13
10
  end
14
11
 
15
12
  def new
13
+ breadcrumb 'All', :posts_path, match: :force
16
14
  breadcrumb 'New Post', new_post_path
17
15
  end
18
16
 
19
17
  def create
20
- breadcrumb 'New Post', new_post_path, force: true
21
18
  render action: :new
22
19
  end
23
20
  end
@@ -1,9 +1,11 @@
1
- <% if breadcrumbs? %>
1
+ <% if breadcrumb_trail.any? %>
2
2
  <ul id='breadcrumbs'>
3
- <% breadcrumbs do |name, url, styles| %>
4
- <li class="<%= styles %>">
5
- <%= link_to name, url %>
6
- <span><%= styles == 'selected' ? '' : '::' %></span>
3
+ <% breadcrumb_trail do |crumb| %>
4
+ <li class="<%= crumb.current? ? 'selected' : '' %>">
5
+ <%= link_to crumb.name, crumb.url %>
6
+ <% unless crumb.current? %>
7
+ <span>::</span>
8
+ <% end %>
7
9
  </li>
8
10
  <% end %>
9
11
  </ul>
@@ -2,8 +2,6 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>RailsApp</title>
5
- <%= stylesheet_link_tag "application" %>
6
- <%= javascript_include_tag "application" %>
7
5
  <%= csrf_meta_tags %>
8
6
  </head>
9
7
  <body>
@@ -8,7 +8,7 @@ RailsApp::Application.configure do
8
8
  config.cache_classes = true
9
9
 
10
10
  # Configure static asset server for tests with Cache-Control for performance
11
- config.serve_static_assets = true
11
+ config.serve_static_files = true
12
12
  config.static_cache_control = "public, max-age=3600"
13
13
 
14
14
  # Show full error reports and disable caching
@@ -0,0 +1,22 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key is used for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rake secret` to generate a secure secret key.
9
+
10
+ # Make sure the secrets in this file are kept private
11
+ # if you're sharing your code publicly.
12
+
13
+ development:
14
+ secret_key_base: c392df63ec28b42b36b92a5b9e8603fa62d7807024d07801ab162ec7a2a165a87d27a4a8535ce09cd2bf4a82afe45e3080fb8cc56613d608e5b18335594782b3
15
+
16
+ test:
17
+ secret_key_base: 4b1fba0d12c53b8b21880fda47b603b3dcca117ccf41fcc70091351b88ede5d4c5c91371f407cd056efd66fa5f306c23add65a89d4304e06a4243289ee97be1d
18
+
19
+ # Do not keep production secrets in the repository,
20
+ # instead read values from the environment.
21
+ production:
22
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
data/spec/spec_helper.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # encoding: utf-8
2
2
 
3
- if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS'])
3
+ if (ENV['COVERAGE'] || ENV['TRAVIS']) && RUBY_VERSION < '2.4.0'
4
4
  require 'simplecov'
5
5
  require 'coveralls'
6
6
 
7
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
8
8
  SimpleCov::Formatter::HTMLFormatter,
9
9
  Coveralls::SimpleCov::Formatter
10
- ]
10
+ ])
11
11
 
12
12
  SimpleCov.start do
13
13
  command_name 'spec'
@@ -0,0 +1,9 @@
1
+ class DummyController < ActionController::Base
2
+ def self.before_filter(options, &block)
3
+ yield self.new
4
+ end
5
+ class << self
6
+ alias before_action before_filter
7
+ end
8
+ include Loaf::ControllerExtensions
9
+ end
@@ -1,7 +1,47 @@
1
+ require 'action_view'
2
+
1
3
  class DummyView < ActionView::Base
4
+ module FakeRequest
5
+ class Request
6
+ attr_accessor :path, :fullpath, :protocol, :host_with_port
7
+ def get?
8
+ true
9
+ end
10
+ end
11
+ def request
12
+ @request ||= Request.new
13
+ end
14
+ def params
15
+ @params ||= {}
16
+ end
17
+ end
18
+
19
+ include FakeRequest
20
+ include ActionView::Helpers::UrlHelper
2
21
  include Loaf::ViewExtensions
22
+
3
23
  attr_reader :_breadcrumbs
4
24
 
5
- def url_for(*); end
6
- def current_page?(*); end
25
+ routes = ActionDispatch::Routing::RouteSet.new
26
+ routes.draw do
27
+ get "/" => "foo#bar", :as => :home
28
+ get "/posts" => "foo#posts"
29
+ get "/posts/:title" => "foo#posts"
30
+ get "/post/:id" => "foo#post", :as => :post
31
+ get "/post/:title" => "foo#title"
32
+ get "/post/:id/comments" => "foo#comments"
33
+
34
+ namespace :blog do
35
+ get "/" => "foo#bar"
36
+ end
37
+ end
38
+
39
+ include routes.url_helpers
40
+
41
+ def set_path(path)
42
+ request.path = path
43
+ request.fullpath = path
44
+ request.protocol = 'http://'
45
+ request.host_with_port = 'www.example.com'
46
+ end
7
47
  end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe Loaf::Configuration do
4
+ it "allows to set and read attributes" do
5
+ config = Loaf::Configuration.new
6
+
7
+ config.crumb_length = 4
8
+
9
+ expect(config.crumb_length).to eq(4)
10
+ end
11
+
12
+ it "accepts attributes at initialization" do
13
+ options = { crumb_length: 12 }
14
+ config = Loaf::Configuration.new(options)
15
+
16
+ expect(config.crumb_length).to eq(12)
17
+ end
18
+
19
+ it "exports configuration as hash" do
20
+ config = Loaf::Configuration.new
21
+ expect(config.to_hash).to eq({
22
+ capitalize: false,
23
+ crumb_length: 30,
24
+ locales_path: '/'
25
+ })
26
+ end
27
+
28
+ it "yields configuration" do
29
+ conf = double(:conf)
30
+ allow(Loaf).to receive(:configuration).and_return(conf)
31
+ expect { |b|
32
+ Loaf.configure(&b)
33
+ }.to yield_with_args(conf)
34
+ end
35
+ end
@@ -1,14 +1,5 @@
1
1
  # encoding: utf-8
2
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
3
  RSpec.describe Loaf::ControllerExtensions do
13
4
 
14
5
  context 'when classes extend controller_extensions' do
@@ -16,18 +7,18 @@ RSpec.describe Loaf::ControllerExtensions do
16
7
  it { expect(DummyController).to respond_to(:breadcrumb) }
17
8
  it { expect(DummyController.new).to respond_to(:add_breadcrumb) }
18
9
  it { expect(DummyController.new).to respond_to(:breadcrumb) }
19
- it { expect(DummyController.new).to respond_to(:add_breadcrumbs) }
20
10
  it { expect(DummyController.new).to respond_to(:clear_breadcrumbs) }
21
11
  end
22
12
 
23
13
  context 'class methods' do
24
- it 'invokes before_filter' do
25
- allow(DummyController).to receive(:before_filter)
14
+ it 'invokes before_action' do
15
+ allow(DummyController).to receive(:before_action)
16
+ allow(DummyController).to receive(:respond_to?).and_return(true)
26
17
  DummyController.breadcrumb('name', 'url_path')
27
- expect(DummyController).to have_received(:before_filter)
18
+ expect(DummyController).to have_received(:before_action)
28
19
  end
29
20
 
30
- it 'delegates to instance' do
21
+ it 'delegates breadcrumb registration to controller instance' do
31
22
  name = 'List objects'
32
23
  url = :object_path
33
24
  options = {force: true}
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'spec_helper'
3
+ require 'fileutils'
4
4
  require 'generators/loaf/install_generator'
5
5
 
6
6
  RSpec.describe Loaf::Generators::InstallGenerator, type: :generator do
@@ -12,5 +12,6 @@ RSpec.describe Loaf::Generators::InstallGenerator, type: :generator do
12
12
  run_generator
13
13
  locale = file("config/locales/loaf.en.yml")
14
14
  expect(locale).to exist
15
+ FileUtils.rm_rf(File.expand_path("../../../tmp", __FILE__))
15
16
  end
16
17
  end
@@ -0,0 +1,232 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe Loaf::ViewExtensions, '#breadcrumb_trail' do
4
+ it "resolves breadcrumb paths" do
5
+ view = DummyView.new
6
+ view.breadcrumb('home', :home_path)
7
+ view.breadcrumb('posts', :posts_path)
8
+ view.set_path('/posts')
9
+
10
+ yielded = []
11
+ block = -> (crumb) { yielded << crumb.to_a }
12
+ view.breadcrumb_trail(&block)
13
+
14
+ expect(yielded).to eq([
15
+ ['home', '/', false],
16
+ ['posts', '/posts', true]
17
+ ])
18
+ end
19
+
20
+ it "matches current path with :inclusive option as default" do
21
+ view = DummyView.new
22
+ view.breadcrumb('home', :home_path)
23
+ view.breadcrumb('posts', :posts_path)
24
+ view.set_path('/posts?id=73-title')
25
+
26
+ yielded = []
27
+ block = -> (crumb) { yielded << crumb.to_a }
28
+ view.breadcrumb_trail(&block)
29
+
30
+ expect(yielded).to eq([
31
+ ['home', '/', false],
32
+ ['posts', '/posts', true]
33
+ ])
34
+ end
35
+
36
+ it "matches current path with :inclusive when query params" do
37
+ view = DummyView.new
38
+ view.breadcrumb('posts', '/posts', match: :inclusive)
39
+ view.set_path('/posts?foo=bar')
40
+
41
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', true]])
42
+ end
43
+
44
+ it "matches current path with :inclusive when nested" do
45
+ view = DummyView.new
46
+ view.breadcrumb('posts', '/posts', match: :inclusive)
47
+ view.set_path('/posts/1/comment')
48
+
49
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', true]])
50
+ end
51
+
52
+ it "matches current path with :inclusive when nested" do
53
+ view = DummyView.new
54
+ view.breadcrumb('posts', '/posts', match: :inclusive)
55
+ view.set_path('/posts/1/comment')
56
+
57
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', true]])
58
+ end
59
+
60
+ it "doesn't match with :inclusive when unrelated path" do
61
+ view = DummyView.new
62
+ view.breadcrumb('posts', '/posts', match: :inclusive)
63
+ view.set_path('/post/1')
64
+
65
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', false]])
66
+ end
67
+
68
+ it "matches current path with :inclusive when extra trailing slash" do
69
+ view = DummyView.new
70
+ view.breadcrumb('posts', '/posts/', match: :inclusive)
71
+ view.set_path('/posts')
72
+
73
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts/', true]])
74
+ end
75
+
76
+ it "matches current path with :inclusive when absolute path" do
77
+ view = DummyView.new
78
+ view.breadcrumb('posts', 'http://www.example.com/posts/', match: :inclusive)
79
+ view.set_path('/posts')
80
+
81
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([
82
+ ['posts', 'http://www.example.com/posts/', true]
83
+ ])
84
+ end
85
+
86
+ it "matches current path with :exact when trailing slash" do
87
+ view = DummyView.new
88
+ view.breadcrumb('posts', '/posts/', match: :exact)
89
+ view.set_path('/posts')
90
+
91
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts/', true]])
92
+ end
93
+
94
+ it "fails to match current path with :exact when nested" do
95
+ view = DummyView.new
96
+ view.breadcrumb('posts', '/posts', match: :exact)
97
+ view.set_path('/posts/1/comment')
98
+
99
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', false]])
100
+ end
101
+
102
+ it "fails to match current path with :exact when query params" do
103
+ view = DummyView.new
104
+ view.breadcrumb('posts', '/posts', match: :exact)
105
+ view.set_path('/posts?foo=bar')
106
+
107
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', false]])
108
+ end
109
+
110
+ it "matches current path with :exclusive option when query params" do
111
+ view = DummyView.new
112
+ view.breadcrumb('posts', '/posts', match: :exclusive)
113
+ view.set_path('/posts?foo=bar')
114
+
115
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', true]])
116
+ end
117
+
118
+ it "fails to match current path with :exclusive option when nested" do
119
+ view = DummyView.new
120
+ view.breadcrumb('posts', '/posts', match: :exclusive)
121
+ view.set_path('/posts/1/comment')
122
+
123
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', false]])
124
+ end
125
+
126
+ it "matches current path with regex option when query params" do
127
+ view = DummyView.new
128
+ view.breadcrumb('posts', '/posts', match: %r{/po})
129
+ view.set_path('/posts?foo=bar')
130
+
131
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', true]])
132
+ end
133
+
134
+ it "matches current path with query params option" do
135
+ view = DummyView.new
136
+ view.breadcrumb('posts', '/posts', match: {foo: :bar})
137
+ view.set_path('/posts?foo=bar&baz=boo')
138
+
139
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', true]])
140
+ end
141
+
142
+ it "fails to match current path with query params option" do
143
+ view = DummyView.new
144
+ view.breadcrumb('posts', '/posts', match: {foo: :bar})
145
+ view.set_path('/posts?foo=2&baz=boo')
146
+
147
+ expect(view.breadcrumb_trail.map(&:to_a)).to eq([['posts', '/posts', false]])
148
+ end
149
+
150
+ it "failse to recognize the match option" do
151
+ view = DummyView.new
152
+ view.breadcrumb('posts', 'http://www.example.com/posts/', match: :boom)
153
+ view.set_path('/posts')
154
+ block = -> (*args) { }
155
+ expect {
156
+ view.breadcrumb_trail(&block)
157
+ }.to raise_error(ArgumentError, "Unknown `:boom` match option!")
158
+ end
159
+
160
+ it "forces current path" do
161
+ view = DummyView.new
162
+ view.breadcrumb('home', :home_path)
163
+ view.breadcrumb('posts', :posts_path, match: :force)
164
+ view.set_path('/')
165
+
166
+ yielded = []
167
+ block = -> (crumb) { yielded << crumb.to_a }
168
+ view.breadcrumb_trail(&block)
169
+
170
+ expect(yielded).to eq([
171
+ ['home', '/', true],
172
+ ['posts', '/posts', true]
173
+ ])
174
+ end
175
+
176
+ it "returns enumerator without block" do
177
+ view = DummyView.new
178
+ view.breadcrumb('home', :home_path)
179
+ view.breadcrumb('posts', :posts_path)
180
+ view.set_path('/posts')
181
+
182
+ result = view.breadcrumb_trail
183
+
184
+ expect(result).to be_a(Enumerable)
185
+ expect(result.take(2).map(&:to_a)).to eq([
186
+ ['home', '/', false],
187
+ ['posts', '/posts', true]
188
+ ])
189
+ end
190
+
191
+ it 'validates passed options' do
192
+ view = DummyView.new
193
+ block = -> (name, url, styles) { }
194
+ expect {
195
+ view.breadcrumb_trail(unknown: true, &block)
196
+ }.to raise_error(Loaf::InvalidOptions)
197
+ end
198
+
199
+ it 'uses global configuration for crumb formatting' do
200
+ allow(Loaf.configuration).to receive(:crumb_length).and_return(10)
201
+ view = DummyView.new
202
+ view.breadcrumb('home-sweet-home', :home_path)
203
+ view.breadcrumb('posts-for-everybody', :posts_path)
204
+ view.set_path('/posts')
205
+
206
+ yielded = []
207
+ block = -> (crumb) { yielded << crumb.to_a }
208
+ view.breadcrumb_trail(&block)
209
+
210
+ expect(yielded).to eq([
211
+ ['home-sw...', '/', false],
212
+ ['posts-f...', '/posts', true]
213
+ ])
214
+ end
215
+
216
+ it "allows to overwrite global configuration" do
217
+ allow(Loaf.configuration).to receive(:crumb_length).and_return(10)
218
+ view = DummyView.new
219
+ view.breadcrumb('home-sweet-home', :home_path)
220
+ view.breadcrumb('posts-for-everybody', :posts_path)
221
+ view.set_path('/posts')
222
+
223
+ yielded = []
224
+ block = -> (crumb) { yielded << crumb.to_a }
225
+ view.breadcrumb_trail(crumb_length: 15, &block)
226
+
227
+ expect(yielded).to eq([
228
+ ['home-sweet-home', '/', false],
229
+ ['posts-for-ev...', '/posts', true]
230
+ ])
231
+ end
232
+ end