loaf 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -8
- data/.ruby-version +1 -0
- data/.travis.yml +23 -2
- data/Appraisals +18 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +16 -1
- data/README.md +69 -52
- data/Rakefile +5 -3
- data/bin/setup +7 -0
- data/gemfiles/rails3.2.gemfile +21 -0
- data/gemfiles/rails4.0.gemfile +22 -0
- data/gemfiles/rails4.1.gemfile +21 -0
- data/gemfiles/rails4.2.gemfile +21 -0
- data/lib/loaf.rb +24 -1
- data/lib/loaf/configuration.rb +15 -22
- data/lib/loaf/controller_extensions.rb +25 -12
- data/lib/loaf/crumb.rb +13 -1
- data/lib/loaf/crumb_formatter.rb +14 -13
- data/lib/loaf/options_validator.rb +10 -2
- data/lib/loaf/translation.rb +15 -8
- data/lib/loaf/version.rb +1 -8
- data/lib/loaf/view_extensions.rb +42 -15
- data/loaf.gemspec +10 -17
- data/spec/integration/configuration_spec.rb +7 -8
- data/spec/integration/crumbs_routing_spec.rb +31 -28
- data/spec/rails_app/app/controllers/application_controller.rb +0 -2
- data/spec/rails_app/app/controllers/posts_controller.rb +13 -2
- data/spec/rails_app/app/views/layouts/_breadcrumbs.html.erb +2 -0
- data/spec/rails_app/app/views/posts/index.html.erb +0 -2
- data/spec/rails_app/app/views/posts/new.html.erb +3 -0
- data/spec/rails_app/app/views/posts/show.html.erb +1 -0
- data/spec/rails_app/config/environments/development.rb +2 -0
- data/spec/rails_app/config/environments/production.rb +2 -0
- data/spec/rails_app/config/environments/test.rb +2 -3
- data/spec/rails_app/config/routes.rb +0 -2
- data/spec/rails_app/{app/mailers → log}/.gitkeep +0 -0
- data/spec/spec_helper.rb +42 -4
- data/spec/support/dummy_view.rb +7 -0
- data/spec/unit/controller_extensions_spec.rb +63 -0
- data/spec/unit/crumb_formatter_spec.rb +38 -0
- data/spec/unit/options_validator_spec.rb +17 -0
- data/spec/unit/translation_spec.rb +22 -0
- data/spec/unit/view_extensions/breadcrumb_spec.rb +24 -0
- data/spec/unit/view_extensions/breadcrumbs_spec.rb +128 -0
- data/spec/unit/view_extensions/has_breadcrumbs_spec.rb +12 -0
- data/tasks/console.rake +10 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +29 -0
- metadata +50 -100
- data/.rvmrc +0 -28
- data/Gemfile.lock +0 -132
- data/spec/integration/nested_crumbs_spec.rb +0 -5
- data/spec/loaf/controller_extensions_spec.rb +0 -55
- data/spec/loaf/crumb_formatter_spec.rb +0 -33
- data/spec/loaf/options_validator_spec.rb +0 -29
- data/spec/loaf/translation_spec.rb +0 -23
- data/spec/loaf/view_extensions_spec.rb +0 -114
- data/spec/loaf_spec.rb +0 -5
- data/spec/rails_app/app/assets/images/rails.png +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +0 -9
- data/spec/rails_app/app/assets/stylesheets/application.css +0 -7
- data/spec/rails_app/app/helpers/application_helper.rb +0 -2
- data/spec/rails_app/app/models/.gitkeep +0 -0
@@ -1,12 +1,23 @@
|
|
1
|
+
class Post < Struct.new(:id); end
|
2
|
+
|
1
3
|
class PostsController < ApplicationController
|
2
4
|
|
3
|
-
|
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
|
-
|
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
|
@@ -0,0 +1 @@
|
|
1
|
+
<% breadcrumb 'Show Post in view', post_path(@post.id) %>
|
@@ -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
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|
-
|
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.
|
14
|
-
|
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,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
|