mariner 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.autotest +10 -0
  2. data/.gitignore +18 -0
  3. data/.pairs +6 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +12 -0
  7. data/LICENSE +22 -0
  8. data/README.md +59 -0
  9. data/Rakefile +13 -0
  10. data/lib/mariner.rb +49 -0
  11. data/lib/mariner/errors.rb +26 -0
  12. data/lib/mariner/helper.rb +96 -0
  13. data/lib/mariner/railtie.rb +21 -0
  14. data/lib/mariner/renderer/base.rb +42 -0
  15. data/lib/mariner/store.rb +76 -0
  16. data/lib/mariner/unordered_list_renderer.rb +202 -0
  17. data/lib/mariner/url.rb +54 -0
  18. data/lib/mariner/version.rb +3 -0
  19. data/mariner.gemspec +20 -0
  20. data/spec/integrations/unordered_list_renderer_spec.rb +90 -0
  21. data/spec/mariner_spec.rb +29 -0
  22. data/spec/navigation/helper_spec.rb +131 -0
  23. data/spec/navigation/railtie_spec.rb +17 -0
  24. data/spec/navigation/renderer/base_spec.rb +25 -0
  25. data/spec/navigation/store_spec.rb +80 -0
  26. data/spec/navigation/unordered_list_render_spec.rb +93 -0
  27. data/spec/navigation/url_spec.rb +45 -0
  28. data/spec/rails_app/.gitignore +15 -0
  29. data/spec/rails_app/Rakefile +7 -0
  30. data/spec/rails_app/app/assets/javascripts/application.js +15 -0
  31. data/spec/rails_app/app/assets/stylesheets/application.css +13 -0
  32. data/spec/rails_app/app/controllers/application_controller.rb +6 -0
  33. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  34. data/spec/rails_app/app/mailers/.gitkeep +0 -0
  35. data/spec/rails_app/app/models/.gitkeep +0 -0
  36. data/spec/rails_app/app/views/application/condensed.html.erb +1 -0
  37. data/spec/rails_app/app/views/application/normal.html.erb +1 -0
  38. data/spec/rails_app/app/views/layouts/application.html.erb +12 -0
  39. data/spec/rails_app/config.ru +4 -0
  40. data/spec/rails_app/config/application.rb +64 -0
  41. data/spec/rails_app/config/boot.rb +3 -0
  42. data/spec/rails_app/config/database.yml +3 -0
  43. data/spec/rails_app/config/environment.rb +5 -0
  44. data/spec/rails_app/config/environments/test.rb +37 -0
  45. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  46. data/spec/rails_app/config/initializers/inflections.rb +15 -0
  47. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  48. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  49. data/spec/rails_app/config/initializers/session_store.rb +8 -0
  50. data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
  51. data/spec/rails_app/config/locales/en.yml +5 -0
  52. data/spec/rails_app/config/routes.rb +9 -0
  53. data/spec/rails_app/db/.gitkeep +0 -0
  54. data/spec/rails_app/lib/assets/.gitkeep +0 -0
  55. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  56. data/spec/rails_app/log/.gitkeep +0 -0
  57. data/spec/rails_app/script/rails +6 -0
  58. data/spec/rails_app/vendor/assets/javascripts/.gitkeep +0 -0
  59. data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
  60. data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
  61. data/spec/spec_helper.rb +8 -0
  62. metadata +175 -0
