ramenu 3.0.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/.gitignore +12 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE +23 -0
- data/README.md +372 -0
- data/Rakefile +13 -0
- data/init.rb +1 -0
- data/lib/ramenu.rb +13 -0
- data/lib/ramenu/action_controller.rb +223 -0
- data/lib/ramenu/config.rb +44 -0
- data/lib/ramenu/menus.rb +167 -0
- data/lib/ramenu/railtie.rb +12 -0
- data/lib/ramenu/ramenu_definer.rb +23 -0
- data/lib/ramenu/ramenu_methods.rb +39 -0
- data/lib/ramenu/version.rb +14 -0
- data/ramenu.gemspec +28 -0
- data/test/dummy.rb +34 -0
- data/test/minitest_helper.rb +19 -0
- data/test/test_helper.rb +22 -0
- data/test/unit/action_controller_test.rb +109 -0
- data/test/unit/builder_test.rb +117 -0
- data/test/unit/element_test.rb +52 -0
- data/test/unit/simple_builder_test.rb +68 -0
- metadata +183 -0
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ramenu'
|
data/lib/ramenu.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'ramenu/menus'
|
2
|
+
require 'ramenu/version'
|
3
|
+
require 'ramenu/action_controller'
|
4
|
+
require 'ramenu/railtie'
|
5
|
+
require 'ramenu/ramenu_methods'
|
6
|
+
require 'ramenu/ramenu_definer'
|
7
|
+
require 'ramenu/config'
|
8
|
+
|
9
|
+
module Ramenu
|
10
|
+
|
11
|
+
DEFAULT_GROUP = :default
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
module Ramenu
|
2
|
+
module ActionController
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extend ClassMethods
|
7
|
+
helper HelperMethods
|
8
|
+
helper_method :add_menu, :menus, :flags
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
module Utils
|
13
|
+
|
14
|
+
def self.instance_proc(string)
|
15
|
+
if string.kind_of?(String)
|
16
|
+
proc { |controller| controller.instance_eval(string) }
|
17
|
+
else
|
18
|
+
string
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# This is an horrible method with an horrible name.
|
23
|
+
#
|
24
|
+
# convert_to_set_of_strings(nil, [:foo, :bar])
|
25
|
+
# # => nil
|
26
|
+
# convert_to_set_of_strings(true, [:foo, :bar])
|
27
|
+
# # => ["foo", "bar"]
|
28
|
+
# convert_to_set_of_strings(:foo, [:foo, :bar])
|
29
|
+
# # => ["foo"]
|
30
|
+
# convert_to_set_of_strings([:foo, :bar, :baz], [:foo, :bar])
|
31
|
+
# # => ["foo", "bar", "baz"]
|
32
|
+
#
|
33
|
+
def self.convert_to_set_of_strings(value, keys)
|
34
|
+
if value == true
|
35
|
+
keys.map(&:to_s).to_set
|
36
|
+
elsif value
|
37
|
+
Array(value).map(&:to_s).to_set
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
module HelperMethods
|
44
|
+
|
45
|
+
def render_ramenu(options = {}, &block)
|
46
|
+
# passing all flags to Builder (static + volatile)
|
47
|
+
options[:flags] = flags(options[:menu])
|
48
|
+
builder = (options.delete(:builder) || Menus::SimpleBuilder).new(self, menus(options[:menu]), options)
|
49
|
+
content = builder.render.html_safe
|
50
|
+
if block_given?
|
51
|
+
capture(content, &block)
|
52
|
+
else
|
53
|
+
content
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
module ClassMethods
|
60
|
+
|
61
|
+
#
|
62
|
+
# flags methods
|
63
|
+
#
|
64
|
+
|
65
|
+
# get flag value
|
66
|
+
def get_flag(name, filter_options = {})
|
67
|
+
before_filter(filter_options) do |controller|
|
68
|
+
controller.send(:get_flag, name, filter_options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# set flag value
|
73
|
+
def set_flag(name, value, filter_options = {})
|
74
|
+
before_filter(filter_options) do |controller|
|
75
|
+
controller.send(:set_flag, name, value, filter_options)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# reset flag value
|
80
|
+
def reset_flag(name, filter_options = {})
|
81
|
+
before_filter(filter_options) do |controller|
|
82
|
+
controller.send(:reset_flag, name, filter_options)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# menus methods
|
88
|
+
#
|
89
|
+
|
90
|
+
# add a menu
|
91
|
+
def add_menu(name, path = nil, filter_options = {}, &block)
|
92
|
+
# This isn't really nice here
|
93
|
+
if eval = Utils.convert_to_set_of_strings(filter_options.delete(:eval), %w(name path))
|
94
|
+
name = Utils.instance_proc(name) if eval.include?("name")
|
95
|
+
unless path.nil?
|
96
|
+
path = Utils.instance_proc(path) if eval.include?("path")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
before_filter(filter_options) do |controller|
|
101
|
+
# if path isn't defined, use current path
|
102
|
+
path = request.fullpath if path.nil?
|
103
|
+
|
104
|
+
controller.send(:add_menu, name, path, filter_options, &block)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
alias :add_menu_for_current :add_menu
|
108
|
+
|
109
|
+
# define volatile menus/flags in a block
|
110
|
+
def definer(name = nil, filter_options = {}, &block)
|
111
|
+
before_filter(filter_options) do |controller|
|
112
|
+
controller.send(:definer, name, filter_options, &block)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
protected
|
118
|
+
|
119
|
+
# common
|
120
|
+
|
121
|
+
def definer(name = nil, options = {}, &block)
|
122
|
+
static = options[:static] || false
|
123
|
+
|
124
|
+
menus = static ? static_menus(name) : volatile_menus(name)
|
125
|
+
flags = static ? static_flags(name) : volatile_flags(name)
|
126
|
+
|
127
|
+
# use a definer to allow block
|
128
|
+
rd = Ramenu::RamenuDefiner.new(menus, flags, options)
|
129
|
+
yield rd if block_given?
|
130
|
+
end
|
131
|
+
|
132
|
+
# flags
|
133
|
+
|
134
|
+
# get flag value
|
135
|
+
def get_flag(name, options = {})
|
136
|
+
# getting options
|
137
|
+
static = options[:static] || false
|
138
|
+
volatile = options[:volatile] || false
|
139
|
+
|
140
|
+
f = static_flags(options[:flagset]) if static
|
141
|
+
f = volatile_flags(options[:flagset]) if volatile
|
142
|
+
f = flags(options[:flagset]) unless static || volatile
|
143
|
+
|
144
|
+
f[name] if f.include?(name)
|
145
|
+
end
|
146
|
+
|
147
|
+
# reset flag value
|
148
|
+
def reset_flag(name, options = {})
|
149
|
+
set_flag(name, nil, options) unless name.nil?
|
150
|
+
end
|
151
|
+
|
152
|
+
# set flag value
|
153
|
+
def set_flag(name, value = nil, options = {})
|
154
|
+
# getting options
|
155
|
+
static = options[:static] || false
|
156
|
+
|
157
|
+
# setting flag
|
158
|
+
if static
|
159
|
+
set_static_flag(name, value, options)
|
160
|
+
else #if volatile
|
161
|
+
# default is volatile when nothing's set
|
162
|
+
set_volatile_flag(name, value, options)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# add a static flag, which will be kept for next instances
|
167
|
+
def set_static_flag(name, value, options = {})
|
168
|
+
flagset = options[:flagset]
|
169
|
+
Ramenu.set_flag_in(static_flags(flagset), name, value, options)
|
170
|
+
end
|
171
|
+
|
172
|
+
# add a volatile flag, only valid in the current instances
|
173
|
+
def set_volatile_flag(name, value, options = {})
|
174
|
+
flagset = options[:flagset]
|
175
|
+
Ramenu.set_flag_in(volatile_flags(flagset), name, value, options)
|
176
|
+
end
|
177
|
+
|
178
|
+
# return volatile flags defined in the current instance
|
179
|
+
def volatile_flags(flagset = nil)
|
180
|
+
flagset = :default if flagset.nil?
|
181
|
+
@flags ||= {}
|
182
|
+
@flags[flagset] ||= {}
|
183
|
+
@flags[flagset]
|
184
|
+
end
|
185
|
+
# return static flags defined in the configuration
|
186
|
+
def static_flags(flagset = nil)
|
187
|
+
Ramenu.static_flags(flagset)
|
188
|
+
end
|
189
|
+
# return all defined flags, static ones first then volatile ones
|
190
|
+
def flags(flagset = nil)
|
191
|
+
static_flags(flagset).merge(volatile_flags(flagset))
|
192
|
+
end
|
193
|
+
|
194
|
+
# add a static menu, which will be kept for next instances
|
195
|
+
def add_static_menu(name, path, options = {}, &block)
|
196
|
+
menu = options[:menu]
|
197
|
+
Ramenu.add_menu_to(static_menus(menu), name, path, options, &block)
|
198
|
+
end
|
199
|
+
|
200
|
+
# add a volatile menu, only valid in the current instances
|
201
|
+
def add_volatile_menu(name, path, options = {}, &block)
|
202
|
+
menu = options[:menu]
|
203
|
+
Ramenu.add_menu_to(volatile_menus(menu), name, path, options, &block)
|
204
|
+
end
|
205
|
+
alias :add_menu :add_volatile_menu
|
206
|
+
|
207
|
+
# return volatile menus defined in the current instance
|
208
|
+
def volatile_menus(menu = nil)
|
209
|
+
menu = :default if menu.nil?
|
210
|
+
@ramenu_menus ||= {}
|
211
|
+
@ramenu_menus[menu] ||= []
|
212
|
+
end
|
213
|
+
# return static menus defined in the configuration
|
214
|
+
def static_menus(menu = nil)
|
215
|
+
Ramenu.static_menus(menu)
|
216
|
+
end
|
217
|
+
# return all defined menus, static ones first then volatile ones
|
218
|
+
def menus(menu = nil)
|
219
|
+
static_menus(menu) + volatile_menus(menu)
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'active_support/configurable'
|
2
|
+
|
3
|
+
module Ramenu
|
4
|
+
# Configures global settings for Ramenu
|
5
|
+
def self.configure(&block)
|
6
|
+
yield @config ||= Ramenu::Configuration.new
|
7
|
+
end
|
8
|
+
|
9
|
+
# Global settings for Ramenu
|
10
|
+
def self.config
|
11
|
+
@config
|
12
|
+
end
|
13
|
+
|
14
|
+
# need a Class for 3.0
|
15
|
+
class Configuration #:nodoc:
|
16
|
+
include ActiveSupport::Configurable
|
17
|
+
config_accessor :menus
|
18
|
+
config_accessor :flags
|
19
|
+
|
20
|
+
# common
|
21
|
+
def definer(name = nil, options = {}, &block)
|
22
|
+
# menus
|
23
|
+
menus = Ramenu.static_menus(name)
|
24
|
+
# flags
|
25
|
+
flags = Ramenu.static_flags(name)
|
26
|
+
|
27
|
+
# use a definer to allow block
|
28
|
+
rd = RamenuDefiner.new(menus, flags, options)
|
29
|
+
yield rd if block_given?
|
30
|
+
end
|
31
|
+
|
32
|
+
# create a new static flag in the configuration
|
33
|
+
def set_flag(name, value = nil, options = {})
|
34
|
+
flags = Ramenu.static_flags(options[:flagset])
|
35
|
+
Ramenu.set_flag_in(flags, name, value, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
# create a new static menus in the configuration
|
39
|
+
def add_menu(name, path = nil, options = {}, &block)
|
40
|
+
menus = Ramenu.static_menus(options[:menu])
|
41
|
+
Ramenu.add_menu_to(menus, name, path, options, &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/ramenu/menus.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
module Ramenu
|
2
|
+
|
3
|
+
module Menus
|
4
|
+
|
5
|
+
# The Builder class represents the abstract class for any custom Builder.
|
6
|
+
#
|
7
|
+
# To create a custom Builder, just extend this class
|
8
|
+
# and implement the following abstract methods:
|
9
|
+
#
|
10
|
+
# * <tt>#render</tt>: Renders and returns the collection of navigation elements
|
11
|
+
#
|
12
|
+
class Builder
|
13
|
+
|
14
|
+
# Initializes a new Builder with <tt>context</tt>,
|
15
|
+
# <tt>element</tt> and <tt>options</tt>.
|
16
|
+
#
|
17
|
+
# @param [ActionView::Base] context The view context.
|
18
|
+
# @param [Array<Element>] elements The collection of Elements.
|
19
|
+
# @param [Hash] options Hash of options to customize the rendering behavior.
|
20
|
+
#
|
21
|
+
def initialize(context, elements, options = {})
|
22
|
+
@context = context
|
23
|
+
@elements = elements
|
24
|
+
@options = options
|
25
|
+
end
|
26
|
+
|
27
|
+
# Renders Elements and returns the Breadcrumb navigation for the view.
|
28
|
+
#
|
29
|
+
# @return [String] The result of the menu rendering.
|
30
|
+
#
|
31
|
+
# @abstract You must implement this method in your custom Builder.
|
32
|
+
def render
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
# get flag associated to element
|
37
|
+
def flag_for(element, option = :flag)
|
38
|
+
flag = nil
|
39
|
+
flag_selector = element.options[option]
|
40
|
+
unless flag_selector.nil?
|
41
|
+
flag = @options[:flags][flag_selector] if @options[:flags].include?(flag_selector)
|
42
|
+
end
|
43
|
+
return flag
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def compute_name(element)
|
49
|
+
case name = element.name
|
50
|
+
when Symbol
|
51
|
+
begin
|
52
|
+
@context.send(name)
|
53
|
+
rescue NoMethodError
|
54
|
+
key = 'ramenu.menus.' + @options[:menu].to_s + element.translation_key
|
55
|
+
I18n.t(key)
|
56
|
+
end
|
57
|
+
when Proc
|
58
|
+
name.call(@context)
|
59
|
+
else
|
60
|
+
name.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def compute_path(element)
|
65
|
+
case path = element.path
|
66
|
+
when Symbol
|
67
|
+
@context.send(path)
|
68
|
+
when Proc
|
69
|
+
path.call(@context)
|
70
|
+
when Hash
|
71
|
+
@context.url_for(path)
|
72
|
+
else
|
73
|
+
path.to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
# The SimpleBuilder is the default menu builder.
|
80
|
+
# It provides basic functionalities to render a menu navigation.
|
81
|
+
#
|
82
|
+
# The SimpleBuilder accepts a limited set of options.
|
83
|
+
# If you need more flexibility, create a custom Builder and
|
84
|
+
# pass the option :builder => BuilderClass to the <tt>render_menus</tt> helper method.
|
85
|
+
#
|
86
|
+
class SimpleBuilder < Builder
|
87
|
+
|
88
|
+
def render
|
89
|
+
@elements.collect do |element|
|
90
|
+
render_element(element)
|
91
|
+
end.join(@options[:separator] || " » ")
|
92
|
+
end
|
93
|
+
|
94
|
+
def render_element(element)
|
95
|
+
content = @context.link_to_unless_current(compute_name(element), compute_path(element), element.options)
|
96
|
+
|
97
|
+
# rendering sub-elements
|
98
|
+
if (element.childs.length > 0)
|
99
|
+
content = content + " |"
|
100
|
+
element.childs.each do |child|
|
101
|
+
content = content + @context.link_to_unless_current(compute_name(child), compute_path(child)) + "|"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if @options[:tag]
|
106
|
+
@context.content_tag(@options[:tag], content)
|
107
|
+
else
|
108
|
+
content
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Represents a navigation element in the menu collection.
|
116
|
+
#
|
117
|
+
class Element
|
118
|
+
|
119
|
+
# @return [String] The element/link name.
|
120
|
+
attr_accessor :name
|
121
|
+
# @return [String] The element/link URL.
|
122
|
+
attr_accessor :path
|
123
|
+
# @return [Hash] The element/link childs
|
124
|
+
attr_accessor :childs
|
125
|
+
# @return [Element] The element/link parent
|
126
|
+
attr_accessor :parent
|
127
|
+
# @return [Hash] The element/link URL.
|
128
|
+
attr_accessor :options
|
129
|
+
|
130
|
+
# Initializes the Element with given parameters.
|
131
|
+
#
|
132
|
+
# @param [String] name The element/link name.
|
133
|
+
# @param [String] path The element/link URL.
|
134
|
+
# @param [Hash] options The element/link URL.
|
135
|
+
# @return [Element]
|
136
|
+
#
|
137
|
+
def initialize(name, path, options = {})
|
138
|
+
self.name = name
|
139
|
+
self.path = path
|
140
|
+
self.childs = []
|
141
|
+
#self.parent = @options[:parent]
|
142
|
+
self.parent = options.delete(:parent)
|
143
|
+
self.options = options
|
144
|
+
end
|
145
|
+
|
146
|
+
def translation_key
|
147
|
+
key = ''
|
148
|
+
elem = self
|
149
|
+
while !elem.nil? do
|
150
|
+
key = '.' + elem.name.to_s + key if elem.name.is_a?(Symbol)
|
151
|
+
key = '.' + elem.name.to_sym.to_s + key if elem.name.is_a?(String)
|
152
|
+
elem = elem.parent
|
153
|
+
end
|
154
|
+
key += '.root' if self.childs.count > 0
|
155
|
+
return key
|
156
|
+
end
|
157
|
+
|
158
|
+
def add_menu(name, path, options = {}, &block)
|
159
|
+
opts = options.merge({:parent => self})
|
160
|
+
self.childs << Ramenu.new_ramenu_element(name, path, opts, &block)
|
161
|
+
end
|
162
|
+
alias :add_child :add_menu
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|