ducktrails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fbf690b1296a9de6e0cf9e70843900c366836428
4
+ data.tar.gz: b69671826c7dd007ef7688647a1c65d406625eea
5
+ SHA512:
6
+ metadata.gz: fb63bd77873ac042ec08435c11e2a68ea0cac911bf20e3c8a5fd1ffe8e4e34b4d9776324978c12c9d22542401bd990006a3989d108abce45b9c623e8c989db77
7
+ data.tar.gz: c054b643724161eccb18480ece94c1da7efa41fecc3167befb96c11a06467c037eb2550300c82e55e4d86261bcf77a4128ef852942fc0ab83610c6758df9e72b
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Kevin Brown
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.md ADDED
@@ -0,0 +1,52 @@
1
+ # 🦆 Ducktrails
2
+
3
+ Automatically generates breadcrumbs based on routes.
4
+
5
+ **Warning: This API is still alpha; we welcome PRs and ideas as issues.**
6
+
7
+ [![Ducktails Theme](http://i.imgur.com/g0PXjHX.png)](https://www.youtube.com/watch?v=CMU2NwaaXEA "Ducktails Theme")
8
+
9
+ ## Usage
10
+ For basic applications using a restful architecture, ducktrails should generate the breadcrumbs automatically.
11
+
12
+ For example, if the uri is `/users/#{user-id}/posts/#{post-id}`
13
+
14
+ Would render:
15
+
16
+ `Home / All Users / user-name / All Posts / post-name`
17
+
18
+ ## Installation
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'ducktrails'
23
+ ```
24
+
25
+ And then execute:
26
+ ```bash
27
+ $ bundle
28
+ ```
29
+
30
+ Or install it yourself as:
31
+ ```bash
32
+ $ gem install ducktrails
33
+ ```
34
+
35
+ ## Contributing
36
+
37
+ Please refer to each project's style guidelines and guidelines for submitting patches and additions. In general, we follow the "fork-and-pull" Git workflow.
38
+
39
+ 1. Fork the repo on GitHub
40
+ 2. Clone the project to your own machine
41
+ 1. `bundle`
42
+ 2. Create the test db `bundle exec rake --rakefile test/dummy/Rakefile db:setup`
43
+ 3. `bundle exec rake` to test.
44
+ 3. Ensure your test coverage is A+
45
+ 4. Commit changes to your own branch
46
+ 5. Push your work back up to your fork
47
+ 6. Submit a Pull request so that we can review your changes
48
+
49
+ NOTE: **Be sure to merge the latest from "upstream" before making a pull request!**
50
+
51
+ ## License
52
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'bundler/gem_tasks'
8
+
9
+ require 'rake/testtask'
10
+
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.libs << 'test'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+
19
+ task default: :test
@@ -0,0 +1,2 @@
1
+ Ducktrails::Engine.routes.draw do
2
+ end
@@ -0,0 +1,10 @@
1
+ <div class="breadcrumb-container">
2
+ <div class="container">
3
+ <ol class="breadcrumb">
4
+ <li><%= home_crumb %></li>
5
+ <% links.each do |link| %>
6
+ <%= render partial: 'ducktrails/crumb_link', locals: { link: link } %>
7
+ <% end %>
8
+ </ol>
9
+ </div>
10
+ </div>
@@ -0,0 +1,3 @@
1
+ <li>
2
+ <%= link_to(link[:text], link[:uri]) %>
3
+ </li>
@@ -0,0 +1,12 @@
1
+ module Configurable
2
+ include ActiveSupport::Concern
3
+ private
4
+
5
+ def collection_prefix
6
+ "#{Ducktrails.config.collection_prefix} "
7
+ end
8
+
9
+ def home_name
10
+ Ducktrails.config.home_name
11
+ end
12
+ end
@@ -0,0 +1,44 @@
1
+ require 'active_support/configurable'
2
+
3
+ module Ducktrails
4
+ # Configures global settings for Ducktrails
5
+ # Ducktrails.configure do |config|
6
+ # config.default_per_page = 10
7
+ # end
8
+ def self.configure(&block)
9
+ yield @config ||= Ducktrails::Configuration.new
10
+ end
11
+
12
+ # Global settings for Ducktrails
13
+ def self.config
14
+ @config
15
+ end
16
+
17
+ class Configuration #:nodoc:
18
+ include ActiveSupport::Configurable
19
+ config_accessor :root_path
20
+ config_accessor :home_name
21
+ # TODO: How to set this?
22
+ config_accessor :collection_prefix
23
+ config_accessor :default_key
24
+ config_accessor :fallback_to_uri
25
+ config
26
+ def param_name
27
+ config.param_name.respond_to?(:call) ? config.param_name.call : config.param_name
28
+ end
29
+
30
+ # define param_name writer (copied from AS::Configurable)
31
+ writer, line = 'def param_name=(value); config.param_name = value; end', __LINE__
32
+ singleton_class.class_eval writer, __FILE__, line
33
+ class_eval writer, __FILE__, line
34
+ end
35
+
36
+ # this is ugly. why can't we pass the default value to config_accessor...?
37
+ configure do |config|
38
+ config.root_path = '/'
39
+ config.home_name = 'Home'
40
+ config.collection_prefix = 'All'
41
+ config.default_key = :id
42
+ config.fallback_to_uri = true
43
+ end
44
+ end
@@ -0,0 +1,6 @@
1
+ module Ducktrails
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Ducktrails
4
+ config.autoload_paths += Dir["#{config.root}/lib/**/"]
5
+ end
6
+ end
@@ -0,0 +1,110 @@
1
+ require 'concerns/configurable'
2
+
3
+ DEFAULTS = {
4
+ key: :name,
5
+ policy: true
6
+ }
7
+
8
+ module Ducktrails
9
+ class LinkCollection < Array
10
+ include Configurable
11
+
12
+ attr_accessor :resources, :current_uri, :request
13
+
14
+ def initialize(resources, current_uri, request)
15
+ @resources ||= set_default_resources(resources)
16
+ @current_uri ||= current_uri
17
+ @request ||= request
18
+ end
19
+
20
+ def links
21
+ build_links
22
+ end
23
+
24
+ private
25
+
26
+ # All the logic to build the links
27
+ # Should render an index & show if action is show
28
+ # Should render an index & new/edit if action is new/edit
29
+ # Should render an index as _current_page if action is index
30
+ # If resources are empty, generate breadcrumbs from the uri?
31
+ def build_links
32
+ return generate_uri_breadcrumbs if Ducktrails.config.fallback_to_uri
33
+ raise 'Please provide block configuration for breadcrumbs.'
34
+ end
35
+
36
+ def generate_uri_breadcrumbs
37
+ split_uri.inject([]) do |links, uri_resource|
38
+ links << build_uri_link(uri_resource)
39
+ end.compact
40
+ end
41
+
42
+ def build_link(text, uri)
43
+ {
44
+ text: text,
45
+ uri: uri
46
+ }
47
+ end
48
+
49
+ def build_uri_link(uri_segment)
50
+ index = split_uri.index(uri_segment)
51
+ if resources[uri_segment.to_sym].present?
52
+ return unless resources[uri_segment.to_sym][:policy]
53
+ # Build resource link
54
+ # example /institutions/:institution_id/iterations/:id
55
+ build_link(text_link(resources[uri_segment.to_sym], index.odd?), split_uri[0..index].join('/').prepend('/'))
56
+ elsif index.odd? && resources[split_uri[index - 1].to_sym].present?
57
+ return unless resources[split_uri[index - 1].to_sym][:policy]
58
+ build_link(text_link(resources[split_uri[index - 1].to_sym], index.odd?), split_uri[0..index].join('/').prepend('/'))
59
+ else
60
+ # build links based off of uri
61
+ build_link(text_link(uri_segment.underscore.humanize, index.odd?), split_uri[0..index].join('/').prepend('/'))
62
+ end
63
+ end
64
+
65
+ # TODO factor out the resource & key to use config if key is nil
66
+ def text_link(resource, show_action = nil)
67
+ if resource.is_a?(String)
68
+ return resource if show_action
69
+ return resource.prepend(collection_prefix)
70
+ end
71
+
72
+ if resource[:resource].nil?
73
+ return request_pattern[:controller].split('/').last.underscore.humanize.pluralize.prepend(collection_prefix)
74
+ end
75
+
76
+ if show_action
77
+ return resource[:resource].send(resource[:key])
78
+ else
79
+ return resourcer(resource)
80
+ end
81
+ end
82
+
83
+ def resourcer(resource)
84
+ resource = resource[:resource].object if resource[:resource].respond_to?(:object)
85
+ resource.class.name.split('::').first.underscore.humanize.pluralize.prepend(collection_prefix)
86
+ end
87
+
88
+ def request_pattern
89
+ @request_pattern ||= Rails.application.routes.recognize_path(current_uri)
90
+ end
91
+
92
+ def split_uri
93
+ @split_uri ||= current_uri.split('/').reject(&:empty?)
94
+ end
95
+
96
+ def action
97
+ @action ||= request_pattern[:action]
98
+ end
99
+
100
+ def set_default_resources(yield_resources)
101
+ yield_resources.inject({}) do |resources, resource|
102
+ resources.merge(
103
+ {
104
+ resource[0] => DEFAULTS.merge(resource[1])
105
+ }
106
+ )
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,23 @@
1
+ module Ducktrails
2
+ class Tag
3
+ include ::ActionView::Context
4
+
5
+ def initialize(template, options = {})
6
+ @template = template
7
+ @options = options.dup
8
+ @params = template
9
+ @views_prefix = @options.delete(:views_prefix)
10
+ end
11
+
12
+ def to_s(locals = {})
13
+ @template.render partial_path, links: locals[:links]
14
+ end
15
+
16
+ def partial_path
17
+ [
18
+ 'ducktrails',
19
+ self.class.name.demodulize.underscore
20
+ ].compact.join("/")
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Ducktrails
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,47 @@
1
+ require 'action_view'
2
+ require 'action_view/context'
3
+ require 'ducktrails/tags'
4
+
5
+ module Ducktrails
6
+ module ViewHelpers
7
+ class Breadcrumber < Tag
8
+
9
+ def initialize(options = {})
10
+ @template = options[:template]
11
+ @output_buffer = ActionView::OutputBuffer.new
12
+ end
13
+
14
+ def render(&block)
15
+ @output_buffer
16
+ end
17
+ end
18
+
19
+ def breadcrumbs(options = {})
20
+ ducktrail_render(LinkCollection.new(yield, current_uri, current_request).links)
21
+ end
22
+
23
+ def home_crumb(options = {})
24
+ link_to(Ducktrails.config.home_name, '/')
25
+ end
26
+
27
+ private
28
+
29
+ def current_uri
30
+ request.fullpath
31
+ end
32
+
33
+ def current_request
34
+ request
35
+ end
36
+
37
+ def current_action
38
+ Rails.application.routes.recognize_path(current_uri)[:action]
39
+ end
40
+
41
+ def ducktrail_render(links)
42
+ @_ducktrail_render ||= Breadcrumber.new(template: self).to_s(links: links)
43
+ end
44
+ end
45
+
46
+ ActionView::Base.send :include, Ducktrails::ViewHelpers
47
+ end
data/lib/ducktrails.rb ADDED
@@ -0,0 +1,22 @@
1
+ module Ducktrails
2
+ end
3
+
4
+ begin
5
+ require 'rails'
6
+ rescue LoadError
7
+ #do nothing
8
+ end
9
+
10
+ $stderr.puts <<-EOC if !defined?(Rails)
11
+ warning: no framework detected.
12
+
13
+ Your Gemfile might not be configured properly.
14
+ ---- e.g. ----
15
+ Rails:
16
+ gem 'ducktrails'
17
+ EOC
18
+
19
+ require 'ducktrails/config'
20
+ require 'ducktrails/engine'
21
+ require 'ducktrails/tags'
22
+ require 'ducktrails/view_helpers'
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ducktrails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kevin Brown
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: capybara
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: RESTful breadcrumbs
56
+ email:
57
+ - chevinbrown@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - app/config/routes.rb
66
+ - app/views/ducktrails/_breadcrumber.html.erb
67
+ - app/views/ducktrails/_crumb_link.html.erb
68
+ - lib/ducktrails.rb
69
+ - lib/ducktrails/concerns/configurable.rb
70
+ - lib/ducktrails/config.rb
71
+ - lib/ducktrails/engine.rb
72
+ - lib/ducktrails/link_collection.rb
73
+ - lib/ducktrails/tags.rb
74
+ - lib/ducktrails/version.rb
75
+ - lib/ducktrails/view_helpers.rb
76
+ homepage: http://github.com/proctoru/ducktrails
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 2.0.0
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.6.8
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: 'Ducktrails: Breadcrumbs that are duckin'' awesome.'
100
+ test_files: []