mariner 0.0.2

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.
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