simple-navigation 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ *1.1.1
2
+
3
+ * Change plugin into a GemPlugin
data/README ADDED
@@ -0,0 +1,19 @@
1
+
2
+ == Simple Navigation
3
+
4
+ Simple Navigation is a plugin for creating a navigation (optionally with sub navigation) for your rails app.
5
+
6
+ Source code:
7
+ git://github.com/andi/simple-navigation.git
8
+
9
+ Documentation:
10
+ http://wiki.github.com/andi/simple-navigation
11
+
12
+ Online Demo:
13
+ http://simple-navigation-demo.andischacke.com
14
+
15
+ Discussion Group for Feedback and Questions
16
+ http://groups.google.com/group/simple-navigation
17
+
18
+ Copyright (c) 2009 Andi Schacke, released under the MIT license
19
+
@@ -0,0 +1,65 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run specs.'
6
+ task :default => :spec
7
+
8
+ desc 'Run the specs'
9
+ Spec::Rake::SpecTask.new(:spec) do |t|
10
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
11
+ t.spec_files = FileList['spec/**/*_spec.rb']
12
+ end
13
+
14
+ desc 'Generate documentation for the simple_navigation plugin.'
15
+ Rake::RDocTask.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'SimpleNavigation'
18
+ rdoc.options << '--line-numbers' << '--inline-source'
19
+ rdoc.rdoc_files.include('README')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ begin
24
+ require 'jeweler'
25
+ Jeweler::Tasks.new do |gemspec|
26
+ gemspec.name = "simple-navigation"
27
+ gemspec.summary = "Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app."
28
+ gemspec.email = "andreas.schacke@gmail.com"
29
+ gemspec.homepage = "http://github.com/andi/simple-navigation"
30
+ gemspec.description = "Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app."
31
+ gemspec.authors = ["Andi Schacke"]
32
+ gemspec.rdoc_options = ["--inline-source", "--charset=UTF-8"]
33
+ gemspec.files += ["CHANGELOG"]
34
+ gemspec.rubyforge_project = 'andi'
35
+ end
36
+ rescue LoadError
37
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
38
+ end
39
+
40
+ begin
41
+ require 'rake/contrib/sshpublisher'
42
+ namespace :rubyforge do
43
+
44
+ desc "Release gem and RDoc documentation to RubyForge"
45
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
46
+
47
+ namespace :release do
48
+ desc "Publish RDoc to RubyForge."
49
+ task :docs => [:rdoc] do
50
+ config = YAML.load(
51
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
52
+ )
53
+
54
+ host = "#{config['username']}@rubyforge.org"
55
+ remote_dir = "/var/www/gforge-projects/simple-navigation/"
56
+ local_dir = 'rdoc'
57
+
58
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
59
+ end
60
+ end
61
+ end
62
+ rescue LoadError
63
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
64
+ end
65
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 1
4
+ :major: 1
@@ -0,0 +1 @@
1
+ Creates a template config file for the simple-navigation plugin. You will find the generated file in config/navigation.rb.
@@ -0,0 +1,8 @@
1
+ class NavigationConfigGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.file "config/navigation.rb", "config/navigation.rb"
5
+ m.readme "../../../README"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,28 @@
1
+ # Configures your navigation
2
+ SimpleNavigation::Configuration.run do |navigation|
3
+ # Specify a custom renderer if needed.
4
+ # The default renderer is SimpleNavigation::Renderer::List which renders HTML lists.
5
+ # navigation.renderer = Your::Custom::Renderer
6
+
7
+ # Specify the class that will be applied to active navigation items. Defaults to 'selected'
8
+ # navigation.selected_class = 'your_selected_class'
9
+
10
+ # Define the primary navigation
11
+ navigation.items do |primary|
12
+ # Add an item to the primary navigation. The following params apply:
13
+ # key - a symbol which uniquely defines your navigation item in the scope of the primary_navigation
14
+ # name - will be displayed in the rendered navigation. This can also be a call to your I18n-framework.
15
+ # url - the address that the generated item links to. You can also use url_helpers (named routes, restful routes helper, url_for etc.)
16
+ # html_options - can be used to specify attributes that will be included in the rendered navigation item (e.g. id, class etc.)
17
+ #
18
+ primary.item :key_1, 'name', url, html_options
19
+
20
+ # Add an item which has a sub navigation (same params, but with block)
21
+ primary.item :key_2, 'name', url, html_options do |sub_nav|
22
+ # Add an item to the sub navigation (same params again)
23
+ sub_nav.item :key_2_1, 'name', url, html_options
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,21 @@
1
+ # A plugin for generating a simple navigation. See README for resources on usage instructions.
2
+ module SimpleNavigation
3
+
4
+ mattr_accessor :config_file
5
+
6
+ # Reads the specified config_file and stores it for later evaluation.
7
+ def self.load_config(config_file)
8
+ self.config_file = IO.read(config_file)
9
+ end
10
+
11
+ # Returns the singleton instance of the SimpleNavigation::Configuration
12
+ def self.config
13
+ Configuration.instance
14
+ end
15
+
16
+ # Returns the ItemContainer that contains the items for the primary navigation
17
+ def self.primary_navigation
18
+ config.primary_navigation
19
+ end
20
+
21
+ end
@@ -0,0 +1,41 @@
1
+ require 'singleton'
2
+
3
+ module SimpleNavigation
4
+
5
+ # Responsible for evaluating and handling the config/navigation.rb file.
6
+ class Configuration
7
+ include Singleton
8
+
9
+ attr_accessor :renderer
10
+ attr_accessor :selected_class
11
+ attr_reader :primary_navigation
12
+
13
+ # Evals the config_file inside the specified context (usually a controller or view)
14
+ def self.eval_config(context)
15
+ context.instance_eval(SimpleNavigation.config_file)
16
+ end
17
+
18
+ # Starts processing the configuration
19
+ def self.run(&block)
20
+ block.call Configuration.instance
21
+ end
22
+
23
+ # Sets the config's default-settings
24
+ def initialize
25
+ @renderer = SimpleNavigation::Renderer::List
26
+ @selected_class = 'selected'
27
+ end
28
+
29
+ # Yields an SimpleNavigation::ItemContainer for adding navigation items
30
+ def items(&block)
31
+ @primary_navigation = ItemContainer.new
32
+ block.call @primary_navigation
33
+ end
34
+
35
+ # Returns true if the config_file has already been evaluated.
36
+ def loaded?
37
+ !@primary_navigation.nil?
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,74 @@
1
+ #TODO: add :except and :only options to navigation method
2
+ module SimpleNavigation
3
+
4
+ # Adds methods for handling the current 'active' navigation to the controllers.
5
+ #
6
+ # On the controller class level, use the navigation method to set the active navigation for all actions in the controller.
7
+ #
8
+ # ==== Examples
9
+ # class AccountController << ActionController
10
+ # navigation :account
11
+ # ...
12
+ # end
13
+ #
14
+ # class AccountSettingsController << ActionController
15
+ # navigation :account, :settings
16
+ # ...
17
+ # end
18
+ #
19
+ # The first example sets the current_primary_navigation to :account for all actions. No active sub_navigation.
20
+ # The second example sets the current_primary_navigation to :account and the current_sub_navigation to :settings.
21
+ #
22
+ # On the controller instance level, use the current_navigation method to define the active navigation for a specific action.
23
+ # The navigation item that is set in current_navigation overrides the one defined on the controller class level (see navigation method).
24
+ #
25
+ # ==== Example
26
+ # class AccountController << ActionController
27
+ # navigation :account
28
+ #
29
+ # def your_special_action
30
+ # ...
31
+ # current_navigation :special
32
+ # end
33
+ # end
34
+ #
35
+ # This overrides :account as active navigation for your_special_action and sets it to :special.
36
+ #
37
+ # Note: The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
38
+ module ControllerMethods
39
+ def self.included(base) #:nodoc:
40
+ base.class_eval do
41
+ extend ClassMethods
42
+ include InstanceMethods
43
+ helper SimpleNavigation::Helpers
44
+ end
45
+ end
46
+
47
+ module ClassMethods
48
+ # Sets the active navigation for all actions in this controller.
49
+ #
50
+ # The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
51
+ def navigation(primary_navigation, sub_navigation=nil)
52
+ self.class_eval do
53
+ define_method :set_navigation do
54
+ current_navigation(primary_navigation, sub_navigation)
55
+ end
56
+ before_filter :set_navigation
57
+ end
58
+ end
59
+ end
60
+
61
+ module InstanceMethods
62
+
63
+ # Sets the active navigation. Call this method in any action to override the controller-wide active navigation
64
+ # specified by navigation.
65
+ #
66
+ # The specified symbols must match the keys for your navigation items in your config/navigation.rb file.
67
+ def current_navigation(primary_navigation, sub_navigation=nil)
68
+ @current_primary_navigation = primary_navigation
69
+ @current_secondary_navigation = sub_navigation
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,51 @@
1
+ module SimpleNavigation
2
+
3
+ # View helpers to render the navigation.
4
+ #
5
+ # Use render_primary_navigation to render your primary navigation with the configured renderer.
6
+ # Use render_sub_navigation to render the sub navigation belonging to the active primary navigation.
7
+ # Use render_navigation to render the primary navigation with the corresponding sub navigation rendered inside primary navigation item which is active.
8
+ #
9
+ # ==== Examples (using Haml)
10
+ # #primary_navigation= render_primary_navigation
11
+ #
12
+ # #sub_navigation= render_sub_navigation
13
+ #
14
+ # #main_navigation= render_navigation
15
+ #
16
+ module Helpers
17
+
18
+ # Renders the navigation according to the specified <tt>level</tt>.
19
+ #
20
+ # The <tt>level</tt> defaults to :nested which renders the the sub_navigation for an active primary_navigation inside that active primary_navigation item.
21
+ #
22
+ # Other possible levels are
23
+ #
24
+ # :primary which only renders the primary_navigation (also see render_primary_navigation) and :secondary which only renders the sub_navigation (see render_sub_navigation).
25
+ def render_navigation(level = :nested)
26
+ SimpleNavigation::Configuration.eval_config(self) unless SimpleNavigation.config.loaded?
27
+ case level
28
+ when :primary:
29
+ SimpleNavigation.primary_navigation.render(@current_primary_navigation)
30
+ when :secondary:
31
+ primary = SimpleNavigation.primary_navigation[@current_primary_navigation]
32
+ primary.sub_navigation.render(@current_secondary_navigation) if primary && primary.sub_navigation
33
+ when :nested:
34
+ SimpleNavigation.primary_navigation.render(@current_primary_navigation, true, @current_secondary_navigation)
35
+ else
36
+ raise ArgumentError, "Invalid navigation level: #{level}"
37
+ end
38
+ end
39
+
40
+ # Renders the primary_navigation with the configured renderer. Calling render_navigation(:primary) has the same effect.
41
+ def render_primary_navigation
42
+ render_navigation(:primary)
43
+ end
44
+
45
+ # Renders the sub_navigation with the configured renderer. Calling render_navigation(:secondary) has the same effect.
46
+ def render_sub_navigation
47
+ render_navigation(:secondary)
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,40 @@
1
+ module SimpleNavigation
2
+
3
+ # Represents an item in your navigation. Gets generated by the item method in the config-file.
4
+ class Item
5
+ attr_reader :key, :name, :url, :sub_navigation
6
+
7
+ # see ItemContainer#item
8
+ def initialize(key, name, url, html_options, sub_nav_block)
9
+ @key = key
10
+ @name = name
11
+ @url = url
12
+ @html_options = html_options
13
+ if sub_nav_block
14
+ @sub_navigation = ItemContainer.new
15
+ sub_nav_block.call @sub_navigation
16
+ end
17
+ end
18
+
19
+ # Returns true if this navigation item should be rendered as 'selected' for the specified current_navigation.
20
+ def selected?(current_navigation)
21
+ key == current_navigation
22
+ end
23
+
24
+ # Returns the html-options hash for the item, i.e. the options specified for this item in the config-file.
25
+ # It also adds the 'selected' class to the list of classes if necessary.
26
+ def html_options(current_navigation)
27
+ default_options = {:id => key.to_s}
28
+ options = default_options.merge(@html_options)
29
+ options[:class] = [@html_options[:class], self.selected_class(current_navigation)].flatten.compact.join(' ')
30
+ options.delete(:class) if options[:class].blank?
31
+ options
32
+ end
33
+
34
+ def selected_class(current_navigation) #:nodoc:
35
+ selected?(current_navigation) ? SimpleNavigation.config.selected_class : nil
36
+ end
37
+
38
+
39
+ end
40
+ end
@@ -0,0 +1,43 @@
1
+ module SimpleNavigation
2
+
3
+ # Holds the Items for a navigation 'level' (either the primary_navigation or a sub_navigation).
4
+ class ItemContainer
5
+
6
+ attr_reader :items
7
+ attr_accessor :renderer, :dom_id
8
+
9
+ def initialize #:nodoc:
10
+ @items = []
11
+ @renderer = Configuration.instance.renderer
12
+ end
13
+
14
+ # Creates a new navigation item.
15
+ #
16
+ # The <tt>key</tt> is a symbol which uniquely defines your navigation item in the scope of the primary_navigation or the sub_navigation.
17
+ #
18
+ # The <tt>name</tt> will be displayed in the rendered navigation. This can also be a call to your I18n-framework.
19
+ #
20
+ # The <tt>url</tt> is the address that the generated item points to. You can also use url_helpers (named routes, restful routes helper, url_for etc.)
21
+ #
22
+ # The <tt>html_options</tt> can be used to specify attributes that will be included in the rendered navigation item (e.g. id, class etc.)
23
+ #
24
+ # The <tt>block</tt> - if specified - will hold the item's sub_navigation.
25
+ def item(key, name, url, html_options={}, &block)
26
+ @items << Item.new(key, name, url, html_options, block)
27
+ end
28
+
29
+ # Returns the Item with the specified key, nil otherwise.
30
+ def [](navi_key)
31
+ items.find {|i| i.key == navi_key}
32
+ end
33
+
34
+ # Renders the items in this ItemContainer using the configured renderer.
35
+ #
36
+ # Set <tt>include_sub_navigation</tt> to true if you want to nest the sub_navigation into the active primary_navigation
37
+ def render(current_navigation, include_sub_navigation=false, current_sub_navigation=nil)
38
+ self.renderer.new(current_navigation, current_sub_navigation).render(self, include_sub_navigation)
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,30 @@
1
+ module SimpleNavigation
2
+ module Renderer
3
+
4
+ # This is the base class for all renderers.
5
+ #
6
+ # A renderer is responsible for rendering an ItemContainer (primary or a sub_navigation) and its containing items to HTML.
7
+ # It must be initialized with the current_navigation for the rendered ItemContainer and
8
+ # optionally with the current_sub_navigation (if the sub_navigation will be nested).
9
+ class Base
10
+ include ActionView::Helpers::UrlHelper
11
+ include ActionView::Helpers::TagHelper
12
+
13
+ attr_reader :current_navigation, :current_sub_navigation
14
+
15
+ def initialize(current_navigation, current_sub_navigation=nil) #:nodoc:
16
+ @current_navigation = current_navigation
17
+ @current_sub_navigation = current_sub_navigation
18
+ end
19
+
20
+ # Renders the specified ItemContainer to HTML.
21
+ #
22
+ # If <tt>include_sub_navigation</tt> is set to true, the renderer should nest the sub_navigation for the active navigation
23
+ # inside that navigation item.
24
+ def render(item_container, include_sub_navigation=false)
25
+ raise 'subclass responsibility'
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ module SimpleNavigation
2
+ module Renderer
3
+
4
+ # Renders an ItemContainer as a <ul> element and its containing items as <li> elements.
5
+ # It adds the 'selected' class to li element AND the link inside the li element that is currently active.
6
+ # If the sub navigation should be included, it renders another <ul> containing the sub navigation inside the active <li> element.
7
+ #
8
+ # By default, the renderer sets the item's key as dom_id for the rendered <li> element. The id can be explicitely specified by setting
9
+ # the id in the html-options of the 'item' method in the config/navigation.rb file.
10
+ class List < Renderer::Base
11
+
12
+ def render(item_container, include_sub_navigation=false)
13
+ list_content = item_container.items.inject([]) do |list, item|
14
+ html_options = item.html_options(current_navigation)
15
+ li_content = link_to(item.name, item.url, :class => item.selected_class(current_navigation))
16
+ li_content << (item.sub_navigation.render(current_sub_navigation)) if include_sub_navigation && item.sub_navigation && item.selected?(current_navigation)
17
+ list << content_tag(:li, li_content, html_options)
18
+ end
19
+ content_tag(:ul, list_content, {:id => item_container.dom_id})
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ config_file_path = File.join(RAILS_ROOT, 'config', 'navigation.rb')
2
+ SimpleNavigation.load_config(config_file_path) if File.exists?(config_file_path)
3
+ ActionController::Base.send(:include, SimpleNavigation::ControllerMethods)
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation do
4
+
5
+ describe 'load_config' do
6
+
7
+ before(:each) do
8
+ @config_file = '"my_navigation_config"'
9
+ IO.stub!(:read).and_return(@config_file)
10
+ end
11
+
12
+ it "should load the navigation-configfile into a string" do
13
+ IO.should_receive(:read).with('./config/navigation.rb')
14
+ SimpleNavigation.load_config('./config/navigation.rb')
15
+ end
16
+ it "should store that string in a module-var" do
17
+ SimpleNavigation.load_config('./config/navigation.rb')
18
+ SimpleNavigation.config_file.should == @config_file
19
+ end
20
+ end
21
+
22
+ describe 'config' do
23
+ it {SimpleNavigation.config.should == SimpleNavigation::Configuration.instance}
24
+ end
25
+
26
+ end
27
+
28
+ describe SimpleNavigation::Configuration do
29
+
30
+ before(:each) do
31
+ @config = SimpleNavigation::Configuration.instance
32
+ end
33
+
34
+ describe 'self.run' do
35
+ it "should yield the singleton Configuration object" do
36
+ SimpleNavigation::Configuration.run do |c|
37
+ c.should == @config
38
+ end
39
+ end
40
+ end
41
+
42
+ describe 'self.eval_config' do
43
+ before(:each) do
44
+ @context = mock(:context)
45
+ @config_file = stub(:config_file)
46
+ SimpleNavigation.stub!(:config_file).and_return(@config_file)
47
+ end
48
+ it "should instance_eval the config_file-string inside the context" do
49
+ @context.should_receive(:instance_eval).with(@config_file)
50
+ SimpleNavigation::Configuration.eval_config(@context)
51
+ end
52
+ end
53
+
54
+ describe 'initialize' do
55
+ it "should set the List-Renderer as default upon initialize" do
56
+ @config.renderer.should == SimpleNavigation::Renderer::List
57
+ end
58
+ it "should set the selected_class to 'selected' as default" do
59
+ @config.selected_class.should == 'selected'
60
+ end
61
+ end
62
+ describe 'items' do
63
+ before(:each) do
64
+ @container = stub(:items_container)
65
+ SimpleNavigation::ItemContainer.stub!(:new).and_return(@container)
66
+ end
67
+ it "should should yield an new ItemContainer" do
68
+ @config.items do |container|
69
+ container.should == @container
70
+ end
71
+ end
72
+ it "should assign the ItemContainer to an instance-var" do
73
+ @config.items {}
74
+ @config.primary_navigation.should == @container
75
+ end
76
+ end
77
+
78
+
79
+ end
80
+
81
+
@@ -0,0 +1,75 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ ActionController::Base.send(:include, SimpleNavigation::ControllerMethods)
4
+
5
+ describe SimpleNavigation::ControllerMethods do
6
+
7
+ def stub_loading_config
8
+ SimpleNavigation::Configuration.stub!(:load)
9
+ end
10
+
11
+ before(:each) do
12
+ stub_loading_config
13
+ class ApplicationController < ActionController::Base
14
+ end
15
+ @controller = ApplicationController.new
16
+ end
17
+
18
+ describe 'when being included' do
19
+ it "should extend the ClassMethods" do
20
+ @controller.class.should respond_to(:navigation)
21
+ end
22
+ it "should include the InstanceMethods" do
23
+ @controller.should respond_to(:current_navigation)
24
+ end
25
+ it "should install the Helpers Module" do
26
+ @controller.master_helper_module.included_modules.should include(SimpleNavigation::Helpers)
27
+ end
28
+ end
29
+
30
+ describe 'class_methods' do
31
+
32
+ describe 'navigation' do
33
+
34
+ def call_navigation(key1, key2=nil)
35
+ @controller.class_eval do
36
+ navigation key1, key2
37
+ end
38
+ end
39
+
40
+ it "should not have an instance-method 'set_navigation if navigation-method has not been called" do
41
+ @controller.respond_to?(:set_navigation).should be_false
42
+ end
43
+ it 'should create an instance-method "set_navigation" when being called' do
44
+ call_navigation(:key)
45
+ @controller.respond_to?(:set_navigation).should be_true
46
+ end
47
+ it 'the created method should call current_navigation with the specified keys' do
48
+ call_navigation(:primary, :secondary)
49
+ @controller.should_receive(:current_navigation).with(:primary, :secondary)
50
+ @controller.set_navigation
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ describe 'instance_methods' do
57
+
58
+ describe 'current_navigation' do
59
+ it "should set the current_primary_navigation as specified" do
60
+ @controller.current_navigation(:first)
61
+ @controller.instance_variable_get(:@current_primary_navigation).should == :first
62
+ end
63
+ it "should set the current_secondary_navigation as specified" do
64
+ @controller.current_navigation(:first, :second)
65
+ @controller.instance_variable_get(:@current_secondary_navigation).should == :second
66
+ end
67
+ it "should set the current_secondary_navigation to nil if no secondary is specified" do
68
+ @controller.current_navigation(:first)
69
+ @controller.instance_variable_get(:@current_secondary_navigation).should be_nil
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation::Helpers do
4
+ class ControllerMock
5
+ include SimpleNavigation::Helpers
6
+ end
7
+
8
+ before(:each) do
9
+ @controller = ControllerMock.new
10
+ SimpleNavigation.config.stub!(:loaded?).and_return(true)
11
+ @primary_navigation = stub(:primary_navigation)
12
+ SimpleNavigation.stub!(:primary_navigation).and_return(@primary_navigation)
13
+ end
14
+
15
+ describe 'render_navigation' do
16
+ context 'primary' do
17
+ before(:each) do
18
+ @controller.instance_variable_set(:@current_primary_navigation, :current_primary)
19
+ end
20
+ it "should call render on the primary_navigation" do
21
+ @primary_navigation.should_receive(:render).with(:current_primary)
22
+ @controller.render_navigation(:primary)
23
+ end
24
+ end
25
+
26
+ context 'secondary' do
27
+ context 'with current_primary_navigation set' do
28
+ before(:each) do
29
+ @sub_navigation = stub(:sub_navigation, :null_object => true)
30
+ @primary_navigation.stub!(:[]).and_return(@sub_navigation)
31
+ @controller.instance_variable_set(:@current_primary_navigation, :current_primary)
32
+ @controller.instance_variable_set(:@current_secondary_navigation, :current_secondary)
33
+ end
34
+ it "should find the sub_navigation belonging to the current primary_navigation" do
35
+ @primary_navigation.should_receive(:[]).with(:current_primary)
36
+ @controller.render_navigation(:secondary)
37
+ end
38
+ it "should call render on the current primary_navigation's sub_navigation" do
39
+ @sub_navigation.should_receive(:render).with(:current_secondary)
40
+ @controller.render_navigation(:secondary)
41
+ end
42
+ end
43
+ context 'without current_primary_navigation set' do
44
+ before(:each) do
45
+ @primary_navigation.stub!(:[]).and_return(nil)
46
+ @controller.instance_variable_set(:@current_primary_navigation, nil)
47
+ end
48
+ it "should not raise an error" do
49
+ lambda{@controller.render_navigation(:secondary)}.should_not raise_error
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ context 'nested' do
56
+ before(:each) do
57
+ @controller.instance_variable_set(:@current_primary_navigation, :current_primary)
58
+ @controller.instance_variable_set(:@current_secondary_navigation, :current_secondary)
59
+ end
60
+ it "should call render on the primary navigation" do
61
+ @primary_navigation.should_receive(:render).with(anything, anything, anything)
62
+ @controller.render_navigation(:nested)
63
+ end
64
+ it "should call render with the current_primary_navigation" do
65
+ @primary_navigation.should_receive(:render).with(:current_primary, anything, anything)
66
+ @controller.render_navigation(:nested)
67
+ end
68
+ it "should call render with the include_subnavigation option set" do
69
+ @primary_navigation.should_receive(:render).with(anything, true, anything)
70
+ @controller.render_navigation(:nested)
71
+ end
72
+ it "should call render with the current_sub_navigation" do
73
+ @primary_navigation.should_receive(:render).with(anything, anything, :current_secondary)
74
+ @controller.render_navigation(:nested)
75
+ end
76
+ end
77
+
78
+ context 'unknown level' do
79
+ it {lambda {@controller.render_navigation(:unknown)}.should raise_error(ArgumentError)}
80
+ end
81
+ end
82
+
83
+ describe 'render_primary_navigation' do
84
+ it "should delegate to render_navigation(:primary)" do
85
+ @controller.should_receive(:render_navigation).with(:primary)
86
+ @controller.render_primary_navigation
87
+ end
88
+ end
89
+
90
+ describe 'render_sub_navigation' do
91
+ it "should delegate to render_navigation(:secondary)" do
92
+ @controller.should_receive(:render_navigation).with(:secondary)
93
+ @controller.render_sub_navigation
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1,94 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation::ItemContainer do
4
+ before(:each) do
5
+ @item_container = SimpleNavigation::ItemContainer.new
6
+ end
7
+ describe 'initialize' do
8
+ it "should set the renderer to the globally-configured renderer per default" do
9
+ SimpleNavigation::Configuration.instance.should_receive(:renderer)
10
+ @item_container = SimpleNavigation::ItemContainer.new
11
+ end
12
+ it "should have an empty items-array" do
13
+ @item_container = SimpleNavigation::ItemContainer.new
14
+ @item_container.items.should be_empty
15
+ end
16
+ end
17
+
18
+ describe 'item' do
19
+
20
+ context 'block given' do
21
+ before(:each) do
22
+ @sub_container = stub(:sub_container)
23
+ SimpleNavigation::ItemContainer.stub!(:new).and_return(@sub_container)
24
+ end
25
+
26
+ it "should should yield an new ItemContainer" do
27
+ @item_container.item('key', 'name', 'url', 'options') do |container|
28
+ container.should == @sub_container
29
+ end
30
+ end
31
+ it "should create a new Navigation-Item with the given params and the specified block" do
32
+ SimpleNavigation::Item.should_receive(:new).with('key', 'name', 'url', 'options', @proc)
33
+ @item_container.item('key', 'name', 'url', 'options', &@proc)
34
+ end
35
+ it "should add the created item to the list of items" do
36
+ @item_container.items.should_receive(:<<)
37
+ @item_container.item('key', 'name', 'url', 'options') {}
38
+ end
39
+ end
40
+
41
+ context 'no block given' do
42
+ it "should create a new Navigation_item with the given params and nil as sub_navi" do
43
+ SimpleNavigation::Item.should_receive(:new).with('key', 'name', 'url', 'options', nil)
44
+ @item_container.item('key', 'name', 'url', 'options')
45
+ end
46
+ it "should add the created item to the list of items" do
47
+ @item_container.items.should_receive(:<<)
48
+ @item_container.item('key', 'name', 'url', 'options')
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ describe '[]' do
55
+
56
+ before(:each) do
57
+ @item_container.item(:first, 'first', 'bla')
58
+ @item_container.item(:second, 'second', 'bla')
59
+ @item_container.item(:third, 'third', 'bla')
60
+ end
61
+
62
+ it "should return the item with the specified navi_key" do
63
+ @item_container[:second].name.should == 'second'
64
+ end
65
+ it "should return nil if no item exists for the specified navi_key" do
66
+ @item_container[:invalid].should be_nil
67
+ end
68
+ end
69
+
70
+ describe 'render' do
71
+ before(:each) do
72
+ @renderer = stub(:renderer)
73
+ @renderer_instance = stub(:renderer_instance, :null_object => true)
74
+ @renderer.stub!(:new).and_return(@renderer_instance)
75
+ @item_container.stub!(:renderer).and_return(@renderer)
76
+ @items = stub(:items)
77
+ @item_container.stub!(:items).and_return(@items)
78
+ end
79
+ it "should instatiate a renderer with the current_primary and current_secondary" do
80
+ @renderer.should_receive(:new).with(:current_navigation, nil)
81
+ @item_container.render(:current_navigation)
82
+ end
83
+ it "should call render on the renderer and pass self" do
84
+ @renderer_instance.should_receive(:render).with(@item_container, anything)
85
+ @item_container.render(:current_navigation)
86
+ end
87
+ it "should call render on the renderer and pass the include_sub_navigation option" do
88
+ @renderer_instance.should_receive(:render).with(anything, true)
89
+ @item_container.render(:current_navigation, true, :current_sub_navigation)
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,101 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SimpleNavigation::Item do
4
+
5
+ describe 'initialize' do
6
+
7
+ end
8
+
9
+ describe 'selected?' do
10
+ before(:each) do
11
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', {}, nil)
12
+ end
13
+ it {@item.selected?(:my_key).should be_true}
14
+ it {@item.selected?(:my_other_key).should be_false}
15
+ end
16
+
17
+ describe 'selected_class' do
18
+ before(:each) do
19
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', {}, nil)
20
+ end
21
+
22
+ context 'item is selected' do
23
+ before(:each) do
24
+ @item.stub!(:selected?).and_return(true)
25
+ end
26
+ it {@item.instance_eval {selected_class(:bla).should == 'selected'}}
27
+ end
28
+
29
+ context 'item is not selected' do
30
+ before(:each) do
31
+ @item.stub!(:selected?).and_return(false)
32
+ end
33
+ it {@item.instance_eval {selected_class(:bla).should == nil}}
34
+ end
35
+ end
36
+
37
+ describe 'html_options' do
38
+ describe 'class' do
39
+ context 'with classes defined in options' do
40
+ before(:each) do
41
+ @options = {:class => 'my_class'}
42
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
43
+ end
44
+ context 'with item selected' do
45
+ before(:each) do
46
+ @item.stub!(:selected?).and_return(true)
47
+ end
48
+ it {@item.html_options(:bla)[:class].should == 'my_class selected'}
49
+ end
50
+
51
+ context 'with item not selected' do
52
+ before(:each) do
53
+ @item.stub!(:selected?).and_return(false)
54
+ end
55
+ it {@item.html_options(:bla)[:class].should == 'my_class'}
56
+ end
57
+ end
58
+
59
+ context 'without classes in options' do
60
+ before(:each) do
61
+ @options = {}
62
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
63
+ end
64
+ context 'with item selected' do
65
+ before(:each) do
66
+ @item.stub!(:selected?).and_return(true)
67
+ end
68
+ it {@item.html_options(:bla)[:class].should == 'selected'}
69
+ end
70
+
71
+ context 'with item not selected' do
72
+ before(:each) do
73
+ @item.stub!(:selected?).and_return(false)
74
+ end
75
+ it {@item.html_options(:bla)[:class].should be_blank}
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'id' do
81
+ context 'with id defined in options' do
82
+ before(:each) do
83
+ @options = {:id => 'my_id'}
84
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
85
+ end
86
+ it {@item.html_options(:bla)[:id].should == 'my_id'}
87
+ end
88
+
89
+ context 'with no id definied in options (using default id)' do
90
+ before(:each) do
91
+ @options = {}
92
+ @item = SimpleNavigation::Item.new(:my_key, 'name', 'url', @options, nil)
93
+ end
94
+ it {@item.html_options(:bla)[:id].should == 'my_key'}
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+
101
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe SimpleNavigation::Renderer::Base do
4
+ before(:each) do
5
+ @base_renderer = SimpleNavigation::Renderer::Base.new(:current_primary, :current_secondary)
6
+ end
7
+ it "should inclue ActionView::Helpers::UrlHelper" do
8
+ @base_renderer.should respond_to(:link_to)
9
+ end
10
+ it "should include ActionView::Helpers::TagHelper" do
11
+ @base_renderer.should respond_to(:content_tag)
12
+ end
13
+ it {@base_renderer.current_navigation.should == :current_primary}
14
+ it {@base_renderer.current_sub_navigation.should == :current_secondary}
15
+ end
@@ -0,0 +1,94 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'html/document' unless defined? HTML::Document
3
+
4
+ describe SimpleNavigation::Renderer::List do
5
+
6
+ describe 'render' do
7
+
8
+ def sub_items
9
+ [
10
+ SimpleNavigation::Item.new(:subnav1, 'subnav1', 'subnav1_url', {}, nil),
11
+ SimpleNavigation::Item.new(:subnav2, 'subnav2', 'subnav2_url', {}, nil)
12
+ ]
13
+ end
14
+
15
+ def primary_items
16
+ @item1 = SimpleNavigation::Item.new(:users, 'users', 'first_url', {:id => 'my_id'}, nil)
17
+ @item2 = SimpleNavigation::Item.new(:invoices, 'invoices', 'second_url', {}, nil)
18
+ @item3 = SimpleNavigation::Item.new(:accounts, 'accounts', 'third_url', {:style => 'float:right'}, nil)
19
+ @item2.instance_variable_set(:@sub_navigation, item_container(sub_items))
20
+ [@item1, @item2, @item3]
21
+ end
22
+
23
+ def item_container(items)
24
+ container = SimpleNavigation::ItemContainer.new
25
+ container.dom_id = 'nav_dom_id'
26
+ container.instance_variable_set(:@items, items)
27
+ container
28
+ end
29
+
30
+ def primary_navigation
31
+ @item_container = item_container(primary_items)
32
+ @item_container
33
+ end
34
+
35
+ def render(current_navigation=nil, include_subnav=false)
36
+ @renderer = SimpleNavigation::Renderer::List.new(current_navigation)
37
+ HTML::Document.new(@renderer.render(primary_navigation, include_subnav)).root
38
+ end
39
+
40
+ it "should render a ul-tag around the items" do
41
+ HTML::Selector.new('ul').select(render).should have(1).entries
42
+ end
43
+ it "the rendered ul-tag should have the specified dom_id" do
44
+ HTML::Selector.new('ul#nav_dom_id').select(render).should have(1).entries
45
+ end
46
+ it "should render a li tag for each item" do
47
+ HTML::Selector.new('li').select(render).should have(3).entries
48
+ end
49
+ it "should render an a-tag inside each li-tag" do
50
+ HTML::Selector.new('li a').select(render).should have(3).entries
51
+ end
52
+ it "should pass the specified html_options to the li element" do
53
+ HTML::Selector.new('li[style=float:right]').select(render).should have(1).entries
54
+ end
55
+ it "should give the li the id specified in the html_options" do
56
+ HTML::Selector.new('li#my_id').select(render).should have(1).entries
57
+ end
58
+ it "should give the li the default id (stringified key) if no id is specified in the html_options" do
59
+ HTML::Selector.new('ul li#invoices').select(render).should have(1).entries
60
+ end
61
+ it "should not apply the the default id where there is an id specified in the html_options" do
62
+ HTML::Selector.new('ul li#users').select(render).should be_empty
63
+ end
64
+
65
+ context 'with current_navigation set' do
66
+ it "should mark the matching li-item as selected (with the css_class specified in configuration)" do
67
+ HTML::Selector.new('li.selected').select(render(:invoices)).should have(1).entries
68
+ end
69
+ it "should also mark the links inside the selected li's as selected" do
70
+ HTML::Selector.new('li.selected a.selected').select(render(:invoices)).should have(1).entries
71
+ end
72
+
73
+ end
74
+
75
+ context 'without current_navigation set' do
76
+ it "should not mark any of the items as selected" do
77
+ HTML::Selector.new('li.selected').select(render).should be_empty
78
+ end
79
+ it "should not mark any links as selected" do
80
+ HTML::Selector.new('a.selected').select(render).should be_empty
81
+ end
82
+ end
83
+
84
+ context 'nested sub_navigation' do
85
+ it "should nest the current_primary's subnavigation inside the selected li-element" do
86
+ HTML::Selector.new('li.selected ul li').select(render(:invoices, true)).should have(2).entries
87
+ end
88
+ it "should be possible to identify sub items using an html selector (using ids)" do
89
+ HTML::Selector.new('#invoices #subnav1').select(render(:invoices, true)).should have(1).entries
90
+ end
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,24 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require 'rubygems'
3
+ require 'spec'
4
+ require 'active_support'
5
+ require 'action_controller'
6
+
7
+ RAILS_ROOT = './' unless defined? RAILS_ROOT
8
+
9
+ $:.unshift File.dirname(__FILE__)
10
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
11
+
12
+ require 'simple_navigation/configuration'
13
+ require 'simple_navigation/helpers'
14
+ require 'simple_navigation/controller_methods'
15
+ require 'simple_navigation/item'
16
+ require 'simple_navigation/item_container'
17
+ require 'simple_navigation/renderer/base'
18
+ require 'simple_navigation/renderer/list'
19
+
20
+ require 'simple_navigation'
21
+
22
+ # Spec::Runner.configure do |config|
23
+ # no special config
24
+ # endx
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-navigation
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Andi Schacke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-14 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app.
17
+ email: andreas.schacke@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - CHANGELOG
26
+ - Rakefile
27
+ - VERSION.yml
28
+ - generators/navigation_config/USAGE
29
+ - generators/navigation_config/navigation_config_generator.rb
30
+ - generators/navigation_config/templates/config/navigation.rb
31
+ - lib/simple_navigation.rb
32
+ - lib/simple_navigation/configuration.rb
33
+ - lib/simple_navigation/controller_methods.rb
34
+ - lib/simple_navigation/helpers.rb
35
+ - lib/simple_navigation/item.rb
36
+ - lib/simple_navigation/item_container.rb
37
+ - lib/simple_navigation/renderer/base.rb
38
+ - lib/simple_navigation/renderer/list.rb
39
+ - rails/init.rb
40
+ - spec/lib/configuration_spec.rb
41
+ - spec/lib/controller_methods_spec.rb
42
+ - spec/lib/helpers_spec.rb
43
+ - spec/lib/item_container_spec.rb
44
+ - spec/lib/item_spec.rb
45
+ - spec/lib/renderer/base_spec.rb
46
+ - spec/lib/renderer/list_spec.rb
47
+ - spec/spec_helper.rb
48
+ - README
49
+ has_rdoc: true
50
+ homepage: http://github.com/andi/simple-navigation
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --inline-source
54
+ - --charset=UTF-8
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project: andi
72
+ rubygems_version: 1.3.1
73
+ signing_key:
74
+ specification_version: 2
75
+ summary: Simple Navigation is a ruby library for creating a navigation (optionally with sub navigation) for your rails app.
76
+ test_files:
77
+ - spec/lib/configuration_spec.rb
78
+ - spec/lib/controller_methods_spec.rb
79
+ - spec/lib/helpers_spec.rb
80
+ - spec/lib/item_container_spec.rb
81
+ - spec/lib/item_spec.rb
82
+ - spec/lib/renderer/base_spec.rb
83
+ - spec/lib/renderer/list_spec.rb
84
+ - spec/spec_helper.rb