backstack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +38 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/art/bowling_pins.graffle +0 -0
- data/backstack.gemspec +127 -0
- data/lib/backstack.rb +161 -0
- data/lib/backstacklib.rb +115 -0
- data/test/neutral/helper.rb +27 -0
- data/test/neutral/test_backstacklib.rb +181 -0
- data/test/rails_root/.gitignore +4 -0
- data/test/rails_root/Gemfile +33 -0
- data/test/rails_root/Gemfile.lock +77 -0
- data/test/rails_root/README +256 -0
- data/test/rails_root/Rakefile +12 -0
- data/test/rails_root/app/controllers/application_controller.rb +7 -0
- data/test/rails_root/app/controllers/c1_controller.rb +8 -0
- data/test/rails_root/app/controllers/c2_controller.rb +11 -0
- data/test/rails_root/app/controllers/c3_controller.rb +17 -0
- data/test/rails_root/app/controllers/c4_controller.rb +22 -0
- data/test/rails_root/app/helpers/application_helper.rb +2 -0
- data/test/rails_root/app/helpers/c1_helper.rb +2 -0
- data/test/rails_root/app/helpers/c2_helper.rb +2 -0
- data/test/rails_root/app/helpers/c3_helper.rb +2 -0
- data/test/rails_root/app/helpers/c4_helper.rb +2 -0
- data/test/rails_root/app/views/c1/a.html.erb +1 -0
- data/test/rails_root/app/views/c2/b.html.erb +1 -0
- data/test/rails_root/app/views/c2/c.html.erb +1 -0
- data/test/rails_root/app/views/c3/d.html.erb +1 -0
- data/test/rails_root/app/views/c3/e.html.erb +1 -0
- data/test/rails_root/app/views/c3/f.html.erb +1 -0
- data/test/rails_root/app/views/c4/g.html.erb +1 -0
- data/test/rails_root/app/views/c4/h.html.erb +1 -0
- data/test/rails_root/app/views/c4/i.html.erb +1 -0
- data/test/rails_root/app/views/c4/j.html.erb +1 -0
- data/test/rails_root/app/views/layouts/_pins.html.erb +64 -0
- data/test/rails_root/app/views/layouts/application.html.erb +15 -0
- data/test/rails_root/config/application.rb +47 -0
- data/test/rails_root/config/boot.rb +6 -0
- data/test/rails_root/config/environment.rb +5 -0
- data/test/rails_root/config/environments/development.rb +26 -0
- data/test/rails_root/config/environments/production.rb +49 -0
- data/test/rails_root/config/environments/test.rb +35 -0
- data/test/rails_root/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_root/config/initializers/inflections.rb +10 -0
- data/test/rails_root/config/initializers/mime_types.rb +5 -0
- data/test/rails_root/config/initializers/secret_token.rb +7 -0
- data/test/rails_root/config/initializers/session_store.rb +8 -0
- data/test/rails_root/config/locales/en.yml +5 -0
- data/test/rails_root/config/routes.rb +15 -0
- data/test/rails_root/config.ru +4 -0
- data/test/rails_root/db/seeds.rb +7 -0
- data/test/rails_root/lib/tasks/.gitkeep +0 -0
- data/test/rails_root/public/404.html +26 -0
- data/test/rails_root/public/422.html +26 -0
- data/test/rails_root/public/500.html +26 -0
- data/test/rails_root/public/favicon.ico +0 -0
- data/test/rails_root/public/images/rails.png +0 -0
- data/test/rails_root/public/javascripts/.gitkeep +0 -0
- data/test/rails_root/public/javascripts/application.js +0 -0
- data/test/rails_root/public/robots.txt +5 -0
- data/test/rails_root/public/stylesheets/.gitkeep +0 -0
- data/test/rails_root/public/stylesheets/application.css +27 -0
- data/test/rails_root/script/rails +6 -0
- data/test/rails_root/test/functional/c1_controller_test.rb +10 -0
- data/test/rails_root/test/functional/c2_controller_test.rb +15 -0
- data/test/rails_root/test/functional/c3_controller_test.rb +20 -0
- data/test/rails_root/test/functional/c4_controller_test.rb +24 -0
- data/test/rails_root/test/integration/backstack_test.rb +96 -0
- data/test/rails_root/test/performance/browsing_test.rb +9 -0
- data/test/rails_root/test/test_helper.rb +7 -0
- data/test/rails_root/test/unit/helpers/c1_helper_test.rb +4 -0
- data/test/rails_root/test/unit/helpers/c2_helper_test.rb +4 -0
- data/test/rails_root/test/unit/helpers/c3_helper_test.rb +4 -0
- data/test/rails_root/test/unit/helpers/c4_helper_test.rb +4 -0
- data/test/rails_root/vendor/plugins/.gitkeep +0 -0
- metadata +176 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "minitest", ">= 0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.6.0"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.6.3)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
minitest (2.3.1)
|
10
|
+
rake (0.9.2)
|
11
|
+
rcov (0.9.9)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 1.0.0)
|
18
|
+
jeweler (~> 1.6.0)
|
19
|
+
minitest
|
20
|
+
rcov
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Kevin Swope
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= backstack
|
2
|
+
|
3
|
+
This is in extreme beta. The docs are not yet written and will
|
4
|
+
probably be supplimented with an illustrated blog posting.
|
5
|
+
|
6
|
+
Backstack is a gem plugin (currently just rails) that dynamically and
|
7
|
+
intelligently generates a "back" link, or breadcrumb trail. Sounds so
|
8
|
+
simple, why wouldn't it be?
|
9
|
+
|
10
|
+
To get a quick idea of what it does, goes to the test/rails_root
|
11
|
+
directory and 'rails server'
|
12
|
+
|
13
|
+
The plugin guts are in:
|
14
|
+
https://github.com/kswope/backstack/blob/master/lib/backstack.rb and
|
15
|
+
https://github.com/kswope/backstack/blob/master/lib/backstacklib.rb
|
16
|
+
|
17
|
+
Non-plugin tests are in:
|
18
|
+
https://github.com/kswope/backstack/blob/master/test/neutral/test_backstacklib.rb
|
19
|
+
|
20
|
+
Most rails tests are in:
|
21
|
+
https://github.com/kswope/backstack/blob/master/test/rails_root/test/integration/backstack_test.rb
|
22
|
+
|
23
|
+
|
24
|
+
== Contributing to backstack
|
25
|
+
|
26
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
27
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
28
|
+
* Fork the project
|
29
|
+
* Start a feature/bugfix branch
|
30
|
+
* Commit and push until you are happy with your contribution
|
31
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
32
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
33
|
+
|
34
|
+
== Copyright
|
35
|
+
|
36
|
+
Copyright (c) 2011 Kevin Swope. See LICENSE.txt for
|
37
|
+
further details.
|
38
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
|
6
|
+
begin
|
7
|
+
Bundler.setup(:default, :development)
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
|
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 = "backstack"
|
20
|
+
gem.homepage = "http://github.com/kswope/backstack"
|
21
|
+
gem.license = "MIT"
|
22
|
+
gem.summary = %Q{Rails plugin used to generate "back" links or a breadcrumb trail.}
|
23
|
+
gem.description = %Q{Rails plugin used to dynamically and intelligently generate "back" links or a breadcrumb trail.}
|
24
|
+
gem.email = "git-kevdev@snkmail.com"
|
25
|
+
gem.authors = ["Kevin Swope"]
|
26
|
+
# dependencies defined in Gemfile
|
27
|
+
end
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
29
|
+
|
30
|
+
task :default => :test
|
31
|
+
task :test => [:test_neutral, :test_rails]
|
32
|
+
|
33
|
+
require 'rake/testtask'
|
34
|
+
Rake::TestTask.new(:test_neutral) do |test|
|
35
|
+
test.libs << 'lib' << 'test/neutral'
|
36
|
+
test.pattern = 'test/neutral/**/test_*.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
|
40
|
+
# Bundler.setup (above) sets this and ruins rail's chance for loading
|
41
|
+
# properly in the test below. Somebody tell me why a gem is setting
|
42
|
+
# ENV variables.
|
43
|
+
ENV['BUNDLE_GEMFILE'] = nil
|
44
|
+
|
45
|
+
desc "Run tests in rails root"
|
46
|
+
rails_root = "test/rails_root"
|
47
|
+
command = "rake"
|
48
|
+
task :test_rails do |t|
|
49
|
+
chdir rails_root do
|
50
|
+
puts "*** descending into #{rails_root} and running '#{command}'"
|
51
|
+
system command
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
Binary file
|
data/backstack.gemspec
ADDED
@@ -0,0 +1,127 @@
|
|
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 = %q{backstack}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Kevin Swope"]
|
12
|
+
s.date = %q{2011-07-09}
|
13
|
+
s.description = %q{Rails plugin used to dynamically and intelligently generate "back" links or a breadcrumb trail.}
|
14
|
+
s.email = %q{git-kevdev@snkmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"art/bowling_pins.graffle",
|
28
|
+
"backstack.gemspec",
|
29
|
+
"lib/backstack.rb",
|
30
|
+
"lib/backstacklib.rb",
|
31
|
+
"test/neutral/helper.rb",
|
32
|
+
"test/neutral/test_backstacklib.rb",
|
33
|
+
"test/rails_root/.gitignore",
|
34
|
+
"test/rails_root/Gemfile",
|
35
|
+
"test/rails_root/Gemfile.lock",
|
36
|
+
"test/rails_root/README",
|
37
|
+
"test/rails_root/Rakefile",
|
38
|
+
"test/rails_root/app/controllers/application_controller.rb",
|
39
|
+
"test/rails_root/app/controllers/c1_controller.rb",
|
40
|
+
"test/rails_root/app/controllers/c2_controller.rb",
|
41
|
+
"test/rails_root/app/controllers/c3_controller.rb",
|
42
|
+
"test/rails_root/app/controllers/c4_controller.rb",
|
43
|
+
"test/rails_root/app/helpers/application_helper.rb",
|
44
|
+
"test/rails_root/app/helpers/c1_helper.rb",
|
45
|
+
"test/rails_root/app/helpers/c2_helper.rb",
|
46
|
+
"test/rails_root/app/helpers/c3_helper.rb",
|
47
|
+
"test/rails_root/app/helpers/c4_helper.rb",
|
48
|
+
"test/rails_root/app/views/c1/a.html.erb",
|
49
|
+
"test/rails_root/app/views/c2/b.html.erb",
|
50
|
+
"test/rails_root/app/views/c2/c.html.erb",
|
51
|
+
"test/rails_root/app/views/c3/d.html.erb",
|
52
|
+
"test/rails_root/app/views/c3/e.html.erb",
|
53
|
+
"test/rails_root/app/views/c3/f.html.erb",
|
54
|
+
"test/rails_root/app/views/c4/g.html.erb",
|
55
|
+
"test/rails_root/app/views/c4/h.html.erb",
|
56
|
+
"test/rails_root/app/views/c4/i.html.erb",
|
57
|
+
"test/rails_root/app/views/c4/j.html.erb",
|
58
|
+
"test/rails_root/app/views/layouts/_pins.html.erb",
|
59
|
+
"test/rails_root/app/views/layouts/application.html.erb",
|
60
|
+
"test/rails_root/config.ru",
|
61
|
+
"test/rails_root/config/application.rb",
|
62
|
+
"test/rails_root/config/boot.rb",
|
63
|
+
"test/rails_root/config/environment.rb",
|
64
|
+
"test/rails_root/config/environments/development.rb",
|
65
|
+
"test/rails_root/config/environments/production.rb",
|
66
|
+
"test/rails_root/config/environments/test.rb",
|
67
|
+
"test/rails_root/config/initializers/backtrace_silencers.rb",
|
68
|
+
"test/rails_root/config/initializers/inflections.rb",
|
69
|
+
"test/rails_root/config/initializers/mime_types.rb",
|
70
|
+
"test/rails_root/config/initializers/secret_token.rb",
|
71
|
+
"test/rails_root/config/initializers/session_store.rb",
|
72
|
+
"test/rails_root/config/locales/en.yml",
|
73
|
+
"test/rails_root/config/routes.rb",
|
74
|
+
"test/rails_root/db/seeds.rb",
|
75
|
+
"test/rails_root/lib/tasks/.gitkeep",
|
76
|
+
"test/rails_root/public/404.html",
|
77
|
+
"test/rails_root/public/422.html",
|
78
|
+
"test/rails_root/public/500.html",
|
79
|
+
"test/rails_root/public/favicon.ico",
|
80
|
+
"test/rails_root/public/images/rails.png",
|
81
|
+
"test/rails_root/public/javascripts/.gitkeep",
|
82
|
+
"test/rails_root/public/javascripts/application.js",
|
83
|
+
"test/rails_root/public/robots.txt",
|
84
|
+
"test/rails_root/public/stylesheets/.gitkeep",
|
85
|
+
"test/rails_root/public/stylesheets/application.css",
|
86
|
+
"test/rails_root/script/rails",
|
87
|
+
"test/rails_root/test/functional/c1_controller_test.rb",
|
88
|
+
"test/rails_root/test/functional/c2_controller_test.rb",
|
89
|
+
"test/rails_root/test/functional/c3_controller_test.rb",
|
90
|
+
"test/rails_root/test/functional/c4_controller_test.rb",
|
91
|
+
"test/rails_root/test/integration/backstack_test.rb",
|
92
|
+
"test/rails_root/test/performance/browsing_test.rb",
|
93
|
+
"test/rails_root/test/test_helper.rb",
|
94
|
+
"test/rails_root/test/unit/helpers/c1_helper_test.rb",
|
95
|
+
"test/rails_root/test/unit/helpers/c2_helper_test.rb",
|
96
|
+
"test/rails_root/test/unit/helpers/c3_helper_test.rb",
|
97
|
+
"test/rails_root/test/unit/helpers/c4_helper_test.rb",
|
98
|
+
"test/rails_root/vendor/plugins/.gitkeep"
|
99
|
+
]
|
100
|
+
s.homepage = %q{http://github.com/kswope/backstack}
|
101
|
+
s.licenses = ["MIT"]
|
102
|
+
s.require_paths = ["lib"]
|
103
|
+
s.rubygems_version = %q{1.6.2}
|
104
|
+
s.summary = %q{Rails plugin used to generate "back" links or a breadcrumb trail.}
|
105
|
+
|
106
|
+
if s.respond_to? :specification_version then
|
107
|
+
s.specification_version = 3
|
108
|
+
|
109
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
110
|
+
s.add_development_dependency(%q<minitest>, [">= 0"])
|
111
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
112
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
|
113
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
114
|
+
else
|
115
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
116
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
117
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
118
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
119
|
+
end
|
120
|
+
else
|
121
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
122
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
123
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
124
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
data/lib/backstack.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require "backstacklib"
|
2
|
+
|
3
|
+
|
4
|
+
module BackStack
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.send :extend, ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
# maybe later
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
include BackStackLib
|
17
|
+
|
18
|
+
# Normalize controller and action to "controller#action", unless
|
19
|
+
# second param already has "#". This is up here in the class methods
|
20
|
+
# because normalizing controller/actions is utilized both here
|
21
|
+
# and in the ApplicationControllers objects
|
22
|
+
def bs_action_normal(controller, x)
|
23
|
+
x.to_s.index("#") ? "#{x}" : "#{controller}##{x}"
|
24
|
+
end
|
25
|
+
|
26
|
+
# This is the "macro" you put at the top of your controllers
|
27
|
+
def backstack(edges)
|
28
|
+
|
29
|
+
# Note: its a little hard to follow but @bs_graph is a instance
|
30
|
+
# variable of the class ApplicationController::Base (not an
|
31
|
+
# object of AC::B). There will only be one in the rails runtime,
|
32
|
+
# and may behave differently depending on whether we're in dev
|
33
|
+
# or prod mode, because dev mode reloads classes with each
|
34
|
+
# request, and prod hopefully doesn't. We'll write this module
|
35
|
+
# to work correctly under both circumstances.
|
36
|
+
|
37
|
+
# In rails we're going to use the string "controller#action" to
|
38
|
+
# identify the page. We're NOT going to let bs_add_edges
|
39
|
+
# normalize that because it might be used for other frameworks.
|
40
|
+
# If the user didn't pass in the controller we'll add it here.
|
41
|
+
# The complete value should look like "controller#action", for
|
42
|
+
# both keys and values.
|
43
|
+
normalizer = lambda {|x| bs_action_normal(controller_name, x) }
|
44
|
+
|
45
|
+
# Add new edges to existing graph, and extract out the names.
|
46
|
+
# bs_add_edges will also accumulate names for us.
|
47
|
+
@bs_graph, @bs_names = bs_add_edges(@bs_graph, @bs_names,
|
48
|
+
edges, normalizer)
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
# So ApplicationController methods can reach @bs_graph and
|
53
|
+
# @bs_names. I wanted to use @@bs_graph, so both AC::B and the
|
54
|
+
# instance of AC could reach it, but this mysteriously breaks
|
55
|
+
# rails routing! So here are getters than we can use and access
|
56
|
+
# from the AC instance as self.class.get_bs_graph. RoR can be a
|
57
|
+
# real pit of dispair sometimes.
|
58
|
+
def get_bs_graph
|
59
|
+
@bs_graph
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_bs_names
|
63
|
+
@bs_names
|
64
|
+
end
|
65
|
+
|
66
|
+
send :include, InstanceMethods
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
# These functions will be available in views
|
71
|
+
module Helpers
|
72
|
+
|
73
|
+
def backstack_link(text, *args)
|
74
|
+
|
75
|
+
bs_graph = controller.class.get_bs_graph # found it! lol
|
76
|
+
|
77
|
+
# If we don't have these we can't do anything
|
78
|
+
return unless session[:bs_stack] && bs_graph
|
79
|
+
|
80
|
+
# If the top of stack (current location) is stacked on top of
|
81
|
+
# link the graph indicates it closes to, then create a link from
|
82
|
+
# that.
|
83
|
+
current = session[:bs_stack][-1]
|
84
|
+
previous = session[:bs_stack][-2]
|
85
|
+
|
86
|
+
if current && previous && bs_graph[current.first].include?(previous.first)
|
87
|
+
return link_to(text, previous.second, *args)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
# Iterator to build breadcrumb trails
|
93
|
+
def backstack_trail
|
94
|
+
|
95
|
+
hashify = lambda{|x|
|
96
|
+
c, a = x[0].split /#/
|
97
|
+
{:controller => c, :action => a, :fullpath => x[1], :name => x[2]}
|
98
|
+
}
|
99
|
+
|
100
|
+
if block_given?
|
101
|
+
session[:bs_stack].each { |x| yield hashify.call(x) }
|
102
|
+
else # return an array
|
103
|
+
session[:bs_stack].map { |x| hashify.call(x) }
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
ActionController::Base.send :include, BackStack
|
115
|
+
ActionView::Helpers.send :include, BackStack::Helpers
|
116
|
+
|
117
|
+
|
118
|
+
# note, do not do this here:
|
119
|
+
# class ApplicationController < ActionController::Base
|
120
|
+
# it will prevent application_controller.rb from loading
|
121
|
+
class ActionController::Base
|
122
|
+
|
123
|
+
include BackStackLib
|
124
|
+
|
125
|
+
# Debugging method for calling inside controller, probably best as
|
126
|
+
# before_filter :backstack_dump
|
127
|
+
# in application_controller.rb
|
128
|
+
def backstack_dump
|
129
|
+
|
130
|
+
# don't accidentally run in production
|
131
|
+
return unless Rails.env == 'development'
|
132
|
+
|
133
|
+
puts "=== backstack_dump() " + '=' * 50
|
134
|
+
|
135
|
+
puts "backstack graph: #{self.class.get_bs_graph}"
|
136
|
+
puts "backstack names: #{self.class.get_bs_names}"
|
137
|
+
puts "backstack stack: #{session[:bs_stack]}"
|
138
|
+
|
139
|
+
puts '=' * 71
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
def bs_pusher
|
146
|
+
|
147
|
+
action = self.class.bs_action_normal(controller_name, action_name)
|
148
|
+
|
149
|
+
session[:bs_stack] = bs_push(self.class.get_bs_graph,
|
150
|
+
session[:bs_stack],
|
151
|
+
action,
|
152
|
+
request.fullpath,
|
153
|
+
self.class.get_bs_names[action])
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
before_filter :bs_pusher
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
|
data/lib/backstacklib.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# BackStackLib should know nothing about rails, sinatra or whatever
|
2
|
+
# framework this gem is supporting. It should also have no storage of
|
3
|
+
# its own. Keep it that way.
|
4
|
+
module BackStackLib
|
5
|
+
|
6
|
+
# Combine a "graph", described by connected nodes, in hash form,
|
7
|
+
# with another.
|
8
|
+
#
|
9
|
+
# Input graph must be normalized and described like this (could also
|
10
|
+
# be {}). Normalized means key is not a collection data type (not
|
11
|
+
# an array) but the value IS an array.
|
12
|
+
#
|
13
|
+
# In other words, don't pass as the first argument anything that hasn't
|
14
|
+
# been already normalized by this method, or use {} to start
|
15
|
+
#
|
16
|
+
# An example of normalized is {:b=>[:a], :c=>[:a], :z=>[:a, :x]}
|
17
|
+
# which reads "b is connected to a and c is connected to a and z is
|
18
|
+
# connected to both :a and :x", or more relevantly "b closes to a
|
19
|
+
# and c closes to a and z closes to both a and x".
|
20
|
+
#
|
21
|
+
# When this method is run it combines the *already* normalized graph
|
22
|
+
# (could be {}), with a another graph description, which for
|
23
|
+
# convenience can be in more of a shorthand, like {[:f, :e, :d] =>
|
24
|
+
# :c}, which reads "f, e, and d all close to c"
|
25
|
+
#
|
26
|
+
# The returned value will be a combination of the graphs, in a
|
27
|
+
# normalized form, for example {:b=>[:a], :c=>[:a], :f=>[:b, :c],
|
28
|
+
# :e=>[:b, :c], :d=>[:b, :c]}
|
29
|
+
#
|
30
|
+
# Note: the shorthand form of the edges parameter can be taken as far as
|
31
|
+
# something like this {[:d, :e, :f] => [:b, :c]}
|
32
|
+
#
|
33
|
+
# New feature: named nodes. Instead of {:c => :a}, the "key" can be
|
34
|
+
# named like this {{:c => "Charlie"} => :a}. We're going to remove
|
35
|
+
# those named keys, replace them with just the key, and return them as
|
36
|
+
# the second value
|
37
|
+
#
|
38
|
+
# Decided to allow user to pass a normalizer proc/lambda in to
|
39
|
+
# modify all the keys and values.
|
40
|
+
def bs_add_edges(graph, names, edges, normalizer=nil)
|
41
|
+
|
42
|
+
graph ||= {}
|
43
|
+
names ||= {}
|
44
|
+
|
45
|
+
edges.each do |k,v| # k is a scalar or array, same with v
|
46
|
+
|
47
|
+
# Does this [x].flatten idiom make it less readable?
|
48
|
+
[k].flatten.each do |x|
|
49
|
+
|
50
|
+
# Extract names out into their own hash, and normalize key
|
51
|
+
if x.class == Hash # if its a hash it contains a name
|
52
|
+
names[x.first[0]] = x.first[1]
|
53
|
+
x = x.first[0] # remove name and replace with normal key
|
54
|
+
end
|
55
|
+
|
56
|
+
# Run normalizer on all keys and values of new edges
|
57
|
+
if normalizer
|
58
|
+
x = normalizer.call(x)
|
59
|
+
v = [v].flatten.map{|y| normalizer.call(y)}
|
60
|
+
# also run normalizer on names keys
|
61
|
+
names = Hash[names.map {|k,v| [normalizer.call(k), v]}]
|
62
|
+
end
|
63
|
+
|
64
|
+
# If merge finds dupe keys it will use block to determine
|
65
|
+
# value, which in our case is to combine the two values.
|
66
|
+
graph.merge!(x => [v].flatten) do |key, old_v, new_v|
|
67
|
+
[old_v, new_v].flatten
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
[graph, names]
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
# Judging by graph, push onto stack if appropriate. Pushing doesn't
|
79
|
+
# necessarily build stack up, it might cause a rewind and actually
|
80
|
+
# shrink stack.
|
81
|
+
def bs_push(graph, stack, action, fullpath, name=nil)
|
82
|
+
|
83
|
+
# bs_push might be called before there is a graph or stack
|
84
|
+
graph ||= {}
|
85
|
+
stack ||= []
|
86
|
+
|
87
|
+
element = [action, fullpath, name]
|
88
|
+
|
89
|
+
# if action closes to what's on top of stack, build stack up
|
90
|
+
if graph[action] && stack.last && graph[action].include?(stack.last.first)
|
91
|
+
stack.push element
|
92
|
+
return stack
|
93
|
+
end
|
94
|
+
|
95
|
+
# if action already in stack rewind *past* it and place on stack
|
96
|
+
# (we rewind past it and push because the path part might be
|
97
|
+
# different)
|
98
|
+
if i = stack.find_index {|x| x.first == action}
|
99
|
+
stack = stack.slice(0,i)
|
100
|
+
stack.push element
|
101
|
+
return stack
|
102
|
+
end
|
103
|
+
|
104
|
+
# if none of the clever stuff above happened then just replace top
|
105
|
+
# of stack
|
106
|
+
if stack.empty?
|
107
|
+
return [element]
|
108
|
+
else
|
109
|
+
stack[-1] = element
|
110
|
+
return stack
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
require "backstacklib"
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
# All this following stuff is already in the Rakefile, why is it also
|
6
|
+
# here jeweler? -kswope
|
7
|
+
|
8
|
+
# require 'rubygems'
|
9
|
+
# require 'bundler'
|
10
|
+
|
11
|
+
# begin
|
12
|
+
# Bundler.setup(:default, :development)
|
13
|
+
# rescue Bundler::BundlerError => e
|
14
|
+
# $stderr.puts e.message
|
15
|
+
# $stderr.puts "Run `bundle install` to install missing gems"
|
16
|
+
# exit e.status_code
|
17
|
+
# end
|
18
|
+
# require 'minitest/unit'
|
19
|
+
|
20
|
+
# #$LOAD_PATH.unshift(File.dirname(__FILE__))
|
21
|
+
# #$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
22
|
+
# require 'backstacklib'
|
23
|
+
|
24
|
+
# class MiniTest::Unit::TestCase
|
25
|
+
# end
|
26
|
+
|
27
|
+
# MiniTest::Unit.autorun
|