navtastic 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f71489809ad37489fff943b48ecc3c00224a7d5d
4
+ data.tar.gz: 8d52c7216084c2e84d620ae1f94b7464fc4c68ad
5
+ SHA512:
6
+ metadata.gz: c9a022d6a93b60adbc98dfed4d8fe26b9a9b4d35c6ac1e37a83e9a6c511cd4c021ed15e5fd4cc6871d40c585b032b13e6062c503550d11892fdccf7802d69015
7
+ data.tar.gz: 6b3678f6e320f10eab9f158845ec34cdb634f0b3babe35fa9c7649dfd907148a348438b6a7febb60bfef866fe185e76fe8225ff3b0b1cf0dc1b251750a9c7b85
@@ -0,0 +1,70 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+ jobs:
7
+ build:
8
+ docker:
9
+ # specify the version you desire here
10
+ - image: circleci/ruby:2.4.1
11
+
12
+ # Specify service dependencies here if necessary
13
+ # CircleCI maintains a library of pre-built images
14
+ # documented at https://circleci.com/docs/2.0/circleci-images/
15
+ # - image: circleci/postgres:9.4
16
+
17
+ working_directory: ~/navtastic
18
+
19
+ steps:
20
+ - checkout
21
+
22
+ - run:
23
+ name: install dependencies
24
+ command: |
25
+ echo "gem 'rspec_junit_formatter'" >> Gemfile
26
+ echo "gem 'rubocop-junit-formatter'" >> Gemfile
27
+ echo "gem 'simplecov', require: false" >> Gemfile
28
+
29
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
30
+
31
+ - run:
32
+ name: install code climate test reporter
33
+ command: |
34
+ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
35
+ chmod +x ./cc-test-reporter
36
+ sudo mkdir -p $CIRCLE_TEST_REPORTS/phpunit
37
+
38
+ # run tests!
39
+ - run:
40
+ name: run tests
41
+ command: |
42
+ mkdir /tmp/test-results
43
+
44
+ ./cc-test-reporter before-build
45
+
46
+ COVERAGE=true bundle exec rspec --format progress \
47
+ --format RspecJunitFormatter \
48
+ --out /tmp/test-results/rspec.xml \
49
+ --format progress
50
+
51
+ bundle exec rubocop \
52
+ --require $(bundle show rubocop-junit-formatter)/lib/rubocop/formatter/junit_formatter.rb \
53
+ --format RuboCop::Formatter::JUnitFormatter \
54
+ --out /tmp/test-results/rubocop.xml \
55
+ --format progress \
56
+ --parallel
57
+
58
+ - run:
59
+ name: upload reports to code climate
60
+ when: "always"
61
+ command: |
62
+ ./cc-test-reporter format-coverage -t simplecov $CIRCLE_ARTIFACTS/coverage/.resultset.json
63
+ ./cc-test-reporter upload-coverage
64
+
65
+ # collect reports
66
+ - store_test_results:
67
+ path: /tmp/test-results
68
+ - store_artifacts:
69
+ path: /tmp/test-results
70
+ destination: test-results
@@ -0,0 +1,13 @@
1
+ engines:
2
+ duplication:
3
+ enabled: true
4
+ config:
5
+ languages:
6
+ - ruby:
7
+ exclude_paths:
8
+ - "spec/"
9
+ fixme:
10
+ enabled: true
11
+ rubocop:
12
+ enabled: true
13
+ channel: rubocop-0-48
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ /spec/reports/
4
+ /spec/examples.txt
5
+
6
+ ## Documentation cache and generated files:
7
+ /.yardoc/
8
+ /_yardoc/
9
+ /doc/
10
+ /rdoc/
11
+ /coverage/
12
+
13
+ # for a library or gem, you might want to ignore these files since the code is
14
+ # intended to run in multiple environments; otherwise, check them in:
15
+ Gemfile.lock
16
+ .ruby-version
17
+ .ruby-gemset
18
+
@@ -0,0 +1,21 @@
1
+ require: rubocop-rspec
2
+
3
+ AllCops:
4
+ Include:
5
+ - '**/Gemfile'
6
+ - '**/Rakefile'
7
+ Exclude:
8
+ - 'spec/demo/**/*'
9
+ - 'vendor/**/*'
10
+ TargetRubyVersion: 2.4
11
+
12
+ Metrics/BlockLength:
13
+ Exclude:
14
+ - 'spec/**/*_spec.rb'
15
+ - 'spec/support/matchers/**/*'
16
+
17
+ Style/FrozenStringLiteralComment:
18
+ Enabled: false
19
+
20
+ Style/StringLiterals:
21
+ Enabled: false
@@ -0,0 +1,4 @@
1
+ --markup=markdown
2
+ --no-private
3
+ -
4
+ LICENSE
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## 0.0.1 - 2017-08-21
6
+
7
+ ### Added
8
+
9
+ - Defining menu's and submenus
10
+ - Rendering a simple menu
11
+ - Highlighting current menu item
12
+ - Runtime parameters
13
+
14
+ [Unreleased]: https://github.com/aramvisser/navtastic/compare/v0.0.1...HEAD
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Aram Visser
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,143 @@
1
+ # Navtastic
2
+
3
+ [![Build Status](https://img.shields.io/circleci/project/github/aramvisser/navtastic.svg)](https://circleci.com/gh/aramvisser/navtastic)
4
+ [![Code Coverage](https://img.shields.io/codeclimate/coverage/github/aramvisser/navtastic.svg)](https://codeclimate.com/github/aramvisser/navtastic)
5
+ [![Inline docs](https://inch-ci.org/github/aramvisser/navtastic.svg?branch=master)](https://inch-ci.org/github/aramvisser/navtastic)
6
+ [![MIT License](https://img.shields.io/github/license/aramvisser/navtastic.svg)](https://github.com/aramvisser/navtastic/blob/master/LICENSE)
7
+
8
+ Navtastic is way to create and render complex navigation menus. It allows for runtime configurations
9
+ of menus.
10
+
11
+ - Keep menu content and rendering logic separate
12
+ - Automatically highlight the current page
13
+
14
+ ## Table of Contents
15
+
16
+ - [Installation](#installation)
17
+ - [Example](#example)
18
+ - [Documentation](#documentation)
19
+ - [Submenus](#submenus)
20
+ - [Current item](#current-item)
21
+ - [Runtime parameters](#runtime-parameters)
22
+
23
+ ## Installation
24
+
25
+ Add it to your Gemfile:
26
+
27
+ ```ruby
28
+ gem 'navtastic'
29
+ ```
30
+
31
+ Run the following command to install it:
32
+
33
+ ```console
34
+ bundle install
35
+ ```
36
+
37
+ ## Example
38
+
39
+ Define a menu somwhere:
40
+
41
+ ```ruby
42
+ Navtastic.define :main_menu do |menu|
43
+ menu.item "Home", '/'
44
+ menu.item "Posts", '/posts'
45
+ menu.item "About", '/about'
46
+ end
47
+ ```
48
+
49
+ Render it in your partials:
50
+
51
+ ```erb
52
+ <%= Navtastic.render :main_menu, current_url %>
53
+ ```
54
+
55
+ Using the default renderer, assuming that the current url starts with `/posts`, will result in:
56
+
57
+ ```html
58
+ <ul>
59
+ <li>
60
+ <a href="/">Home</a>
61
+ </li>
62
+ <li class="current">
63
+ <a href="/posts">Posts</a>
64
+ </li>
65
+ <li>
66
+ <a href="/about">About</a>
67
+ </li>
68
+ </ul>
69
+ ```
70
+
71
+ ## Documentation
72
+
73
+ ## Submenus
74
+
75
+ Every item can have a submenu. They can be nested as deeply as you want (or at least until Ruby starts complaining).
76
+
77
+ ```ruby
78
+ Navtastic.define :main_menu do |menu|
79
+ menu.item "Home", '/' do |submenu|
80
+ submenu.item "Posts", '/posts'
81
+ submenu.item "About", '/about'
82
+ end
83
+
84
+ menu.item "Settings" do |submenu|
85
+ submenu.item "General", '/settings'
86
+ submenu.item "Profile", '/settings/profile'
87
+ end
88
+ end
89
+ ```
90
+
91
+ By default, submenus will be rendered inside the `<li>` tag of the parent item.
92
+
93
+ ```html
94
+ <ul>
95
+ <li>
96
+ <a href="/">Parent</a>
97
+ <ul>
98
+ <li>
99
+ <a href="/child">Child</a>
100
+ </li>
101
+ </ul>
102
+ </li>
103
+ </ul>
104
+ ```
105
+
106
+ ### Current item
107
+
108
+ The current active item is decided by the `current_url` parameter when rendering a menu. It is the
109
+ item with the longest url that starts with the current_url.
110
+
111
+ For example, if there is a menu containing these urls:
112
+
113
+ - `/`
114
+ - `/posts`
115
+ - `/posts/featured`
116
+
117
+ If the current_url is `/posts/featured/2017`, the `/posts/featured` item will be highlighted. If the
118
+ current_url is `/posts/123`, then `/posts` is highlighted.
119
+
120
+ The root url `/` will always match, if no other items match the current _url. If there is no item
121
+ with `/` as url in the menu and no other urls match, nothing will be highlighted.
122
+
123
+ ### Runtime parameters
124
+
125
+ You can pass runtime parameters when defining a menu. For example, passing the current user and
126
+ change the menu accordingly.
127
+
128
+ ```ruby
129
+ # Define the menu
130
+ Navtastic.define :main_menu do |menu, params|
131
+ menu.item "Home", "/"
132
+
133
+ if params[:current_user]
134
+ menu.item "Profile", "/users/#{params[:current_user].id}"
135
+ menu.item "Logout", "/logout"
136
+ else
137
+ menu.item "Login", "/login"
138
+ end
139
+ end
140
+
141
+ # Render it with the current user as a parameter
142
+ Navtastic.render :main_menu, current_url, current_user: User.current
143
+ ```
@@ -0,0 +1,19 @@
1
+ require 'rspec/core/rake_task'
2
+ require 'rubocop/rake_task'
3
+ require 'yard'
4
+ require './spec/demo/server'
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.rspec_opts = "--order rand"
8
+ end
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ YARD::Rake::YardocTask.new
13
+
14
+ desc "Run the demo server"
15
+ task :demo do
16
+ DemoServer.new(9090).start
17
+ end
18
+
19
+ task default: %i[spec rubocop]
@@ -0,0 +1,61 @@
1
+ require 'navtastic/item'
2
+ require 'navtastic/menu'
3
+ require 'navtastic/renderer'
4
+ require 'navtastic/version'
5
+
6
+ # Main module containing some convenience methods
7
+ module Navtastic
8
+ # @private
9
+ #
10
+ # @return [Hash<Object,Block>] all stored menus
11
+ @menu_store = {}
12
+
13
+ # Define a new menu to be rendered later
14
+ #
15
+ # @example Define a new menu
16
+ # Navtastic.define :main do |menu, params|
17
+ # menu.item "Home", "/"
18
+ # end
19
+ #
20
+ # @param name the name of the menu
21
+ #
22
+ # @yield [menu, params] block to generate a new menu
23
+ # @yieldparam menu [Menu] the menu to be initialized
24
+ # @yieldparam params [Hash] runtime parameters
25
+ #
26
+ # @raise [ArgumentError] if no block was given
27
+ def self.define(name, &block)
28
+ raise ArgumentError, "no block given" unless block_given?
29
+
30
+ name = name.to_sym if name.is_a? String
31
+ @menu_store[name] = block
32
+ end
33
+
34
+ # Render a stored menu
35
+ #
36
+ # @param name the name of the defined menu
37
+ # @param current_url [String] the url of the current page
38
+ # @param params [Hash] runtime parameters
39
+ #
40
+ # @raise [KeyError] if the menu was not defined
41
+ #
42
+ # @return [Renderer] the renderer for the menu
43
+ def self.render(name, current_url, params = {})
44
+ name = name.to_sym if name.is_a? String
45
+ block = @menu_store[name]
46
+
47
+ raise KeyError, "menu not defined: #{name.inspect}" if block.nil?
48
+
49
+ menu = Menu.new
50
+ block.call(menu, params)
51
+ menu.current_url = current_url
52
+ Renderer.render(menu)
53
+ end
54
+
55
+ # A list of all defined menus
56
+ #
57
+ # @return [Array]
58
+ def self.all_menus
59
+ @menu_store.keys
60
+ end
61
+ end
@@ -0,0 +1,49 @@
1
+ module Navtastic
2
+ # A single menu item
3
+ class Item
4
+ # @return [String] the name to be displayed in the menu
5
+ attr_reader :name
6
+
7
+ # @return [String,nil] the url to link to if item is a link, nil otherwise
8
+ attr_reader :url
9
+
10
+ # @return [Menu,nil] the submenu of this item, if defined
11
+ attr_accessor :submenu
12
+
13
+ # Create a new item
14
+ #
15
+ # This should not be used directly. Use the {Menu#item} method instead.
16
+ #
17
+ # @private
18
+ #
19
+ # @param menu [Menu] the menu this items belongs to
20
+ # @param name [String] the name to display when rendering
21
+ # @param url [String] the url to link to, if the item is a link
22
+ def initialize(menu, name, url = nil)
23
+ @menu = menu
24
+ @name = name
25
+ @url = url
26
+
27
+ @submenu = nil
28
+ end
29
+
30
+ # Check if this item is the current item in the menu
31
+ #
32
+ # @see file:README.md#Current_item documentation on how the current item is
33
+ # selected
34
+ #
35
+ # @return [Bool] if the item is the current item
36
+ def current?
37
+ @menu.current_item == self
38
+ end
39
+
40
+ # @return [Bool] true if the item has a submenu, false other
41
+ def submenu?
42
+ !@submenu.nil?
43
+ end
44
+
45
+ def inspect
46
+ "#<Item \"#{name}\" [#{url}] current?:#{current?}>"
47
+ end
48
+ end
49
+ end