simple-navigation-4.0.3/ 0000755 0000041 0000041 00000000000 12513767261 015206 5 ustar www-data www-data simple-navigation-4.0.3/Rakefile 0000644 0000041 0000041 00000000474 12513767261 016660 0 ustar www-data www-data require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require 'rdoc/task'
RSpec::Core::RakeTask.new(:spec)
task default: :spec
RDoc::Task.new do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'SimpleNavigation'
rdoc.options << '--inline-source'
rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
end
simple-navigation-4.0.3/Gemfile 0000644 0000041 0000041 00000000047 12513767261 016502 0 ustar www-data www-data source 'https://rubygems.org'
gemspec
simple-navigation-4.0.3/simple-navigation.gemspec 0000644 0000041 0000041 00000004043 12513767261 022202 0 ustar www-data www-data # coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'simple_navigation/version'
Gem::Specification.new do |spec|
spec.name = 'simple-navigation'
spec.version = SimpleNavigation::VERSION
spec.authors = ['Andi Schacke', 'Mark J. Titorenko', 'Simon Courtois']
spec.email = ['andi@codeplant.ch']
spec.description = "With the simple-navigation gem installed you can easily " \
"create multilevel navigations for your Rails, Sinatra or "\
"Padrino applications. The navigation is defined in a " \
"single configuration file. It supports automatic as well "\
"as explicit highlighting of the currently active " \
"navigation through regular expressions."
spec.summary = "simple-navigation is a ruby library for creating navigations "\
"(with multiple levels) for your Rails2, Rails3, Rails4, Sinatra or " \
"Padrino application."
spec.homepage = 'http://github.com/codeplant/simple-navigation'
spec.license = 'MIT'
spec.files = `git ls-files -z`.split("\x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ['lib']
spec.rdoc_options = ['--inline-source', '--charset=UTF-8']
spec.add_runtime_dependency 'activesupport', '>= 2.3.2'
spec.add_development_dependency 'bundler', '~> 1.5'
spec.add_development_dependency 'capybara'
spec.add_development_dependency 'coveralls', '~> 0.7'
spec.add_development_dependency 'guard-rspec', '~> 4.2'
spec.add_development_dependency 'memfs', '~> 0.4.1'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rdoc'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'tzinfo', '>= 0'
end
simple-navigation-4.0.3/.rspec 0000644 0000041 0000041 00000000065 12513767261 016324 0 ustar www-data www-data --color
--format=documentation
--require spec_helper
simple-navigation-4.0.3/spec/ 0000755 0000041 0000041 00000000000 12513767261 016140 5 ustar www-data www-data simple-navigation-4.0.3/spec/simple_navigation_spec.rb 0000644 0000041 0000041 00000013637 12513767261 023221 0 ustar www-data www-data describe SimpleNavigation do
before { subject.config_file_path = 'path_to_config' }
describe 'config_file_path=' do
before { subject.config_file_paths = ['existing_path'] }
it 'overrides the config_file_paths' do
subject.config_file_path = 'new_path'
expect(subject.config_file_paths).to eq ['new_path']
end
end
describe '.default_config_file_path' do
before { allow(subject).to receive_messages(root: 'root') }
it 'returns the config file path according to :root setting' do
expect(subject.default_config_file_path).to eq 'root/config'
end
end
describe 'Regarding renderers' do
it 'registers the builtin renderers by default' do
expect(subject.registered_renderers).not_to be_empty
end
describe '.register_renderer' do
let(:renderer) { double(:renderer) }
it 'adds the specified renderer to the list of renderers' do
subject.register_renderer(my_renderer: renderer)
expect(subject.registered_renderers[:my_renderer]).to be renderer
end
end
end
describe '.set_env' do
before do
subject.config_file_paths = []
allow(subject).to receive_messages(default_config_file_path: 'default_path')
subject.set_env('root', 'my_env')
end
it 'sets the root' do
expect(subject.root).to eq 'root'
end
it 'sets the environment' do
expect(subject.environment).to eq 'my_env'
end
it 'adds the default-config path to the list of config_file_paths' do
expect(subject.config_file_paths).to eq ['default_path']
end
end
describe '.load_config', memfs: true do
let(:paths) { ['/path/one', '/path/two'] }
before do
FileUtils.mkdir_p(paths)
allow(subject).to receive_messages(config_file_paths: paths)
end
context 'when the config file for the context exists' do
before do
File.open('/path/two/navigation.rb', 'w') { |f| f.puts 'default content' }
File.open('/path/one/other_navigation.rb', 'w') { |f| f.puts 'other content' }
end
context 'when no context is provided' do
it 'stores the configuration in config_files for the default context' do
subject.load_config
expect(subject.config_files[:default]).to eq "default content\n"
end
end
context 'when a context is provided' do
it 'stores the configuration in config_files for the given context' do
subject.load_config(:other)
expect(subject.config_files[:other]).to eq "other content\n"
end
end
context 'and environment is production' do
before { allow(subject).to receive_messages(environment: 'production') }
it 'loads the config file only for the first call' do
subject.load_config
File.open('/path/two/navigation.rb', 'w') { |f| f.puts 'new content' }
subject.load_config
expect(subject.config_files[:default]).to eq "default content\n"
end
end
context "and environment isn't production" do
it 'loads the config file for every call' do
subject.load_config
File.open('/path/two/navigation.rb', 'w') { |f| f.puts 'new content' }
subject.load_config
expect(subject.config_files[:default]).to eq "new content\n"
end
end
end
context "when the config file for the context doesn't exists" do
it 'raises an exception' do
expect{ subject.load_config }.to raise_error
end
end
end
describe '.config' do
it 'returns the Configuration singleton instance' do
expect(subject.config).to be SimpleNavigation::Configuration.instance
end
end
describe '.active_item_container_for' do
let(:primary) { double(:primary) }
before { allow(subject.config).to receive_messages(primary_navigation: primary) }
context 'when level is :all' do
it 'returns the primary_navigation' do
nav = subject.active_item_container_for(:all)
expect(nav).to be primary
end
end
context 'when level is :leaves' do
it 'returns the currently active leaf-container' do
expect(primary).to receive(:active_leaf_container)
subject.active_item_container_for(:leaves)
end
end
context 'when level is a Range' do
it 'takes the min of the range to lookup the active container' do
expect(primary).to receive(:active_item_container_for).with(2)
subject.active_item_container_for(2..3)
end
end
context 'when level is an Integer' do
it 'considers the Integer to lookup the active container' do
expect(primary).to receive(:active_item_container_for).with(1)
subject.active_item_container_for(1)
end
end
context 'when level is something else' do
it 'raises an exception' do
expect{
subject.active_item_container_for('something else')
}.to raise_error
end
end
end
describe '.load_adapter' do
shared_examples 'loading the right adapter' do |framework, adapter|
context "when the context is #{framework}" do
before do
allow(subject).to receive_messages(framework: framework)
subject.load_adapter
end
it "returns the #{framework} adapter" do
adapter_class = SimpleNavigation::Adapters.const_get(adapter)
expect(subject.adapter_class).to be adapter_class
end
end
end
it_behaves_like 'loading the right adapter', :rails, :Rails
it_behaves_like 'loading the right adapter', :padrino, :Padrino
it_behaves_like 'loading the right adapter', :sinatra, :Sinatra
end
describe '.init_adapter_from' do
let(:adapter) { double(:adapter) }
let(:adapter_class) { double(:adapter_class, new: adapter) }
it 'sets the adapter to a new instance of adapter_class' do
subject.adapter_class = adapter_class
subject.init_adapter_from(:default)
expect(subject.adapter).to be adapter
end
end
end
simple-navigation-4.0.3/spec/initializers/ 0000755 0000041 0000041 00000000000 12513767261 020646 5 ustar www-data www-data simple-navigation-4.0.3/spec/initializers/coveralls.rb 0000644 0000041 0000041 00000000045 12513767261 023164 0 ustar www-data www-data require 'coveralls'
Coveralls.wear!
simple-navigation-4.0.3/spec/initializers/memfs.rb 0000644 0000041 0000041 00000000204 12513767261 022276 0 ustar www-data www-data require 'memfs'
RSpec.configure do |config|
config.around(memfs: true) do |example|
MemFs.activate { example.run }
end
end
simple-navigation-4.0.3/spec/initializers/rspec.rb 0000644 0000041 0000041 00000000173 12513767261 022310 0 ustar www-data www-data RSpec.configure do |config|
config.expect_with(:rspec) do |c|
c.syntax = :expect
end
config.order = :random
end
simple-navigation-4.0.3/spec/initializers/rails.rb 0000644 0000041 0000041 00000000055 12513767261 022305 0 ustar www-data www-data begin
require 'rails'
rescue LoadError
end
simple-navigation-4.0.3/spec/initializers/have_css_matcher.rb 0000644 0000041 0000041 00000000777 12513767261 024504 0 ustar www-data www-data RSpec::Matchers.define :have_css do |expected, times|
match do |actual|
selector = HTML::Selector.new(expected).select(actual)
if times
expect(selector.size).to eq times
else
expect(selector.size).to be >= 1
end
end
failure_message do |actual|
"expected #{actual.to_s} to have #{times || 1} elements matching '#{expected}'"
end
failure_message_when_negated do |actual|
"expected #{actual.to_s} not to have #{times || 1} elements matching '#{expected}'"
end
end
simple-navigation-4.0.3/spec/spec_helper.rb 0000644 0000041 0000041 00000004007 12513767261 020757 0 ustar www-data www-data require 'initializers/have_css_matcher'
require 'initializers/memfs'
require 'initializers/coveralls'
require 'initializers/rails'
require 'initializers/rspec'
require 'capybara/rspec'
require 'bundler/setup'
Bundler.require
if defined? Rails
require 'fake_app/rails_app'
require 'rspec/rails'
Capybara.app = RailsApp::Application
RSpec.configure do |config|
config.before do
SimpleNavigation.config_files.clear
setup_adapter_for :rails
end
end
end
def setup_adapter_for(framework, context = double(:context))
if framework == :rails
allow(context).to receive_messages(view_context: ActionView::Base.new)
end
allow(SimpleNavigation).to receive_messages(framework: framework)
SimpleNavigation.load_adapter
SimpleNavigation.init_adapter_from(context)
end
def select_an_item(item)
allow(item).to receive_messages(selected?: true)
end
def setup_container(dom_id, dom_class)
container = SimpleNavigation::ItemContainer.new(1)
container.dom_id = dom_id
container.dom_class = dom_class
container
end
def setup_navigation(dom_id, dom_class)
setup_adapter_for :rails
container = setup_container(dom_id, dom_class)
setup_items(container)
container
end
# FIXME: adding the :link option for the list renderer messes up the other
# renderers
def setup_items(container)
container.item :users, 'Users', '/users', html: { id: 'users_id' }, link_html: { id: 'users_link_id' }
container.item :invoices, 'Invoices', '/invoices' do |invoices|
invoices.item :paid, 'Paid', '/invoices/paid'
invoices.item :unpaid, 'Unpaid', '/invoices/unpaid'
end
container.item :accounts, 'Accounts', '/accounts', html: { style: 'float:right' }
container.item :miscellany, 'Miscellany'
container.items.each do |item|
allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
if item.sub_navigation
item.sub_navigation.items.each do |item|
allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
end
end
end
end
simple-navigation-4.0.3/spec/integration/ 0000755 0000041 0000041 00000000000 12513767261 020463 5 ustar www-data www-data simple-navigation-4.0.3/spec/integration/rendering_navigation_spec.rb 0000644 0000041 0000041 00000000463 12513767261 026221 0 ustar www-data www-data RSpec.feature 'Rendering navigation' do
background do
SimpleNavigation.set_env(RailsApp::Application.root, 'test')
end
scenario 'Rendering basic navigation', type: :feature do
visit '/base_spec'
expect(page).to have_content('Item 1')
expect(page).to have_content('Item 2')
end
end
simple-navigation-4.0.3/spec/simple_navigation/ 0000755 0000041 0000041 00000000000 12513767261 021650 5 ustar www-data www-data simple-navigation-4.0.3/spec/simple_navigation/renderer/ 0000755 0000041 0000041 00000000000 12513767261 023456 5 ustar www-data www-data simple-navigation-4.0.3/spec/simple_navigation/renderer/text_spec.rb 0000644 0000041 0000041 00000002714 12513767261 026005 0 ustar www-data www-data module SimpleNavigation
module Renderer
describe Text do
let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
let(:item) { nil }
let(:options) {{ level: :all }}
let(:output) { renderer.render(navigation) }
let(:renderer) { Text.new(options) }
before { select_an_item(navigation[item]) if item }
describe '#render' do
context 'when no item is selected' do
it 'renders an empty string' do
expect(output).to eq ''
end
end
context 'when an item is selected' do
let(:item) { :invoices }
it "renders the selected item's name" do
expect(output).to eq 'Invoices'
end
end
context 'when a sub navigation item is selected' do
before do
allow(navigation[:invoices]).to receive_messages(selected?: true)
allow(navigation[:invoices].sub_navigation[:unpaid]).to \
receive_messages(selected?: true, selected_by_condition?: true)
end
it 'separates the items with a space' do
expect(output).to eq 'Invoices Unpaid'
end
context "and the :join_with option is set" do
let(:options) {{ level: :all, join_with: ' | ' }}
it 'separates the items with the specified separator' do
expect(output).to eq 'Invoices | Unpaid'
end
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/renderer/list_spec.rb 0000644 0000041 0000041 00000006117 12513767261 025775 0 ustar www-data www-data module SimpleNavigation
module Renderer
describe List do
let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
let(:item) { nil }
let(:options) {{ level: :all }}
let(:output) { HTML::Document.new(raw_output).root }
let(:raw_output) { renderer.render(navigation) }
let(:renderer) { List.new(options) }
before { select_an_item(navigation[item]) if item }
describe '#render' do
it "renders an 'ul' tag for the navigation" do
expect(output).to have_css('ul')
end
it "sets the right html id on the rendered 'ul' tag" do
expect(output).to have_css('ul#nav_id')
end
it "sets the right html classes on the rendered 'ul' tag" do
expect(output).to have_css('ul.nav_class')
end
context 'when an item has no specified id' do
it "renders the item's 'li' tag with the item's stingified key as id" do
expect(output).to have_css('li#invoices')
end
end
context 'when an item has a specified id' do
it "renders the item's 'li' tag with the specified id" do
expect(output).to have_css('li#users_id')
end
end
context 'when no item is selected' do
it "renders each item as 'li' tag without any selected class" do
expect(output).not_to have_css('ul li.selected')
end
it "renders each item as 'a' tag without any selected class" do
expect(output).not_to have_css('ul li a.selected')
end
end
context 'when an item is selected' do
let(:item) { :invoices }
it "renders the item's 'li' tag with its id and selected classes" do
expect(output).to have_css('li#invoices.selected')
end
it "renders the item's 'a' tag with the selected classes" do
expect(output).to have_css('li#invoices a.selected')
end
end
context 'when the :ordered option is true' do
let(:options) {{ level: :all, ordered: true }}
it "renders an 'ol' tag for the navigation" do
expect(output).to have_css('ol')
end
it "sets the right html id on the rendered 'ol' tag" do
expect(output).to have_css('ol#nav_id')
end
it "sets the right html classes on the rendered 'ol' tag" do
expect(output).to have_css('ol.nav_class')
end
end
context 'when a sub navigation item is selected' do
before do
allow(navigation[:invoices]).to receive_messages(selected?: true)
allow(navigation[:invoices].sub_navigation[:unpaid]).to \
receive_messages(selected?: true, selected_by_condition?: true)
end
it 'renders the parent items as selected' do
expect(output).to have_css('li#invoices.selected')
end
it "renders the selected nested item's link as selected" do
expect(output).to have_css('li#unpaid.selected')
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/renderer/base_spec.rb 0000644 0000041 0000041 00000016314 12513767261 025734 0 ustar www-data www-data module SimpleNavigation
module Renderer
describe Base do
subject(:base) { Base.new(options) }
let(:adapter) { double(:adapter) }
let(:options) { Hash.new }
before { allow(SimpleNavigation).to receive_messages(adapter: adapter) }
it 'delegates the :link_to method to adapter' do
allow(adapter).to receive_messages(link_to: 'link_to')
expect(base.link_to).to eq 'link_to'
end
it 'delegates the :content_tag method to adapter' do
allow(adapter).to receive_messages(content_tag: 'content_tag')
expect(base.content_tag).to eq 'content_tag'
end
describe '#initialize' do
it "sets the renderer adapter to the SimpleNavigation one" do
expect(base.adapter).to be adapter
end
end
describe '#options' do
it "returns the renderer's options" do
expect(base.options).to be options
end
end
describe '#render' do
it "raise an exception to indicate it's a subclass responsibility" do
expect{ base.render(:container) }.to raise_error
end
end
describe '#expand_all?' do
context 'when :options is set' do
context 'and the :expand_all option is true' do
let(:options) {{ expand_all: true }}
it 'returns true' do
expect(base.expand_all?).to be true
end
end
context 'and the :expand_all option is false' do
let(:options) {{ expand_all: false }}
it 'returns false' do
expect(base.expand_all?).to be false
end
end
end
context "when :options isn't set" do
let(:options) { Hash.new }
it 'returns false' do
expect(base.expand_all?).to be false
end
end
end
describe '#skip_if_empty?' do
context 'when :options is set' do
context 'and the :skip_if_empty option is true' do
let(:options) {{ skip_if_empty: true }}
it 'returns true' do
expect(base.skip_if_empty?).to be true
end
end
context 'and the :skip_if_empty option is false' do
let(:options) {{ skip_if_empty: false }}
it 'returns true' do
expect(base.skip_if_empty?).to be false
end
end
end
context "when :options isn't set" do
let(:options) { Hash.new }
it 'returns true' do
expect(base.skip_if_empty?).to be false
end
end
end
describe '#level' do
context 'and the :level option is set' do
let(:options) {{ level: 1 }}
it 'returns the specified level' do
expect(base.level).to eq 1
end
end
context "and the :level option isn't set" do
let(:options) { Hash.new }
it 'returns :all' do
expect(base.level).to eq :all
end
end
end
describe '#consider_sub_navigation?' do
let(:item) { double(:item) }
before { allow(item).to receive_messages(sub_navigation: sub_navigation) }
context 'when the item has no sub navigation' do
let(:sub_navigation) { nil }
it 'returns false' do
expect(base.send(:consider_sub_navigation?, item)).to be false
end
end
context 'when the item has sub navigation' do
let(:sub_navigation) { double(:sub_navigation) }
context 'and the renderer has an unknown level' do
before { allow(base).to receive_messages(level: 'unknown') }
it 'returns false' do
expect(base.send(:consider_sub_navigation?, item)).to be false
end
end
context 'and the renderer has a level set to :all' do
before { allow(base).to receive_messages(level: :all) }
it 'returns false' do
expect(base.send(:consider_sub_navigation?, item)).to be true
end
end
context "when the renderer's level is a number" do
before { allow(base).to receive_messages(level: 2) }
it 'returns false' do
expect(base.send(:consider_sub_navigation?, item)).to be false
end
end
context "when the renderer's level is a Range" do
before { allow(base).to receive_messages(level: 2..3) }
context "and sub navigation's level is greater than range.max" do
before { allow(sub_navigation).to receive_messages(level: 4) }
it 'returns false' do
expect(base.send(:consider_sub_navigation?, item)).to be false
end
end
context "and sub navigation's level is equal to range.max" do
before { allow(sub_navigation).to receive_messages(level: 3) }
it 'returns true' do
expect(base.send(:consider_sub_navigation?, item)).to be true
end
end
context "and sub navigation's level is equal to range.min" do
before { allow(sub_navigation).to receive_messages(level: 2) }
it 'returns true' do
expect(base.send(:consider_sub_navigation?, item)).to be true
end
end
end
end
end
describe '#include_sub_navigation?' do
let(:item) { double(:item) }
context 'when consider_sub_navigation? is true' do
before { allow(base).to receive_messages(consider_sub_navigation?: true) }
context 'and expand_sub_navigation? is true' do
before { allow(base).to receive_messages(expand_sub_navigation?: true) }
it 'returns true' do
expect(base.include_sub_navigation?(item)).to be true
end
end
context 'and expand_sub_navigation? is false' do
before { allow(base).to receive_messages(expand_sub_navigation?: false) }
it 'returns false' do
expect(base.include_sub_navigation?(item)).to be false
end
end
end
context 'consider_sub_navigation? is false' do
before { allow(base).to receive_messages(consider_sub_navigation?: false) }
context 'and expand_sub_navigation? is true' do
before { allow(base).to receive_messages(expand_sub_navigation?: true) }
it 'returns false' do
expect(base.include_sub_navigation?(item)).to be false
end
end
context 'and expand_sub_navigation? is false' do
before { allow(base).to receive_messages(expand_sub_navigation?: false) }
it 'returns false' do
expect(base.include_sub_navigation?(item)).to be false
end
end
end
end
describe '#render_sub_navigation_for' do
let(:item) { double(:item, sub_navigation: sub_navigation) }
let(:sub_navigation) { double(:sub_navigation) }
it 'renders the sub navigation passing it the options' do
expect(sub_navigation).to receive(:render).with(options)
base.render_sub_navigation_for(item)
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/renderer/links_spec.rb 0000644 0000041 0000041 00000005367 12513767261 026150 0 ustar www-data www-data module SimpleNavigation
module Renderer
describe Links do
describe '#render' do
let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
let(:item) { nil }
let(:options) {{ level: :all }}
let(:output) { HTML::Document.new(raw_output).root }
let(:raw_output) { renderer.render(navigation) }
let(:renderer) { Links.new(options) }
before { select_an_item(navigation[item]) if item }
it "renders a 'div' tag for the navigation" do
expect(output).to have_css('div')
end
it "sets the right html id on the rendered 'div' tag" do
expect(output).to have_css('div#nav_id')
end
it "sets the right html classes on the rendered 'div' tag" do
expect(output).to have_css('div.nav_class')
end
it "renders an 'a' tag for each item" do
expect(output).to have_css('a', 3)
end
it "renders the 'a' tags with the corresponding item's :html_options" do
expect(output).to have_css('a[style=float:right]')
end
context 'when an item has a specified id' do
it "renders the 'a' tags with the specified id" do
expect(output).to have_css('a#users_id')
end
end
context 'when an item has no specified id' do
it "uses a default id by stringifying the item's key" do
expect(output).to have_css('a#invoices')
end
end
context 'when no item is selected' do
it "renders items without the 'selected' class" do
expect(output).not_to have_css('a.selected')
end
end
context 'when an item is selected' do
let(:item) { :invoices }
it "renders the selected item with the 'selected' class" do
expect(output).to have_css('a#invoices.selected')
end
end
context "when the :join_with option is set" do
let(:options) {{ level: :all, join_with: ' | ' }}
it 'separates the items with the specified separator' do
expect(raw_output.scan(' | ').size).to eq 3
end
end
context 'when a sub navigation item is selected' do
before do
allow(navigation[:invoices]).to receive_messages(selected?: true)
allow(navigation[:invoices].sub_navigation[:unpaid]).to \
receive_messages(selected?: true, selected_by_condition?: true)
end
it 'renders the main parent as selected' do
expect(output).to have_css('a#invoices.selected')
end
it "doesn't render the nested item's link" do
expect(output).not_to have_css('a#unpaid')
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/renderer/breadcrumbs_spec.rb 0000644 0000041 0000041 00000007260 12513767261 027313 0 ustar www-data www-data module SimpleNavigation
module Renderer
describe Breadcrumbs do
let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
let(:item) { nil }
let(:options) {{ level: :all }}
let(:output) { HTML::Document.new(raw_output).root }
let(:raw_output) { renderer.render(navigation) }
let(:renderer) { Breadcrumbs.new(options) }
before { select_an_item(navigation[item]) if item }
describe '#render' do
it "renders a 'div' tag for the navigation" do
expect(output).to have_css('div')
end
it "sets the right html id on the rendered 'div' tag" do
expect(output).to have_css('div#nav_id')
end
it "sets the right html classes on the rendered 'div' tag" do
expect(output).to have_css('div.nav_class')
end
context 'when no item is selected' do
it "doesn't render any 'a' tag in the 'div' tag" do
expect(output).not_to have_css('div a')
end
end
context 'when an item is selected' do
let(:item) { :invoices }
it "renders the selected 'a' tag" do
expect(output).to have_css('div a')
end
it "remders the 'a' tag without any html id" do
expect(output).not_to have_css('div a[id]')
end
it "renders the 'a' tag without any html class" do
expect(output).not_to have_css('div a[class]')
end
context 'and the :allow_classes_and_ids option is true' do
let(:options) {{ level: :all, allow_classes_and_ids: true }}
it "renders the 'a' tag with the selected class" do
expect(output).to have_css('div a.selected')
end
context "and the item hasn't any id explicitly set" do
it "renders the 'a' tag without any html id" do
expect(output).not_to have_css('div a[id]')
end
end
context 'and the item has an explicitly set id' do
let(:item) { :users }
it "renders the 'a' tag with an html id" do
expect(output).to have_css('div a#breadcrumb_users_link_id')
end
end
end
end
context 'and the :prefix option is set' do
let(:options) {{ prefix: 'You are here: ' }}
context 'and there are no items to render' do
let(:item) { nil }
it "doesn't render the prefix before the breadcrumbs" do
expect(raw_output).not_to match(/^
You are here: /)
end
end
context 'and there are items to render' do
let(:item) { :invoices }
it 'renders the prefix before the breadcrumbs' do
expect(raw_output).to match(/^You are here: /)
end
end
end
context 'when a sub navigation item is selected' do
before do
allow(navigation[:invoices]).to receive_messages(selected?: true)
allow(navigation[:invoices].sub_navigation[:unpaid]).to \
receive_messages(selected?: true, selected_by_condition?: true)
end
it 'renders all items as links' do
expect(output).to have_css('div a', 2)
end
context 'when the :static_leaf option is true' do
let(:options) {{ level: :all, static_leaf: true }}
it 'renders the items as links' do
expect(output).to have_css('div a')
end
it 'renders the last item as simple text' do
expect(output).to have_css('div span')
end
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/renderer/json_spec.rb 0000644 0000041 0000041 00000004010 12513767261 025761 0 ustar www-data www-data module SimpleNavigation
module Renderer
describe Json do
describe '#render' do
let!(:navigation) { setup_navigation('nav_id', 'nav_class') }
let(:item) { :invoices }
let(:options) {{ level: :all }}
let(:output) { renderer.render(navigation) }
let(:parsed_output) { JSON.parse(output) }
let(:renderer) { Json.new(options) }
before { select_an_item(navigation[item]) if item }
context 'when an item is selected' do
it 'renders the selected page' do
invoices_item = parsed_output.find { |item| item['name'] == 'Invoices' }
expect(invoices_item).to include('selected' => true)
end
end
# FIXME: not sure if :as_hash returning an array makes sense...
context 'when the :as_hash option is true' do
let(:options) {{ level: :all, as_hash: true }}
it 'returns a hash' do
expect(output).to be_an Array
end
it 'renders the selected page' do
invoices_item = output.find { |item| item[:name] == 'Invoices' }
expect(invoices_item).to include(selected: true)
end
end
context 'when a sub navigation item is selected' do
let(:invoices_item) do
parsed_output.find { |item| item['name'] == 'Invoices' }
end
let(:unpaid_item) do
invoices_item['items'].find { |item| item['name'] == 'Unpaid' }
end
before do
allow(navigation[:invoices]).to receive_messages(selected?: true)
allow(navigation[:invoices].sub_navigation[:unpaid]).to \
receive_messages(selected?: true, selected_by_condition?: true)
end
it 'marks all the parent items as selected' do
expect(invoices_item).to include('selected' => true)
end
it 'marks the item as selected' do
expect(unpaid_item).to include('selected' => true)
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/adapters/ 0000755 0000041 0000041 00000000000 12513767261 023453 5 ustar www-data www-data simple-navigation-4.0.3/spec/simple_navigation/adapters/rails_spec.rb 0000644 0000041 0000041 00000023513 12513767261 026130 0 ustar www-data www-data module SimpleNavigation
module Adapters
describe Rails do
let(:action_controller) { ActionController::Base }
let(:adapter) { Rails.new(context) }
let(:context) { double(:context, controller: controller) }
let(:controller) { double(:controller) }
let(:request) { double(:request) }
let(:simple_navigation) { SimpleNavigation }
let(:template) { double(:template, request: request) }
describe '.register' do
before { allow(action_controller).to receive(:include) }
it 'calls set_env' do
app_path = RailsApp::Application.root
expect(simple_navigation).to receive(:set_env).with(app_path, 'test')
simple_navigation.register
end
it 'extends the ActionController::Base with the Helpers' do
expect(action_controller).to receive(:include)
.with(SimpleNavigation::Helpers)
simple_navigation.register
end
shared_examples 'installing helper method' do |method|
it "installs the #{method} method as helper method" do
simple_navigation.register
helper_methods = action_controller.send(:_helper_methods)
expect(helper_methods).to include(method)
end
end
it_behaves_like 'installing helper method', :render_navigation
it_behaves_like 'installing helper method', :active_navigation_item_name
it_behaves_like 'installing helper method', :active_navigation_item_key
it_behaves_like 'installing helper method', :active_navigation_item
it_behaves_like 'installing helper method', :active_navigation_item_container
end
describe '#initialize' do
context "when the controller's template is set" do
before { allow(controller).to receive_messages(instance_variable_get: template) }
it "sets the adapter's request accordingly" do
expect(adapter.request).to be request
end
end
context "when the controller's template is not set" do
before { allow(controller).to receive_messages(instance_variable_get: nil) }
it "sets the adapter's request to nil" do
expect(adapter.request).to be_nil
end
end
it "sets the adapter's controller to the context's controller" do
expect(adapter.controller).to be controller
end
context "when the controller's template is stored as instance var (Rails2)" do
context "when the controller's template is set" do
before { allow(controller).to receive_messages(instance_variable_get: template) }
it "sets the adapter's template accordingly" do
expect(adapter.template).to be template
end
end
context "when the controller's template is not set" do
before { allow(controller).to receive_messages(instance_variable_get: nil) }
it "set the adapter's template to nil" do
expect(adapter.template).to be_nil
end
end
end
context "when the controller's template is stored as view_context (Rails3)" do
context 'and the template is set' do
before { allow(controller).to receive_messages(view_context: template) }
it "sets the adapter's template accordingly" do
expect(adapter.template).to be template
end
end
context 'and the template is not set' do
before { allow(controller).to receive_messages(view_context: nil) }
it "sets the adapter's template to nil" do
expect(adapter.template).to be_nil
end
end
end
end
describe '#request_uri' do
context "when the adapter's request is set" do
before { allow(adapter).to receive_messages(request: request) }
context 'and request.fullpath is defined' do
let(:request) { double(:request, fullpath: '/fullpath') }
it "sets the adapter's request_uri to the request.fullpath" do
expect(adapter.request_uri).to eq '/fullpath'
end
end
context 'and request.fullpath is not defined' do
let(:request) { double(:request, request_uri: '/request_uri') }
before { allow(adapter).to receive_messages(request: request) }
it "sets the adapter's request_uri to the request.request_uri" do
expect(adapter.request_uri).to eq '/request_uri'
end
end
end
context "when the adapter's request is not set" do
before { allow(adapter).to receive_messages(request: nil) }
it "sets the adapter's request_uri to an empty string" do
expect(adapter.request_uri).to eq ''
end
end
end
describe '#request_path' do
context "when the adapter's request is set" do
let(:request) { double(:request, path: '/request_path') }
before { allow(adapter).to receive_messages(request: request) }
it "sets the adapter's request_path to the request.path" do
expect(adapter.request_path).to eq '/request_path'
end
end
context "when the adapter's request is not set" do
before { allow(adapter).to receive_messages(request: nil) }
it "sets the adapter's request_path to an empty string" do
expect(adapter.request_path).to eq ''
end
end
end
describe '#context_for_eval' do
context "when the adapter's controller is set" do
before { adapter.instance_variable_set(:@controller, controller) }
context "and the adapter's template is set" do
before { adapter.instance_variable_set(:@template, template) }
it "sets the adapter's context_for_eval to the template" do
expect(adapter.context_for_eval).to be template
end
end
context "and the adapter's template is not set" do
before { adapter.instance_variable_set(:@template, nil) }
it "sets the adapter's context_for_eval to the controller" do
expect(adapter.context_for_eval).to be controller
end
end
end
context "when the adapter's controller is not set" do
before { adapter.instance_variable_set(:@controller, nil) }
context "and the adapter's template is set" do
before { adapter.instance_variable_set(:@template, template) }
it "sets the adapter's context_for_eval to the template" do
expect(adapter.context_for_eval).to be template
end
end
context "and the adapter's template is not set" do
before { adapter.instance_variable_set(:@template, nil) }
it 'raises an exception' do
expect{ adapter.context_for_eval }.to raise_error
end
end
end
end
describe '#current_page?' do
context "when the adapter's template is set" do
before { allow(adapter).to receive_messages(template: template) }
it 'delegates the call to the template' do
expect(template).to receive(:current_page?).with(:page)
adapter.current_page?(:page)
end
end
context "when the adapter's template is not set" do
before { allow(adapter).to receive_messages(template: nil) }
it 'returns false' do
expect(adapter.current_page?(:page)).to be_falsey
end
end
context 'when the given url is nil' do
it 'returns false' do
expect(adapter.current_page?(nil)).to be_falsey
end
end
end
describe '#link_to' do
let(:options) { double(:options) }
context "when the adapter's template is set" do
before { allow(adapter).to receive_messages(template: template, html_safe: 'safe_text') }
context 'with considering item names as safe' do
before { SimpleNavigation.config.consider_item_names_as_safe = true }
after { SimpleNavigation.config.consider_item_names_as_safe = false }
it 'delegates the call to the template (with html_safe text)' do
expect(template).to receive(:link_to)
.with('safe_text', 'url', options)
adapter.link_to('text', 'url', options)
end
end
context 'with considering item names as UNsafe (default)' do
it 'delegates the call to the template (with html_safe text)' do
expect(template).to receive(:link_to)
.with('text', 'url', options)
adapter.link_to('text', 'url', options)
end
end
end
context "when the adapter's template is not set" do
before { allow(adapter).to receive_messages(template: nil) }
it 'returns nil' do
expect(adapter.link_to('text', 'url', options)).to be_nil
end
end
end
describe '#content_tag' do
let(:options) { double(:options) }
context "when the adapter's template is set" do
before { allow(adapter).to receive_messages(template: template, html_safe: 'safe_text') }
it 'delegates the call to the template (with html_safe text)' do
expect(template).to receive(:content_tag)
.with(:div, 'safe_text', options)
adapter.content_tag(:div, 'text', options)
end
end
context "when the adapter's template is not set" do
before { allow(adapter).to receive_messages(template: nil) }
it 'returns nil' do
expect(adapter.content_tag(:div, 'text', options)).to be_nil
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/adapters/padrino_spec.rb 0000644 0000041 0000041 00000001623 12513767261 026450 0 ustar www-data www-data module SimpleNavigation
module Adapters
describe Padrino do
let(:adapter) { SimpleNavigation::Adapters::Padrino.new(context) }
let(:content) { double(:content) }
let(:context) { double(:context, request: request) }
let(:request) { double(:request) }
describe '#link_to' do
it 'delegates to context' do
expect(context).to receive(:link_to)
.with('name', 'url', :my_option => true)
adapter.link_to('name', 'url', :my_option => true)
end
end
describe '#content_tag' do
it 'delegates to context' do
expect(content).to receive(:html_safe).and_return('content')
expect(context).to receive(:content_tag)
.with('type', 'content', my_option: true)
adapter.content_tag('type', content, my_option: true)
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/adapters/sinatra_spec.rb 0000644 0000041 0000041 00000007176 12513767261 026466 0 ustar www-data www-data describe SimpleNavigation::Adapters::Sinatra do
let(:adapter) { SimpleNavigation::Adapters::Sinatra.new(context) }
let(:context) { double(:context) }
let(:request) { double(:request, fullpath: '/full?param=true', path: '/full') }
before { allow(context).to receive_messages(request: request) }
describe '#context_for_eval' do
context "when adapter's context is not set" do
it 'raises an exception' do
allow(adapter).to receive_messages(context: nil)
expect{ adapter.context_for_eval }.to raise_error
end
end
context "when adapter's context is set" do
it 'returns the context' do
expect(adapter.context_for_eval).to be context
end
end
end
describe '#request_uri' do
it 'returns the request.fullpath' do
expect(adapter.request_uri).to eq '/full?param=true'
end
end
describe '#request_path' do
it 'returns the request.path' do
expect(adapter.request_path).to eq '/full'
end
end
describe '#current_page?' do
before { allow(request).to receive_messages(scheme: 'http', host_with_port: 'my_host:5000') }
shared_examples 'detecting current page' do |url, expected|
context "when url is #{url}" do
it "returns #{expected}" do
expect(adapter.current_page?(url)).to be expected
end
end
end
context 'when URL is not encoded' do
it_behaves_like 'detecting current page', '/full?param=true', true
it_behaves_like 'detecting current page', '/full?param3=true', false
it_behaves_like 'detecting current page', '/full', true
it_behaves_like 'detecting current page', 'http://my_host:5000/full?param=true', true
it_behaves_like 'detecting current page', 'http://my_host:5000/full?param3=true', false
it_behaves_like 'detecting current page', 'http://my_host:5000/full', true
it_behaves_like 'detecting current page', 'https://my_host:5000/full', false
it_behaves_like 'detecting current page', 'http://my_host:6000/full', false
it_behaves_like 'detecting current page', 'http://my_other_host:5000/full', false
end
context 'when URL is encoded' do
before do
allow(request).to receive_messages(fullpath: '/full%20with%20spaces?param=true',
path: '/full%20with%20spaces')
end
it_behaves_like 'detecting current page', '/full%20with%20spaces?param=true', true
it_behaves_like 'detecting current page', '/full%20with%20spaces?param3=true', false
it_behaves_like 'detecting current page', '/full%20with%20spaces', true
it_behaves_like 'detecting current page', 'http://my_host:5000/full%20with%20spaces?param=true', true
it_behaves_like 'detecting current page', 'http://my_host:5000/full%20with%20spaces?param3=true', false
it_behaves_like 'detecting current page', 'http://my_host:5000/full%20with%20spaces', true
it_behaves_like 'detecting current page', 'https://my_host:5000/full%20with%20spaces', false
it_behaves_like 'detecting current page', 'http://my_host:6000/full%20with%20spaces', false
it_behaves_like 'detecting current page', 'http://my_other_host:5000/full%20with%20spaces', false
end
end
describe '#link_to' do
it 'returns a link with the correct class and id' do
link = adapter.link_to('link', 'url', class: 'clazz', id: 'id')
expect(link).to eq "link"
end
end
describe '#content_tag' do
it 'returns a tag with the correct class and id' do
tag = adapter.content_tag(:div, 'content', class: 'clazz', id: 'id')
expect(tag).to eq "content
"
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/items_provider_spec.rb 0000644 0000041 0000041 00000002341 12513767261 026242 0 ustar www-data www-data module SimpleNavigation
describe ItemsProvider do
let(:items_provider) { ItemsProvider.new(provider) }
describe '#items' do
let(:items) { double(:items) }
context 'when provider is a symbol' do
let(:context) { double(:context, provider_method: items) }
let(:provider) { :provider_method }
before { allow(SimpleNavigation).to receive_messages(context_for_eval: context) }
it 'retrieves the items from the evaluation context' do
expect(items_provider.items).to eq items
end
end
context 'when provider responds to :items' do
let(:provider) { double(:provider, items: items) }
it 'retrieves the items from the provider object' do
expect(items_provider.items).to eq items
end
end
context 'provider is a collection' do
let(:provider) { [] }
it 'retrieves the items by returning the provider' do
expect(items_provider.items).to eq provider
end
end
context 'when provider is something else' do
let(:provider) { double(:provider) }
it 'raises an exception' do
expect{ items_provider.items }.to raise_error
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/config_file_spec.rb 0000644 0000041 0000041 00000001174 12513767261 025456 0 ustar www-data www-data require 'simple_navigation/config_file'
module SimpleNavigation
describe ConfigFile do
subject(:config_file) { ConfigFile.new(context) }
let(:context) { :default }
describe '#name' do
context 'when the context is :default' do
it 'returns navigation.rb' do
expect(config_file.name).to eq 'navigation.rb'
end
end
context 'when the context is different from :default' do
let(:context) { :HelloWorld }
it 'returns UNDERSCORED_CONTEXT_navigation.rb' do
expect(config_file.name).to eq 'hello_world_navigation.rb'
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/item_adapter_spec.rb 0000644 0000041 0000041 00000012421 12513767261 025645 0 ustar www-data www-data module SimpleNavigation
describe ItemAdapter do
let(:item_adapter) { ItemAdapter.new(item) }
context 'when item is an object' do
let(:item) { double(:item, key: 'key', name: 'name', url: 'url') }
shared_examples 'delegating to item' do |meth|
it "delegates #{meth} to item" do
expect(item).to receive(meth)
item_adapter.public_send(meth)
end
end
it_behaves_like 'delegating to item', :key
it_behaves_like 'delegating to item', :url
it_behaves_like 'delegating to item', :name
describe '#initialize' do
it 'sets the item' do
expect(item_adapter.item).to be item
end
end
describe '#options' do
context 'when item responds to options' do
let(:options) { double(:options) }
before { allow(item).to receive_messages(options: options) }
it "returns the item's options" do
expect(item_adapter.options).to be options
end
end
context 'item does not respond to options' do
it 'returns an empty hash' do
expect(item_adapter.options).to eq({})
end
end
end
describe '#items' do
context 'when item responds to items' do
context 'and items is nil' do
before { allow(item).to receive_messages(items: nil) }
it 'returns nil' do
expect(item_adapter.items).to be_nil
end
end
context 'when items is not nil' do
context 'and items is empty' do
before { allow(item).to receive_messages(items: []) }
it 'returns nil' do
expect(item_adapter.items).to be_nil
end
end
context 'and items is not empty' do
let(:items) { [true] }
before { allow(item).to receive_messages(items: items) }
it 'returns the items' do
expect(item_adapter.items).to eq items
end
end
end
end
context "when item doesn't respond to items" do
it 'returns nil' do
expect(item_adapter.items).to be_nil
end
end
end
describe '#to_simple_navigation_item' do
let(:container) { double(:container) }
before { allow(item).to receive_messages(items: [], options: {}) }
it 'creates an Item' do
expect(Item).to receive(:new)
.with(container, 'key', 'name', 'url', {})
item_adapter.to_simple_navigation_item(container)
end
end
end
context 'when item is a kind of hash' do
class ModifiedHash < Hash; end
let(:item) { ModifiedHash[key: 'key', url: 'url', name: 'name'] }
shared_examples 'delegating to item' do |meth|
it "delegates #{meth} to item" do
expect(item_adapter.item).to receive(meth)
item_adapter.public_send(meth)
end
end
it_behaves_like 'delegating to item', :key
it_behaves_like 'delegating to item', :url
it_behaves_like 'delegating to item', :name
describe '#initialize' do
it 'sets the item' do
expect(item_adapter.item).not_to be_nil
end
it 'converts the item into an object' do
expect(item_adapter.item).to respond_to(:url)
end
end
describe '#options' do
context 'when item responds to options' do
before { item[:options] = { my: :options } }
it "returns the item's options" do
expect(item_adapter.options).to eq({ my: :options })
end
end
context 'when item does not respond to options' do
it 'returns an empty hash' do
expect(item_adapter.options).to eq({})
end
end
end
describe '#items' do
context 'when item responds to items' do
context 'and items is nil' do
before { item[:items] = nil }
it 'returns nil' do
expect(item_adapter.items).to be_nil
end
end
context 'when items is not nil' do
context 'and items is empty' do
it 'returns nil' do
expect(item_adapter.items).to be_nil
end
end
context 'and items is not empty' do
before { item[:items] = ['not', 'empty'] }
it 'returns the items' do
expect(item_adapter.items).to eq ['not', 'empty']
end
end
end
end
context 'when item does not respond to items' do
it 'returns nil' do
expect(item_adapter.items).to be_nil
end
end
end
describe '#to_simple_navigation_item' do
let(:container) { double(:container) }
before { item.merge(options: {}) }
it 'passes the right arguments to Item' do
expect(Item).to receive(:new)
.with(container, 'key', 'name', 'url', {})
item_adapter.to_simple_navigation_item(container)
end
it 'creates an Item' do
created_item = item_adapter.to_simple_navigation_item(container)
expect(created_item).to be_an(Item)
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/configuration_spec.rb 0000644 0000041 0000041 00000012407 12513767261 026062 0 ustar www-data www-data module SimpleNavigation
describe Configuration do
subject(:config) { Configuration.instance }
describe '.run' do
it "yields the singleton Configuration object" do
expect{ |blk| Configuration.run(&blk) }.to yield_with_args(config)
end
end
describe '.eval_config' do
let(:config_files) {{ default: 'default', my_context: 'my_context' }}
let(:eval_context) { double(:eval_context) }
before do
allow(eval_context).to receive(:instance_eval)
allow(SimpleNavigation).to \
receive_messages(context_for_eval: eval_context, config_files: config_files)
end
context "with default navigation context" do
it "calls instance_eval with the default config_file-string inside the context" do
expect(eval_context).to receive(:instance_eval).with('default')
Configuration.eval_config
end
end
context 'with non default navigation context' do
it "calls instance_eval with the specified config_file-string inside the context" do
expect(eval_context).to receive(:instance_eval).with('my_context')
Configuration.eval_config(:my_context)
end
end
end
describe '#initialize' do
it 'sets the List-Renderer as default' do
expect(config.renderer).to be Renderer::List
end
it 'sets the selected_class to "selected" as default' do
expect(config.selected_class).to eq 'selected'
end
it 'sets the active_leaf_class to "simple-navigation-active-leaf" as default' do
expect(config.active_leaf_class).to eq 'simple-navigation-active-leaf'
end
it 'sets autogenerate_item_ids to true as default' do
expect(config.autogenerate_item_ids).to be true
end
it 'sets auto_highlight to true as default' do
expect(config.auto_highlight).to be true
end
it 'sets the id_generator to a callable object' do
expect(config.id_generator).to respond_to(:call)
end
it 'sets the name_generator to a callable object' do
expect(config.name_generator).to respond_to(:call)
end
it 'sets the consider_item_names_as_safe to false' do
expect(config.consider_item_names_as_safe).to be false
end
it 'sets highlights_on_subpath to false as default' do
expect(config.highlight_on_subpath).to be false
end
it 'sets ignore_query_params_on_auto_highlight to true as default' do
expect(config.ignore_query_params_on_auto_highlight).to be true
end
it 'sets ignore_anchors_on_auto_highlight to true as default' do
expect(config.ignore_anchors_on_auto_highlight).to be true
end
end
describe '#items' do
let(:container) { double(:items_container) }
before { allow(ItemContainer).to receive_messages(new: container) }
context 'when a block is given' do
context 'and items_provider is specified' do
let(:provider) { double(:provider) }
it 'raises an exception' do
expect{ config.items(provider) {} }.to raise_error
end
end
context 'when no items_provider is specified' do
it 'yields an new ItemContainer' do
expect{ |blk| config.items(&blk) }.to yield_with_args(container)
end
it 'assigns the ItemContainer to an instance-var' do
config.items {}
expect(config.primary_navigation).to be container
end
it "doesn't set the items on the container" do
expect(container).not_to receive(:items=)
config.items {}
end
end
end
context 'when no block is given' do
context 'and items_provider is specified' do
let(:external_provider) { double(:external_provider) }
let(:items) { double(:items) }
let(:items_provider) { double(:items_provider, items: items) }
before do
allow(SimpleNavigation::ItemsProvider).to receive_messages(new: items_provider)
allow(container).to receive(:items=)
end
it 'creates a new Provider object for the specified provider' do
expect(ItemsProvider).to receive(:new).with(external_provider)
config.items(external_provider)
end
it 'calls items on the provider object' do
expect(items_provider).to receive(:items)
config.items(external_provider)
end
it 'sets the items on the container' do
expect(container).to receive(:items=).with(items)
config.items(external_provider)
end
end
context 'when items_provider is not specified' do
it "raises an exception" do
expect{ config.items }.to raise_error
end
end
end
end
describe '#loaded?' do
context 'when primary_nav is set' do
it 'returns true' do
config.instance_variable_set(:@primary_navigation, :bla)
expect(config).to be_loaded
end
end
context 'when primary_nav is not set' do
it 'returns false if no primary_nav is set' do
config.instance_variable_set(:@primary_navigation, nil)
expect(config).not_to be_loaded
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/helpers_spec.rb 0000644 0000041 0000041 00000034214 12513767261 024655 0 ustar www-data www-data module SimpleNavigation
describe Helpers do
subject(:controller) { test_controller_class.new }
let(:invoices_item) { navigation[:invoices] }
let(:item) { nil }
let(:navigation) { setup_navigation('nav_id', 'nav_class') }
let(:test_controller_class) do
Class.new { include SimpleNavigation::Helpers }
end
let(:unpaid_item) { invoices_item.sub_navigation[:unpaid] }
before do
allow(Configuration).to receive(:eval_config)
allow(SimpleNavigation).to receive_messages(load_config: nil,
primary_navigation: navigation,
config_file?: true,
context_for_eval: controller)
select_an_item(navigation[item]) if item
end
describe '#active_navigation_item_name' do
context 'when no item is selected' do
it 'returns an empty string for no parameters' do
expect(controller.active_navigation_item_name).to eq ''
end
it "returns an empty string for level: 1" do
item_name = controller.active_navigation_item_name(level: 1)
expect(item_name).to eq ''
end
it 'returns an empty string for level: 2' do
item_name = controller.active_navigation_item_name(level: 2)
expect(item_name).to eq ''
end
it 'returns an empty string for level: :all' do
item_name = controller.active_navigation_item_name(level: :all)
expect(item_name).to eq ''
end
end
context 'when an item is selected' do
context "and it's a primary item" do
let(:item) { :invoices }
it 'returns an empty string' do
expect(controller.active_navigation_item_name).to eq ''
end
it "returns the selected item's name for level: 1" do
item_name = controller.active_navigation_item_name(level: 1)
expect(item_name).to eq 'Invoices'
end
it 'returns an empty string for level: 2' do
item_name = controller.active_navigation_item_name(level: 2)
expect(item_name).to eq ''
end
it 'returns an empty string for level: :all' do
item_name = controller.active_navigation_item_name(level: :all)
expect(item_name).to eq ''
end
end
context "and it's a sub navigation item" do
before do
select_an_item(invoices_item)
select_an_item(unpaid_item)
end
it "returns the selected item's name" do
expect(controller.active_navigation_item_name).to eq 'Unpaid'
end
it "returns the selected item's parent name for level: 1" do
item_name = controller.active_navigation_item_name(level: 1)
expect(item_name).to eq 'Invoices'
end
it "returns the selected item's name for level: 2" do
item_name = controller.active_navigation_item_name(level: 2)
expect(item_name).to eq 'Unpaid'
end
it "returns the selected item's name for level: :all" do
item_name = controller.active_navigation_item_name(level: :all)
expect(item_name).to eq 'Unpaid'
end
end
end
end
describe '#active_navigation_item_key' do
context 'when no item is selected' do
it 'returns nil' do
expect(controller.active_navigation_item_key).to be_nil
end
it 'returns nil for no parameters' do
expect(controller.active_navigation_item_key).to be_nil
end
it "returns nil for level: 1" do
item_key = controller.active_navigation_item_key(level: 1)
expect(item_key).to be_nil
end
it 'returns nil for level: 2' do
item_key = controller.active_navigation_item_key(level: 2)
expect(item_key).to be_nil
end
it 'returns nil for level: :all' do
item_key = controller.active_navigation_item_key(level: :all)
expect(item_key).to be_nil
end
end
context 'when an item is selected' do
context "and it's a primary item" do
let(:item) { :invoices }
it 'returns nil for no parameters' do
expect(controller.active_navigation_item_key).to be_nil
end
it "returns the selected item's name for level: 1" do
item_key = controller.active_navigation_item_key(level: 1)
expect(item_key).to eq :invoices
end
it 'returns nil for level: 2' do
item_key = controller.active_navigation_item_key(level: 2)
expect(item_key).to be_nil
end
it 'returns nil for level: :all' do
item_key = controller.active_navigation_item_key(level: :all)
expect(item_key).to be_nil
end
end
context "and it's a sub navigation item" do
before do
select_an_item(invoices_item)
select_an_item(unpaid_item)
end
it "returns the selected item's name" do
expect(controller.active_navigation_item_key).to eq :unpaid
end
it "returns the selected item's parent name for level: 1" do
item_key = controller.active_navigation_item_key(level: 1)
expect(item_key).to eq :invoices
end
it "returns the selected item's name for level: 2" do
item_key = controller.active_navigation_item_key(level: 2)
expect(item_key).to eq :unpaid
end
it "returns the selected item's name for level: :all" do
item_key = controller.active_navigation_item_key(level: :all)
expect(item_key).to eq :unpaid
end
end
end
end
describe '#active_navigation_item' do
context 'when no item is selected' do
it 'returns nil for no parameters' do
expect(controller.active_navigation_item).to be_nil
end
it "returns nil for level: 1" do
item_key = controller.active_navigation_item(level: 1)
expect(item_key).to be_nil
end
it 'returns nil for level: 2' do
item_key = controller.active_navigation_item(level: 2)
expect(item_key).to be_nil
end
it 'returns nil for level: :all' do
item_key = controller.active_navigation_item(level: :all)
expect(item_key).to be_nil
end
end
context 'when an item is selected' do
context "and it's a primary item" do
let(:item) { :invoices }
it 'returns nil for no parameters' do
expect(controller.active_navigation_item).to be_nil
end
it "returns the selected item's name for level: 1" do
item_key = controller.active_navigation_item(level: 1)
expect(item_key).to be invoices_item
end
it 'returns nil for level: 2' do
item_key = controller.active_navigation_item(level: 2)
expect(item_key).to be_nil
end
it 'returns nil for level: :all' do
item_key = controller.active_navigation_item(level: :all)
expect(item_key).to be_nil
end
end
context "and it's a sub navigation item" do
before do
select_an_item(invoices_item)
select_an_item(unpaid_item)
end
it "returns the selected item's name for no parameters" do
expect(controller.active_navigation_item).to be unpaid_item
end
it "returns the selected item's parent name for level: 1" do
item_key = controller.active_navigation_item(level: 1)
expect(item_key).to be invoices_item
end
it "returns the selected item's name for level: 2" do
item_key = controller.active_navigation_item(level: 2)
expect(item_key).to eq unpaid_item
end
it "returns the selected item's name for level: :all" do
item_key = controller.active_navigation_item(level: :all)
expect(item_key).to eq unpaid_item
end
end
end
end
describe '#active_navigation_item_container' do
shared_examples 'returning items container' do
it 'returns the primary navigation for no parameters' do
expect(controller.active_navigation_item_container).to be navigation
end
it "returns the primary navigation for level: 1" do
item_container = controller.active_navigation_item_container(level: 1)
expect(item_container).to be navigation
end
it 'returns the primary navigation level: :all' do
item_container =
controller.active_navigation_item_container(level: :all)
expect(item_container).to be navigation
end
end
context 'when no item is selected' do
it_behaves_like 'returning items container'
it 'returns nil for level: 2' do
item_container = controller.active_navigation_item_container(level: 2)
expect(item_container).to be_nil
end
end
context 'when an item is selected' do
context "and it's a primary item" do
let(:item) { :invoices }
it_behaves_like 'returning items container'
it 'returns the invoices items container for level: 2' do
item_container =
controller.active_navigation_item_container(level: 2)
expect(item_container).to be invoices_item.sub_navigation
end
end
context "and it's a sub navigation item" do
before do
select_an_item(invoices_item)
select_an_item(unpaid_item)
end
it_behaves_like 'returning items container'
it 'returns the invoices items container for level: 2' do
item_container =
controller.active_navigation_item_container(level: 2)
expect(item_container).to be invoices_item.sub_navigation
end
end
end
end
describe '#render_navigation' do
it 'evaluates the configuration on every request' do
expect(SimpleNavigation).to receive(:load_config).twice
2.times { controller.render_navigation }
end
it 'loads the :default configuration' do
expect(SimpleNavigation).to receive(:load_config).with(:default)
controller.render_navigation
end
it "doesn't set the items directly" do
expect(SimpleNavigation.config).not_to receive(:items)
controller.render_navigation
end
it 'looks up the active_item_container based on the level' do
expect(SimpleNavigation).to receive(:active_item_container_for)
.with(:all)
controller.render_navigation
end
context 'when the :context option is specified' do
it 'loads the configuration for the specified context' do
expect(SimpleNavigation).to receive(:load_config).with(:my_context)
controller.render_navigation(context: :my_context)
end
end
context 'when the :items option is specified' do
let(:items) { double(:items) }
it 'sets the items directly' do
expect(SimpleNavigation.config).to receive(:items).with(items)
controller.render_navigation(items: items)
end
end
context 'when the :level option is set' do
context 'and its value is 1' do
it 'calls render on the primary navigation' do
expect(navigation).to receive(:render).with(level: 1)
controller.render_navigation(level: 1)
end
end
context 'and its value is 2' do
context 'and the active_item_container is set' do
let(:item_container) { double(:container).as_null_object }
before do
allow(SimpleNavigation).to receive_messages(active_item_container_for: item_container)
end
it 'finds the selected sub navigation for the specified level' do
expect(SimpleNavigation).to receive(:active_item_container_for)
.with(2)
controller.render_navigation(level: 2)
end
it 'calls render on the active item_container' do
expect(item_container).to receive(:render).with(level: 2)
controller.render_navigation(level: 2)
end
end
context "and the active_item_container isn't set" do
it "doesn't raise an exception" do
expect{
controller.render_navigation(level: 2)
}.not_to raise_error
end
end
end
context "and its value isn't a valid level" do
it 'raises an exception' do
expect{
controller.render_navigation(level: :invalid)
}.to raise_error
end
end
end
context 'when the :levels option is set' do
before { allow(SimpleNavigation).to receive_messages(active_item_container_for: navigation) }
it 'treats it like the :level option' do
expect(navigation).to receive(:render).with(level: 2)
controller.render_navigation(levels: 2)
end
end
context 'when a block is given' do
it 'calls the block passing it an item container' do
expect{ |blk|
controller.render_navigation(&blk)
}.to yield_with_args(ItemContainer)
end
end
context 'when no primary configuration is defined' do
before { allow(SimpleNavigation).to receive_messages(primary_navigation: nil) }
it 'raises an exception' do
expect{controller.render_navigation}.to raise_error
end
end
context "when active_item_container is set" do
let(:active_item_container) { double(:container).as_null_object }
before do
allow(SimpleNavigation).to receive_messages(active_item_container_for: active_item_container)
end
it 'calls render on the active_item_container' do
expect(active_item_container).to receive(:render)
controller.render_navigation
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/config_file_finder_spec.rb 0000644 0000041 0000041 00000002701 12513767261 027002 0 ustar www-data www-data require 'fileutils'
require 'simple_navigation/config_file_finder'
module SimpleNavigation
describe ConfigFileFinder do
subject(:finder) { ConfigFileFinder.new(paths) }
let(:paths) { ['/path/one', '/path/two'] }
describe '#find', memfs: true do
before { FileUtils.mkdir_p(paths) }
context 'when the context is :default' do
let(:context) { :default }
context 'and a navigation.rb file is found in one of the paths' do
before { FileUtils.touch('/path/one/navigation.rb') }
it 'returns its full path' do
expect(finder.find(context)).to eq '/path/one/navigation.rb'
end
end
context 'and no navigation.rb file is found in the paths' do
it 'raises an exception' do
expect{ finder.find(context) }.to raise_error
end
end
end
context 'when the context is :other' do
let(:context) { :other }
context 'and a other_navigation.rb file is found in one of the paths' do
before { FileUtils.touch('/path/two/other_navigation.rb') }
it 'returns its full path' do
expect(finder.find(context)).to eq '/path/two/other_navigation.rb'
end
end
context 'and no other_navigation.rb file is found in the paths' do
it 'raise an exception' do
expect{ finder.find(context) }.to raise_error
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/item_spec.rb 0000644 0000041 0000041 00000034327 12513767261 024156 0 ustar www-data www-data module SimpleNavigation
describe Item do
let!(:item_container) { ItemContainer.new }
let(:adapter) { double(:adapter) }
let(:item_args) { [item_container, :my_key, 'name', url, options] }
let(:item) { Item.new(*item_args) }
let(:options) { Hash.new }
let(:url) { 'url' }
before { allow(SimpleNavigation).to receive_messages(adapter: adapter) }
describe '#highlights_on' do
let(:options) {{ highlights_on: :test }}
it "returns the item's highlights_on option" do
expect(item.highlights_on).to eq :test
end
end
describe '#initialize' do
context 'when there is a sub_navigation' do
let(:subnav_container) { double(:subnav_container).as_null_object }
shared_examples 'creating sub navigation container' do
it 'creates a sub navigation container with a level+1' do
expect(item.sub_navigation.level).to eq 2
end
end
context 'when a block is given' do
it_behaves_like 'creating sub navigation container' do
let(:item) { Item.new(*item_args) {} }
end
it 'calls the block' do
allow(ItemContainer).to receive_messages(new: subnav_container)
expect{ |blk|
Item.new(*item_args, &blk)
}.to yield_with_args(subnav_container)
end
end
context 'when no block is given' do
context 'and items are given' do
let(:items) { [] }
let(:options) {{ items: items }}
it_behaves_like 'creating sub navigation container'
it "sets the items on the subnav_container" do
expect(item.sub_navigation.items).to eq items
end
end
context 'and no items are given' do
it "doesn't create a new ItemContainer" do
item = Item.new(*item_args)
expect(item.sub_navigation).to be_nil
end
end
end
end
context 'when a :method option is given' do
let(:options) {{ method: :delete }}
it "sets the item's method" do
expect(item.method).to eq :delete
end
end
context 'when no :method option is given' do
it "sets the item's method to nil" do
expect(item.method).to be_nil
end
end
context 'when an :highlights_on option is given' do
let(:highlights_on) { double(:highlights_on) }
let(:options) {{ highlights_on: highlights_on }}
it "sets the item's highlights_on" do
expect(item.highlights_on).to eq highlights_on
end
end
context 'when no :highlights_on option is given' do
it "sets the item's highlights_on to nil" do
expect(item.highlights_on).to be_nil
end
end
context 'when a url is given' do
context 'and it is a string' do
it "sets the item's url accordingly" do
expect(item.url).to eq 'url'
end
end
context 'and it is a proc' do
let(:url) { proc{ "my_" + "url" } }
it "sets the item's url accordingly" do
expect(item.url).to eq 'my_url'
end
end
context 'and it is nil' do
let(:url) { nil }
it "sets the item's url accordingly" do
expect(item.url).to be_nil
end
end
end
context 'when no url nor options is specified' do
let(:item_args) { [item_container, :my_key, 'name'] }
it "sets the item's url to nil" do
expect(item.url).to be_nil
end
end
context 'when only a url is given' do
let(:item_args) { [item_container, :my_key, 'name', 'url'] }
it "set the item's url accordingly" do
expect(item.url).to eq 'url'
end
end
context 'when url and options are given' do
let(:options) {{ html: { option: true } }}
before { allow(adapter).to receive_messages(current_page?: false) }
it "set the item's url accordingly" do
expect(item.url).to eq 'url'
end
it "sets the item's html_options accordingly" do
allow(item).to \
receive_messages(selected_by_subnav?: false,
selected_by_condition?: false)
expect(item.html_options).to include(option: true)
end
end
end
describe '#link_html_options' do
let(:options) {{ link_html: :test }}
it "returns the item's link_html option" do
expect(item.link_html_options).to eq :test
end
end
describe '#method' do
let(:options) {{ method: :test }}
it "returns the item's method option" do
expect(item.method).to eq :test
end
end
describe '#name' do
before do
allow(SimpleNavigation.config).to \
receive_messages(name_generator: proc{ |name| "#{name}" })
end
context 'when no option is given' do
context 'and the name_generator uses only the name' do
it 'uses the default name_generator' do
expect(item.name).to eq 'name'
end
end
context 'and the name_generator uses only the item itself' do
before do
allow(SimpleNavigation.config).to \
receive_messages(name_generator: proc{ |name, item| "#{item.key}" })
end
it 'uses the default name_generator' do
expect(item.name).to eq 'my_key'
end
end
end
context 'when the :apply_generator is false' do
it "returns the item's name" do
expect(item.name(apply_generator: false)).to eq 'name'
end
end
context 'when a block is given' do
let(:item_args) { [item_container, :my_key, -> { 'Name in block' }, url, options] }
it "returns the item's name that is defined in the block" do
expect(item.name).to include 'Name in block'
end
end
end
describe '#selected?' do
context 'when the item has no :highlights_on option' do
before { allow(SimpleNavigation).to receive_messages(config: config) }
context 'and auto highlighting is off' do
let(:config) { double(:config, auto_highlight: false) }
it 'returns false' do
expect(item.selected?).to be false
end
end
context 'and auto highlighting is on' do
let(:config) { double(:config, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true, auto_highlight: true) }
context "and the current url matches the item's url" do
before { allow(adapter).to receive_messages(current_page?: true) }
it 'returns true' do
expect(item.selected?).to be true
end
end
context "and the current url does not match the item's url" do
let(:config) do
double(:config, auto_highlight: false, highlight_on_subpath: false)
end
before { allow(adapter).to receive_messages(current_page?: false) }
it 'returns false' do
expect(item.selected?).to be false
end
end
context 'and highlights_on_subpath is on' do
let(:config) do
double(:config, auto_highlight: true, highlight_on_subpath: true, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true)
end
context "and the current url is a sub path of the item's url" do
before do
allow(adapter).to \
receive_messages(current_page?: false, request_uri: 'url/test')
end
it 'returns true' do
expect(item.selected?).to be true
end
end
context "and the current url is not a sub path of the item's url" do
before do
allow(adapter).to \
receive_messages(current_page?: false, request_uri: 'other/test')
end
it 'returns false' do
expect(item.selected?).to be false
end
end
end
end
end
context 'when the item has a :highlights_on option' do
context 'and it is a regular expression' do
before { allow(adapter).to receive_messages(request_uri: '/test') }
context 'and the current url matches the expression' do
let(:options) {{ highlights_on: /test/ }}
it 'returns true' do
expect(item.selected?).to be true
end
end
context 'and the current url does not match the expression' do
let(:options) {{ highlights_on: /other/ }}
it 'returns false' do
expect(item.selected?).to be false
end
end
end
context 'and it is a callable object' do
context 'and the call returns true' do
let(:options) {{ highlights_on: -> { true } }}
it 'returns true' do
expect(item.selected?).to be true
end
end
context 'and the call returns false' do
let(:options) {{ highlights_on: -> { false } }}
it 'returns false' do
expect(item.selected?).to be false
end
end
end
context 'and it is the :subpath symbol' do
let(:options) {{ highlights_on: :subpath }}
context "and the current url is a sub path of the item's url" do
before do
allow(adapter).to receive_messages(request_uri: 'url/test')
end
it 'returns true' do
expect(item.selected?).to be true
end
end
context "and the current url is not a sub path of the item's url" do
before do
allow(adapter).to receive_messages(request_uri: 'other/test')
end
it 'returns false' do
expect(item.selected?).to be false
end
end
end
context 'and it is non usable' do
let(:options) {{ highlights_on: :hello }}
it 'raises an exception' do
expect{ item.selected? }.to raise_error
end
end
end
end
describe '#selected_class' do
context 'when the item is selected' do
before { allow(item).to receive_messages(selected?: true) }
it 'returns the default selected_class' do
expect(item.selected_class).to eq 'selected'
end
context 'and selected_class is defined in the context' do
before { allow(item_container).to receive_messages(selected_class: 'defined') }
it "returns the context's selected_class" do
expect(item.selected_class).to eq 'defined'
end
end
end
context 'when the item is not selected' do
before { allow(item).to receive_messages(selected?: false) }
it 'returns nil' do
expect(item.selected_class).to be_nil
end
end
end
describe ':html_options argument' do
let(:selected_classes) { 'selected simple-navigation-active-leaf' }
context 'when the :class option is given' do
let(:options) {{ html: { class: 'my_class' } }}
context 'and the item is selected' do
before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) }
it "adds the specified class to the item's html classes" do
expect(item.html_options[:class]).to include('my_class')
end
it "doesn't replace the default html classes of a selected item" do
expect(item.html_options[:class]).to include(selected_classes)
end
end
context "and the item isn't selected" do
before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) }
it "sets the specified class as the item's html classes" do
expect(item.html_options[:class]).to include('my_class')
end
end
end
context "when the :class option isn't given" do
context 'and the item is selected' do
before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) }
it "sets the default html classes of a selected item" do
expect(item.html_options[:class]).to include(selected_classes)
end
end
context "and the item isn't selected" do
before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) }
it "doesn't set any html class on the item" do
expect(item.html_options[:class]).to be_blank
end
end
end
shared_examples 'generating id' do |id|
it "sets the item's html id to the specified id" do
expect(item.html_options[:id]).to eq id
end
end
describe 'when the :id option is given' do
let(:options) {{ html: { id: 'my_id' } }}
before do
allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids)
allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
end
context 'and :autogenerate_item_ids is true' do
let(:generate_ids) { true }
it_behaves_like 'generating id', 'my_id'
end
context 'and :autogenerate_item_ids is false' do
let(:generate_ids) { false }
it_behaves_like 'generating id', 'my_id'
end
end
context "when the :id option isn't given" do
before do
allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids)
allow(item).to receive_messages(selected?: false, selected_by_condition?: false)
end
context 'and :autogenerate_item_ids is true' do
let(:generate_ids) { true }
it_behaves_like 'generating id', 'my_key'
end
context 'and :autogenerate_item_ids is false' do
let(:generate_ids) { false }
it "doesn't set any html id on the item" do
expect(item.html_options[:id]).to be_blank
end
end
end
end
end
end
simple-navigation-4.0.3/spec/simple_navigation/item_container_spec.rb 0000644 0000041 0000041 00000047444 12513767261 026224 0 ustar www-data www-data module SimpleNavigation
describe ItemContainer do
subject(:item_container) { ItemContainer.new }
shared_examples 'adding the item to the list' do
it 'adds the item to the list' do
allow(Item).to receive_messages(new: item)
item_container.item(*args)
expect(item_container.items).to include(item)
end
end
shared_examples 'not adding the item to the list' do
it "doesn't add the item to the list" do
allow(Item).to receive_messages(new: item)
item_container.item(*args)
expect(item_container.items).not_to include(item)
end
end
describe '#initialize' do
it 'sets an empty items array' do
expect(item_container.items).to be_empty
end
end
describe '#dom_attributes' do
let(:dom_attributes) {{ id: 'test_id', class: 'test_class' }}
before { item_container.dom_attributes = dom_attributes }
it "returns the container's dom_attributes" do
expect(item_container.dom_attributes).to eq dom_attributes
end
context 'when the dom_attributes do not contain any id or class' do
let(:dom_attributes) {{ test: 'test' }}
context "and the container hasn't any dom_id" do
it "returns the contaier's dom_attributes without any id" do
expect(item_container.dom_attributes).not_to include(:id)
end
end
context 'and the container has a dom_id' do
before { item_container.dom_id = 'test_id' }
it "returns the contaier's dom_attributes including the #dom_id" do
expect(item_container.dom_attributes).to include(id: 'test_id')
end
end
context "and the container hasn't any dom_class" do
it "returns the contaier's dom_attributes without any class" do
expect(item_container.dom_attributes).not_to include(:class)
end
end
context 'and the container has a dom_class' do
before { item_container.dom_class = 'test_class' }
it "returns the contaier's dom_attributes including the #dom_class" do
expect(item_container.dom_attributes).to include(class: 'test_class')
end
end
end
end
describe '#items=' do
let(:item) {{ key: :my_key, name: 'test', url: '/' }}
let(:items) { [item] }
let(:item_adapter) { double(:item_adapter).as_null_object }
let(:real_item) { double(:real_item) }
before do
allow(ItemAdapter).to receive_messages(new: item_adapter)
allow(item_adapter).to receive(:to_simple_navigation_item)
.with(item_container)
.and_return(real_item)
end
context 'when the item should be added' do
before { allow(item_container).to receive_messages(should_add_item?: true) }
it 'converts it to an Item and adds it to the items collection' do
item_container.items = items
expect(item_container.items).to include(real_item)
end
end
context 'when the item should not be added' do
before { allow(item_container).to receive_messages(should_add_item?: false) }
it "doesn't add it to the items collection" do
item_container.items = items
expect(item_container.items).not_to include(real_item)
end
end
end
describe '#selected?' do
let(:item_1) { double(:item, selected?: false) }
let(:item_2) { double(:item, selected?: false) }
before do
item_container.instance_variable_set(:@items, [item_1, item_2])
end
context 'when no item is selected' do
it 'returns nil' do
expect(item_container).not_to be_selected
end
end
context 'when an item is selected' do
it 'returns true' do
allow(item_1).to receive_messages(selected?: true)
expect(item_container).to be_selected
end
end
end
describe '#selected_item' do
let(:item_1) { double(:item, selected?: false) }
let(:item_2) { double(:item, selected?: false) }
before(:each) do
allow(SimpleNavigation).to receive_messages(current_navigation_for: :nav)
allow(item_container).to receive_messages(:[] => nil)
item_container.instance_variable_set(:@items, [item_1, item_2])
end
context "when navigation isn't explicitely set" do
context 'and no item is selected' do
it 'returns nil' do
expect(item_container.selected_item).to be_nil
end
end
context 'and an item selected' do
before { allow(item_1).to receive_messages(selected?: true) }
it 'returns the selected item' do
expect(item_container.selected_item).to be item_1
end
end
end
end
describe '#active_item_container_for' do
context "when the desired level is the same as the container's" do
it 'returns the container itself' do
expect(item_container.active_item_container_for(1)).to be item_container
end
end
context "when the desired level is different than the container's" do
context 'and no subnavigation is selected' do
before { allow(item_container).to receive_messages(selected_sub_navigation?: false) }
it 'returns nil' do
expect(item_container.active_item_container_for(2)).to be_nil
end
end
context 'and a subnavigation is selected' do
let(:sub_navigation) { double(:sub_navigation) }
let(:selected_item) { double(:selected_item) }
before do
allow(item_container).to \
receive_messages(selected_sub_navigation?: true, selected_item: selected_item)
allow(selected_item).to receive_messages(sub_navigation: sub_navigation)
end
it 'calls recursively on the sub_navigation' do
expect(sub_navigation).to receive(:active_item_container_for)
.with(2)
item_container.active_item_container_for(2)
end
end
end
end
describe '#active_leaf_container' do
context 'when the current container has a selected subnavigation' do
let(:sub_navigation) { double(:sub_navigation) }
let(:selected_item) { double(:selected_item) }
before do
allow(item_container).to receive_messages(selected_sub_navigation?: true,
selected_item: selected_item)
allow(selected_item).to receive_messages(sub_navigation: sub_navigation)
end
it 'calls recursively on the sub_navigation' do
expect(sub_navigation).to receive(:active_leaf_container)
item_container.active_leaf_container
end
end
context 'when the current container is the leaf already' do
before { allow(item_container).to receive_messages(selected_sub_navigation?: false) }
it 'returns itsself' do
expect(item_container.active_leaf_container).to be item_container
end
end
end
describe '#item' do
let(:options) { Hash.new }
let(:item) { double(:item) }
context 'when a block is given' do
let(:block) { proc{} }
let(:sub_container) { double(:sub_container) }
it 'yields a new ItemContainer' do
allow_any_instance_of(Item).to \
receive_messages(sub_navigation: sub_container)
expect{ |blk|
item_container.item('key', 'name', 'url', options, &blk)
}.to yield_with_args(sub_container)
end
it "creates a new Item with the given params and block" do
allow(Item).to receive(:new)
.with(item_container, 'key', 'name', 'url', options, &block)
.and_return(item)
item_container.item('key', 'name', 'url', options, &block)
expect(item_container.items).to include(item)
end
it 'adds the created item to the list of items' do
item_container.item('key', 'name', 'url', options) {}
expect(item_container.items).not_to include(item)
end
end
context 'when no block is given' do
it 'creates a new Item with the given params and no sub navigation' do
allow(Item).to receive(:new)
.with(item_container, 'key', 'name', 'url', options)
.and_return(item)
item_container.item('key', 'name', 'url', options)
expect(item_container.items).to include(item)
end
it 'adds the created item to the list of items' do
allow(Item).to receive_messages(new: item)
item_container.item('key', 'name', 'url', options) {}
expect(item_container.items).to include(item)
end
end
describe 'Optional url and optional options' do
context 'when item specifed without url or options' do
it_behaves_like 'adding the item to the list' do
let(:args) { ['key', 'name'] }
end
end
context 'when item is specified with only a url' do
it_behaves_like 'adding the item to the list' do
let(:args) { ['key', 'name', 'url'] }
end
end
context 'when item is specified with only options' do
context 'and options do not contain any condition' do
it_behaves_like 'adding the item to the list' do
let(:args) { ['key', 'name', { option: true }] }
end
end
context 'and options contains a negative condition' do
it_behaves_like 'not adding the item to the list' do
let(:args) { ['key', 'name', nil, { if: ->{ false }, option: true }] }
end
end
context 'and options contains a positive condition' do
it_behaves_like 'adding the item to the list' do
let(:args) { ['key', 'name', nil, { if: ->{ true }, option: true }] }
end
end
end
context 'when item is specified with a url and options' do
context 'and options do not contain any condition' do
it_behaves_like 'adding the item to the list' do
let(:args) { ['key', 'name', 'url', { option: true }] }
end
end
context 'and options contains a negative condition' do
it_behaves_like 'not adding the item to the list' do
let(:args) { ['key', 'name', 'url', { if: ->{ false }, option: true }] }
end
end
context 'and options contains a positive condition' do
it_behaves_like 'adding the item to the list' do
let(:args) { ['key', 'name', 'url', { if: ->{ true }, option: true }] }
end
end
end
context 'when a frozen options hash is given' do
let(:options) do
{ html: { id: 'test' } }.freeze
end
it 'does not raise an exception' do
expect{
item_container.item('key', 'name', 'url', options)
}.not_to raise_error
end
end
describe "container options" do
before do
allow(item_container).to receive_messages(should_add_item?: add_item)
item_container.item :key, 'name', 'url', options
end
context 'when the container :id option is specified' do
let(:options) {{ container: { id: 'c_id' } }}
context 'and the item should be added' do
let(:add_item) { true }
it 'changes its dom_id' do
expect(item_container.dom_id).to eq 'c_id'
end
end
context "and the item shouldn't be added" do
let(:add_item) { false }
it "doesn't change its dom_id" do
expect(item_container.dom_id).to be_nil
end
end
end
context 'when the container :class option is specified' do
let(:options) {{ container: { class: 'c_class' } }}
context 'and the item should be added' do
let(:add_item) { true }
it 'changes its dom_class' do
expect(item_container.dom_class).to eq 'c_class'
end
end
context "and the item shouldn't be added" do
let(:add_item) { false }
it "doesn't change its dom_class" do
expect(item_container.dom_class).to be_nil
end
end
end
context 'when the container :attributes option is specified' do
let(:options) {{ container: { attributes: { option: true } } }}
context 'and the item should be added' do
let(:add_item) { true }
it 'changes its dom_attributes' do
expect(item_container.dom_attributes).to eq(option: true)
end
end
context "and the item shouldn't be added" do
let(:add_item) { false }
it "doesn't change its dom_attributes" do
expect(item_container.dom_attributes).to eq({})
end
end
end
context 'when the container :selected_class option is specified' do
let(:options) {{ container: { selected_class: 'sel_class' } }}
context 'and the item should be added' do
let(:add_item) { true }
it 'changes its selected_class' do
expect(item_container.selected_class).to eq 'sel_class'
end
end
context "and the item shouldn't be added" do
let(:add_item) { false }
it "doesn't change its selected_class" do
expect(item_container.selected_class).to be_nil
end
end
end
end
end
describe 'Conditions' do
context 'when an :if option is given' do
let(:options) {{ if: proc{condition} }}
let(:condition) { nil }
context 'and it evals to true' do
let(:condition) { true }
it 'creates a new Item' do
expect(Item).to receive(:new)
item_container.item('key', 'name', 'url', options)
end
end
context 'and it evals to false' do
let(:condition) { false }
it "doesn't create a new Item" do
expect(Item).not_to receive(:new)
item_container.item('key', 'name', 'url', options)
end
end
context 'and it is not a proc or a method' do
it 'raises an error' do
expect{
item_container.item('key', 'name', 'url', { if: 'text' })
}.to raise_error
end
end
end
context 'when an :unless option is given' do
let(:options) {{ unless: proc{condition} }}
let(:condition) { nil }
context 'and it evals to false' do
let(:condition) { false }
it 'creates a new Navigation-Item' do
expect(Item).to receive(:new)
item_container.item('key', 'name', 'url', options)
end
end
context 'and it evals to true' do
let(:condition) { true }
it "doesn't create a new Navigation-Item" do
expect(Item).not_to receive(:new)
item_container.item('key', 'name', 'url', options)
end
end
end
end
end
describe '#[]' do
before do
item_container.item(:first, 'first', 'bla')
item_container.item(:second, 'second', 'bla')
item_container.item(:third, 'third', 'bla')
end
it 'returns the item with the specified navi_key' do
expect(item_container[:second].name).to eq 'second'
end
context 'when no item exists for the specified navi_key' do
it 'returns nil' do
expect(item_container[:invalid]).to be_nil
end
end
end
describe '#render' do
# TODO
let(:renderer_instance) { double(:renderer).as_null_object }
let(:renderer_class) { double(:renderer_class, new: renderer_instance) }
context 'when renderer is specified as an option' do
context 'and is specified as a class' do
it 'instantiates the passed renderer_class with the options' do
expect(renderer_class).to receive(:new)
.with(renderer: renderer_class)
item_container.render(renderer: renderer_class)
end
it 'calls render on the renderer and passes self' do
expect(renderer_instance).to receive(:render).with(item_container)
item_container.render(renderer: renderer_class)
end
end
context 'and is specified as a symbol' do
before do
SimpleNavigation.registered_renderers = {
my_renderer: renderer_class
}
end
it "instantiates the passed renderer_class with the options" do
expect(renderer_class).to receive(:new).with(renderer: :my_renderer)
item_container.render(renderer: :my_renderer)
end
it 'calls render on the renderer and passes self' do
expect(renderer_instance).to receive(:render).with(item_container)
item_container.render(renderer: :my_renderer)
end
end
end
context 'when no renderer is specified' do
let(:options) { Hash.new }
before { allow(item_container).to receive_messages(renderer: renderer_class) }
it "instantiates the container's renderer with the options" do
expect(renderer_class).to receive(:new).with(options)
item_container.render(options)
end
it 'calls render on the renderer and passes self' do
expect(renderer_instance).to receive(:render).with(item_container)
item_container.render(options)
end
end
end
describe '#renderer' do
context 'when no renderer is set explicitly' do
it 'returns globally-configured renderer' do
expect(item_container.renderer).to be Configuration.instance.renderer
end
end
context 'when a renderer is set explicitly' do
let(:renderer) { double(:renderer) }
before { item_container.renderer = renderer }
it 'returns the specified renderer' do
expect(item_container.renderer).to be renderer
end
end
end
describe '#level_for_item' do
before(:each) do
item_container.item(:p1, 'p1', 'p1')
item_container.item(:p2, 'p2', 'p2') do |p2|
p2.item(:s1, 's1', 's1')
p2.item(:s2, 's2', 's2') do |s2|
s2.item(:ss1, 'ss1', 'ss1')
s2.item(:ss2, 'ss2', 'ss2')
end
p2.item(:s3, 's3', 's3')
end
item_container.item(:p3, 'p3', 'p3')
end
shared_examples 'returning the level of an item' do |item, level|
specify{ expect(item_container.level_for_item(item)).to eq level }
end
it_behaves_like 'returning the level of an item', :p1, 1
it_behaves_like 'returning the level of an item', :p3, 1
it_behaves_like 'returning the level of an item', :s1, 2
it_behaves_like 'returning the level of an item', :ss1, 3
it_behaves_like 'returning the level of an item', :x, nil
end
describe '#empty?' do
context 'when there are no items' do
it 'returns true' do
item_container.instance_variable_set(:@items, [])
expect(item_container).to be_empty
end
end
context 'when there are some items' do
it 'returns false' do
item_container.instance_variable_set(:@items, [double(:item)])
expect(item_container).not_to be_empty
end
end
end
end
end
simple-navigation-4.0.3/spec/fake_app/ 0000755 0000041 0000041 00000000000 12513767261 017706 5 ustar www-data www-data simple-navigation-4.0.3/spec/fake_app/config/ 0000755 0000041 0000041 00000000000 12513767261 021153 5 ustar www-data www-data simple-navigation-4.0.3/spec/fake_app/config/navigation.rb 0000644 0000041 0000041 00000000256 12513767261 023642 0 ustar www-data www-data SimpleNavigation::Configuration.run do |navigation|
navigation.items do |nav|
nav.item :item_1, 'Item 1', '/item_1'
nav.item :item_2, 'Item 2', '/item_2'
end
end
simple-navigation-4.0.3/spec/fake_app/rails_app.rb 0000644 0000041 0000041 00000001434 12513767261 022207 0 ustar www-data www-data ENV['RAILS_ENV'] ||= 'test'
require 'action_controller/railtie'
require 'simple_navigation'
module RailsApp
class Application < Rails::Application
config.active_support.deprecation = :log
config.cache_classes = true
config.eager_load = false
config.root = __dir__
config.secret_token = 'x'*100
config.session_store :cookie_store, key: '_myapp_session'
end
class TestsController < ActionController::Base
def base
render inline: <<-END
<%= render_navigation %>
END
end
end
end
Rails.backtrace_cleaner.remove_silencers!
RailsApp::Application.initialize!
RailsApp::Application.routes.draw do
get '/base_spec' => 'rails_app/tests#base'
end
simple-navigation-4.0.3/.travis.yml 0000644 0000041 0000041 00000000310 12513767261 017311 0 ustar www-data www-data before_install:
- gem install bundler
rvm:
- 2.0.0
- 2.1.5
- 2.2.1
gemfile:
- gemfiles/rails-4-2-stable.gemfile
- gemfiles/rails-4-1-stable.gemfile
- gemfiles/rails-3-2-stable.gemfile
simple-navigation-4.0.3/lib/ 0000755 0000041 0000041 00000000000 12513767261 015754 5 ustar www-data www-data simple-navigation-4.0.3/lib/simple_navigation.rb 0000644 0000041 0000041 00000013255 12513767261 022017 0 ustar www-data www-data # cherry picking active_support stuff
require 'active_support/core_ext/array'
require 'active_support/core_ext/hash'
require 'active_support/core_ext/module/attribute_accessors'
require 'simple_navigation/version'
require 'simple_navigation/configuration'
require 'simple_navigation/item_adapter'
require 'simple_navigation/item'
require 'simple_navigation/item_container'
require 'simple_navigation/items_provider'
require 'simple_navigation/renderer'
require 'simple_navigation/adapters'
require 'simple_navigation/config_file_finder'
require 'simple_navigation/railtie' if defined?(::Rails)
require 'forwardable'
# A plugin for generating a simple navigation. See README for resources on
# usage instructions.
module SimpleNavigation
mattr_accessor :adapter,
:adapter_class,
:config_files,
:config_file_paths,
:default_renderer,
:environment,
:registered_renderers,
:root
# Cache for loaded config files
self.config_files = {}
# Allows for multiple config_file_paths. Needed if a plugin itself uses
# simple-navigation and therefore has its own config file
self.config_file_paths = []
# Maps renderer keys to classes. The keys serve as shortcut in the
# render_navigation calls (renderer: :list)
self.registered_renderers = {
list: SimpleNavigation::Renderer::List,
links: SimpleNavigation::Renderer::Links,
breadcrumbs: SimpleNavigation::Renderer::Breadcrumbs,
text: SimpleNavigation::Renderer::Text,
json: SimpleNavigation::Renderer::Json
}
class << self
extend Forwardable
def_delegators :adapter, :context_for_eval,
:current_page?,
:request,
:request_path,
:request_uri
def_delegators :adapter_class, :register
# Sets the root path and current environment as specified. Also sets the
# default config_file_path.
def set_env(root, environment)
self.root = root
self.environment = environment
config_file_paths << default_config_file_path
end
# Returns the current framework in which the plugin is running.
def framework
return :rails if defined?(Rails)
return :padrino if defined?(Padrino)
return :sinatra if defined?(Sinatra)
return :nanoc if defined?(Nanoc3)
fail 'simple_navigation currently only works for Rails, Sinatra and ' \
'Padrino apps'
end
# Loads the adapter for the current framework
def load_adapter
self.adapter_class =
case framework
when :rails then SimpleNavigation::Adapters::Rails
when :sinatra then SimpleNavigation::Adapters::Sinatra
when :padrino then SimpleNavigation::Adapters::Padrino
when :nanoc then SimpleNavigation::Adapters::Nanoc
end
end
# Creates a new adapter instance based on the context in which
# render_navigation has been called.
def init_adapter_from(context)
self.adapter = adapter_class.new(context)
end
def default_config_file_path
File.join(root, 'config')
end
# Resets the list of config_file_paths to the specified path
def config_file_path=(path)
self.config_file_paths = [path]
end
# Reads the config_file for the specified navigation_context and stores it
# for later evaluation.
def load_config(navigation_context = :default)
if environment == 'production'
update_config(navigation_context)
else
update_config!(navigation_context)
end
end
# Returns the singleton instance of the SimpleNavigation::Configuration
def config
SimpleNavigation::Configuration.instance
end
# Returns the ItemContainer that contains the items for the
# primary navigation
def primary_navigation
config.primary_navigation
end
# Returns the active item container for the specified level.
# Valid levels are
# * :all - in this case the primary_navigation is returned.
# * :leaves - the 'deepest' active item_container will be returned
# * a specific level - the active item_container for the specified level
# will be returned
# * a range of levels - the active item_container for the range's minimum
# will be returned
#
# Returns nil if there is no active item_container for the specified level.
def active_item_container_for(level)
case level
when :all then primary_navigation
when :leaves then primary_navigation.active_leaf_container
when Integer then primary_navigation.active_item_container_for(level)
when Range then primary_navigation.active_item_container_for(level.min)
else
fail ArgumentError, "Invalid navigation level: #{level}"
end
end
# Registers a renderer.
#
# === Example
# To register your own renderer:
#
# SimpleNavigation.register_renderer my_renderer: My::RendererClass
#
# Then in the view you can call:
#
# render_navigation(renderer: :my_renderer)
def register_renderer(renderer_hash)
registered_renderers.merge!(renderer_hash)
end
private
def config_file(navigation_context)
ConfigFileFinder.new(config_file_paths).find(navigation_context)
end
def read_config(navigation_context)
File.read config_file(navigation_context)
end
def update_config(navigation_context)
config_files[navigation_context] ||= read_config(navigation_context)
end
def update_config!(navigation_context)
config_files[navigation_context] = read_config(navigation_context)
end
end
end
SimpleNavigation.load_adapter
simple-navigation-4.0.3/lib/simple-navigation.rb 0000644 0000041 0000041 00000000034 12513767261 021724 0 ustar www-data www-data require 'simple_navigation'
simple-navigation-4.0.3/lib/generators/ 0000755 0000041 0000041 00000000000 12513767261 020125 5 ustar www-data www-data simple-navigation-4.0.3/lib/generators/navigation_config/ 0000755 0000041 0000041 00000000000 12513767261 023611 5 ustar www-data www-data simple-navigation-4.0.3/lib/generators/navigation_config/navigation_config_generator.rb 0000644 0000041 0000041 00000001173 12513767261 031672 0 ustar www-data www-data class NavigationConfigGenerator < Rails::Generators::Base
def self.source_root
@source_root ||= begin
tpl_dir = %w[.. .. .. .. generators navigation_config templates]
tpl_dir_path = File.join(tpl_dir)
File.expand_path(tpl_dir_path, __FILE__)
end
end
desc 'Creates a template config file for the simple-navigation plugin. ' \
'You will find the generated file in config/navigation.rb.'
def navigation_config
copy_file('config/navigation.rb', 'config/navigation.rb')
readme_path = File.join(%w[.. .. .. .. README.md])
say File.read(File.expand_path(readme_path, __FILE__))
end
end
simple-navigation-4.0.3/lib/simple_navigation/ 0000755 0000041 0000041 00000000000 12513767261 021464 5 ustar www-data www-data simple-navigation-4.0.3/lib/simple_navigation/configuration.rb 0000644 0000041 0000041 00000006476 12513767261 024675 0 ustar www-data www-data require 'singleton'
module SimpleNavigation
# Responsible for evaluating and handling the config/navigation.rb file.
class Configuration
include Singleton
attr_accessor :autogenerate_item_ids,
:auto_highlight,
:consider_item_names_as_safe,
:highlight_on_subpath,
:ignore_query_params_on_auto_highlight,
:ignore_anchors_on_auto_highlight
attr_reader :primary_navigation
attr_writer :active_leaf_class,
:id_generator,
:name_generator,
:renderer,
:selected_class
# Evals the config_file for the given navigation_context
def self.eval_config(navigation_context = :default)
context = SimpleNavigation.config_files[navigation_context]
SimpleNavigation.context_for_eval.instance_eval(context)
end
# Starts processing the configuration
def self.run(&block)
block.call Configuration.instance
end
# Sets the config's default-settings
def initialize
@autogenerate_item_ids = true
@auto_highlight = true
@consider_item_names_as_safe = false
@highlight_on_subpath = false
@ignore_anchors_on_auto_highlight = true
@ignore_query_params_on_auto_highlight = true
end
def active_leaf_class
@active_leaf_class ||= 'simple-navigation-active-leaf'
end
def id_generator
@id_generator ||= :to_s.to_proc
end
# This is the main method for specifying the navigation items.
# It can be used in two ways:
#
# 1. Declaratively specify your items in the config/navigation.rb file
# using a block. It then yields an SimpleNavigation::ItemContainer
# for adding navigation items.
# 2. Directly provide your items to the method (e.g. when loading your
# items from the database).
#
# ==== Example for block style (configuration file)
# config.items do |primary|
# primary.item :my_item, 'My item', my_item_path
# ...
# end
#
# ==== To consider when directly providing items
# items_provider should be:
# * a methodname (as symbol) that returns your items. The method needs to
# be available in the view (i.e. a helper method)
# * an object that responds to :items
# * an enumerable containing your items
# The items you specify have to fullfill certain requirements.
# See SimpleNavigation::ItemAdapter for more details.
#
def items(items_provider = nil, &block)
if (items_provider && block) || (items_provider.nil? && block.nil?)
fail('please specify either items_provider or block, but not both')
end
self.primary_navigation = ItemContainer.new
if block
block.call primary_navigation
else
primary_navigation.items = ItemsProvider.new(items_provider).items
end
end
# Returns true if the config_file has already been evaluated.
def loaded?
!primary_navigation.nil?
end
def name_generator
@name_generator ||= proc { |name| name }
end
def renderer
@renderer ||= SimpleNavigation.default_renderer ||
SimpleNavigation::Renderer::List
end
def selected_class
@selected_class ||= 'selected'
end
private
attr_writer :primary_navigation
end
end
simple-navigation-4.0.3/lib/simple_navigation/renderer/ 0000755 0000041 0000041 00000000000 12513767261 023272 5 ustar www-data www-data simple-navigation-4.0.3/lib/simple_navigation/renderer/breadcrumbs.rb 0000644 0000041 0000041 00000003647 12513767261 026122 0 ustar www-data www-data module SimpleNavigation
module Renderer
# Renders an ItemContainer as a