xebec 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/README.md +105 -0
- data/Rakefile +6 -0
- data/VERSION +1 -0
- data/developer_tasks/doc.rake +29 -0
- data/developer_tasks/gem.rake +34 -0
- data/developer_tasks/test.rake +20 -0
- data/doc/example_app/Gemfile +2 -0
- data/doc/example_app/README.md +9 -0
- data/doc/example_app/app/controllers/application_controller.rb +22 -0
- data/doc/example_app/app/controllers/pages_controller.rb +7 -0
- data/doc/example_app/app/controllers/projects_controller.rb +49 -0
- data/doc/example_app/app/views/layouts/_site_nav_bar.html.erb +16 -0
- data/doc/example_app/app/views/layouts/application.html.erb +15 -0
- data/doc/example_app/app/views/pages/about_us.html.erb +1 -0
- data/doc/example_app/app/views/pages/faq.html.erb +1 -0
- data/doc/example_app/app/views/pages/feedback.html.erb +1 -0
- data/doc/example_app/app/views/pages/home.html.erb +1 -0
- data/doc/example_app/app/views/pages/privacy_policy.html.erb +1 -0
- data/doc/example_app/app/views/projects/budget.html.erb +1 -0
- data/doc/example_app/app/views/projects/edit.html.erb +1 -0
- data/doc/example_app/app/views/projects/history.html.erb +1 -0
- data/doc/example_app/app/views/projects/index.html.erb +1 -0
- data/doc/example_app/app/views/projects/show.html.erb +1 -0
- data/doc/example_app/config/locales/en.yml +7 -0
- data/doc/example_app/config/routes.rb +10 -0
- data/init.rb +7 -0
- data/lib/xebec.rb +6 -0
- data/lib/xebec/controller_support.rb +77 -0
- data/lib/xebec/has_nav_bars.rb +31 -0
- data/lib/xebec/nav_bar.rb +50 -0
- data/lib/xebec/nav_bar_helper.rb +61 -0
- data/lib/xebec/nav_bar_proxy.rb +88 -0
- data/lib/xebec/nav_item.rb +21 -0
- data/rails/init.rb +3 -0
- data/tasks/README.md +3 -0
- data/test/controller_support_test.rb +47 -0
- data/test/nav_bar_helper_test.rb +62 -0
- data/test/nav_bar_proxy_test.rb +136 -0
- data/test/nav_bar_test.rb +49 -0
- data/test/test_helper.rb +49 -0
- metadata +133 -0
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
## Xebec ##
|
2
|
+
|
3
|
+
Xebec is a Gem and Rails plugin that helps you build navigation for your website.
|
4
|
+
Tired of building custom navigation code for each site?
|
5
|
+
|
6
|
+
Have you seen Ryan Heath's [Navigation Helper](http://github.com/rpheath/navigation_helper)? It's very usable, but it only does one navigation bar. I often have sites where there are many, e.g.
|
7
|
+
|
8
|
+
+-----------------------------------------------------------+
|
9
|
+
| MyApp | Home | Sign Out | FAQ | | # "site" nav bar
|
10
|
+
|===========================================================|
|
11
|
+
| | *Projects* | Friends | | # "area" nav bar
|
12
|
+
|===========================================================|
|
13
|
+
| | Project Overview | *Budget* | History | | # "tabs" nav bar
|
14
|
+
| |
|
15
|
+
| |
|
16
|
+
| Project "Foo" Budget |
|
17
|
+
| ==================== |
|
18
|
+
| ... |
|
19
|
+
+-----------------------------------------------------------+
|
20
|
+
|
21
|
+
Each navigation bar has dynamic content. The *site* one will often have a "Sign In" and "Sign Up" link when no user is signed-in, but will have a "Sign Out" link otherwise. The *area* bar will often change based on the permissions/roles of the person signed in. The *tabs* bar will certainly depend on the area and the permissions/roles, and possibly also the features of the item being viewed. (Do all projects have budgets? If the "Budget" link goes to "./budget" then it doesn't have to be generated for each project, but it might not be so easy in other cases.)
|
22
|
+
|
23
|
+
(Of course, these *site*, *area*, and *tabs* aren't the only possibilities, merely a common pattern.)
|
24
|
+
|
25
|
+
Another common pattern is to differentiate the currently-selected navigation item in each applicable bar. (The asterisks in the above display.) In the case above, it probably makes sense to leave the "Projects" *area* item as a link when browsing a specific project so the user may easily return to the projects listing page. On the other hand, the currently active *tabs* item probably doesn't need to be a link. Clicking that would be the equivalent of a refresh.
|
26
|
+
|
27
|
+
Thus, Xebec.
|
28
|
+
|
29
|
+
### Installing Xebec in a Rails Application ###
|
30
|
+
|
31
|
+
#### Add the Gem Dependency ####
|
32
|
+
|
33
|
+
If you're using Bundler, add this to your `Gemfile`:
|
34
|
+
|
35
|
+
gem "xebec"
|
36
|
+
|
37
|
+
If not, add this to `config/environment.rb`:
|
38
|
+
|
39
|
+
config.gem 'xebec'
|
40
|
+
|
41
|
+
#### Add the Helpers ####
|
42
|
+
|
43
|
+
Add this to your `ApplicationController`:
|
44
|
+
|
45
|
+
class ApplicationController < ActionController::Base
|
46
|
+
helper Xebec::NavBarHelper
|
47
|
+
end
|
48
|
+
|
49
|
+
### Rendering a Navigation Bar ###
|
50
|
+
|
51
|
+
To render a navigation bar, render `nav_bar` in your view, passing the name of the bar:
|
52
|
+
|
53
|
+
<%= nav_bar :site %>
|
54
|
+
|
55
|
+
If you want to render the navigation bar only if it contains any items, use `nav_bar_unless_empty`:
|
56
|
+
|
57
|
+
<%= nav_bar_unless_empty :area >
|
58
|
+
|
59
|
+
If you only have one navigation bar on your site, you can leave off the name, like so:
|
60
|
+
|
61
|
+
<%= nav_bar %>
|
62
|
+
|
63
|
+
Xebec will assign this navigation bar the name `:default` in case you need to refer to it elsewhere, but you probably won't.
|
64
|
+
|
65
|
+
### Populating a Navigation Bar ###
|
66
|
+
|
67
|
+
To add items to your navigation bar in a view, call `nav_bar` with a block containing any number of `nav_item` calls:
|
68
|
+
|
69
|
+
<%
|
70
|
+
nav_bar :site do |nb|
|
71
|
+
nb.nav_item :home, root_path
|
72
|
+
nb.nav_item :sign_in unless signed_in? # assumes sign_in_path
|
73
|
+
end
|
74
|
+
%>
|
75
|
+
|
76
|
+
### Highlighting the "Current" Element of a Navigation Bar ###
|
77
|
+
|
78
|
+
The `nav_bar` helper method will add the "current" class to the currently-selected item of each navigation bar. Highlighting the item requires just some basic CSS:
|
79
|
+
|
80
|
+
ul.navbar { color: green; }
|
81
|
+
ul.navbar li.current { color: purple; }
|
82
|
+
|
83
|
+
Each rendered navigation bar will include its name as a CSS class if you want to style them differently:
|
84
|
+
|
85
|
+
ul.navbar.site { color: green; }
|
86
|
+
ul.navbar.area { color: white; background-color: green; }
|
87
|
+
|
88
|
+
### Setting the "Current" Element of a Navigation Bar ###
|
89
|
+
|
90
|
+
A navigation bar will automatically set an item as selected if its URL matches the current page URL. That will work for pages like "FAQ" above, but what if you want "Projects" to be highlighted not only for the projects list page but also for any page in the "Projects" area, such as an individual project's "Budget" tab? You can manually set the *current* item in a navigation bar like so:
|
91
|
+
|
92
|
+
<% nav_bar(:area).current = :projects %>
|
93
|
+
|
94
|
+
### Example Application ###
|
95
|
+
|
96
|
+
To see the full range of features that Xebec supports, including internationalization and `before_filter`s for your controllers, check out the example application in `doc/example_app/`.
|
97
|
+
|
98
|
+
## What's a *xebec*? ##
|
99
|
+
|
100
|
+
Apple's dictionary provides the following entry:
|
101
|
+
|
102
|
+
> **xe‧bec** |ˈzēˌbek| (also **ze‧bec**)
|
103
|
+
noun historical
|
104
|
+
a small three-masted Mediterranean sailing ship with lateen and sometimes square sails.
|
105
|
+
ORIGIN mid 18th cent.: alteration (influenced by Spanish ***xabeque***) of French ***chebec***, via Italian from Arabic ***šabbāk***.
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,29 @@
|
|
1
|
+
desc "Generate RDoc"
|
2
|
+
task :doc => ['doc:generate']
|
3
|
+
|
4
|
+
namespace :doc do
|
5
|
+
project_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
6
|
+
doc_destination = File.join(project_root, 'doc', 'rdoc')
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'yard'
|
10
|
+
require 'yard/rake/yardoc_task'
|
11
|
+
|
12
|
+
YARD::Rake::YardocTask.new(:generate) do |yt|
|
13
|
+
yt.files = Dir.glob(File.join(project_root, 'lib', '**', '*.rb')) +
|
14
|
+
[ File.join(project_root, 'README.md') ]
|
15
|
+
yt.options = ['--output-dir', doc_destination, '--readme', 'README.md']
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
desc "Generate YARD Documentation"
|
19
|
+
task :generate do
|
20
|
+
abort "Please install the YARD gem to generate rdoc."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Remove generated documenation"
|
25
|
+
task :clean do
|
26
|
+
rm_r doc_dir if File.exists?(doc_destination)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
namespace :gem do
|
2
|
+
begin
|
3
|
+
require 'jeweler'
|
4
|
+
Jeweler::Tasks.new do |gemspec|
|
5
|
+
gemspec.name = "xebec"
|
6
|
+
gemspec.summary = "Navigation helpers"
|
7
|
+
gemspec.description = "Helpers for generating navigation bars"
|
8
|
+
gemspec.email = "james.a.rosen@gmail.com"
|
9
|
+
gemspec.homepage = "http://github.com/jamesarosen/xebec"
|
10
|
+
gemspec.authors = ["James Rosen"]
|
11
|
+
gemspec.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Xebec Documentation", "--charset", "utf-8"]
|
12
|
+
gemspec.platform = Gem::Platform::RUBY
|
13
|
+
gemspec.add_development_dependency 'shoulda', '~> 2.10.3'
|
14
|
+
gemspec.add_development_dependency 'mocha', '~> 0.9.8'
|
15
|
+
gemspec.add_development_dependency 'redgreen', '~> 1.2.2'
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler not available. Install it with [sudo] gem install jeweler -s http://gemscutter.org"
|
19
|
+
end
|
20
|
+
|
21
|
+
task :push do
|
22
|
+
command = ('gem push')
|
23
|
+
command << " -p $#{ENV['http_proxy']}" if ENV['http_proxy']
|
24
|
+
command << " #{latest_gem}"
|
25
|
+
puts "Pushing gem..."
|
26
|
+
IO.popen(command) { |io| io.each { |line| puts ' ' + line } }
|
27
|
+
end
|
28
|
+
|
29
|
+
def latest_gem
|
30
|
+
result = File.expand_path(Dir.glob(File.join(File.dirname(__FILE__), '..', 'pkg', '*.gem')).sort.last)
|
31
|
+
abort "No gems found in pkg/. Did you run gem:build?" if result.nil?
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
project_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
4
|
+
|
5
|
+
lib_directories = FileList.new do |fl|
|
6
|
+
fl.include "#{project_root}/lib"
|
7
|
+
fl.include "#{project_root}/test/lib"
|
8
|
+
end
|
9
|
+
|
10
|
+
test_files = FileList.new do |fl|
|
11
|
+
fl.include "#{project_root}/test/**/*_test.rb"
|
12
|
+
fl.exclude "#{project_root}/test/test_helper.rb"
|
13
|
+
fl.exclude "#{project_root}/test/lib/**/*.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
Rake::TestTask.new(:test) do |t|
|
17
|
+
t.libs = lib_directories
|
18
|
+
t.test_files = test_files
|
19
|
+
t.verbose = true
|
20
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
This is an example Rails application that shows off the features of Xebec. Things to check out:
|
2
|
+
|
3
|
+
* declaring the Xebec dependency in your [Gemfile](./Gemfile)
|
4
|
+
* adding the Xebec helpers in your [ApplicationController](./app/controllers/application_controller.rb)
|
5
|
+
* how to render navigation bars in your [layout](./app/views/layouts/application.html.erb)
|
6
|
+
* how to declare and populate a navigation bar in a [view](./app/views/layouts/_site_nav_bar.html.erb)
|
7
|
+
* how to declare and populate a navigation bar in a [controller](./app/controllers/application_controller.rb)
|
8
|
+
* how to declare and populate a navigation bar in an [action](./app/controllers/projects_controller.rb)
|
9
|
+
* how to change the text that is displayed for a navigation item using [i18n](./config/locales/en.yml)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ApplicationController < ActionController::Base
|
2
|
+
|
3
|
+
# Add Xebec's view helper methods:
|
4
|
+
helper Xebec::NavBarHelper
|
5
|
+
|
6
|
+
# If you prefer to declare your navigation in your
|
7
|
+
# controllers, start by including Xebec's controller support:
|
8
|
+
include Xebec::ControllerSupport
|
9
|
+
|
10
|
+
# then declare and populate some navigation bars:
|
11
|
+
nav_bar :area do |nb|
|
12
|
+
nb.nav_item :projects # assumes projects_path
|
13
|
+
end
|
14
|
+
|
15
|
+
nav_bar :footer do |nb|
|
16
|
+
nb.nav_item :about_us, page_path(:about_us)
|
17
|
+
nb.nav_item :faq, page_path(:faq)
|
18
|
+
nb.nav_item :feedback, page_path(:feedback)
|
19
|
+
nb.nav_item :privacy_policy, page_path(:privacy_policy)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class ProjectsController < ApplicationController
|
2
|
+
|
3
|
+
# set the selected item for the :area navigation bar
|
4
|
+
# for all actions in this controller:
|
5
|
+
nav_bar :area { |nb| nb.selected = :projects }
|
6
|
+
|
7
|
+
def index
|
8
|
+
params[:sort] ||= 'recent'
|
9
|
+
# set up tabs for the project-list view:
|
10
|
+
nav_bar(:tabs) do |nb|
|
11
|
+
nb.nav_item :by_alpha, projects_path(:sort => 'by_alpha')
|
12
|
+
nb.nav_item :recent, projects_path(:sort => 'recent')
|
13
|
+
nb.selected = params[:sort]
|
14
|
+
end
|
15
|
+
@projects = Project.ordered_by(params[:sort])
|
16
|
+
end
|
17
|
+
|
18
|
+
def show(selected_tab = :overview)
|
19
|
+
@project = Project.find(params[:id])
|
20
|
+
prepare_project_tabs selected_tab
|
21
|
+
end
|
22
|
+
|
23
|
+
def budget
|
24
|
+
show :budget
|
25
|
+
end
|
26
|
+
|
27
|
+
def history
|
28
|
+
show :history
|
29
|
+
end
|
30
|
+
|
31
|
+
def edit
|
32
|
+
show :edit
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
# Extract navigation bar setup that is common to
|
38
|
+
# multiple methods:
|
39
|
+
def prepare_project_tabs(selected)
|
40
|
+
nav_bar(:tabs) do |nb|
|
41
|
+
nb.nav_item :overview, project_path(@project)
|
42
|
+
nb.nav_item :budget, budget_project_path(@project)
|
43
|
+
nb.nav_item :history, history_project_path(@project)
|
44
|
+
nb.nav_item :edit, edit_project_path(@project)
|
45
|
+
nb.selected = selected
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%=
|
2
|
+
# If you want to keep your navigation code in your views, you might
|
3
|
+
# want to use partials like this one. Notice that this tag is an
|
4
|
+
# "output" tag (%= as opposed to %). That means that the
|
5
|
+
# navigation bar will be rendered as an HTML list here. If you want to
|
6
|
+
# modify a navigation bar in a view without rendering it, use a
|
7
|
+
# non-outputting tag.
|
8
|
+
nav_bar :site do |nb|
|
9
|
+
nb.nav_item :home, root_path
|
10
|
+
nb.nav_item :sign_in unless signed_in?
|
11
|
+
nb.nav_item :sign_up unless signed_in?
|
12
|
+
nb.nav_item :sign_out if signed_in?
|
13
|
+
nb.nav_item :profile, edit_user_path(current_user) if signed_in?
|
14
|
+
nb.nav_item :company, 'http://example.com'
|
15
|
+
end
|
16
|
+
%>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<body>
|
2
|
+
<div id='header'>
|
3
|
+
<h1>My Site</h1>
|
4
|
+
<%= render :partial => '/layouts/site_nav_bar' %>
|
5
|
+
</div>
|
6
|
+
<%= nav_bar_unless_empty :area %>
|
7
|
+
<div id='content'>
|
8
|
+
<%= nav_bar_unless_empty :tabs %>
|
9
|
+
<%= yield %>
|
10
|
+
</div>
|
11
|
+
<div id='footer'>
|
12
|
+
© 2293 My Happy Company
|
13
|
+
<%= nav_bar :footer %>
|
14
|
+
</div>
|
15
|
+
</body>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>About Us</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Frequently Asked Questions</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Feedback</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Welcome!</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Privacy Policy</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Project Budget</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Edit Project</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Project History</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Projects</h2>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h2>Project Overview</h2>
|
data/init.rb
ADDED
data/lib/xebec.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'xebec/has_nav_bars'
|
2
|
+
|
3
|
+
module Xebec
|
4
|
+
|
5
|
+
# Include this module in Rails controllers if you want to declare
|
6
|
+
# navigation bars in your controllers instead of or in addition to
|
7
|
+
# in your views.
|
8
|
+
module ControllerSupport
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.extend Xebec::ControllerSupport::ClassMethods
|
12
|
+
base.send :include, Xebec::ControllerSupport::InstanceMethods
|
13
|
+
base.send :include, Xebec::HasNavBars
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
# Declare and populate a navigation bar. This method
|
19
|
+
# is a shorthand for creating a +before_filter+ that looks
|
20
|
+
# up and populates a navigation bar.
|
21
|
+
#
|
22
|
+
# @param [String, Symbol] name the name of the navigation bar;
|
23
|
+
# optional
|
24
|
+
#
|
25
|
+
# @param [Hash] options the options for the +before_filter+;
|
26
|
+
# optional.
|
27
|
+
#
|
28
|
+
# @yield [Xebec::NavBar] nav_bar the navigation bar -- NB: does
|
29
|
+
# NOT yield at call-time, but at action
|
30
|
+
# run-time, as a before filter. The block
|
31
|
+
# is evaluated in the scope of the controller
|
32
|
+
# instance.
|
33
|
+
#
|
34
|
+
# @return [nil]
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# nav_bar :tabs, :only => [:index, :sent, :received, :new] do |nb|
|
38
|
+
# nb.nav_item :received, received_messages_path(current_user)
|
39
|
+
# nb.nav_item :sent, sent_messages_path(current_user)
|
40
|
+
# nb.nav_item :new, new_message_path
|
41
|
+
# end
|
42
|
+
def nav_bar(name = Xebec::NavBar::DEFAULT_NAME, options = {}, &block)
|
43
|
+
append_before_filter options do
|
44
|
+
nav_bar name, &block
|
45
|
+
end
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
module InstanceMethods
|
52
|
+
|
53
|
+
# Declare and populate a navigation bar.
|
54
|
+
#
|
55
|
+
# @param [String, Symbol] name the name of the navigation bar
|
56
|
+
#
|
57
|
+
# @yield [Xebec::NavBar] nav_bar the navigation bar. The block
|
58
|
+
# is evaluated in the scope of the
|
59
|
+
# controller instance.
|
60
|
+
#
|
61
|
+
# @return [Xebec::NavBar]
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# nav_bar :tabs do |nb|
|
65
|
+
# nb.nav_item :overview, @project
|
66
|
+
# nb.nav_item :budget, project_budget_path(@project)
|
67
|
+
# nb.nav_item :edit, edit_project_path(@project)
|
68
|
+
# end
|
69
|
+
def nav_bar(name = Xebec::NavBar::DEFAULT_NAME, &block)
|
70
|
+
look_up_nav_bar_and_eval name, &block
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'xebec/nav_bar'
|
2
|
+
|
3
|
+
module Xebec
|
4
|
+
|
5
|
+
# A supporting mixin for NavBarHelper and ControllerSupport.
|
6
|
+
# Looks up navigation bars by name.
|
7
|
+
module HasNavBars #:nodoc:
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
# Looks up the named nav bar, creates it if it
|
12
|
+
# doesn't exist, and evaluates the the block, if
|
13
|
+
# given, in the scope of +self+, yielding the nav bar.
|
14
|
+
def look_up_nav_bar_and_eval(name = nil, &block)
|
15
|
+
name ||= Xebec::NavBar::DEFAULT_NAME
|
16
|
+
look_up_nav_bar(name).tap do |bar|
|
17
|
+
block.bind(self).call(bar) if block_given?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def look_up_nav_bar(name)
|
22
|
+
nav_bars[name] ||= NavBar.new(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def nav_bars
|
26
|
+
@nav_bars ||= {}
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'xebec/nav_item'
|
2
|
+
|
3
|
+
module Xebec
|
4
|
+
|
5
|
+
class NavBar
|
6
|
+
|
7
|
+
DEFAULT_NAME = :default
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :items
|
11
|
+
attr_accessor :current
|
12
|
+
|
13
|
+
# Create a new NavBar object.
|
14
|
+
#
|
15
|
+
# @param [String] name the name of the navigation bar; defaults to :default
|
16
|
+
def initialize(name = nil)
|
17
|
+
@name = name || DEFAULT_NAME
|
18
|
+
@items = []
|
19
|
+
@current = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# Add a navigation item to this bar.
|
23
|
+
#
|
24
|
+
# @param [String, Symbol] name the name of the item
|
25
|
+
# @param [String, Proc] href the URL of the item; optional
|
26
|
+
#
|
27
|
+
# To customize the link text, set the internationalization key
|
28
|
+
# <tt>navbar.{{nav bar name}}.{{nav item name}}</tt>.
|
29
|
+
#
|
30
|
+
# @see Xebec::NavBarHelper#nav_bar
|
31
|
+
# @see Xebec::NavBarProxy#to_s
|
32
|
+
def nav_item(name, href = nil)
|
33
|
+
items << Xebec::NavItem.new(name, href)
|
34
|
+
end
|
35
|
+
|
36
|
+
def empty?
|
37
|
+
items.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
"<NavBar #{name}>"
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'xebec/nav_bar'
|
2
|
+
require 'xebec/nav_bar_proxy'
|
3
|
+
require 'xebec/has_nav_bars'
|
4
|
+
|
5
|
+
module Xebec
|
6
|
+
|
7
|
+
module NavBarHelper
|
8
|
+
|
9
|
+
include Xebec::HasNavBars
|
10
|
+
|
11
|
+
# If called in an output expression ("<%= navbar %>" in ERB
|
12
|
+
# or "=navbar" in HAML), renders the navigation bar.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# <%= navbar :tabs%>
|
16
|
+
# # => <ul class="navbar tabs">...</ul>
|
17
|
+
#
|
18
|
+
# @see Xebec::NavBarProxy#to_s
|
19
|
+
#
|
20
|
+
# If called with a block, yields the underlying NavBar for
|
21
|
+
# modification.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# <% navbar do |nb|
|
25
|
+
# nb.nav_item :home
|
26
|
+
# nb.nav_item :faq, pages_path(:page => :faq)
|
27
|
+
# end %>
|
28
|
+
#
|
29
|
+
# @see Xebec::NavBar#nav_item
|
30
|
+
# @see Xebec::HasNavBars#nav_bar
|
31
|
+
#
|
32
|
+
# @return [Xebec::NavBarProxy]
|
33
|
+
def nav_bar(name = nil, &block)
|
34
|
+
look_up_nav_bar_and_eval name, &block
|
35
|
+
end
|
36
|
+
|
37
|
+
# Renders a navigation bar if and only if it contains any
|
38
|
+
# navigation items. Unlike +nav_bar+, this method does not
|
39
|
+
# accept a block.
|
40
|
+
#
|
41
|
+
# @return [String, Xebec::NavBarProxy]
|
42
|
+
def nav_bar_unless_empty(name = nil)
|
43
|
+
bar = look_up_nav_bar name
|
44
|
+
bar.empty? ? '' : bar
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
# Override HasNavBars#look_up_nav_bar to replace with a
|
50
|
+
# proxy if necessary.
|
51
|
+
def look_up_nav_bar(name)
|
52
|
+
bar = super(name)
|
53
|
+
if bar.kind_of?(Xebec::NavBar)
|
54
|
+
bar = nav_bars[bar.name] = NavBarProxy.new(bar, self)
|
55
|
+
end
|
56
|
+
bar
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'xebec/nav_bar'
|
2
|
+
|
3
|
+
module Xebec
|
4
|
+
|
5
|
+
# A proxy for a Xebec::NavBar that knows how to turn the NavBar
|
6
|
+
# into an HTML list using ActionView helper methods.
|
7
|
+
class NavBarProxy
|
8
|
+
|
9
|
+
# Create a new NavBar proxy object. The proxy will pass all
|
10
|
+
# methods on to the NavBar except for +to_s+, which will
|
11
|
+
# render the NavBar as an HTML list.
|
12
|
+
#
|
13
|
+
# @param [Xebec::NavBar] bar the navigation bar to proxy
|
14
|
+
# @param [#tag AND #content_tag AND #link_to] helper the ActionView helper
|
15
|
+
def initialize(bar, helper)
|
16
|
+
raise ArgumentError.new("#{bar || '<nil>'} is not a NavBar") unless bar.kind_of?(NavBar)
|
17
|
+
raise ArgumentError.new("#{helper || '<nil>'} does not seem to be a view helper") unless
|
18
|
+
helper.respond_to?(:content_tag) && helper.respond_to?(:link_to_unless_current)
|
19
|
+
@bar, @helper = bar, helper
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [String] the proxied navigation bar as an HTML list.
|
23
|
+
#
|
24
|
+
# The HREF for each navigation item is generated as follows:
|
25
|
+
#
|
26
|
+
# * if the item was declared with a link
|
27
|
+
# (e.g. <tt>nav_item :faq, page_path(:page => :faq)</tt>),
|
28
|
+
# use that link
|
29
|
+
# * else, try to use the route named after the navigation item
|
30
|
+
# (e.g. <tt>nav_item :home</tt> uses <tt>home_path</tt>)
|
31
|
+
#
|
32
|
+
# The link text for each navigation is generated as follows:
|
33
|
+
#
|
34
|
+
# * if the internationalization key
|
35
|
+
# <tt>navbar.{{nav bar name}}.{{nav item name}}</tt> is
|
36
|
+
# defined, use that value
|
37
|
+
# * else, use <tt>nav_item.name.titleize</tt>
|
38
|
+
def to_s
|
39
|
+
klass = "navbar #{bar.name}"
|
40
|
+
if bar.empty?
|
41
|
+
helper.tag(:ul, { :class => klass }, false)
|
42
|
+
else
|
43
|
+
helper.content_tag :ul, { :class => klass } do
|
44
|
+
bar.items.map do |item|
|
45
|
+
render_nav_item item
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def respond_to?(sym)
|
52
|
+
return true if bar.respond_to?(sym)
|
53
|
+
super
|
54
|
+
end
|
55
|
+
|
56
|
+
def method_missing(sym, *args, &block)
|
57
|
+
return bar.send(sym, *args, &block) if bar.respond_to?(sym)
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
attr_reader :bar, :helper
|
64
|
+
|
65
|
+
def render_nav_item(item)
|
66
|
+
text = text_for_nav_item item
|
67
|
+
href = href_for_nav_item item
|
68
|
+
klass = is_current_nav_item?(item, href) ? 'current' : ''
|
69
|
+
helper.content_tag :li, :class => klass do
|
70
|
+
helper.link_to_unless_current text, href
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def text_for_nav_item(item)
|
75
|
+
I18n.t "navbar.#{bar.name}.#{item.name}", :default => item.name.to_s.titleize
|
76
|
+
end
|
77
|
+
|
78
|
+
def href_for_nav_item(item)
|
79
|
+
item.href or helper.send("#{item.name}_path")
|
80
|
+
end
|
81
|
+
|
82
|
+
def is_current_nav_item?(item, href)
|
83
|
+
bar.current == item.name || bar.current.blank? && helper.current_page?(href)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Xebec
|
2
|
+
|
3
|
+
class NavItem
|
4
|
+
|
5
|
+
attr_reader :name, :href
|
6
|
+
|
7
|
+
# Create a new navigation item.
|
8
|
+
#
|
9
|
+
# @param [String, Symbol] name the name of the item
|
10
|
+
# @param [String, Hash, ActiveRecord::Base] href whither the navigation item links;
|
11
|
+
# defaults to the named route, "#{name}_path"
|
12
|
+
#
|
13
|
+
# @see ActionView::Helpers::UrlHelper#url_for
|
14
|
+
def initialize(name, href = nil)
|
15
|
+
raise ArgumentError.new("#{name || '<nil>'} is not a valid name for a navigation item") if name.blank?
|
16
|
+
@name, @href = name, href
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/rails/init.rb
ADDED
data/tasks/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require 'xebec'
|
3
|
+
|
4
|
+
class ControllerSupportTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@controller_class = Class.new(ActionController::Base).tap do |c|
|
8
|
+
c.instance_eval do
|
9
|
+
include Xebec::ControllerSupport
|
10
|
+
def public_nav_bar(*args, &block)
|
11
|
+
nav_bar(*args, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
@controller = @controller_class.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def call_before_filters
|
19
|
+
@controller_class.before_filters.each do |filter|
|
20
|
+
filter.bind(@controller).call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'ControllerSupport::ClassMethods#nav_bar' do
|
25
|
+
|
26
|
+
should 'append a before_filter that looks up the named navigation bar' do
|
27
|
+
@controller_class.public_nav_bar :turtles
|
28
|
+
@controller.expects(:nav_bar).with(:turtles)
|
29
|
+
call_before_filters
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'append a before_filter with the given options' do
|
33
|
+
options = { :only => :show }
|
34
|
+
@controller_class.expects(:append_before_filter).with(options)
|
35
|
+
@controller_class.public_nav_bar :foo, options
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'append a before_filter that passes the given block to the named nav bar instance' do
|
39
|
+
@controller_class.public_nav_bar(:baz) { |nb| nb.nav_item :help }
|
40
|
+
bar = @controller.nav_bar :baz
|
41
|
+
bar.expects(:nav_item).with(:help)
|
42
|
+
call_before_filters
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require 'xebec'
|
3
|
+
|
4
|
+
class NavBarHelperTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context 'NavBarHelper#nav_bar' do
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@helper = new_nav_bar_helper
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'return a NavBar proxy' do
|
13
|
+
assert @helper.nav_bar.kind_of?(Xebec::NavBarProxy)
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'return a NavBar with the given name' do
|
17
|
+
assert_equal :snacks, @helper.nav_bar(:snacks).name
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'return the same NavBar for repeated calls with the same name' do
|
21
|
+
snacks = @helper.nav_bar(:snacks)
|
22
|
+
assert_equal snacks, @helper.nav_bar(:snacks)
|
23
|
+
end
|
24
|
+
|
25
|
+
should "evaluate a block in the helper's scope" do
|
26
|
+
@helper.expects(:zoink!)
|
27
|
+
@helper.nav_bar do
|
28
|
+
zoink!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
should "yield the NavBar proxy to the given block" do
|
33
|
+
bar = @helper.nav_bar
|
34
|
+
bar.expects :zoink!
|
35
|
+
@helper.nav_bar do |nb|
|
36
|
+
nb.zoink!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'NavBarHelper#nav_bar_unless_empty' do
|
43
|
+
setup do
|
44
|
+
@helper = new_nav_bar_helper
|
45
|
+
@bar = @helper.nav_bar(:pets)
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with an empty navigation bar' do
|
49
|
+
should 'return an empty String' do
|
50
|
+
assert @helper.nav_bar_unless_empty(:pets).blank?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with a non-empty navigation bar' do
|
55
|
+
setup { @bar.nav_item :cats, '/cats' }
|
56
|
+
should 'return a navigation bar' do
|
57
|
+
assert !@helper.nav_bar_unless_empty(:pets).blank?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require 'xebec'
|
3
|
+
|
4
|
+
class NavBarProxyTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context 'creating a NavBar proxy' do
|
7
|
+
should 'require a NavBar' do
|
8
|
+
assert_raises(ArgumentError) do
|
9
|
+
Xebec::NavBarProxy.new('foobar', new_nav_bar_helper)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
should 'require a NavBarHelper' do
|
13
|
+
assert_raises(ArgumentError) do
|
14
|
+
Xebec::NavBarProxy.new(Xebec::NavBar.new, 'baz')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'a NavBar proxy' do
|
20
|
+
|
21
|
+
setup do
|
22
|
+
clear_translations!
|
23
|
+
@bar = Xebec::NavBar.new('elephants')
|
24
|
+
@helper = new_nav_bar_helper
|
25
|
+
@proxy = Xebec::NavBarProxy.new(@bar, @helper)
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'respond to :name' do
|
29
|
+
assert @proxy.respond_to?(:name)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "return the NavBar's name when sent :name" do
|
33
|
+
assert_equal 'elephants', @proxy.name
|
34
|
+
end
|
35
|
+
|
36
|
+
should 'not respond to a method that the underlying NavBar does not' do
|
37
|
+
assert !@proxy.respond_to?(:cromulize)
|
38
|
+
end
|
39
|
+
|
40
|
+
should "render a navigation bar with the class 'navbar' and the bar's name" do
|
41
|
+
assert_select_from @proxy.to_s, "ul.navbar.elephants"
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with an empty NavBar' do
|
45
|
+
|
46
|
+
should 'render an empty navigation bar' do
|
47
|
+
assert_select_from @proxy.to_s, 'ul.navbar', /$^/
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'with a NavBar that has a navigation item declared as a name' do
|
53
|
+
setup do
|
54
|
+
@helper.stubs(:foo_path).returns("/foo")
|
55
|
+
@bar.nav_item :foo
|
56
|
+
end
|
57
|
+
should 'render a navigation bar with the appropriate items' do
|
58
|
+
assert_select_from @proxy.to_s, 'ul.navbar' do
|
59
|
+
assert_select 'li' do
|
60
|
+
assert_select 'a[href="/foo"]', 'Foo'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'with a NavBar that has a navigation item set as current' do
|
67
|
+
setup do
|
68
|
+
@bar.nav_item :foo, '/foo'
|
69
|
+
@bar.current = :foo
|
70
|
+
end
|
71
|
+
should 'render a navigation bar with the item marked as current' do
|
72
|
+
assert_select_from @proxy.to_s, 'ul.navbar' do
|
73
|
+
assert_select 'li.current', 'Foo'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
context 'with a NavBar that has a navigation item declared as a name and URL' do
|
80
|
+
setup do
|
81
|
+
@bar.nav_item :foo, 'http://foo.com'
|
82
|
+
end
|
83
|
+
should 'render a navigation bar with the appropriate items' do
|
84
|
+
assert_select_from @proxy.to_s, 'ul.navbar' do
|
85
|
+
assert_select 'li' do
|
86
|
+
assert_select 'a[href="http://foo.com"]', 'Foo'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with a NavBar that has a navigation item that links to the current page' do
|
93
|
+
setup do
|
94
|
+
@helper.stubs(:current_page?).with('/').returns(true)
|
95
|
+
@bar.nav_item :home, '/'
|
96
|
+
@bar.nav_item :sign_up, '/sign_up'
|
97
|
+
end
|
98
|
+
should 'render a non-link navigation item' do
|
99
|
+
assert_select_from @proxy.to_s, 'ul.navbar' do
|
100
|
+
assert_select 'li', 'Home' do
|
101
|
+
assert_select 'a', 0
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
should 'render other items as links' do
|
106
|
+
assert_select_from @proxy.to_s, 'ul.navbar' do
|
107
|
+
assert_select 'li' do
|
108
|
+
assert_select 'a[href="/sign_up"]', 'Sign Up'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
should 'add the "current" class to the current item' do
|
113
|
+
assert_select_from @proxy.to_s, 'ul.navbar' do
|
114
|
+
assert_select 'li.current', 'Home'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "with a NavBar that has a navigation item with an i18n'd title" do
|
120
|
+
setup do
|
121
|
+
define_translation 'navbar.elephants.foo', 'My Foos'
|
122
|
+
@helper.stubs(:foo_path).returns("/foo")
|
123
|
+
@bar.nav_item :foo
|
124
|
+
end
|
125
|
+
should 'render a navigation bar using the internationalized text' do
|
126
|
+
assert_select_from @proxy.to_s, 'ul.navbar' do
|
127
|
+
assert_select 'li' do
|
128
|
+
assert_select 'a', 'My Foos'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
require 'xebec'
|
3
|
+
|
4
|
+
class NavBarTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context 'a NavBar' do
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@bar = Xebec::NavBar.new
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'use :default as its name by default' do
|
13
|
+
assert_equal :default, @bar.name
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'use a specified name' do
|
17
|
+
assert_equal 'fazbot', Xebec::NavBar.new('fazbot').name
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'be empty by default' do
|
21
|
+
assert @bar.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'not have any item specified as current by default' do
|
25
|
+
assert @bar.current.blank?
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with some items' do
|
29
|
+
setup do
|
30
|
+
@bar.nav_item :foo
|
31
|
+
@bar.nav_item :bar
|
32
|
+
end
|
33
|
+
should 'not be empty' do
|
34
|
+
assert !@bar.empty?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'not allow a nameless item to be added' do
|
39
|
+
assert_raises ArgumentError do
|
40
|
+
@bar.nav_item nil
|
41
|
+
end
|
42
|
+
assert_raises ArgumentError do
|
43
|
+
@bar.nav_item ''
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/testcase'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'shoulda'
|
5
|
+
require 'mocha'
|
6
|
+
require 'activesupport'
|
7
|
+
require 'actionpack'
|
8
|
+
require 'action_view'
|
9
|
+
require 'action_controller'
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'redgreen/unicode'
|
13
|
+
rescue
|
14
|
+
require 'redgreen'
|
15
|
+
end
|
16
|
+
|
17
|
+
[['..', 'lib'], ['lib']].each do |lib_dir|
|
18
|
+
lib_path = File.expand_path(File.join(File.dirname(__FILE__), *lib_dir))
|
19
|
+
$: << lib_path unless $:.include?(lib_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'xebec'
|
23
|
+
|
24
|
+
Test::Unit::TestCase.class_eval do
|
25
|
+
include ActionController::Assertions::SelectorAssertions
|
26
|
+
|
27
|
+
def assert_select_from(text, *args, &block)
|
28
|
+
@selected = HTML::Document.new(text).root.children
|
29
|
+
assert_select(*args, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def new_nav_bar_helper
|
33
|
+
ActionView::Base.new.tap do |helper|
|
34
|
+
helper.extend Xebec::NavBarHelper
|
35
|
+
helper.stubs(:current_page?).returns(false)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear_translations!
|
40
|
+
I18n.reload!
|
41
|
+
end
|
42
|
+
|
43
|
+
def define_translation(key, value)
|
44
|
+
hash = key.to_s.split('.').reverse.inject(value) do |value, key_part|
|
45
|
+
{ key_part.to_sym => value }
|
46
|
+
end
|
47
|
+
I18n.backend.send :merge_translations, I18n.locale, hash
|
48
|
+
end
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xebec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Rosen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-04 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.10.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: mocha
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.8
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: redgreen
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.2
|
44
|
+
version:
|
45
|
+
description: Helpers for generating navigation bars
|
46
|
+
email: james.a.rosen@gmail.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.md
|
53
|
+
files:
|
54
|
+
- .gitignore
|
55
|
+
- README.md
|
56
|
+
- Rakefile
|
57
|
+
- VERSION
|
58
|
+
- developer_tasks/doc.rake
|
59
|
+
- developer_tasks/gem.rake
|
60
|
+
- developer_tasks/test.rake
|
61
|
+
- doc/example_app/Gemfile
|
62
|
+
- doc/example_app/README.md
|
63
|
+
- doc/example_app/app/controllers/application_controller.rb
|
64
|
+
- doc/example_app/app/controllers/pages_controller.rb
|
65
|
+
- doc/example_app/app/controllers/projects_controller.rb
|
66
|
+
- doc/example_app/app/views/layouts/_site_nav_bar.html.erb
|
67
|
+
- doc/example_app/app/views/layouts/application.html.erb
|
68
|
+
- doc/example_app/app/views/pages/about_us.html.erb
|
69
|
+
- doc/example_app/app/views/pages/faq.html.erb
|
70
|
+
- doc/example_app/app/views/pages/feedback.html.erb
|
71
|
+
- doc/example_app/app/views/pages/home.html.erb
|
72
|
+
- doc/example_app/app/views/pages/privacy_policy.html.erb
|
73
|
+
- doc/example_app/app/views/projects/budget.html.erb
|
74
|
+
- doc/example_app/app/views/projects/edit.html.erb
|
75
|
+
- doc/example_app/app/views/projects/history.html.erb
|
76
|
+
- doc/example_app/app/views/projects/index.html.erb
|
77
|
+
- doc/example_app/app/views/projects/show.html.erb
|
78
|
+
- doc/example_app/config/locales/en.yml
|
79
|
+
- doc/example_app/config/routes.rb
|
80
|
+
- init.rb
|
81
|
+
- lib/xebec.rb
|
82
|
+
- lib/xebec/controller_support.rb
|
83
|
+
- lib/xebec/has_nav_bars.rb
|
84
|
+
- lib/xebec/nav_bar.rb
|
85
|
+
- lib/xebec/nav_bar_helper.rb
|
86
|
+
- lib/xebec/nav_bar_proxy.rb
|
87
|
+
- lib/xebec/nav_item.rb
|
88
|
+
- rails/init.rb
|
89
|
+
- tasks/README.md
|
90
|
+
- test/controller_support_test.rb
|
91
|
+
- test/nav_bar_helper_test.rb
|
92
|
+
- test/nav_bar_proxy_test.rb
|
93
|
+
- test/nav_bar_test.rb
|
94
|
+
- test/test_helper.rb
|
95
|
+
has_rdoc: true
|
96
|
+
homepage: http://github.com/jamesarosen/xebec
|
97
|
+
licenses: []
|
98
|
+
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options:
|
101
|
+
- --line-numbers
|
102
|
+
- --inline-source
|
103
|
+
- --title
|
104
|
+
- Xebec Documentation
|
105
|
+
- --charset
|
106
|
+
- utf-8
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
version:
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: "0"
|
120
|
+
version:
|
121
|
+
requirements: []
|
122
|
+
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 1.3.5
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Navigation helpers
|
128
|
+
test_files:
|
129
|
+
- test/controller_support_test.rb
|
130
|
+
- test/nav_bar_helper_test.rb
|
131
|
+
- test/nav_bar_proxy_test.rb
|
132
|
+
- test/nav_bar_test.rb
|
133
|
+
- test/test_helper.rb
|