mmmenu 0.5.0

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.
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: []