waiter 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .idea
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in menu_builder.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Daniel Vandersluis
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # Waiter
2
+
3
+ Waiter serves up menus for your application:
4
+ * Provides a quick DSL for building menus, without having to specify any HTML.
5
+ * Makes assumptions based on what's provided in the DSL so that the specification does not need to be unnecessarily verbose.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'waiter'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install waiter
20
+
21
+ ## Usage
22
+
23
+ ### Building a menu
24
+
25
+ To create a new menu:
26
+
27
+ Waiter::Menu.serve do |menu|
28
+ menu.file
29
+ menu.edit
30
+ menu.view
31
+ # ...
32
+ end
33
+
34
+ The above defines a menu with three items. By default, each item name (ie. "file", "edit", etc.) corresponds both to the I18n string to use (so `menu.file` will call `I18n.t(:file)`) as well as to the controller to use (`menu.file` will correspond to `FileController`, and the menu item will link to `FileController#index` by default).
35
+
36
+ Of course, there will be situations where the path may need to be explicitly specified. In this case, the `:controller`
37
+ and `:action` options can be specified:
38
+
39
+ Waiter::Menu.serve do |menu|
40
+ menu.file :controller => 'documents', :action => 'show'
41
+ end
42
+
43
+ In this case the File menu will correspond to `DocumentsController#show`, and will only light up for that action. If
44
+ no specific action is given, the menu item will be lit up for all actions within the given controller.
45
+
46
+ There may also be times where you need multiple controllers to light up the same menu item. This can be achieved by
47
+ passing an array to the `:controllers` option:
48
+
49
+ Waiter::Menu.serve do |menu|
50
+ menu.file :controller => 'documents', :controllers => ['files', 'print', ... ]
51
+ end
52
+
53
+ This will create a menu that links to `DocumentsController#index`, which will be lit up the user hits any action within the `FilesController`, `PrintController`, as well as the `DocumentsController`.
54
+
55
+
56
+ ### Submenus
57
+
58
+ Menus can also have submenus (currently only one level of nesting is supported when drawing a menu, but infinite
59
+ levels are supported when building a menu). A submenu is defined with the same syntax as a root menu item, and is
60
+ passed as a block to the root menu item.
61
+
62
+ Submenus automatically assume the controller to use is the controller specified by its root menu item, so a
63
+ controller does not need to be specified unless it differs. As well, the menu item name is assumed to be used
64
+ for the action within that controller, so action does not need to be specified unless it differs from the name.
65
+ An id can also be specified if necessary (with the `:id` option).
66
+
67
+ Waiter::Menu.serve do |menu|
68
+ menu.file, :controllers => ['print'] do |file|
69
+ file.new # Corresponds to FileController#new
70
+ file.open :action => :read # Corresponds to FileController#read
71
+ file.save :action => :write # Corresponds to FileController#write
72
+ file.print, :controller => 'print' # Corresponds to PrintController#print
73
+ end
74
+ end
75
+
76
+ If an action isn't explicitly given, and the menu item name does not correspond to an actual action, the default
77
+ action for the controller will be used instead.
78
+
79
+
80
+ ### Menu Options
81
+
82
+ There are two options that you can use when building your menu. Options can be passed into build when defining
83
+ a menu or specified once the menu is defined by accessing the menu.options hash.
84
+
85
+ `string_prefix`: Allows for a prefix for I18n strings to be specified.
86
+
87
+ Waiter::Menu.serve(:string_prefix => 'menu_') do |menu|
88
+ menu.file
89
+ end
90
+
91
+ # will use I18n.t(:menu_file) instead of I18n.t(:file)
92
+
93
+ `selected`: Allows the selected menu item to be overridden, so a specified menu item can be lit up regardless of
94
+ what the current controller/action is. This can be useful if there is an action that falls under different menu
95
+ items depending on application context, or if there is a controller that may correspond to multiple menu items.
96
+ A good way to achieve this would be to add a before_filter to set an instance variable which is then passed into
97
+ the selected option.
98
+
99
+ before_filter :set_current_menu
100
+
101
+ def set_current_menu
102
+ case params[:action]
103
+ when 'foo' then @current_menu = "menu1"
104
+ when 'bar' then @current_menu = "menu2"
105
+ end
106
+ end
107
+
108
+ Waiter::Menu.serve(:selected => @current_menu) do |menu|
109
+ end
110
+
111
+ Note that the value passed to `:selected` should match the name of the menu item.
112
+
113
+
114
+ ### Drawing (outputting) a menu
115
+
116
+ To draw a created menu, use the `Waiter::Menu::Drawer` class. The class requires the current context to be
117
+ passed in so that `ActionController` methods can be used. In general (ie. if the menu is being drawn from a helper)
118
+ the context is self.
119
+
120
+ menu = Waiter::Menu.serve do |menu|
121
+ # ...
122
+ end
123
+
124
+ Waiter::Menu::Drawer.new(menu, context).draw
125
+
126
+ If a different `Drawer` is desired, `Waiter::Menu::Drawer` can be subclassed and the methods `draw` and `draw_submenu` overridden to provide an alternate format.
127
+
128
+ ## Contributing
129
+
130
+ 1. Fork it
131
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
132
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
133
+ 4. Push to the branch (`git push origin my-new-feature`)
134
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/waiter.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "waiter/version"
2
+ require "waiter/menu"
3
+ require "waiter/menu/builder"
4
+ require "waiter/menu/drawer"
@@ -0,0 +1,26 @@
1
+ module Waiter
2
+ class Menu
3
+ attr_accessor :options, :submenus
4
+
5
+ class << self
6
+ def serve(options = {})
7
+ yield Builder.new(obj = self.new(options))
8
+ obj
9
+ end
10
+ end
11
+
12
+ def initialize(options = {})
13
+ @menu_items = []
14
+ @submenus = {}
15
+ @options = options
16
+ end
17
+
18
+ def add(name, args = {})
19
+ @menu_items << [name, args]
20
+ end
21
+
22
+ def items
23
+ @menu_items
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ module Waiter
2
+ class Menu
3
+ # Builds a menu structure from the DSL
4
+ class Builder
5
+ def initialize(menu)
6
+ @menu = menu
7
+ end
8
+
9
+ def method_missing(name, *args, &block)
10
+ @menu.add name, *args
11
+ if block_given?
12
+ @menu.submenus[name] = Menu.new(@menu.options.merge(:controller => (args.first.andand[:controller] || name)))
13
+ yield Builder.new(@menu.submenus[name])
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,91 @@
1
+ module Waiter
2
+ class Menu
3
+ # Outputs a Menu into HTML
4
+ class Drawer
5
+ # @context is a Controller binding, which allows the ActionView helpers to work in the correct context
6
+ delegate :link_to, :content_tag, :params, :to => :@context
7
+
8
+ def initialize(menu, context)
9
+ @context = context
10
+ @menu = menu
11
+ end
12
+
13
+ def draw
14
+ content_tag :div, :id => "menu" do
15
+ out = ActiveSupport::SafeBuffer.new
16
+
17
+ @menu.items.each do |(name, menu)|
18
+ menu[:controller] = name unless menu[:controller]
19
+
20
+ # Allow an :if option which will only display the menu if true
21
+ if !menu[:if] or menu[:if].call
22
+ # If there is a :selected option, use that instead of trying to determine the selected menu item
23
+ selected = menu_selected?(name, menu[:controller], menu[:action] || menu[:actions], menu.delete(:controllers))
24
+
25
+ out << content_tag(:span, :class => selected ? "selected" : nil) do
26
+ out2 = ActiveSupport::SafeBuffer.new
27
+ out2 << link_to(I18n.t(@menu.options[:string_prefix].to_s + name.to_s), { :controller => menu.delete(:controller).to_s.absolutify, :action => (menu.delete(:action) || menu.delete(:actions).andand.first) }.merge(menu))
28
+ out2 << draw_submenu(@menu.submenus[name]) if @menu.submenus[name]
29
+ out2
30
+ end
31
+ end
32
+ end
33
+
34
+ out << '<br class="clear" />'.html_safe
35
+ out
36
+ end
37
+ end
38
+
39
+ def draw_submenu(submenu)
40
+ content_tag :table, :class => "dropdown", :cellspacing => 0 do
41
+
42
+ out = ActiveSupport::SafeBuffer.new
43
+
44
+ submenu.items.each do |(name, menu)|
45
+ out << content_tag(:tr) do
46
+ content_tag :td do
47
+ controller = menu.delete(:controller) || submenu.options[:controller]
48
+ action =
49
+ menu.delete(:action) || begin
50
+ controller_class = "#{controller}_controller".classify.constantize
51
+ controller_class.action_methods.include?(name.to_s) ? name : nil
52
+ end rescue nil || :index
53
+
54
+ link_to I18n.t(submenu.options[:string_prefix].to_s + name.to_s), { :controller => controller.to_s.absolutify, :action => action }.merge(menu)
55
+ end
56
+ end
57
+ end
58
+
59
+ out
60
+ end
61
+ end
62
+
63
+ protected
64
+ def menu_selected?(name, controller, action = nil, controllers = [])
65
+ controllers = [] unless controllers
66
+
67
+ if @menu.options[:selected]
68
+ name.to_s == @menu.options[:selected].to_s
69
+ else
70
+ return true if controllers.map(&:to_s).include?(params[:controller])
71
+
72
+ selected = params[:controller] == controller.to_s
73
+
74
+ if action.is_a? Array
75
+ selected &&= action.map(&:to_s).include?(params[:action])
76
+ elsif action
77
+ selected &&= params[:action] == action.to_s
78
+ end
79
+
80
+ selected
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ class String
88
+ def absolutify
89
+ self.gsub(%r{^(?!/)}, "/")
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module Waiter
2
+ VERSION = "0.0.1"
3
+ end
data/waiter.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'waiter/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "waiter"
8
+ gem.version = Waiter::VERSION
9
+ gem.authors = ["Daniel Vandersluis"]
10
+ gem.email = ["dvandersluis@selfmgmt.com"]
11
+ gem.description = "Provides an easy DSL for serving up menus"
12
+ gem.summary = "Quick and easy DSL for generating menus for use in Rails applications"
13
+ gem.homepage = "https://github.com/dvandersluis/waiter"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "activesupport", "> 3.0.0"
21
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: waiter
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Daniel Vandersluis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ prerelease: false
16
+ type: :runtime
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>'
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.0
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ! '>'
27
+ - !ruby/object:Gem::Version
28
+ version: 3.0.0
29
+ name: activesupport
30
+ description: Provides an easy DSL for serving up menus
31
+ email:
32
+ - dvandersluis@selfmgmt.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - lib/waiter.rb
43
+ - lib/waiter/menu.rb
44
+ - lib/waiter/menu/builder.rb
45
+ - lib/waiter/menu/drawer.rb
46
+ - lib/waiter/version.rb
47
+ - waiter.gemspec
48
+ homepage: https://github.com/dvandersluis/waiter
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.24
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Quick and easy DSL for generating menus for use in Rails applications
72
+ test_files: []
73
+ has_rdoc: