├── .github
├── CODEOWNERS
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── config.yml
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ └── ruby-tests.yml
├── .gitignore
├── .rubocop.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE.md
├── README.md
├── Rakefile
├── breadcrumbs.gemspec
├── examples
└── myapp
│ ├── .gitignore
│ ├── Gemfile
│ ├── README.rdoc
│ ├── Rakefile
│ ├── app
│ ├── assets
│ │ ├── images
│ │ │ └── .keep
│ │ └── stylesheets
│ │ │ └── application.css
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── concerns
│ │ │ └── .keep
│ │ └── site_controller.rb
│ ├── helpers
│ │ └── application_helper.rb
│ ├── mailers
│ │ └── .keep
│ ├── models
│ │ ├── .keep
│ │ └── concerns
│ │ │ └── .keep
│ └── views
│ │ ├── layouts
│ │ └── application.html.erb
│ │ └── site
│ │ ├── contact.html.erb
│ │ └── home.html.erb
│ ├── bin
│ ├── bundle
│ ├── rails
│ ├── rake
│ └── setup
│ ├── config.ru
│ ├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── assets.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── cookies_serializer.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── session_store.rb
│ │ └── wrap_parameters.rb
│ ├── locales
│ │ └── en.yml
│ ├── routes.rb
│ └── secrets.yml
│ ├── db
│ └── seeds.rb
│ ├── lib
│ ├── assets
│ │ └── .keep
│ └── tasks
│ │ └── .keep
│ ├── log
│ └── .keep
│ ├── public
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ ├── favicon.ico
│ └── robots.txt
│ └── vendor
│ └── assets
│ └── stylesheets
│ └── .keep
├── lib
├── breadcrumbs.rb
└── breadcrumbs
│ ├── action_controller_ext.rb
│ ├── render.rb
│ ├── render
│ ├── base.rb
│ ├── inline.rb
│ ├── list.rb
│ └── ordered_list.rb
│ └── version.rb
└── test
├── breadcrumbs_test.rb
├── support
└── pt-BR.yml
└── test_helper.rb
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # You can read more about CODEOWNERS at
2 | # https://help.github.com/github/creating-cloning-and-archiving-repositories/about-code-owners
3 |
4 | * @fnando
5 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 | ---
3 | github: [fnando]
4 | custom: ["https://paypal.me/nandovieira/🍕"]
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "🐛 Bug Report"
3 | about: Report a reproducible bug or regression.
4 | title: "Bug: "
5 | labels: "Status: Unconfirmed"
6 | ---
7 |
8 |
14 |
15 | ## Description
16 |
17 | [Add bug description here]
18 |
19 | ## How to reproduce
20 |
21 | [Add steps on how to reproduce this issue]
22 |
23 | ## What do you expect
24 |
25 | [Describe what do you expect to happen]
26 |
27 | ## What happened instead
28 |
29 | [Describe the actual results]
30 |
31 | ## Software:
32 |
33 | - Gem version: [Add gem version here]
34 | - Ruby version: [Add version here]
35 |
36 | ## Full backtrace
37 |
38 | ```text
39 | [Paste full backtrace here]
40 | ```
41 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | contact_links:
3 | - name: "🤨 Q&A"
4 | url: https://github.com/fnando/breadcrumbs/discussions/new?category=q-a
5 | about: Have a question? Ask it away here!
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "💡 Feature request"
3 | about: Have an idea that may be useful? Make a suggestion!
4 | title: 'Feature Request: '
5 | labels: 'Feature request'
6 |
7 | ---
8 |
9 | ## Description
10 |
11 | _A clear and concise description of what the problem is._
12 |
13 | ## Describe the solution
14 |
15 | _A clear and concise description of what you want to happen._
16 |
17 | ## Alternatives you considered
18 |
19 | _A clear and concise description of any alternative solutions or features you've considered._
20 |
21 | ## Additional context
22 |
23 | _Add any other context, screenshots, links, etc about the feature request here._
24 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 | PR Checklist
10 |
11 | ### PR Structure
12 |
13 | - [ ] This PR has reasonably narrow scope (if not, break it down into smaller
14 | PRs).
15 | - [ ] This PR avoids mixing refactoring changes with feature changes (split into
16 | two PRs otherwise).
17 | - [ ] This PR's title starts is concise and descriptive.
18 |
19 | ### Thoroughness
20 |
21 | - [ ] This PR adds tests for the most critical parts of the new functionality or
22 | fixes.
23 | - [ ] I've updated any docs, `.md` files, etc… affected by this change.
24 |
25 |
26 |
27 | ### What
28 |
29 | [TODO: Short statement about what is changing.]
30 |
31 | ### Why
32 |
33 | [TODO: Why this change is being made. Include any context required to understand
34 | the why.]
35 |
36 | ### Known limitations
37 |
38 | [TODO or N/A]
39 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Documentation:
3 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
4 |
5 | version: 2
6 | updates:
7 | - package-ecosystem: "github-actions"
8 | directory: "/"
9 | schedule:
10 | interval: "daily"
11 |
12 | - package-ecosystem: npm
13 | directory: "/"
14 | schedule:
15 | interval: "daily"
16 |
17 | - package-ecosystem: bundler
18 | directory: "/"
19 | schedule:
20 | interval: "daily"
21 |
--------------------------------------------------------------------------------
/.github/workflows/ruby-tests.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: ruby-tests
3 |
4 | on:
5 | pull_request_target:
6 | push:
7 | branches:
8 | - main
9 | workflow_dispatch:
10 | inputs: {}
11 |
12 | jobs:
13 | build:
14 | name: Tests with Ruby ${{ matrix.ruby }} and ${{ matrix.gemfile }}
15 | runs-on: "ubuntu-latest"
16 | if: |
17 | github.actor == 'dependabot[bot]' && github.event_name == 'pull_request_target' ||
18 | github.actor != 'dependabot[bot]'
19 | strategy:
20 | fail-fast: false
21 | matrix:
22 | ruby: ["2.7", "3.0", "3.1", "3.2"]
23 | gemfile:
24 | - Gemfile
25 |
26 | steps:
27 | - uses: actions/checkout@v3
28 |
29 | - uses: actions/cache@v3
30 | with:
31 | path: vendor/bundle
32 | key: >
33 | ${{ runner.os }}-${{ matrix.ruby }}-gems-${{
34 | hashFiles(matrix.gemfile) }}
35 |
36 | - name: Set up Ruby
37 | uses: ruby/setup-ruby@v1
38 | with:
39 | ruby-version: ${{ matrix.ruby }}
40 |
41 | - name: Install gem dependencies
42 | env:
43 | BUNDLE_GEMFILE: ${{ matrix.gemfile }}
44 | run: |
45 | gem install bundler
46 | bundle config path vendor/bundle
47 | bundle update --jobs 4 --retry 3
48 |
49 | - name: Run Tests
50 | env:
51 | BUNDLE_GEMFILE: ${{ matrix.gemfile }}
52 | run: |
53 | bundle exec rake
54 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | pkg
2 | doc
3 | *.lock
4 | coverage
5 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | ---
2 | inherit_gem:
3 | rubocop-fnando: .rubocop.yml
4 |
5 | AllCops:
6 | TargetRubyVersion: 2.7
7 | NewCops: enable
8 | Exclude:
9 | - examples/**/*
10 | - vendor/**/*
11 | - gemfiles/**/*
12 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at me@fnando.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [https://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: https://contributor-covenant.org
74 | [version]: https://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to breadcrumbs
2 |
3 | 👍🎉 First off, thanks for taking the time to contribute! 🎉👍
4 |
5 | The following is a set of guidelines for contributing to this project. These are
6 | mostly guidelines, not rules. Use your best judgment, and feel free to propose
7 | changes to this document in a pull request.
8 |
9 | ## Code of Conduct
10 |
11 | Everyone interacting in this project's codebases, issue trackers, chat rooms and
12 | mailing lists is expected to follow the
13 | [code of conduct](https://github.com/fnando/breadcrumbs/blob/main/CODE_OF_CONDUCT.md).
14 |
15 | ## Reporting bugs
16 |
17 | This section guides you through submitting a bug report. Following these
18 | guidelines helps maintainers and the community understand your report, reproduce
19 | the behavior, and find related reports.
20 |
21 | - Before creating bug reports, please check the open issues; somebody may
22 | already have submitted something similar, and you may not need to create a new
23 | one.
24 | - When you are creating a bug report, please include as many details as
25 | possible, with an example reproducing the issue.
26 |
27 | ## Contributing with code
28 |
29 | Before making any radicals changes, please make sure you discuss your intention
30 | by [opening an issue on Github](https://github.com/fnando/breadcrumbs/issues).
31 |
32 | When you're ready to make your pull request, follow checklist below to make sure
33 | your contribution is according to how this project works.
34 |
35 | 1. [Fork](https://help.github.com/forking/) breadcrumbs
36 | 2. Create a topic branch - `git checkout -b my_branch`
37 | 3. Make your changes using [descriptive commit messages](#commit-messages)
38 | 4. Update CHANGELOG.md describing your changes by adding an entry to the
39 | "Unreleased" section. If this section is not available, create one right
40 | before the last version.
41 | 5. Push to your branch - `git push origin my_branch`
42 | 6. [Create a pull request](https://help.github.com/articles/creating-a-pull-request)
43 | 7. That's it!
44 |
45 | ## Styleguides
46 |
47 | ### Commit messages
48 |
49 | - Use the present tense ("Add feature" not "Added feature")
50 | - Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
51 | - Limit the first line to 72 characters or less
52 | - Reference issues and pull requests liberally after the first line
53 |
54 | ### Changelog
55 |
56 | - Add a message describing your changes to the "Unreleased" section. The
57 | changelog message should follow the same style as the commit message.
58 | - Prefix your message with one of the following:
59 | - `[Added]` for new features.
60 | - `[Changed]` for changes in existing functionality.
61 | - `[Deprecated]` for soon-to-be removed features.
62 | - `[Removed]` for now removed features.
63 | - `[Fixed]` for any bug fixes.
64 | - `[Security]` in case of vulnerabilities.
65 |
66 | ### Ruby code
67 |
68 | - This project uses [Rubocop](https://rubocop.org) to enforce code style. Before
69 | submitting your changes, make sure your tests are passing and code conforms to
70 | the expected style by running `rake`.
71 | - Do not change the library version. This will be done by the maintainer
72 | whenever a new version is about to be released.
73 |
74 | ### JavaScript code
75 |
76 | - This project uses [ESLint](https://eslint.org) to enforce code style. Before
77 | submitting your changes, make sure your tests are passing and code conforms to
78 | the expected style by running `yarn test:ci`.
79 | - Do not change the library version. This will be done by the maintainer
80 | whenever a new version is about to be released.
81 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 | gemspec
5 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Nando Vieira
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Breadcrumbs
2 |
3 | [](https://github.com/fnando/breadcrumbs/actions/workflows/ruby-tests.yml)
4 | [](https://rubygems.org/gems/breadcrumbs)
5 | [](https://rubygems.org/gems/breadcrumbs)
6 |
7 | Breadcrumbs is a simple plugin that adds a `breadcrumbs` object to controllers
8 | and views.
9 |
10 | ## Instalation
11 |
12 | Just run `gem install breadcrumbs`. Or add `gem "breadcrumbs"` to your Gemfile.
13 |
14 | ## Usage
15 |
16 | On your controller (optional):
17 |
18 | ```ruby
19 | class ApplicationController < ActionController::Base
20 | before_action :add_initial_breadcrumbs
21 |
22 | private
23 | def add_initial_breadcrumbs
24 | breadcrumbs.add "Home", root_path
25 | end
26 | end
27 |
28 | class ThingsController < ApplicationController
29 | def index
30 | breadcrumbs.add "Things", things_path
31 | end
32 | end
33 | ```
34 |
35 | You don't need to provide an URL; in that case, a span will be generated instead
36 | of a link:
37 |
38 | ```ruby
39 | breadcrumbs.add "Some page"
40 | ```
41 |
42 | You can set additional HTML attributes if you need to:
43 |
44 | ```ruby
45 | breadcrumbs.add "Home", root_path, id: "home", title: "Go to the home page"
46 | ```
47 |
48 | On your view (possibly application.html.erb):
49 |
50 | ```erb
51 | <%= breadcrumbs.render %>
52 | ```
53 |
54 | You can render as ordered list.
55 |
56 | ```erb
57 | <%= breadcrumbs.render(format: :ordered_list) %>
58 | ```
59 |
60 | You can render as inline links.
61 |
62 | ```erb
63 | <%= breadcrumbs.render(format: :inline) %>
64 | ```
65 |
66 | You can set your own separator:
67 |
68 | ```erb
69 |
70 | You are here: <%= breadcrumbs.render(format: :inline, separator: "|") %>
71 |
72 | ```
73 |
74 | You can also define your own formatter. Just create a class that implements a
75 | `render` instance method and you're good to go.
76 |
77 | ```ruby
78 | class Breadcrumbs::Render::Dl
79 | def render
80 | # return breadcrumbs wrapped in a tag
81 | end
82 | end
83 | ```
84 |
85 | To use your new format, just provide the `:format` option.
86 |
87 | ```ruby
88 | breadcrumbs.render(format: :dl)
89 | ```
90 |
91 | ### I18n
92 |
93 | Breadcrumbs is integrated with I18n. You can set translations like:
94 |
95 | ```yaml
96 | en:
97 | breadcrumbs:
98 | home: "Home"
99 | ```
100 |
101 | And then you just call
102 |
103 | ```ruby
104 | breadcrumbs.add :home
105 | ```
106 |
107 | In fact, you can provide any scope you want.
108 |
109 | ```ruby
110 | breadcrumbs.add :"titles.home"
111 | ```
112 |
113 | If you don't want to translate a label, just pass the option `:i18n` as `false`.
114 |
115 | ```ruby
116 | breadcrumbs.add :home, nil, i18n: false
117 | ```
118 |
119 | ## Maintainer
120 |
121 | - [Nando Vieira](https://github.com/fnando)
122 |
123 | ## Contributors
124 |
125 | - https://github.com/fnando/breadcrumbs/contributors
126 |
127 | ## Contributing
128 |
129 | For more details about how to contribute, please read
130 | https://github.com/fnando/breadcrumbs/blob/main/CONTRIBUTING.md.
131 |
132 | ## License
133 |
134 | The gem is available as open source under the terms of the
135 | [MIT License](https://opensource.org/licenses/MIT). A copy of the license can be
136 | found at https://github.com/fnando/breadcrumbs/blob/main/LICENSE.md.
137 |
138 | ## Code of Conduct
139 |
140 | Everyone interacting in the breadcrumbs project's codebases, issue trackers,
141 | chat rooms and mailing lists is expected to follow the
142 | [code of conduct](https://github.com/fnando/breadcrumbs/blob/main/CODE_OF_CONDUCT.md).
143 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "bundler/gem_tasks"
4 | require "rake/testtask"
5 | require "rubocop/rake_task"
6 |
7 | Rake::TestTask.new(:test) do |t|
8 | t.libs << "test"
9 | t.test_files = FileList["test/**/*_test.rb"]
10 | t.warning = false
11 | end
12 |
13 | RuboCop::RakeTask.new
14 |
15 | task default: %i[test rubocop]
16 |
--------------------------------------------------------------------------------
/breadcrumbs.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "./lib/breadcrumbs/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "breadcrumbs"
7 | s.version = Breadcrumbs::Version::STRING
8 | s.platform = Gem::Platform::RUBY
9 | s.authors = ["Nando Vieira"]
10 | s.email = ["fnando.vieira@gmail.com"]
11 | s.homepage = "http://rubygems.org/gems/breadcrumbs"
12 | s.summary = "Breadcrumbs is a simple plugin that adds a `breadcrumbs` " \
13 | "object to controllers and views."
14 | s.description = s.summary
15 | s.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
16 |
17 | github_url = "https://github.com/fnando/breadcrumbs"
18 | github_tree_url = "#{github_url}/tree/v#{s.version}"
19 |
20 | s.metadata["homepage_uri"] = s.homepage
21 | s.metadata["bug_tracker_uri"] = "#{github_url}/issues"
22 | s.metadata["source_code_uri"] = github_tree_url
23 | s.metadata["changelog_uri"] = "#{github_tree_url}/CHANGELOG.md"
24 | s.metadata["documentation_uri"] = "#{github_tree_url}/README.md"
25 | s.metadata["license_uri"] = "#{github_tree_url}/LICENSE.md"
26 | s.metadata["rubygems_mfa_required"] = "true"
27 |
28 | s.files = `git ls-files`.split("\n")
29 | s.executables = `git ls-files -- bin/*`
30 | .split("\n")
31 | .map {|f| File.basename(f) }
32 | s.require_paths = ["lib"]
33 |
34 | s.add_dependency "actionview"
35 | s.add_dependency "activesupport"
36 | s.add_dependency "i18n"
37 |
38 | s.add_development_dependency "actionpack"
39 | s.add_development_dependency "bundler"
40 | s.add_development_dependency "minitest-utils"
41 | s.add_development_dependency "mocha"
42 | s.add_development_dependency "nokogiri"
43 | s.add_development_dependency "pry-meta"
44 | s.add_development_dependency "rake"
45 | s.add_development_dependency "rubocop"
46 | s.add_development_dependency "rubocop-fnando"
47 | s.add_development_dependency "simplecov"
48 | end
49 |
--------------------------------------------------------------------------------
/examples/myapp/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile '~/.gitignore_global'
6 |
7 | # Ignore bundler config.
8 | /.bundle
9 |
10 | # Ignore all logfiles and tempfiles.
11 | /log/*.log
12 | /tmp
13 |
--------------------------------------------------------------------------------
/examples/myapp/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'rails', '4.2.0.beta1'
4 | gem 'sass-rails', '~> 5.0.0.beta1'
5 | gem 'uglifier', '>= 1.3.0'
6 | gem 'rails-html-sanitizer', '~> 1.0'
7 | gem 'breadcrumbs', path: '../..'
8 |
9 | group :development, :test do
10 | gem 'spring'
11 | end
12 |
13 |
--------------------------------------------------------------------------------
/examples/myapp/README.rdoc:
--------------------------------------------------------------------------------
1 | == README
2 |
3 | This README would normally document whatever steps are necessary to get the
4 | application up and running.
5 |
6 | Things you may want to cover:
7 |
8 | * Ruby version
9 |
10 | * System dependencies
11 |
12 | * Configuration
13 |
14 | * Database creation
15 |
16 | * Database initialization
17 |
18 | * How to run the test suite
19 |
20 | * Services (job queues, cache servers, search engines, etc.)
21 |
22 | * Deployment instructions
23 |
24 | * ...
25 |
26 |
27 | Please feel free to use a different markup language if you do not plan to run
28 | rake doc:app.
29 |
--------------------------------------------------------------------------------
/examples/myapp/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require File.expand_path('../config/application', __FILE__)
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/examples/myapp/app/assets/images/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/app/assets/images/.keep
--------------------------------------------------------------------------------
/examples/myapp/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | *= require_tree .
3 | *= require_self
4 | */
5 |
6 | .breadcrumbs {
7 | font-family: sans-serif;
8 | font-size: 14px;
9 | background: #f5f5f5;
10 | list-style: none;
11 | margin: 0;
12 | padding: 10px;
13 | overflow: hidden;
14 | color: #777;
15 | border-radius: 5px;
16 | }
17 |
18 | .breadcrumbs li {
19 | float: left;
20 | }
21 |
22 | .breadcrumbs li + li:before {
23 | content: '/';
24 | color: #ccc;
25 | margin: 0 10px;
26 | }
27 |
28 | .breadcrumbs a {
29 | color: #428bca;
30 | text-decoration: none;
31 | }
32 |
33 | .breadcrumbs a:hover {
34 | text-decoration: underline;
35 | }
36 |
37 | .breadcrumbs .first {
38 | position: relative;
39 | padding-left: 18px;
40 | }
41 |
42 | .breadcrumbs .first:before {
43 | content: '\2302';
44 | font-size: 20px;
45 | position: absolute;
46 | left: 0;
47 | top: -2px;
48 | color: #ccc;
49 | }
50 |
--------------------------------------------------------------------------------
/examples/myapp/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | # Prevent CSRF attacks by raising an exception.
3 | # For APIs, you may want to use :null_session instead.
4 | protect_from_forgery with: :exception
5 |
6 | before_action :set_root_breadcrumb
7 |
8 | private
9 |
10 | def set_root_breadcrumb
11 | breadcrumbs.add :home, root_path
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/examples/myapp/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/examples/myapp/app/controllers/site_controller.rb:
--------------------------------------------------------------------------------
1 | class SiteController < ApplicationController
2 | def home
3 | end
4 |
5 | def contact
6 | breadcrumbs.add :pages
7 | breadcrumbs.add :contact, contact_path
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/examples/myapp/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/examples/myapp/app/mailers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/app/mailers/.keep
--------------------------------------------------------------------------------
/examples/myapp/app/models/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/app/models/.keep
--------------------------------------------------------------------------------
/examples/myapp/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/app/models/concerns/.keep
--------------------------------------------------------------------------------
/examples/myapp/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Myapp
5 | <%= stylesheet_link_tag 'application', media: 'all' %>
6 | <%= csrf_meta_tags %>
7 |
8 |
9 |
10 | <%= breadcrumbs.render(format: 'list') %>
11 |
12 | <%= yield %>
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/examples/myapp/app/views/site/contact.html.erb:
--------------------------------------------------------------------------------
1 | Contact
2 |
--------------------------------------------------------------------------------
/examples/myapp/app/views/site/home.html.erb:
--------------------------------------------------------------------------------
1 | Home page
2 |
--------------------------------------------------------------------------------
/examples/myapp/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/examples/myapp/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../../config/application', __FILE__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/examples/myapp/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/examples/myapp/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 |
4 | # path to your application root.
5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6 |
7 | Dir.chdir APP_ROOT do
8 | # This script is a starting point to setup your application.
9 | # Add necessary setup steps to this file:
10 |
11 | puts "== Installing dependencies =="
12 | system "gem install bundler --conservative"
13 | system "bundle check || bundle install"
14 |
15 | # puts "\n== Copying sample files =="
16 | # unless File.exist?("config/database.yml")
17 | # system "cp config/database.yml.sample config/database.yml"
18 | # end
19 |
20 | puts "\n== Preparing database =="
21 | system "bin/rake db:setup"
22 |
23 | puts "\n== Removing old logs and tempfiles =="
24 | system "rm -f log/*"
25 | system "rm -rf tmp/cache"
26 |
27 | puts "\n== Restarting application server =="
28 | system "touch tmp/restart.txt"
29 | end
30 |
--------------------------------------------------------------------------------
/examples/myapp/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Rails.application
5 |
--------------------------------------------------------------------------------
/examples/myapp/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | # Pick the frameworks you want:
4 | require "active_model/railtie"
5 | # require "active_record/railtie"
6 | require "action_controller/railtie"
7 | require "action_mailer/railtie"
8 | require "action_view/railtie"
9 | require "sprockets/railtie"
10 | # require "rails/test_unit/railtie"
11 |
12 | # Require the gems listed in Gemfile, including any gems
13 | # you've limited to :test, :development, or :production.
14 | Bundler.require(*Rails.groups)
15 |
16 | module Myapp
17 | class Application < Rails::Application
18 | # Settings in config/environments/* take precedence over those specified here.
19 | # Application configuration should go into files in config/initializers
20 | # -- all .rb files in that directory are automatically loaded.
21 |
22 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
23 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
24 | # config.time_zone = 'Central Time (US & Canada)'
25 |
26 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
27 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
28 | # config.i18n.default_locale = :de
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/examples/myapp/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 |
--------------------------------------------------------------------------------
/examples/myapp/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/examples/myapp/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports and disable caching.
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send.
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger.
20 | config.active_support.deprecation = :log
21 |
22 | # Debug mode disables concatenation and preprocessing of assets.
23 | # This option may cause significant delays in view rendering with a large
24 | # number of complex assets.
25 | config.assets.debug = true
26 |
27 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
28 | # yet still be able to expire them through the digest params.
29 | config.assets.digest = true
30 |
31 | # Adds additional error checking when serving assets at runtime.
32 | # Checks for improperly declared sprockets dependencies.
33 | # Raises helpful error messages.
34 | config.assets.raise_runtime_errors = true
35 |
36 | # Raises error for missing translations
37 | # config.action_view.raise_on_missing_translations = true
38 | end
39 |
--------------------------------------------------------------------------------
/examples/myapp/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # Code is not reloaded between requests.
5 | config.cache_classes = true
6 |
7 | # Eager load code on boot. This eager loads most of Rails and
8 | # your application in memory, allowing both threaded web servers
9 | # and those relying on copy on write to perform better.
10 | # Rake tasks automatically ignore this option for performance.
11 | config.eager_load = true
12 |
13 | # Full error reports are disabled and caching is turned on.
14 | config.consider_all_requests_local = false
15 | config.action_controller.perform_caching = true
16 |
17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like NGINX, varnish or squid.
20 | # config.action_dispatch.rack_cache = true
21 |
22 | # Disable Rails's static asset server (Apache or NGINX will already do this).
23 | config.serve_static_assets = false
24 |
25 | # Compress JavaScripts and CSS.
26 | config.assets.js_compressor = :uglifier
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = false
31 |
32 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
33 | # yet still be able to expire them through the digest params.
34 | config.assets.digest = true
35 |
36 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
37 |
38 | # Specifies the header that your server uses for sending files.
39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
41 |
42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
43 | # config.force_ssl = true
44 |
45 | # Set to :info to decrease the log volume.
46 | config.log_level = :debug
47 |
48 | # Prepend all log lines with the following tags.
49 | # config.log_tags = [ :subdomain, :uuid ]
50 |
51 | # Use a different logger for distributed setups.
52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
53 |
54 | # Use a different cache store in production.
55 | # config.cache_store = :mem_cache_store
56 |
57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
58 | # config.action_controller.asset_host = "http://assets.example.com"
59 |
60 | # Ignore bad email addresses and do not raise email delivery errors.
61 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
62 | # config.action_mailer.raise_delivery_errors = false
63 |
64 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
65 | # the I18n.default_locale when a translation cannot be found).
66 | config.i18n.fallbacks = true
67 |
68 | # Send deprecation notices to registered listeners.
69 | config.active_support.deprecation = :notify
70 |
71 | # Use default logging formatter so that PID and timestamp are not suppressed.
72 | config.log_formatter = ::Logger::Formatter.new
73 | end
74 |
--------------------------------------------------------------------------------
/examples/myapp/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure static asset server for tests with Cache-Control for performance.
16 | config.serve_static_assets = true
17 | config.static_cache_control = 'public, max-age=3600'
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 |
34 | # Print deprecation notices to the stderr.
35 | config.active_support.deprecation = :stderr
36 |
37 | # Raises error for missing translations
38 | # config.action_view.raise_on_missing_translations = true
39 | end
40 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Version of your assets, change this if you want to expire all your assets.
4 | Rails.application.config.assets.version = '1.0'
5 |
6 | # Add additional assets to the asset load path
7 | # Rails.application.config.assets.paths << Emoji.images_path
8 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
4 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_myapp_session'
4 |
--------------------------------------------------------------------------------
/examples/myapp/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | end
10 |
--------------------------------------------------------------------------------
/examples/myapp/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
25 | breadcrumbs:
26 | home: 'My app'
27 | pages: 'Pages'
28 | contact: 'Contact'
29 |
--------------------------------------------------------------------------------
/examples/myapp/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root to: 'site#home'
3 | get :contact, to: 'site#contact'
4 | resources :projects
5 | end
6 |
--------------------------------------------------------------------------------
/examples/myapp/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | development:
14 | secret_key_base: 7343b6667cab06eb7ee86cc0d29fdeff6f3ea8354fc7eabcbbc8e7e370a35169906267a0adf23fc7dd983eb700867c72c346f9c5f507067dca4e7d07028fa687
15 |
16 | test:
17 | secret_key_base: dc87916f434557d81ddee2465a49a0cdd9fd5227ca5fd0ddb5798d5f33d2f8750688ca5d90d70fd7010450e6547d05aae44291de9a2623121408e666b0d644a6
18 |
19 | # Do not keep production secrets in the repository,
20 | # instead read values from the environment.
21 | production:
22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
23 |
--------------------------------------------------------------------------------
/examples/myapp/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7 | # Mayor.create(name: 'Emanuel', city: cities.first)
8 |
--------------------------------------------------------------------------------
/examples/myapp/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/lib/assets/.keep
--------------------------------------------------------------------------------
/examples/myapp/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/lib/tasks/.keep
--------------------------------------------------------------------------------
/examples/myapp/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/log/.keep
--------------------------------------------------------------------------------
/examples/myapp/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The page you were looking for doesn't exist.
62 |
You may have mistyped the address or the page may have moved.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/examples/myapp/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
The change you wanted was rejected.
62 |
Maybe you tried to change something you didn't have access to.
63 |
64 |
If you are the application owner check the logs for more information.
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/examples/myapp/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
We're sorry, but something went wrong.
62 |
63 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/examples/myapp/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/public/favicon.ico
--------------------------------------------------------------------------------
/examples/myapp/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/examples/myapp/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnando/breadcrumbs/756da079c4e14dbd2e153377927aa7ef1d056aa3/examples/myapp/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------
/lib/breadcrumbs.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "i18n"
4 | require "action_view"
5 | require "active_support/inflector"
6 |
7 | require "breadcrumbs/render"
8 | require "breadcrumbs/action_controller_ext" if defined?(ActionController)
9 |
10 | class Breadcrumbs
11 | attr_accessor :items
12 |
13 | def initialize # :nodoc:
14 | self.items = []
15 | end
16 |
17 | # Add a new breadcrumbs.
18 | #
19 | # breadcrumbs.add 'Home'
20 | # breadcrumbs.add 'Home', '/'
21 | # breadcrumbs.add 'Home', '/', class: 'home'
22 | #
23 | # If you provide a symbol as text, it will try to
24 | # find it as I18n scope.
25 | #
26 | def add(text, url = nil, options = {})
27 | options = {i18n: true}.merge(options)
28 | text = translate(text) if options.delete(:i18n)
29 | items << [text.to_s, url, options]
30 | end
31 |
32 | alias << add
33 |
34 | # Render breadcrumbs using the specified format.
35 | # Use HTML lists by default, but can be plain links.
36 | #
37 | # breadcrumbs.render
38 | # breadcrumbs.render(format: "inline")
39 | # breadcrumbs.render(format: "inline", separator: "|")
40 | # breadcrumbs.render(format: "list")
41 | # breadcrumbs.render(format: "ordered_list")
42 | # breadcrumbs.render(id: 'breadcrumbs')
43 | # breadcrumbs.render(class: 'breadcrumbs')
44 | #
45 | # You can also define your own formatter. Just create a class that implements
46 | # a +render+ instance
47 | # method and you're good to go.
48 | #
49 | # class Breadcrumbs::Render::Dl
50 | # def render
51 | # # return breadcrumbs wrapped in a tag
52 | # end
53 | # end
54 | #
55 | # To use your new format, just provide the :format option.
56 | #
57 | # breadcrumbs.render(format: 'dl')
58 | #
59 | def render(options = {})
60 | options[:format] ||= :list
61 |
62 | klass_name = options.delete(:format).to_s.classify
63 | klass = Breadcrumbs::Render.const_get(klass_name)
64 | klass.new(self, options).render
65 | end
66 |
67 | def translate(scope) # :nodoc:
68 | return scope if scope.match?(/\A[\s.]+\z/)
69 |
70 | text = begin
71 | I18n.t(scope, scope: "breadcrumbs", raise: true)
72 | rescue StandardError
73 | nil
74 | end
75 |
76 | text ||= begin
77 | I18n.t(scope, default: scope.to_s)
78 | rescue StandardError
79 | scope
80 | end
81 |
82 | text
83 | end
84 | end
85 |
--------------------------------------------------------------------------------
/lib/breadcrumbs/action_controller_ext.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Breadcrumbs
4 | module ActionController # :nodoc: all
5 | def self.included(base)
6 | base.send :helper_method, :breadcrumbs
7 | end
8 |
9 | def breadcrumbs
10 | @breadcrumbs ||= Breadcrumbs.new
11 | end
12 | end
13 | end
14 |
15 | ActionController::Base.include Breadcrumbs::ActionController
16 |
--------------------------------------------------------------------------------
/lib/breadcrumbs/render.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Breadcrumbs
4 | module Render
5 | require "breadcrumbs/render/base"
6 | require "breadcrumbs/render/inline"
7 | require "breadcrumbs/render/list"
8 | require "breadcrumbs/render/ordered_list"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/lib/breadcrumbs/render/base.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Breadcrumbs
4 | module Render
5 | class Base # :nodoc: all
6 | include ::ActionView::Helpers::TagHelper
7 |
8 | attr_accessor :breadcrumbs, :default_options, :output_buffer
9 |
10 | def initialize(breadcrumbs, default_options = {})
11 | @breadcrumbs = breadcrumbs
12 | @default_options = default_options
13 | end
14 |
15 | def tag(name, content = "", options = {}, &block)
16 | content_tag(name, content, options, &block)
17 | end
18 |
19 | protected def wrap_item(url, text, options)
20 | if url
21 | tag(:a, text, options.merge(href: url))
22 | else
23 | tag(:span, text, options)
24 | end
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/breadcrumbs/render/inline.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Breadcrumbs
4 | module Render
5 | class Inline < Base # :nodoc: all
6 | def render
7 | options = {
8 | class: "breadcrumbs",
9 | separator: "»"
10 | }.merge(default_options)
11 |
12 | html = []
13 | items = breadcrumbs.items
14 | size = items.size
15 |
16 | items.each_with_index do |item, i|
17 | html << render_item(item, i, size)
18 | end
19 |
20 | separator = tag(:span, options[:separator], class: "separator")
21 |
22 | html.join(" #{separator} ").html_safe
23 | end
24 |
25 | def render_item(item, i, size)
26 | text, url, options = *item
27 |
28 | css = [options[:class]].compact
29 | css << "first" if i.zero?
30 | css << "last" if i == size - 1
31 | css << "item-#{i}"
32 |
33 | options[:class] = css.join(" ")
34 | options[:class].gsub!(/^ *(.*?)$/, '\\1')
35 |
36 | wrap_item(url, text, options)
37 | end
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/lib/breadcrumbs/render/list.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Breadcrumbs
4 | module Render
5 | class List < Base # :nodoc: all
6 | def render
7 | options = {class: "breadcrumbs"}.merge(default_options)
8 |
9 | tag(list_style, options) do
10 | html = []
11 | items = breadcrumbs.items
12 | size = items.size
13 |
14 | items.each_with_index do |item, i|
15 | html << render_item(item, i, size)
16 | end
17 |
18 | html.join.html_safe
19 | end
20 | end
21 |
22 | def list_style
23 | :ul
24 | end
25 |
26 | def render_item(item, i, size)
27 | css = []
28 | css << "first" if i.zero?
29 | css << "last" if i == size - 1
30 | css << "item-#{i}"
31 |
32 | text, url, options = *item
33 | text = wrap_item(url, text, options)
34 | tag(:li, text, class: css.join(" "))
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/lib/breadcrumbs/render/ordered_list.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Breadcrumbs
4 | module Render
5 | class OrderedList < List # :nodoc: all
6 | def list_style
7 | :ol
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/breadcrumbs/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class Breadcrumbs
4 | module Version # :nodoc: all
5 | MAJOR = 0
6 | MINOR = 3
7 | PATCH = 0
8 | STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/test/breadcrumbs_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "test_helper"
4 |
5 | class BreadcrumbsTest < Minitest::Test
6 | def setup
7 | @breadcrumbs = Breadcrumbs.new
8 | @inline = Breadcrumbs::Render::Inline.new(@breadcrumbs)
9 | end
10 |
11 | test "returns safe html" do
12 | assert @breadcrumbs.render(format: "list").html_safe?
13 | end
14 |
15 | test "adds item" do
16 | @breadcrumbs.add "Home"
17 |
18 | assert_equal 1, @breadcrumbs.items.count
19 |
20 | @breadcrumbs << "Home"
21 |
22 | assert_equal 2, @breadcrumbs.items.count
23 | end
24 |
25 | test "renders tag with attributes" do
26 | expected = %[Hi!]
27 |
28 | assert_equal expected,
29 | @inline.tag(:span, "Hi!", class: "greetings", id: "hi")
30 | end
31 |
32 | test "renders tag with block" do
33 | assert_equal "Hi!", @inline.tag(:span) { "Hi!" }
34 | end
35 |
36 | test "renders tag with block and attributes" do
37 | expected = %[Hi!]
38 |
39 | assert_equal expected,
40 | @inline.tag(:span, class: "greetings", id: "hi") { "Hi!" }
41 | end
42 |
43 | test "renders nested tags" do
44 | expected = %[Hi!]
45 | actual = @inline.tag(:span, class: "greetings") do
46 | @inline.tag(:strong, "Hi!", id: "hi")
47 | end
48 |
49 | assert_equal expected, actual
50 | end
51 |
52 | test "renders as list" do
53 | @breadcrumbs.add "Home", "/", class: "home"
54 | html = Nokogiri::HTML(@breadcrumbs.render)
55 |
56 | refute_nil html.at("ul.breadcrumbs")
57 | assert_nil html.at("ul.breadcrumbs[format=list]")
58 | end
59 |
60 | test "renders as ordered list" do
61 | @breadcrumbs.add "Home", "/"
62 | html = Nokogiri::HTML(@breadcrumbs.render(format: "ordered_list"))
63 |
64 | refute_nil html.at("ol.breadcrumbs")
65 | end
66 |
67 | test "renders as list with custom attributes" do
68 | @breadcrumbs.add "Home", "/", class: "home"
69 | html = Nokogiri::HTML(@breadcrumbs.render(id: "breadcrumbs", class: "top"))
70 |
71 | refute_nil html.at("ul.top#breadcrumbs")
72 | end
73 |
74 | test "renders as list add items" do
75 | @breadcrumbs.add "Home", "/", class: "home"
76 | @breadcrumbs.add "About", "/about", class: "about"
77 | @breadcrumbs.add "People"
78 |
79 | html = Nokogiri::HTML(@breadcrumbs.render)
80 | items = html.search("li")
81 |
82 | assert_equal 3, items.count
83 |
84 | assert_equal "first item-0", items[0]["class"]
85 | assert_equal "Home", items[0].inner_text
86 |
87 | link = items[0].at("a")
88 |
89 | assert_equal "home", link["class"]
90 | assert_equal "/", link["href"]
91 |
92 | assert_equal "item-1", items[1]["class"]
93 | assert_equal "About", items[1].inner_text
94 |
95 | link = items[1].at("a")
96 |
97 | assert_equal "about", link["class"]
98 | assert_equal "/about", link["href"]
99 |
100 | assert_equal "last item-2", items[2]["class"]
101 | assert_equal "People", items[2].inner_text
102 | assert_nil items[2].at("a")
103 | refute_nil items[2].at("span")
104 | end
105 |
106 | test "renders inline" do
107 | @breadcrumbs.add "Home", "/", class: "home"
108 | html = Nokogiri::HTML(@breadcrumbs.render(format: "inline"))
109 |
110 | assert_nil html.at("ul.breadcrumbs")
111 | end
112 |
113 | test "renders inline add items" do
114 | @breadcrumbs.add "Home", "/", class: "home"
115 | @breadcrumbs.add "About", "/about", class: "about"
116 | @breadcrumbs.add "People"
117 |
118 | html = @breadcrumbs.render(format: "inline")
119 | html = Nokogiri::HTML("#{html}
")
120 | separator = "»"
121 |
122 | items = html.search("div *")
123 |
124 | assert_equal 5, items.count
125 |
126 | assert_equal "a", items[0].name
127 | assert_equal "home first item-0", items[0]["class"]
128 | assert_equal "Home", items[0].inner_text
129 | assert_equal "/", items[0]["href"]
130 |
131 | assert_equal "span", items[1].name
132 | assert_equal "separator", items[1]["class"]
133 | assert_equal separator, items[1].inner_text
134 |
135 | assert_equal "a", items[2].name
136 | assert_equal "about item-1", items[2]["class"]
137 | assert_equal "About", items[2].inner_text
138 | assert_equal "/about", items[2]["href"]
139 |
140 | assert_equal "span", items[3].name
141 | assert_equal "separator", items[3]["class"]
142 | assert_equal separator, items[3].inner_text
143 |
144 | assert_equal "span", items[4].name
145 | assert_equal "last item-2", items[4]["class"]
146 | assert_equal "People", items[4].inner_text
147 | end
148 |
149 | test "renders inline with custom separator" do
150 | @breadcrumbs.add "Home", "/", class: "home"
151 | @breadcrumbs.add "People"
152 |
153 | html = Nokogiri::HTML(@breadcrumbs.render(format: "inline", separator: "|"))
154 |
155 | assert_equal "|", html.at("span.separator").inner_text
156 | end
157 |
158 | test "renders original text when disabling_translation" do
159 | @breadcrumbs.add :home, nil, i18n: false
160 | @breadcrumbs.add :people
161 |
162 | html = Nokogiri::HTML(@breadcrumbs.render)
163 |
164 | items = html.search("li")
165 |
166 | assert_equal "home", items[0].inner_text
167 | assert_equal "Nosso time", items[1].inner_text
168 | end
169 |
170 | test "renders internationalized text using default scope" do
171 | @breadcrumbs.add :home
172 | @breadcrumbs.add :people
173 |
174 | html = Nokogiri::HTML(@breadcrumbs.render)
175 |
176 | items = html.search("li")
177 |
178 | assert_equal "Página inicial", items[0].inner_text
179 | assert_equal "Nosso time", items[1].inner_text
180 | end
181 |
182 | test "renders scope as text for missing scope" do
183 | @breadcrumbs.add :contact
184 | @breadcrumbs.add "Help"
185 |
186 | html = Nokogiri::HTML(@breadcrumbs.render)
187 | items = html.search("li")
188 |
189 | assert_equal "contact", items[0].inner_text
190 | assert_equal "Help", items[1].inner_text
191 | end
192 |
193 | test "extends action controller" do
194 | methods = ActionController::Base.instance_methods
195 |
196 | assert(methods.include?(:breadcrumbs) || methods.include?("breadcrumbs"))
197 | end
198 |
199 | test "escapes text when rendering inline" do
200 | @breadcrumbs.add ""
201 | html = Nokogiri::HTML(@breadcrumbs.render(format: "inline"))
202 |
203 | assert_empty html.search("script")
204 | end
205 |
206 | test "escapes text when rendering list" do
207 | @breadcrumbs.add ""
208 | html = Nokogiri::HTML(@breadcrumbs.render)
209 |
210 | assert_empty html.search("script")
211 | end
212 |
213 | test "renders dots as breadcrumb items" do
214 | @breadcrumbs.add "."
215 | @breadcrumbs.add ".."
216 | @breadcrumbs.add "..."
217 | @breadcrumbs.add ". . ."
218 | html = Nokogiri::HTML(@breadcrumbs.render)
219 |
220 | items = html.search("li")
221 |
222 | assert_equal ".", items[0].inner_text
223 | assert_equal "..", items[1].inner_text
224 | assert_equal "...", items[2].inner_text
225 | assert_equal ". . .", items[3].inner_text
226 | end
227 | end
228 |
--------------------------------------------------------------------------------
/test/support/pt-BR.yml:
--------------------------------------------------------------------------------
1 | ---
2 | pt-BR:
3 | people: "Nosso time"
4 |
5 | breadcrumbs:
6 | home: "Página inicial"
7 | about: "Sobre"
8 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "simplecov"
4 | SimpleCov.start
5 |
6 | require "bundler/setup"
7 | require "minitest/utils"
8 | require "minitest/autorun"
9 | require "cgi"
10 | require "nokogiri"
11 | require "action_controller"
12 |
13 | require "breadcrumbs"
14 |
15 | I18n.load_path << "#{File.dirname(__FILE__)}/support/pt-BR.yml"
16 | I18n.locale = "pt-BR"
17 |
--------------------------------------------------------------------------------