mmmenu 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem "bundler", "~> 1.0.0"
5
+ gem "rspec", "~> 2.8.0"
6
+ gem "jeweler", "~> 1.6.4"
7
+ #gem "rcov", ">= 0"
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,26 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ git (1.2.5)
6
+ jeweler (1.6.4)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.9.2.2)
11
+ rspec (2.8.0)
12
+ rspec-core (~> 2.8.0)
13
+ rspec-expectations (~> 2.8.0)
14
+ rspec-mocks (~> 2.8.0)
15
+ rspec-core (2.8.0)
16
+ rspec-expectations (2.8.0)
17
+ diff-lcs (~> 1.1.2)
18
+ rspec-mocks (2.8.0)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ bundler (~> 1.0.0)
25
+ jeweler (~> 1.6.4)
26
+ rspec (~> 2.8.0)
data/README.markdown ADDED
@@ -0,0 +1,140 @@
1
+ Mmmenu
2
+ ======
3
+
4
+ *Flexible menu generator for rails*
5
+
6
+ Why another menu plugin?
7
+ ------------------------
8
+ All menu plugins I've seen have HTML markup hardcoded into them.
9
+ *Mmmenu* offers you a chance to define your own markup, along with
10
+ a nice DSL to describe multi-level menu structures.
11
+
12
+ INSTALLATION
13
+ ------------
14
+
15
+ 1. gem install mmmenu
16
+ 2. rails generate mmmenu (optional)
17
+
18
+ Basic Usage
19
+ ---------------
20
+
21
+ Imagine you put this into your controller:
22
+
23
+ mmmenu do |l1|
24
+
25
+ l1.add "Articles", "/articles" do |l2|
26
+ l2.add "Create article", new_article_path
27
+ l2.add "Articles authors", "/articles/authors", :match_subpaths => true
28
+ end
29
+ l1.add "Item2", "/path2"
30
+ l1.add "Item3", "/path3"
31
+ l1.add "Item4", "/path4"
32
+
33
+ end
34
+
35
+ As you can see, we specify the paths, so our menu does not depend on the routes.
36
+ `#mmmenu` method automatically puts your menu into @menu instance variable. If you wish to use another variable,
37
+ you may use a more explicit syntax:
38
+
39
+ @my_menu = Mmmenu.new(:request => request) do |l1| { ... }
40
+
41
+ Now let's see what happens in the views:
42
+
43
+ <%= build_mmmenu(@menu) %>
44
+
45
+ And that's it, you get your menu rendered.
46
+
47
+ Customizing Views
48
+ ------------------------
49
+ Now, like I promised, the html-markup is totally
50
+ configurable.
51
+
52
+ Run `rails generate mmmenu`, you'll get your app/helpers/mmmenu_helper.rb file and a bunch of templates copied out of the plugin views/mmmenu directory into app/views/mmmenu directory, thus replacing the plugin default files. Here's what those template files are and what they mean:
53
+
54
+ `_current_item.erb` is responsible for the current item in the menu
55
+ `_item.erb` is responsible for the non-current items
56
+ `level_1.erb` is a wrapper for menu level 1
57
+ `level_2.erb` is a wrapper for menu level 2 (submenu)
58
+
59
+ If you wish to customize deeper levels of menus and items in them, you should take a look at the generated `mmmenu_helper.rb` file
60
+
61
+ Customizing the Helper
62
+ ----------------------------
63
+
64
+ Let's take a look at what's inside this helper:
65
+
66
+ def build_mmmenu(menu)
67
+ menu.item_markup(1) do |link, text, options|
68
+ render(:partial => "mmmenu/item", :locals => { :link => link, :text => text, :options => options })
69
+ end
70
+ menu.current_item_markup(1) do |link, text, options|
71
+ render(:partial => "mmmenu/current_item", :locals => { :link => link, :text => text, :options => options })
72
+ end
73
+ menu.level_markup(1) { |m| render(:partial => "mmmenu/level_1", :locals => { :menu => m }) }
74
+ menu.level_markup(2) { |m| render(:partial => "mmmenu/level_2", :locals => { :menu => m }) }
75
+ menu.build.html_safe
76
+ end
77
+
78
+ You can see now, that `#item_markup` method defines the html markup for menu item,
79
+ and `#level_markup` does the same for menu level wrapper. The first argument is the menu level.
80
+ You may define as much levels as you want, but you don't need to define markup for each level: the deepest level of the markup
81
+ defined will be used for all of the deeper levels.
82
+
83
+ By default, build_mmmenu helper defines two partial templates for level 1 of the menu.
84
+ It does so by calling two methods on a Mmmenu object:
85
+ #current_item_markup defines markup for the current menu item
86
+ #item_markup defines markup for all other menu items
87
+ Both methods accept an optional second argument - a hash of html_options:
88
+
89
+ menu.item_markup(1, :class => "mmmenu")
90
+
91
+ which is later used in the templates like this:
92
+
93
+ <li><%= link_to text, link, options %></li>
94
+
95
+ Note, that this is an example from a default template and options hash may not be present in the customized template.
96
+
97
+ Disclaimer: if you call Mmmenu#item_markup for a certain level, you MUST call Mmmenu#current_item_markup
98
+ for the same level.
99
+
100
+ Most of the time, you will want to customize your views, not the helper, so you may as well delete it from your application/helpers dir.
101
+
102
+
103
+ Finally, let's take a closer look at some of the options and what they mean.
104
+ ---------------------------------------------------------------------
105
+ ##### Current item
106
+ Mmmenu automatically marks each current menu_item with the markup, that you provide in `#current_item_markup` method's block. The item is considered current not only if the paths
107
+ match, but also if one of the children of the item is marked as current. You may as well set the current item manually like that:
108
+
109
+ @menu.current_item = '/articles'
110
+
111
+ In this case `'/articles'` would match against the second argument that you pass to the `#add` method, which is the path the menu itme points to.
112
+ Note that unless the item with such path is not present in the menu, then no item will be makred as current. It is a useful technique when you want
113
+ to prevent the item from being current in the controller. For example:
114
+
115
+ @menu.current_item = '/search-results-pertending-to-be-a-list' if search_query_empty?
116
+
117
+ ##### Paths
118
+ For each menu item you may specify a number of paths, that should match for the item to be active.
119
+ Unless you provide the `:path` option for `Mmmenu#add`, the second argument is used as the matching path.
120
+ If you'd like to specify paths explicitly, do something like this:
121
+
122
+ `l1.add "Articles" articles_path, :paths => [[new_article_path, 'get'], [articles_path, 'post'], [articles_path, 'get']]`
123
+
124
+ This way, the menu item will appear active even when you're on the /articles/new page.
125
+ There's also a third array element, which must be hash. In it may list request_params that should match, for example:
126
+
127
+ `l1.add "Articles" articles_path, :paths => [[articles_path, 'get', {:filter => 'published'}]]`
128
+
129
+ That way, only a request to "/articles?filter=published" will make this menu item active.
130
+ Of course it doesn't matter, if the request contains some other params. But you can make sure it doesn't by saying something like `{:personal => nil}`
131
+
132
+ Alernatively, you can do this:
133
+
134
+ l1.add "Articles" articles_path, :match_subpaths => true
135
+
136
+ Or you may use wildcards:
137
+
138
+ l1.add "Articles" articles_path, :paths => [["/articles/*"]]
139
+
140
+ That's much easier usually.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ require 'rspec/core/rake_task'
6
+
7
+ begin
8
+ Bundler.setup(:default, :development)
9
+ rescue Bundler::BundlerError => e
10
+ $stderr.puts e.message
11
+ $stderr.puts "Run `bundle install` to install missing gems"
12
+ exit e.status_code
13
+ end
14
+ require 'rake'
15
+
16
+ require 'jeweler'
17
+ Jeweler::Tasks.new do |gem|
18
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
19
+ gem.name = "mmmenu"
20
+ gem.homepage = "http://github.com/snitko/mmmenu"
21
+ gem.license = "MIT"
22
+ gem.summary = %Q{Flexible menu generator for Rails.}
23
+ gem.description = %Q{Defines multilevel menu structures, uses custom html templates to render them.}
24
+ gem.email = "roman.snitko@gmail.com"
25
+ gem.authors = ["Roman Snitko"]
26
+ # dependencies defined in Gemfile
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ RSpec::Core::RakeTask.new(:default)
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
@@ -0,0 +1,14 @@
1
+ class MmmenuGenerator < Rails::Generators::Base
2
+
3
+ source_root File.expand_path("../../templates", __FILE__)
4
+
5
+ def create_helper
6
+ copy_file "helpers/mmmenu_helper.rb", "app/helpers/mmmenu_helper.rb"
7
+ copy_file "views/mmmenu/_item.erb", "app/views/mmmenu/_item.erb"
8
+ copy_file "views/mmmenu/_current_item.erb", "app/views/mmmenu/_current_item.erb"
9
+ copy_file "views/mmmenu/_level_1.erb", "app/views/mmmenu/_level_1.erb"
10
+ copy_file "views/mmmenu/_level_2.erb", "app/views/mmmenu/_level_2.erb"
11
+ end
12
+
13
+
14
+ end
@@ -0,0 +1,16 @@
1
+ module MmmenuHelper
2
+
3
+ def build_mmmenu(menu)
4
+ return nil unless menu
5
+ menu.item_markup(1) do |link, text, options|
6
+ render(:partial => "mmmenu/item", :locals => { :link => link, :text => text, :options => options })
7
+ end
8
+ menu.current_item_markup(1) do |link, text, options|
9
+ render(:partial => "mmmenu/current_item", :locals => { :link => link, :text => text, :options => options })
10
+ end
11
+ menu.level_markup(1) { |m| render(:partial => "mmmenu/level_1", :locals => { :menu => m }) }
12
+ menu.level_markup(2) { |m| render(:partial => "mmmenu/level_2", :locals => { :menu => m }) }
13
+ menu.build.html_safe
14
+ end
15
+
16
+ end
@@ -0,0 +1 @@
1
+ <li><%= link_to text, link, options.merge({:class => "current"}) %></li>
@@ -0,0 +1 @@
1
+ <li><%= link_to text, link, options %></li>
@@ -0,0 +1 @@
1
+ <ul class="menu"><%=raw menu %></ul>
@@ -0,0 +1 @@
1
+ <ul class="submenu"><%=raw menu %></ul>
data/lib/mmmenu.rb ADDED
@@ -0,0 +1,163 @@
1
+ require 'mmmenu/level'
2
+ require 'mmmenu/engine'
3
+
4
+ class Mmmenu
5
+
6
+ attr_accessor :current_item
7
+
8
+ def initialize(options, &block)
9
+ @items = options[:items] || Mmmenu::Level.new(&block).to_a
10
+ @current_path = options[:request].path.chomp('/')
11
+ @request_params = options[:request].params
12
+ @request_type = options[:request].method.to_s.downcase
13
+ @item_markup = []
14
+ @current_item_markup = []
15
+ @level_markup = []
16
+ end
17
+
18
+ # The following two methods define
19
+ # the markup for each menu item on the current and
20
+ # lower levels (unless lower levels are not redefined later).
21
+ # Example:
22
+ # @menu.item_markup(0, options) do |link, text, options|
23
+ # "<a href=\"#{link}\" #{options}>#{text}</a>"
24
+ # end
25
+ def item_markup(level, options={}, &block)
26
+ level -= 1
27
+ @item_markup[level] = { :block => block, :options => options }
28
+ end
29
+ def current_item_markup(level, options={}, &block)
30
+ level -= 1
31
+ @current_item_markup[level] = { :block => block, :options => options }
32
+ end
33
+
34
+ # Defines the markup wrapper for the current menu level and
35
+ # lower menu levels (unless lower levels are not redefined later).
36
+ # Example:
37
+ # @menu.level_markup(0) { |level_content| "<div>#{level_content}</div>" }
38
+ def level_markup(level=1, &block)
39
+ level -= 1
40
+ @level_markup[level] = block
41
+ end
42
+
43
+ def build
44
+ build_level[:output]
45
+ end
46
+
47
+ private
48
+
49
+ def build_level(items=@items, level=0)
50
+
51
+ item_markup = build_item_markup(level)
52
+ level_markup = build_level_markup(level)
53
+
54
+ # Parsing of a single menu level happens here
55
+ output = ''
56
+ has_current_item = false
57
+
58
+ raise("Mmmenu object #{self} is empty, no items defined!") if items.nil? or items.empty?
59
+ items.each do |item|
60
+
61
+ item[:html_options] = {} unless item[:html_options]
62
+ child_menu = build_level(item[:children], level+1) if item[:children]
63
+ child_output = child_menu[:output] if child_menu
64
+
65
+ #############################################################
66
+ # Here's where we check if the current item is a current item
67
+ # and we should use a special markup for it
68
+ #############################################################
69
+ if (
70
+ item[:href] == current_item or
71
+ ( current_item.nil? && (
72
+ item_paths_match?(item) or
73
+ (child_menu and child_menu[:has_current_item]) or
74
+ item_href_match?(item)
75
+ ))
76
+ ) && !has_current_item
77
+
78
+ then
79
+ has_current_item = true
80
+ item_output = item_markup[:current][:block].call(item[:href], item[:title], item_markup[:current][:options].merge(item[:html_options]))
81
+ else
82
+ item_output = item_markup[:basic][:block].call(item[:href], item[:title], item_markup[:basic][:options].merge(item[:html_options]))
83
+ end
84
+ #############################################################
85
+
86
+ output += "#{item_output}#{child_output}"
87
+ end
88
+
89
+ output = level_markup.call(output)
90
+ { :has_current_item => has_current_item, :output => output }
91
+
92
+ end
93
+
94
+
95
+ # Matches menu item against :paths option
96
+ def item_paths_match?(item)
97
+ if item[:paths]
98
+
99
+ item[:paths].each do |path|
100
+ if path.kind_of?(Array)
101
+ # IF path matches perfectly
102
+ request_type_option = path[1] || ""
103
+ if ((@current_path == path[0].chomp('/') and @request_type == request_type_option.downcase) or
104
+ # OR IF * wildcard is used and path matches
105
+ (path[0] =~ /\*$/ and @current_path =~ /^#{path[0].chomp('*')}(.+)?$/)) and
106
+ # all listed request params match
107
+ params_match?(path)
108
+ return true
109
+ end
110
+ else
111
+ return true if @current_path == path
112
+ end
113
+ end
114
+
115
+ end
116
+ return false
117
+ end
118
+
119
+ # Matches menu item against the actual path it's pointing to.
120
+ # Is only applied when :path option is not present.
121
+ def item_href_match?(item)
122
+ if item[:href]
123
+ item_href = item[:href].chomp('/')
124
+ if (@current_path == item_href) or # IF path matches perfectly
125
+ (item[:match_subpaths] and @current_path =~ /^#{item_href}(\/.+)?$/) # OR IF :match_subpaths options is used and path matches
126
+ return true
127
+ end
128
+ end unless item[:paths]
129
+ return false
130
+ end
131
+
132
+ def build_item_markup(level)
133
+ if @item_markup[level]
134
+ { :basic => @item_markup[level], :current => @current_item_markup[level] }
135
+ else
136
+ unless @item_markup.empty?
137
+ { :basic => @item_markup.last, :current => @current_item_markup.last }
138
+ else
139
+ { :basic => {:block => lambda { |link,text,options| "#{text} #{link} #{options}\n" }, :options => {} }, :current => { :block => lambda { |link,text,options| "#{text} #{link} #{options} current\n" }, :options => {} } }
140
+ end
141
+ end
142
+ end
143
+
144
+ def build_level_markup(level)
145
+ if @level_markup[level]
146
+ @level_markup[level]
147
+ else
148
+ if @level_markup.empty?
149
+ lambda { |menu| menu }
150
+ else
151
+ @level_markup.last
152
+ end
153
+ end
154
+ end
155
+
156
+ def params_match?(path)
157
+ path[2].each do |k,v|
158
+ return false unless (@request_params[k.to_s].nil? and v.nil?) or @request_params[k.to_s] == v.to_s
159
+ end if path[2]
160
+ true
161
+ end
162
+
163
+ end
@@ -0,0 +1,16 @@
1
+ class Mmmenu::Engine < Rails::Engine
2
+
3
+ paths["app/helpers"] << File.expand_path("../../generators/templates/helpers", __FILE__)
4
+ paths["app/views"] << File.expand_path("../../generators/templates/views", __FILE__)
5
+
6
+ end if defined?(Rails::Engine)
7
+
8
+ ActionController::Base.class_eval do
9
+
10
+ private
11
+
12
+ def mmmenu(&block)
13
+ @menu = Mmmenu.new(:request => request, &block)
14
+ end
15
+
16
+ end if defined?(ActionController::Base)
@@ -0,0 +1,24 @@
1
+ class Mmmenu
2
+
3
+ class Level
4
+
5
+ def initialize(&block)
6
+ @items = []
7
+ yield(self)
8
+ end
9
+
10
+ def add(title, href, options={}, &block)
11
+ children = {}
12
+ if block_given? # which means current item has children
13
+ children = { :children => self.class.new(&block).to_a }
14
+ end
15
+ @items << { :title => title, :href => href }.merge(options).merge(children)
16
+ end
17
+
18
+ def to_a
19
+ @items
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,3 @@
1
+ class Mmmenu
2
+ VERSION = '0.1'
3
+ end
data/mmmenu.gemspec ADDED
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "mmmenu"
8
+ s.version = "0.5.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Roman Snitko"]
12
+ s.date = "2012-02-27"
13
+ s.description = "Defines multilevel menu structures, uses custom html templates to render them."
14
+ s.email = "roman.snitko@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "README.markdown"
17
+ ]
18
+ s.files = [
19
+ "Gemfile",
20
+ "Gemfile.lock",
21
+ "README.markdown",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/generators/mmmenu/mmmenu_generator.rb",
25
+ "lib/generators/templates/helpers/mmmenu_helper.rb",
26
+ "lib/generators/templates/views/mmmenu/_current_item.erb",
27
+ "lib/generators/templates/views/mmmenu/_item.erb",
28
+ "lib/generators/templates/views/mmmenu/_level_1.erb",
29
+ "lib/generators/templates/views/mmmenu/_level_2.erb",
30
+ "lib/mmmenu.rb",
31
+ "lib/mmmenu/engine.rb",
32
+ "lib/mmmenu/level.rb",
33
+ "lib/mmmenu/version.rb",
34
+ "mmmenu.gemspec",
35
+ "spec/lib/mmmenu_level_spec.rb",
36
+ "spec/lib/mmmenu_spec.rb",
37
+ "spec/spec_helper.rb"
38
+ ]
39
+ s.homepage = "http://github.com/snitko/mmmenu"
40
+ s.licenses = ["MIT"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = "1.8.10"
43
+ s.summary = "Flexible menu generator for Rails."
44
+
45
+ if s.respond_to? :specification_version then
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
50
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
51
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
52
+ else
53
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
54
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
55
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
56
+ end
57
+ else
58
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
59
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
61
+ end
62
+ end
63
+
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/mmmenu/level')
2
+
3
+ describe Mmmenu::Level do
4
+
5
+ it "builds a menu level hash representation" do
6
+ @menu_level = Mmmenu::Level.new do |l1|
7
+ l1.add "Title1", "/path1"
8
+ l1.add "Title2", "/path2" do |l2|
9
+ l2.add "SubTitle", "/path2/subpath"
10
+ end
11
+ end
12
+
13
+ @menu_level.to_a.should == [
14
+ {:title => "Title1", :href => "/path1"},
15
+ {:title => "Title2", :href => "/path2", :children => [
16
+ { :title => "SubTitle", :href => "/path2/subpath" }
17
+ ]}
18
+ ]
19
+ end
20
+
21
+ end
@@ -0,0 +1,155 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/mmmenu/level')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/mmmenu')
3
+
4
+ describe Mmmenu do
5
+
6
+ before(:all) do
7
+ @items = [
8
+ { :name => :numbers, :title => 'Item1', :children => [
9
+ { :title => 'Create', :href => '/items1/new', :paths => ['/items1/new'] },
10
+ { :title => 'Index', :href => '/items1/' },
11
+ { :title => 'Print', :href => '/items1/print' }
12
+ ]},
13
+ { :title => 'Item2', :href => '/items2' },
14
+ { :title => 'Item3', :href => '/items3' },
15
+ { :title => 'Item4', :href => '/items4' }
16
+ ]
17
+ end
18
+
19
+ before(:each) do
20
+ @request = mock('request')
21
+ @request.stub!(:path).once.and_return('/items1/new')
22
+ @request.stub!(:method).once.and_return('get')
23
+ @request.stub!(:params).once.and_return({})
24
+ @menu = Mmmenu.new(:items => @items, :request => @request )
25
+ end
26
+
27
+ it "renders one level" do
28
+ set_menu_markup
29
+ @menu.item_markup(2) do |link, text, options|
30
+ " #{text}: #{link}\n"
31
+ end
32
+ @menu.current_item_markup(2) do |link, text, options|
33
+ " #{text}: #{link} current\n"
34
+ end
35
+ @menu.level_markup(1) { |menu| menu }
36
+ @menu.build.should == <<END
37
+ Item1: current
38
+ Create: /items1/new current
39
+ Index: /items1/
40
+ Print: /items1/print
41
+ Item2: /items2
42
+ Item3: /items3
43
+ Item4: /items4
44
+ END
45
+
46
+ end
47
+
48
+ it "chooses the current item depending on request type" do
49
+ items = [
50
+ { :title => 'item1', :href => '/item1', :paths => [['/item', 'post']] },
51
+ { :title => 'item2', :href => '/item2', :paths => [['/item', 'get']] }
52
+ ]
53
+ request = mock('request')
54
+ request.should_receive(:path).once.and_return('/item')
55
+ request.should_receive(:method).once.and_return('get')
56
+ request.should_receive(:params).once.and_return({})
57
+ @menu = Mmmenu.new(:items => items, :request => request )
58
+ set_menu_markup
59
+ @menu.build.should == <<END
60
+ item1: /item1
61
+ item2: /item2 current
62
+ END
63
+
64
+ end
65
+
66
+ it "chooses the current item with a specific request param" do
67
+ items = [
68
+ { :title => 'item1', :href => '/item1', :paths => [['/item1', 'get', {:param => 1}]] },
69
+ { :title => 'item2', :href => '/item1', :paths => [['/item1', 'get', {:param => 2}]] },
70
+ { :title => 'item3', :href => '/item1', :paths => [['/item1', 'get', {:param => nil}]] }
71
+ ]
72
+ request = mock('request')
73
+ request.should_receive(:path).once.and_return('/item1')
74
+ request.should_receive(:params).once.and_return({"param" => "1"})
75
+ request.should_receive(:method).once.and_return('get')
76
+ @menu = Mmmenu.new(:items => items, :request => request )
77
+ set_menu_markup
78
+ @menu.build.should == <<END
79
+ item1: /item1 current
80
+ item2: /item1
81
+ item3: /item1
82
+ END
83
+ end
84
+
85
+ it "chooses current item when forced to do so by explicitly set current_item property" do
86
+ items = [
87
+ { :title => 'item1', :href => '/item1' },
88
+ { :title => 'item2', :href => '/item2' },
89
+ { :title => 'item3', :href => '/item3' }
90
+ ]
91
+ request = mock('request')
92
+ request.should_receive(:path).once.and_return('/item1')
93
+ request.should_receive(:method).once.and_return('get')
94
+ request.should_receive(:params).once
95
+ @menu = Mmmenu.new(:items => items, :request => request )
96
+ @menu.current_item = "/item2"
97
+ set_menu_markup
98
+
99
+ @menu.build.should == <<END
100
+ item1: /item1
101
+ item2: /item2 current
102
+ item3: /item3
103
+ END
104
+ end
105
+
106
+ it "creates menu items in a block using nice DSL" do
107
+
108
+ @menu = Mmmenu.new(:request => @request) do |m|
109
+ m.add 'Item1', '/items1', :match_subpaths => true
110
+ m.add 'Item2', '/items2' do |subm|
111
+ subm.add 'New', '/item2/new'
112
+ subm.add 'Edit', '/item2/edit'
113
+ end
114
+ end
115
+ set_menu_markup
116
+
117
+ @menu.build.should == <<END
118
+ Item1: /items1 current
119
+ Item2: /items2
120
+ New: /item2/new
121
+ Edit: /item2/edit
122
+ END
123
+
124
+ end
125
+
126
+ it "creates menu items in a block using nice DSL and additional options" do
127
+
128
+ @menu = Mmmenu.new(:request => @request) do |m|
129
+ m.add 'Item1', '/items1', :match_subpaths => true
130
+ m.add 'Item2', '/items2' do |subm|
131
+ subm.add 'New', '/item2/new'
132
+ subm.add 'Edit', '/item2/edit'
133
+ end
134
+ end
135
+ set_menu_markup
136
+
137
+ @menu.build.should == <<END
138
+ Item1: /items1 current
139
+ Item2: /items2
140
+ New: /item2/new
141
+ Edit: /item2/edit
142
+ END
143
+
144
+ end
145
+
146
+ def set_menu_markup(level=1)
147
+ @menu.item_markup(level) do |link, text, options|
148
+ "#{text}: #{link}\n"
149
+ end
150
+ @menu.current_item_markup(level) do |link, text, options|
151
+ "#{text}: #{link} current\n"
152
+ end
153
+ end
154
+
155
+ end
File without changes
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mmmenu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Roman Snitko
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &24009500 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *24009500
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &24007940 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 2.8.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *24007940
36
+ - !ruby/object:Gem::Dependency
37
+ name: jeweler
38
+ requirement: &24006480 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.6.4
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *24006480
47
+ description: Defines multilevel menu structures, uses custom html templates to render
48
+ them.
49
+ email: roman.snitko@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - README.markdown
54
+ files:
55
+ - Gemfile
56
+ - Gemfile.lock
57
+ - README.markdown
58
+ - Rakefile
59
+ - VERSION
60
+ - lib/generators/mmmenu/mmmenu_generator.rb
61
+ - lib/generators/templates/helpers/mmmenu_helper.rb
62
+ - lib/generators/templates/views/mmmenu/_current_item.erb
63
+ - lib/generators/templates/views/mmmenu/_item.erb
64
+ - lib/generators/templates/views/mmmenu/_level_1.erb
65
+ - lib/generators/templates/views/mmmenu/_level_2.erb
66
+ - lib/mmmenu.rb
67
+ - lib/mmmenu/engine.rb
68
+ - lib/mmmenu/level.rb
69
+ - lib/mmmenu/version.rb
70
+ - mmmenu.gemspec
71
+ - spec/lib/mmmenu_level_spec.rb
72
+ - spec/lib/mmmenu_spec.rb
73
+ - spec/spec_helper.rb
74
+ homepage: http://github.com/snitko/mmmenu
75
+ licenses:
76
+ - MIT
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ segments:
88
+ - 0
89
+ hash: 2496057170991287488
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 1.8.10
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Flexible menu generator for Rails.
102
+ test_files: []