@@ -0,0 +1,10 @@
1
+ Autotest.add_hook(:initialize) {|at|
2
+ at.add_exception %r{^\.git}
3
+ at.add_exception %r{^./tmp}
4
+ at.add_exception %r{^./spec/rails_app/tmp}
5
+ at.add_exception %r{^./spec/rails_app/log}
6
+ at.add_mapping(%r{^lib/.*\.rb$}) {|f, _|
7
+ Dir['spec/**/*_spec.rb']
8
+ }
9
+ nil
10
+ }
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rvmrc
data/.pairs ADDED
@@ -0,0 +1,6 @@
1
+ pairs:
2
+ aa: Adam Albrecht
3
+ jt: Jesse Trimble
4
+ email:
5
+ prefix: pair
6
+ domain: factorylabs.com
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mariner.gemspec
4
+ gemspec
5
+
6
+ gem 'rake'
7
+ gem 'rspec-rails'
8
+ gem 'capybara'
9
+ gem 'autotest'
10
+ gem 'pivotal_git_scripts'
11
+ gem 'yard'
12
+ gem 'redcarpet'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jesse Trimble
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.
@@ -0,0 +1,59 @@
1
+ # Mariner
2
+
3
+ [![Build Status](https://secure.travis-ci.org/jtrim/mariner.png)](http://travis-ci.org/jtrim/mariner)
4
+
5
+ Mariner helps you manage your site's navigation through a friendly DSL.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'mariner'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install mariner
20
+
21
+ ## Usage
22
+
23
+ Mariner helps you define trees of links through a friendly DSL:
24
+
25
+ Mariner.configure do
26
+
27
+ topbar do # <= arbitrarily-named
28
+
29
+ # Defining Urls is as easy as calling the
30
+ # Rails route helper you want to use:
31
+
32
+ root_path 'Home'
33
+
34
+ # by default, the above renders <a href="/">Home</a>
35
+
36
+ dropdown do # <= also arbitrarily-named
37
+
38
+ # If you specify options, they're passed on to the renderer
39
+ destroy_user_session_path "Logout", "data-method" => :destroy
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ After creating your nav, render it in your views with:
48
+
49
+ <%= render_navigation :topbar %>
50
+
51
+ See Mariner::Helper for usage on `render_navigation`.
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes and tests (`git commit -am 'Added some feature'`)
58
+ 4. Push to the branch (`git push origin my-new-feature`)
59
+ 5. Create new Pull Request
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ begin
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc "Run all examples"
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.rspec_opts = %w[--color]
10
+ end
11
+
12
+ task :default => [:spec]
13
+ rescue LoadError; end
@@ -0,0 +1,49 @@
1
+ $:.unshift(File.expand_path('..', __FILE__)) unless $:.include? File.expand_path('..', __FILE__)
2
+
3
+ require 'abyss'
4
+
5
+ require 'mariner/version'
6
+ require 'mariner/errors'
7
+ require 'mariner/renderer/base'
8
+ require 'mariner/unordered_list_renderer'
9
+ require 'mariner/url'
10
+ require 'mariner/store'
11
+
12
+ require 'mariner/helper'
13
+ require 'mariner/railtie'
14
+
15
+ module Mariner
16
+
17
+ class << self
18
+ attr_accessor :configuration, :rendering_strategies
19
+ end
20
+
21
+ @rendering_strategies = {
22
+ :default => UnorderedListRenderer.new
23
+ }
24
+
25
+ # Public: The public interface to navigation API
26
+ #
27
+ # Examples:
28
+ #
29
+ # Mariner.configure do
30
+ # an_arbitrary_group do
31
+ # root_path "Go Home" #=> where `root_path` is a Rails route helper
32
+ # users_path "Manage Users", { "data-name" => "go-home" } #=> note the optional attributes hash. This
33
+ # # is used by rendering strategies
34
+ # end
35
+ # end
36
+ #
37
+ def self.configure(&block)
38
+ self.configuration ||= Store.new.tap { |s| s.virtual = true }
39
+ self.configuration.instance_eval &block
40
+ end
41
+
42
+ def self.include_helper
43
+ ActiveSupport.on_load(:action_controller) do
44
+ include Mariner::Helper
45
+ helper_method :render_navigation #:notest:
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,26 @@
1
+ module Mariner
2
+
3
+ module Errors
4
+
5
+ # Private: This error is raised when Url tries to use a route helper
6
+ # method that's unavailable or undefined
7
+ #
8
+ class InvalidUrlHelperMethod < RuntimeError
9
+ attr_accessor :name
10
+
11
+ def initialize(name)
12
+ self.name = name
13
+ end
14
+
15
+ def message
16
+ "Unknown url helper method used in navigation configuration: #{name.inspect}"
17
+ end
18
+
19
+ def to_s
20
+ message
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,96 @@
1
+ module Mariner
2
+
3
+ # Public: Gets included in controllers (see the Railtie)
4
+ #
5
+ module Helper
6
+
7
+ # Public: A shortcut for rendering navigation. Made available to both
8
+ # controllers and views.
9
+ #
10
+ # config_path - A symbol or slash-separated string path to the
11
+ # configuration group you want to render.
12
+ #
13
+ # renderer - The rendering strategy to use.
14
+ # Can be a symbol or actual
15
+ # rendering stragey. When a symbol, looks in the
16
+ # `Mariner.rendering_strategies` hash using the given symbol as the key.
17
+ # Raises an error if not found. When a rendering strategy, passes the
18
+ # strategy on to the target group's #render method.
19
+ #
20
+ # Examples:
21
+ #
22
+ # Mariner.configure do
23
+ # a_group do
24
+ # root_path "Home"
25
+ #
26
+ # a_sub_group do
27
+ # users_path "Manage Users"
28
+ # end
29
+ # end
30
+ # end
31
+ #
32
+ # render_navigation
33
+ # #=> renders the entire nav tree
34
+ #
35
+ # render_navigation :a_group
36
+ # #=> renders the `a_group` nav tree
37
+ #
38
+ # render_navigation "a_group/a_sub_group"
39
+ # #=> renders the nav tree of `a_sub_group` under `a_group`
40
+ #
41
+ # render_navigation :a_group, FakeRenderingStrategy.new
42
+ # #=> renders `a_group` with a FakeRenderingStrategy instance
43
+ #
44
+ def render_navigation(config_path=nil, renderer=nil)
45
+ target = target_from_path(config_path)
46
+ strategy = rendering_strategy_from(renderer)
47
+
48
+ strategy ? target.render(strategy) : target.render
49
+ end
50
+
51
+ # Public: For when you want to render all the configurations under
52
+ # a given group but you don't want to render the group itself.
53
+ #
54
+ # Examples:
55
+ #
56
+ # Mariner.configure do
57
+ # group_a do
58
+ # root_path "Home"
59
+ # end
60
+ #
61
+ # group_b do
62
+ # users_path "Manage Users"
63
+ # end
64
+ # end
65
+ #
66
+ # render_navigations
67
+ # #=> renders the group_a and group_b trees and joins the result
68
+ #
69
+ def render_navigations(config_path=nil, renderer=nil)
70
+ target = target_from_path(config_path)
71
+ strategy = rendering_strategy_from(renderer)
72
+
73
+ target.configurations.map do |c|
74
+ _, entity = c
75
+ strategy ? entity.render(strategy) : entity.render
76
+ end.join
77
+ end
78
+
79
+ private
80
+
81
+ def target_from_path(config_path)
82
+ path = config_path ? config_path.to_s.split("/") : []
83
+ path.reduce(Mariner.configuration) { |acc, g| acc.send g }
84
+ end
85
+
86
+ def rendering_strategy_from(renderer)
87
+ return nil unless renderer
88
+ return renderer if renderer && renderer.respond_to?(:render)
89
+ raise "Rendering strategy not found: #{renderer}" if Mariner.rendering_strategies[renderer].nil?
90
+
91
+ Mariner.rendering_strategies[renderer]
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,21 @@
1
+ module Mariner
2
+
3
+ # Private: After Rails initializes:
4
+ # * mixes `Rails.application.routes.url_helpers` into Mariner::Url
5
+ # * includes Mariner::Helper into ActionController::Base
6
+ # * makes a #helper_method out of Helper#render_navigation
7
+ #
8
+ class Railtie < ::Rails::Railtie
9
+
10
+ config.after_initialize do
11
+ Mariner::Url.class_eval { include Rails.application.routes.url_helpers }
12
+
13
+ ActiveSupport.on_load(:action_controller) do
14
+ include Mariner::Helper
15
+ helper_method :render_navigation, :render_navigations
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,42 @@
1
+ module Mariner
2
+
3
+ module Renderer
4
+
5
+ # Public: The base class for renderers used in a rendering strategy.
6
+ #
7
+ # Examples:
8
+ #
9
+ # class FakeRenderingStrategy
10
+ #
11
+ # def factory(type, subject)
12
+ # case type
13
+ # when :group then FakeRenderer.new(subject, self)
14
+ # ...
15
+ #
16
+ # class FakeRenderer < Mariner::Renderer::Base
17
+ #
18
+ # def render
19
+ # ...
20
+ #
21
+ class Base
22
+
23
+ # Public: The subject (a Store or a Url) to render
24
+ #
25
+ attr_accessor :subject
26
+
27
+ # Public: The rendering strategy used that responds to #factory
28
+ #
29
+ attr_accessor :rendering_strategy
30
+
31
+ # Public: Creates a new renderer and assigns #subject and
32
+ # #rendering_strategy
33
+ #
34
+ def initialize(subject, rendering_strategy)
35
+ @subject, @rendering_strategy = subject, rendering_strategy
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,76 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ module Mariner
4
+
5
+ # Public: Uses the Abyss library to provide arbitrarily-deep sets of
6
+ # navigation groups / urls. Think of this as the group when
7
+ # defining nav trees.
8
+ #
9
+ # Examples:
10
+ #
11
+ # Mariner.configure do
12
+ #
13
+ # a_group do # <= This effectivly creates a new Mariner::Store, ...
14
+ # root_path "Home" # <= and this creates a new Mariner::Url within said store.
15
+ # end
16
+ #
17
+ # end
18
+ #
19
+ class Store < ::Abyss::DeepStore
20
+
21
+ # Public: If the group is virtual, the rendering strategy shouldn't
22
+ # generate any output around its nested configurations when.
23
+ # e.g. The UnorderedListRenderer doesn't generate `ul` or `li` tags when
24
+ # the target group is virtual.
25
+ #
26
+ attr_accessor :virtual
27
+ alias :virtual? :virtual
28
+
29
+ # Public: Sets virtual to false by default and defers to
30
+ # ::Abyss::DeepStore for initialization.
31
+ #
32
+ def initialize(*)
33
+ @virtual = false
34
+ super
35
+ end
36
+
37
+ # Public: Abstract method override - overrides ::Abyss::DeepStore#assign
38
+ # to store Urls. This is only called when NOT dealing with a nested
39
+ # group.
40
+ #
41
+ # e.g.:
42
+ #
43
+ # Mariner.configure do
44
+ #
45
+ # a_group do
46
+ # root_path "Home" # <= #assign gets called.
47
+ # end
48
+ #
49
+ # end
50
+ #
51
+ def assign(method_name, values)
52
+ raise ArgumentError, "Wrong number of values specified (#{values.size} for <= 2)" if values.size > 2
53
+
54
+ values[1] ||= {} # link options
55
+ title, options = values
56
+ self.configurations[method_name] = Url.new(method_name, title, options)
57
+ end
58
+
59
+ # Public: Uses a rendering strategy to render itself.
60
+ #
61
+ # rendering_strategy - The rendering strategy to use when rendering.
62
+ #
63
+ # Examples:
64
+ #
65
+ # Mariner.configuration #=> An Mariner::Store instance
66
+ #
67
+ # Mariner.configuration.render
68
+ # Mariner.configuration.render(SomeRenderingStrategy.new)
69
+ #
70
+ def render(rendering_strategy=Mariner.rendering_strategies[:default])
71
+ rendering_strategy.factory(:group, self).render
72
+ end
73
+
74
+ end
75
+
76
+ end