active_link_to 1.0.4 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: fd9a67de186dfcf5e517ed55994051723962da91
4
- data.tar.gz: 153e11c947d56e41e642e45a94295581a868c7f7
2
+ SHA256:
3
+ metadata.gz: 23739b476611e406b4da34c0597867fa72eaf5e218d736732a44b2acfc9bf425
4
+ data.tar.gz: 3edfd60e459ba7b00ea7943cada4db37ac4c94ba23c91768098d62770ed19a2a
5
5
  SHA512:
6
- metadata.gz: 421d92f774bf0e904a8dede4c10910bc2fcd28ae9c7e39cc8f3142628557827224e3aa4bfbb9a67ba52527498e8cdf3e6525f814298cf26140d1ec6406ae3b7c
7
- data.tar.gz: 771b308ba2db04c506d3d7870c98be228388c09dfd8e79f0915721eeba9303f452014d4d4334f72d42f914ab49a7690e7b1ee1bdf0a2027386612ffc7fa45b9f
6
+ metadata.gz: 90a5df4d63147bc0e26757709e00ac5aeb8a51692709a9666948dcfb773bcdf4874f8711a0df9f9ac05760101ad2a4bed34d30c26ff239c99496f13100a8262c
7
+ data.tar.gz: 19d95a895f0bd464afcd0ca91693c99903cf9db248d79b58043e1e5ac8beac79d6a7a4965d38b3800b8ca10902f3f21ab37d8744772539c37863509263f07a9f
@@ -0,0 +1,33 @@
1
+ name: build
2
+ on:
3
+ pull_request:
4
+ push:
5
+ branches: [master]
6
+ jobs:
7
+ lint:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v7
11
+ - uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: "4.0"
14
+ bundler-cache: true
15
+ - run: bundle exec rubocop
16
+
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ include:
23
+ - ruby: "4.0"
24
+ gemfile: Gemfile
25
+ env:
26
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
27
+ steps:
28
+ - uses: actions/checkout@v7
29
+ - uses: ruby/setup-ruby@v1
30
+ with:
31
+ ruby-version: ${{ matrix.ruby }}
32
+ bundler-cache: true
33
+ - run: bundle exec rspec
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .DS_Store
2
+ pkg/
2
3
  Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1,17 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+
5
+ # Everything is too big and too complex, yes.
6
+ Metrics:
7
+ Enabled: false
8
+
9
+ # is_active_link? not getting renamed
10
+ Naming/PredicatePrefix:
11
+ Enabled: false
12
+
13
+ Style/StringLiterals:
14
+ EnforcedStyle: double_quotes
15
+
16
+ Style/Documentation:
17
+ Enabled: false
data/Gemfile CHANGED
@@ -1,10 +1,10 @@
1
- source 'http://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "http://rubygems.org"
2
4
 
3
5
  gemspec
4
6
 
5
- group :test do
6
- gem 'minitest'
7
- gem 'rake'
8
- gem 'rack-test'
9
- gem 'nokogiri'
10
- end
7
+ gem "rake"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rspec-html-matchers", "~> 0.10"
10
+ gem "rubocop", "~> 1.92"
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-17 Oleg Khabarov
1
+ Copyright (c) 2009-26 Oleg Khabarov
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,12 +1,19 @@
1
1
  # active_link_to
2
- [![Gem Version](https://img.shields.io/gem/v/active_link_to.svg?style=flat)](http://rubygems.org/gems/active_link_to) [![Gem Downloads](https://img.shields.io/gem/dt/active_link_to.svg?style=flat)](http://rubygems.org/gems/active_link_to) [![Build Status](https://img.shields.io/travis/comfy/active_link_to.svg?style=flat)](https://travis-ci.org/comfy/active_link_to)
3
2
 
4
3
  Creates a link tag of the given name using a URL created by the set of options. Please see documentation for [link_to](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to), as `active_link_to` is basically a wrapper for it. This method accepts an optional :active parameter that dictates if the given link will have an extra css class attached that marks it as 'active'.
5
4
 
5
+ [![Gem Version](https://img.shields.io/gem/v/active_link_to.svg?style=flat)](http://rubygems.org/gems/active_link_to)
6
+ [![Gem Downloads](https://img.shields.io/gem/dt/active_link_to.svg?style=flat)](http://rubygems.org/gems/active_link_to)
7
+
6
8
  ## Install
7
- When installing for Rails 3/4/5 applications add this to the Gemfile: `gem 'active_link_to'` and run `bundle install`.
8
9
 
9
- For older Rails apps add `config.gem 'active_link_to'` in config/environment.rb and run `rake gems:install`. Or just checkout this repo into /vendor/plugins directory.
10
+ Add to your Gemfile:
11
+
12
+ ```ruby
13
+ gem "active_link_to"
14
+ ```
15
+
16
+ and then run `bundle install`
10
17
 
11
18
  ## Super Simple Example
12
19
  Here's a link that will have a class attached if it happens to be rendered
@@ -28,7 +35,6 @@ active_link_to 'Users', '/users', active: :inclusive
28
35
  Here's a list of available options that can be used as the `:active` value
29
36
 
30
37
  ```
31
- <<<<<<< HEAD
32
38
  * Boolean -> true | false
33
39
  * Symbol -> :exclusive | :inclusive | :exact
34
40
  * Regex -> /regex/
@@ -37,6 +43,28 @@ Here's a list of available options that can be used as the `:active` value
37
43
  * Hash -> { param_a: 1, param_b: 2 }
38
44
  ```
39
45
 
46
+ ## Configuration
47
+ Several of the options that can be set in a calling of the helper can also be set in an
48
+ initializer. For example, if you want to use `is-active` as the active class all the time,
49
+ create `config/initializers/active_link_to.rb` with:
50
+
51
+ ```ruby
52
+ ActiveLinkTo.configure do |config|
53
+ config.class_active = 'is-active'
54
+ end
55
+ ```
56
+
57
+ The full list of configurable values is:
58
+
59
+ - `class_active` with default `"active"`
60
+ - `class_inactive` with default `""`
61
+ - `active_disable` with default `false`
62
+ - `wrap_tag` with default `nil`
63
+ - `wrap_class` with default `""`
64
+
65
+ Setting these values in configuration just changes the default -- setting them in a
66
+ use of the helper should always override the default, as you'd expect.
67
+
40
68
  ## More Examples
41
69
  Most of the functionality of `active_link_to` depends on the current
42
70
  url. Specifically, `request.original_fullpath` value. We covered the basic example
@@ -79,7 +107,7 @@ or action, or both? Or any number of those at the same time? Sure, why not:
79
107
  active_link_to 'User Edit', edit_user_path(@user), active: [['people', 'news'], ['show', 'edit']]
80
108
 
81
109
  # For matching specific controllers and actions:
82
- active_link_to 'User Edit', edit_user_path(@user), :active => [people: :show, news: :edit]
110
+ active_link_to 'User Edit', edit_user_path(@user), active: [people: :show, news: :edit]
83
111
 
84
112
  # for matching all actions under given controllers:
85
113
  active_link_to 'User Edit', edit_user_path(@user), active: [['people', 'news'], []]
@@ -97,7 +125,7 @@ active_link_to 'Users', users_path, active: true
97
125
  If we need to set link to be active based on `params`, we can do that as well:
98
126
 
99
127
  ```ruby
100
- active_link_to 'Admin users', users_path(role_eq: 'admin'), :active => { role_eq: 'admin' }
128
+ active_link_to 'Admin users', users_path(role_eq: 'admin'), active: { role_eq: 'admin' }
101
129
  ```
102
130
 
103
131
  ## More Options
@@ -151,4 +179,4 @@ active_link_to_class(users_path, active: :inclusive)
151
179
 
152
180
  ### Copyright
153
181
 
154
- Copyright (c) 2009-17 Oleg Khabarov. See LICENSE for details.
182
+ Copyright (c) 2009-26 Oleg Khabarov. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,11 +1,10 @@
1
- require 'rubygems'
2
- require 'rake/testtask'
3
- require 'bundler/setup'
1
+ # frozen_string_literal: true
4
2
 
5
- Rake::TestTask.new(:test) do |test|
6
- test.libs << 'lib' << 'test'
7
- test.pattern = 'test/**/*_test.rb'
8
- test.verbose = true
9
- end
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+ require "rspec/core/rake_task"
10
6
 
11
- task default: :test
7
+ RuboCop::RakeTask.new(:rubocop)
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: %i[rubocop spec]
@@ -1,7 +1,7 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- $:.unshift File.expand_path('../lib', __FILE__)
4
- require 'active_link_to/version'
3
+ $LOAD_PATH.unshift File.expand_path("lib", __dir__)
4
+ require "active_link_to/version"
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "active_link_to"
@@ -10,12 +10,17 @@ Gem::Specification.new do |s|
10
10
  s.email = ["oleg@khabarov.ca"]
11
11
  s.homepage = "http://github.com/comfy/active_link_to"
12
12
  s.summary = "ActionView helper to render currently active links"
13
- s.description = "Helpful method when you need to add some logic that figures out if the link (or more often navigation item) is selected based on the current page or other arbitrary condition"
13
+ s.description = "Helpful method when you need to add some logic that figures out " \
14
+ "if the link (or more often navigation item) " \
15
+ "is selected based on the current page or other arbitrary condition"
16
+ s.license = "MIT"
14
17
 
15
18
  s.files = `git ls-files`.split("\n")
16
- s.platform = Gem::Platform::RUBY
17
- s.require_paths = ['lib']
18
19
 
19
- s.add_dependency 'actionpack'
20
- s.add_dependency 'addressable'
20
+ s.required_ruby_version = ">= 2.3.0"
21
+
22
+ s.add_dependency "actionpack"
23
+ s.add_dependency "addressable"
24
+
25
+ s.metadata["rubygems_mfa_required"] = "true"
21
26
  end
@@ -1,57 +1,73 @@
1
- module ActiveLinkTo
1
+ # frozen_string_literal: true
2
2
 
3
- # Wrapper around link_to. Accepts following params:
4
- # :active => Boolean | Symbol | Regex | Controller/Action Pair
5
- # :class_active => String
6
- # :class_inactive => String
7
- # :disable_active => Boolean
8
- # :wrap_tag => Symbol
9
- # Example usage:
10
- # active_link_to('/users', class_active: 'enabled')
11
- # active_link_to(users_path, active: :exclusive, wrap_tag: :li)
3
+ # Wrapper around link_to. Accepts following params:
4
+ # :active => Boolean | Symbol | Regex | Controller/Action Pair
5
+ # :class_active => String
6
+ # :class_inactive => String
7
+ # :active_disable => Boolean
8
+ # :wrap_tag => Symbol
9
+ # Example usage:
10
+ # active_link_to('/users', class_active: 'enabled')
11
+ # active_link_to(users_path, active: :exclusive, wrap_tag: :li)
12
+ #
13
+ module ActiveLinkTo
12
14
  def active_link_to(*args, &block)
13
- if block_given?
14
- name = capture(&block)
15
- options = args[0] || {}
16
- html_options = args[1] || {}
17
- else
18
- name = args[0]
19
- options = args[1] || {}
20
- html_options = args[2] || {}
21
- end
15
+ name = block_given? ? capture(&block) : args.shift
16
+ options = args.shift || {}
17
+ html_options = args.shift || {}
18
+
22
19
  url = url_for(options)
23
20
 
24
- active_options = { }
25
- link_options = { }
21
+ active_options = {}
22
+ link_options = {}
26
23
  html_options.each do |k, v|
27
- if [:active, :class_active, :class_inactive, :active_disable, :wrap_tag, :wrap_class].member?(k)
24
+ if %i[active class_active class_inactive active_disable wrap_tag wrap_class].member?(k)
28
25
  active_options[k] = v
29
26
  else
30
27
  link_options[k] = v
31
28
  end
32
29
  end
33
30
 
34
- css_class = link_options.delete(:class).to_s + ' '
31
+ css_class = link_options.delete(:class).to_s
35
32
 
36
- wrap_tag = active_options[:wrap_tag].present? ? active_options[:wrap_tag] : nil
37
- wrap_class = active_options[:wrap_class].present? ? active_options[:wrap_class] + ' ' : ''
33
+ wrap_tag =
34
+ if active_options.member?(:wrap_tag)
35
+ active_options[:wrap_tag]
36
+ else
37
+ ActiveLinkTo.configuration.wrap_tag
38
+ end
39
+
40
+ wrap_class =
41
+ if active_options.member?(:wrap_class)
42
+ active_options[:wrap_class]
43
+ else
44
+ ActiveLinkTo.configuration.wrap_class
45
+ end
38
46
 
39
47
  if wrap_tag.present?
40
- wrap_class << active_link_to_class(url, active_options)
48
+ wrap_class = "#{wrap_class} #{active_link_to_class(url, active_options)}"
41
49
  wrap_class.strip!
42
50
  else
43
- css_class << active_link_to_class(url, active_options)
51
+ css_class = "#{css_class} #{active_link_to_class(url, active_options)}"
44
52
  css_class.strip!
45
53
  end
46
54
 
47
55
  link_options[:class] = css_class if css_class.present?
48
- link_options['aria-current'] = 'page' if is_active_link?(url, active_options[:active])
56
+ link_options["aria-current"] = "page" if is_active_link?(url, active_options[:active])
49
57
 
50
- link = if active_options[:active_disable] === true && is_active_link?(url, active_options[:active])
51
- content_tag(:span, name, link_options)
52
- else
53
- link_to(name, url, link_options)
54
- end
58
+ should_disable_link =
59
+ if active_options.member?(:active_disable)
60
+ active_options[:active_disable]
61
+ else
62
+ ActiveLinkTo.configuration.active_disable
63
+ end
64
+
65
+ link =
66
+ if should_disable_link && is_active_link?(url, active_options[:active])
67
+ content_tag(:span, name, link_options)
68
+ else
69
+ link_to(name, url, link_options)
70
+ end
55
71
 
56
72
  wrap_tag ? content_tag(wrap_tag, link, class: (wrap_class if wrap_class.present?)) : link
57
73
  end
@@ -62,9 +78,9 @@ module ActiveLinkTo
62
78
  #
63
79
  def active_link_to_class(url, options = {})
64
80
  if is_active_link?(url, options[:active])
65
- options[:class_active] || 'active'
81
+ options[:class_active] || ActiveLinkTo.configuration.class_active
66
82
  else
67
- options[:class_inactive] || ''
83
+ options[:class_inactive] || ActiveLinkTo.configuration.class_inactive
68
84
  end
69
85
  end
70
86
 
@@ -83,32 +99,48 @@ module ActiveLinkTo
83
99
  # is_active_link?('/root', ['users', ['show', 'edit']])
84
100
  #
85
101
  def is_active_link?(url, condition = nil)
102
+ return false if request.nil?
103
+
86
104
  @is_active_link ||= {}
87
105
  @is_active_link[[url, condition]] ||= begin
88
106
  original_url = url
89
- url = Addressable::URI::parse(url).path
90
- path = request.original_fullpath
107
+ url = Addressable::URI.parse(url).path
108
+ path = request.original_fullpath
109
+
91
110
  case condition
92
111
  when :inclusive, nil
93
- !path.match(/^#{Regexp.escape(url).chomp('/')}(\/.*|\?.*)?$/).blank?
112
+ !path.match(%r{^#{Regexp.escape(url).chomp('/')}(/.*|\?.*)?$}).blank?
113
+
94
114
  when :exclusive
95
- !path.match(/^#{Regexp.escape(url)}\/?(\?.*)?$/).blank?
115
+ !path.match(%r{^#{Regexp.escape(url)}/?(\?.*)?$}).blank?
116
+
96
117
  when :exact
97
118
  path == original_url
119
+
98
120
  when Regexp
99
121
  !path.match(condition).blank?
122
+
123
+ # This may come in two forms:
124
+ # - tuple with first item being controller names followed by names of actions
125
+ # - array of hashes where key is list of controllers and value is a list of actions
100
126
  when Array
101
- controllers = [*condition[0]]
102
- actions = [*condition[1]]
103
- (controllers.blank? || controllers.member?(params[:controller])) &&
104
- (actions.blank? || actions.member?(params[:action])) ||
105
- controllers.any? do |controller, action|
106
- params[:controller] == controller.to_s && params[:action] == action.to_s
127
+ pairs =
128
+ if condition.all?(Hash)
129
+ condition[0]
130
+ else
131
+ { condition[0] => condition[1] }
132
+ end
133
+
134
+ pairs.any? do |controllers, actions|
135
+ [*controllers].map(&:to_s).include?(params[:controller]) && [*actions].map(&:to_s).include?(params[:action])
107
136
  end
137
+
108
138
  when TrueClass
109
139
  true
140
+
110
141
  when FalseClass
111
142
  false
143
+
112
144
  when Hash
113
145
  condition.all? do |key, value|
114
146
  params[key].to_s == value.to_s
@@ -118,4 +150,6 @@ module ActiveLinkTo
118
150
  end
119
151
  end
120
152
 
121
- ActionView::Base.send :include, ActiveLinkTo
153
+ ActiveSupport.on_load :action_view do
154
+ include ActiveLinkTo
155
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Instead of explicitly passing options to the active_link_to, you can create
4
+ # an initializer like `config/initializers/active_link_to.rb` with:
5
+ #
6
+ # ActiveLinkTo.configure do |config|
7
+ # config.class_active = "is-active"
8
+ # end
9
+ #
10
+ module ActiveLinkTo
11
+ class Configuration
12
+ attr_accessor :class_active, :class_inactive, :active_disable, :wrap_tag, :wrap_class
13
+
14
+ def initialize
15
+ @class_active = "active"
16
+ @class_inactive = ""
17
+ @active_disable = false
18
+ @wrap_tag = nil
19
+ @wrap_class = ""
20
+ end
21
+ end
22
+
23
+ def self.configuration
24
+ @configuration ||= Configuration.new
25
+ end
26
+
27
+ def self.configuration=(config)
28
+ @configuration = config
29
+ end
30
+
31
+ def self.configure
32
+ yield configuration
33
+ end
34
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveLinkTo
2
- VERSION = "1.0.4"
3
- end
4
+ VERSION = "1.1.0"
5
+ end
@@ -1,3 +1,6 @@
1
- require 'addressable/uri'
2
- require 'active_link_to/active_link_to'
3
- require 'active_link_to/version'
1
+ # frozen_string_literal: true
2
+
3
+ require "addressable/uri"
4
+ require "active_link_to/active_link_to"
5
+ require "active_link_to/configuration"
6
+ require "active_link_to/version"
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe ActiveLinkTo do
6
+ describe "#is_active_link?" do
7
+ it "works for the boolean flag" do
8
+ expect(is_active_link?("/any-path", true)).to be(true)
9
+ expect(is_active_link?("/any-path", false)).to be(false)
10
+ end
11
+
12
+ it "works for the :inclusive flag" do
13
+ current_path_is("/foo")
14
+ expect(is_active_link?("/foo", :inclusive)).to be(true)
15
+
16
+ current_path_is("/foo?param=bar")
17
+ expect(is_active_link?("/foo", :inclusive)).to be(true)
18
+
19
+ current_path_is("/foo/child/sub-child")
20
+ expect(is_active_link?("/foo", :inclusive)).to be(true)
21
+
22
+ current_path_is("/bar")
23
+ expect(is_active_link?("/foo", :inclusive)).to be(false)
24
+ end
25
+
26
+ it "works without value as :inclusive flag is implied" do
27
+ current_path_is("/foo/bar")
28
+ expect(is_active_link?("/foo")).to be(true)
29
+ expect(is_active_link?("/bar")).to be(false)
30
+ end
31
+
32
+ it "doesn't match on a partial path value" do
33
+ current_path_is("/foo/bar")
34
+ expect(is_active_link?("/foo/ba")).to be(false)
35
+ end
36
+
37
+ it "works when path value specifies ending slash" do
38
+ current_path_is("/foo/bar")
39
+ expect(is_active_link?("/foo/")).to be(true)
40
+ end
41
+
42
+ it "doesn't match if path value is partial with ending slash" do
43
+ current_path_is("/foo_bar")
44
+ expect(is_active_link?("/foo/")).to be(false)
45
+ end
46
+
47
+ it "matches on path with dissimilar params" do
48
+ current_path_is("/foo?param=bar")
49
+ expect(is_active_link?("/foo?attr=something-else")).to be(true)
50
+ end
51
+
52
+ it "works for the :exclusive flag" do
53
+ current_path_is("/foo")
54
+ expect(is_active_link?("/foo", :exclusive)).to be(true)
55
+
56
+ current_path_is("/foo?param=bar")
57
+ expect(is_active_link?("/foo", :exclusive)).to be(true)
58
+
59
+ current_path_is("/foo/bar")
60
+ expect(is_active_link?("/foo", :exclusive)).to be(false)
61
+ end
62
+
63
+ it "matches path with dissimilar params for the :exclusive flag" do
64
+ current_path_is("/foo?param=bar")
65
+ expect(is_active_link?("/foo?attr=example", :exclusive)).to be(true)
66
+ end
67
+
68
+ it "works for the :exact flag" do
69
+ current_path_is("/foo?param=bar")
70
+
71
+ expect(is_active_link?("/foo?param=bar", :exact)).to be(true)
72
+ expect(is_active_link?("/foo?param=other", :exact)).to be(false)
73
+ expect(is_active_link?("/foo", :exact)).to be(false)
74
+
75
+ current_path_is("/foo")
76
+ expect(is_active_link?("/foo?param=bar", :exact)).to be(false)
77
+ end
78
+
79
+ it "works for the regex flag" do
80
+ current_path_is("/foo")
81
+ expect(is_active_link?("/", %r{^/foo})).to be(true)
82
+
83
+ current_path_is("/foo/bar")
84
+ expect(is_active_link?("/", %r{^/fo})).to be(true)
85
+
86
+ current_path_is("/bar")
87
+ expect(is_active_link?("/", %r{^/fo})).to be(false)
88
+ end
89
+
90
+ it "works for an array of controller and action names as a flag" do
91
+ # currently active controller/action pair
92
+ params[:controller] = "foos"
93
+ params[:action] = "bar"
94
+
95
+ expect(is_active_link?("/", [["foos"], ["bar"]])).to be(true)
96
+ expect(is_active_link?("/", [["foos"], %w[bar baz]])).to be(true)
97
+ expect(is_active_link?("/", [%w[foos bars], ["bar"]])).to be(true)
98
+ expect(is_active_link?("/", [%w[foos bars], %w[bar baz]])).to be(true)
99
+ expect(is_active_link?("/", [%i[foos bars], %i[bar baz]])).to be(true)
100
+
101
+ expect(is_active_link?("/", %w[foos bar])).to be(true)
102
+ expect(is_active_link?("/", ["foos", %w[bar baz]])).to be(true)
103
+ expect(is_active_link?("/", [%w[foos bars], "bar"])).to be(true)
104
+
105
+ expect(is_active_link?("/", %w[others bar])).to be(false)
106
+ expect(is_active_link?("/", %w[foos other])).to be(false)
107
+ end
108
+
109
+ it "works when flag is defined as a hash" do
110
+ # currently active controller/action pair
111
+ params[:controller] = "foos"
112
+ params[:action] = "bar"
113
+
114
+ expect(is_active_link?("/", [{ foos: :bar }])).to be(true)
115
+ expect(is_active_link?("/", [{ "foos" => "bar" }])).to be(true)
116
+ expect(is_active_link?("/", [{ %i[foos bars] => %w[foo bar], %w[eggs hams] => %i[egg bar] }])).to be(true)
117
+
118
+ expect(is_active_link?("/", [{ foos: :foo, bars: :bar }])).to be(false)
119
+ end
120
+
121
+ it "works for parameter matching" do
122
+ params[:a] = 1
123
+
124
+ expect(is_active_link?("/", { a: 1 })).to be(true)
125
+ expect(is_active_link?("/", { a: 1, b: nil })).to be(true)
126
+
127
+ expect(is_active_link?("/", { a: 1, b: 2 })).to be(false)
128
+ expect(is_active_link?("/", { a: 2 })).to be(false)
129
+
130
+ params[:b] = 2
131
+
132
+ expect(is_active_link?("/", { a: 1, b: 2 })).to be(true)
133
+ expect(is_active_link?("/", { a: 1, b: 2, c: nil })).to be(true)
134
+
135
+ expect(is_active_link?("/", { a: 1 })).to be(true)
136
+ expect(is_active_link?("/", { b: 2 })).to be(true)
137
+ end
138
+
139
+ it "matches if path value has anchor" do
140
+ current_path_is("/foo")
141
+
142
+ expect(is_active_link?("/foo#anchor", :exclusive)).to be(true)
143
+ end
144
+
145
+ it "returns false if request is nil (like in email templates)" do
146
+ allow(self).to receive(:request).and_return(nil)
147
+ expect(is_active_link?("/foo")).to be(false)
148
+ end
149
+ end
150
+
151
+ describe "#active_link_to_class" do
152
+ it "returns css class name for active links" do
153
+ current_path_is("/foo")
154
+
155
+ expect(active_link_to_class("/foo")).to eq("active")
156
+ expect(active_link_to_class("/other")).to eq("")
157
+ end
158
+
159
+ it "can use custom css class names for active and inactive links" do
160
+ current_path_is("/foo")
161
+
162
+ expect(active_link_to_class("/foo", class_active: "on")).to eq("on")
163
+ expect(active_link_to_class("/other", class_inactive: "off")).to eq("off")
164
+ end
165
+ end
166
+
167
+ describe "#active_link_to" do
168
+ it "renders link with active state" do
169
+ current_path_is("/foo")
170
+
171
+ link = active_link_to("label", "/foo")
172
+ expect(link).to have_tag("a", with: { href: "/foo", class: "active" }, text: "label")
173
+
174
+ link = active_link_to("label", "/other")
175
+ expect(link).to have_tag("a", without: { class: "active" })
176
+ end
177
+
178
+ it "doesn't clobber existing class names" do
179
+ current_path_is("/foo")
180
+
181
+ link = active_link_to("label", "/foo", class: "existing")
182
+ expect(link).to have_tag("a", with: { class: %w[active existing] })
183
+ end
184
+
185
+ it "works with custom active and inactive class names" do
186
+ current_path_is("/foo")
187
+
188
+ active_link = active_link_to("label", "/foo", class_active: "on")
189
+ expect(active_link).to have_tag("a", with: { class: "on" })
190
+
191
+ inactive_link = active_link_to("label", "/bar", class_inactive: "off")
192
+ expect(inactive_link).to have_tag("a", with: { class: "off" })
193
+ end
194
+
195
+ it "can render span instead of an active link" do
196
+ current_path_is("/foo")
197
+
198
+ active_link = active_link_to("label", "/foo", active_disable: true)
199
+ expect(active_link).to have_tag("span", with: { class: "active" }, text: "label")
200
+
201
+ inactive_link = active_link_to("label", "/bar", active_disable: true)
202
+ expect(inactive_link).to have_tag("a", without: { class: "active" }, text: "label")
203
+ end
204
+
205
+ it "can use wrapper element around active link" do
206
+ current_path_is("/foo")
207
+
208
+ link = active_link_to("label", "/foo", wrap_tag: :li, wrap_class: "wrap-class", class: "existing")
209
+ expect(link).to have_tag("li", with: { class: %w[wrap-class active] }) do
210
+ with_tag("a", without: { class: "active" }, with: { class: "existing" })
211
+ end
212
+ end
213
+
214
+ it "should not modify passed-in params" do
215
+ current_path_is("/foo")
216
+ params = { class: "testing", active: :inclusive }
217
+
218
+ link = active_link_to "label", "/foo", params
219
+ expect(link).to have_tag("a", with: { href: "/foo", class: %w[active testing] }, text: "label")
220
+ expect(params).to eq({ class: "testing", active: :inclusive })
221
+ end
222
+
223
+ it "marks active link with aria attribute" do
224
+ current_path_is("/foo")
225
+
226
+ active_link = active_link_to("label", "/foo")
227
+ expect(active_link).to have_tag("a", with: { "aria-current": "page", class: "active" })
228
+
229
+ inactive_link = active_link_to("label", "/bar")
230
+ expect(inactive_link).to have_tag("a", without: { "aria-current": "page", class: "active" })
231
+ end
232
+
233
+ it "renders link with utf8 characters" do
234
+ current_path_is("/äöü")
235
+
236
+ link = active_link_to("label", "/äöü")
237
+ expect(link).to have_tag("a", with: { href: "/äöü", class: "active" })
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe ActiveLinkTo::Configuration do
6
+ let(:config) { ActiveLinkTo::Configuration.new }
7
+
8
+ after do
9
+ ActiveLinkTo.configuration = ActiveLinkTo::Configuration.new
10
+ end
11
+
12
+ describe "#class_active" do
13
+ it "has default value" do
14
+ expect(config.class_active).to eq("active")
15
+ end
16
+
17
+ it "uses configured value" do
18
+ ActiveLinkTo.configuration.class_active = "custom-active"
19
+ current_path_is("/foo")
20
+
21
+ active_link = active_link_to("label", "/foo")
22
+ expect(active_link).to have_tag("a", with: { class: "custom-active" })
23
+ end
24
+
25
+ it "uses explicit value" do
26
+ ActiveLinkTo.configuration.class_active = "custom-active"
27
+ current_path_is("/foo")
28
+
29
+ active_link = active_link_to("label", "/foo", class_active: "explicit-active")
30
+ expect(active_link).to have_tag("a", with: { class: "explicit-active" })
31
+ end
32
+ end
33
+
34
+ describe "#class_inactive" do
35
+ it "has default value" do
36
+ expect(config.class_inactive).to eq("")
37
+ end
38
+
39
+ it "uses configured value" do
40
+ ActiveLinkTo.configuration.class_inactive = "custom-inactive"
41
+ current_path_is("/foo")
42
+
43
+ active_link = active_link_to("label", "/bar")
44
+ expect(active_link).to have_tag("a", with: { class: "custom-inactive" })
45
+ end
46
+
47
+ it "uses explicit value" do
48
+ ActiveLinkTo.configuration.class_inactive = "custom-active"
49
+ current_path_is("/foo")
50
+
51
+ active_link = active_link_to("label", "/bar", class_inactive: "explicit-inactive")
52
+ expect(active_link).to have_tag("a", with: { class: "explicit-inactive" })
53
+ end
54
+ end
55
+
56
+ describe "#active_disable" do
57
+ it "has default value" do
58
+ expect(config.active_disable).to eq(false)
59
+ end
60
+
61
+ it "uses configured value" do
62
+ ActiveLinkTo.configuration.active_disable = true
63
+ current_path_is("/foo")
64
+
65
+ active_link = active_link_to("label", "/foo")
66
+ expect(active_link).to have_tag("span", with: { class: "active" }, text: "label")
67
+ end
68
+
69
+ it "uses explicit value" do
70
+ ActiveLinkTo.configuration.active_disable = true
71
+ current_path_is("/foo")
72
+
73
+ active_link = active_link_to("label", "/foo", active_disable: false)
74
+ expect(active_link).to have_tag("a", with: { href: "/foo", class: "active" }, text: "label")
75
+ end
76
+ end
77
+
78
+ describe "#wrap_tag" do
79
+ it "has default value" do
80
+ expect(config.wrap_tag).to eq(nil)
81
+ end
82
+
83
+ it "uses configured value" do
84
+ ActiveLinkTo.configuration.wrap_tag = "configured-tag"
85
+ current_path_is("/foo")
86
+
87
+ link = active_link_to("label", "/foo")
88
+ expect(link).to have_tag("configured-tag", with: { class: "active" }) do
89
+ with_tag("a")
90
+ end
91
+ end
92
+
93
+ it "uses explicit value" do
94
+ ActiveLinkTo.configuration.wrap_tag = "configured-tag"
95
+ current_path_is("/foo")
96
+
97
+ link = active_link_to("label", "/foo", wrap_tag: "explicit-tag")
98
+ expect(link).to have_tag("explicit-tag", with: { class: "active" }) do
99
+ with_tag("a")
100
+ end
101
+
102
+ link = active_link_to("label", "/foo", wrap_tag: nil)
103
+ expect(link).to have_tag("a", with: { class: "active" })
104
+ end
105
+ end
106
+
107
+ describe "#wrap_class" do
108
+ it "has default value" do
109
+ expect(config.wrap_class).to eq("")
110
+ end
111
+
112
+ it "uses configured value" do
113
+ ActiveLinkTo.configuration.wrap_tag = "configured-tag"
114
+ ActiveLinkTo.configuration.wrap_class = "configured-class"
115
+ current_path_is("/foo")
116
+
117
+ link = active_link_to("label", "/foo")
118
+ expect(link).to have_tag("configured-tag", with: { class: %w[configured-class active] }) do
119
+ with_tag("a")
120
+ end
121
+ end
122
+
123
+ it "uses explicit value" do
124
+ ActiveLinkTo.configuration.wrap_tag = "configured-tag"
125
+ ActiveLinkTo.configuration.wrap_class = "configured-class"
126
+ current_path_is("/foo")
127
+
128
+ link = active_link_to("label", "/foo", wrap_class: "explicit-class")
129
+ expect(link).to have_tag("configured-tag", with: { class: %w[explicit-class active] }) do
130
+ with_tag("a")
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ Bundler.setup
5
+
6
+ require "rspec-html-matchers"
7
+
8
+ require "action_view"
9
+ require "active_link_to"
10
+
11
+ # Fake request object that is used in our tests
12
+ module FakeRequest
13
+ class Request
14
+ attr_accessor :original_fullpath
15
+ end
16
+
17
+ def request
18
+ @request ||= Request.new
19
+ end
20
+
21
+ def params
22
+ @params ||= {}
23
+ end
24
+
25
+ def current_path_is(path, purge_cache: true)
26
+ request.original_fullpath = path
27
+
28
+ # method is cached, so we bust it to set path multiple times in one test
29
+ return unless purge_cache && defined?(@is_active_link)
30
+
31
+ remove_instance_variable(:@is_active_link)
32
+ end
33
+ end
34
+
35
+ ActiveLinkTo.include FakeRequest
36
+
37
+ RSpec.configure do |config|
38
+ config.include ActionView::Helpers::UrlHelper
39
+ config.include ActionView::Helpers::TagHelper
40
+ config.include RSpecHtmlMatchers
41
+ config.include ActiveLinkTo
42
+ end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_link_to
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Khabarov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2017-03-17 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: actionpack
@@ -47,7 +46,9 @@ executables: []
47
46
  extensions: []
48
47
  extra_rdoc_files: []
49
48
  files:
49
+ - ".github/workflows/build.yml"
50
50
  - ".gitignore"
51
+ - ".rubocop.yml"
51
52
  - Gemfile
52
53
  - LICENSE
53
54
  - README.md
@@ -55,13 +56,16 @@ files:
55
56
  - active_link_to.gemspec
56
57
  - lib/active_link_to.rb
57
58
  - lib/active_link_to/active_link_to.rb
59
+ - lib/active_link_to/configuration.rb
58
60
  - lib/active_link_to/version.rb
59
- - test/active_link_to_test.rb
60
- - test/test_helper.rb
61
+ - spec/active_link_to_spec.rb
62
+ - spec/configuration_spec.rb
63
+ - spec/spec_helper.rb
61
64
  homepage: http://github.com/comfy/active_link_to
62
- licenses: []
63
- metadata: {}
64
- post_install_message:
65
+ licenses:
66
+ - MIT
67
+ metadata:
68
+ rubygems_mfa_required: 'true'
65
69
  rdoc_options: []
66
70
  require_paths:
67
71
  - lib
@@ -69,16 +73,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
73
  requirements:
70
74
  - - ">="
71
75
  - !ruby/object:Gem::Version
72
- version: '0'
76
+ version: 2.3.0
73
77
  required_rubygems_version: !ruby/object:Gem::Requirement
74
78
  requirements:
75
79
  - - ">="
76
80
  - !ruby/object:Gem::Version
77
81
  version: '0'
78
82
  requirements: []
79
- rubyforge_project:
80
- rubygems_version: 2.5.1
81
- signing_key:
83
+ rubygems_version: 4.0.9
82
84
  specification_version: 4
83
85
  summary: ActionView helper to render currently active links
84
86
  test_files: []
@@ -1,233 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class ActiveLinkToTest < MiniTest::Test
4
-
5
- def test_is_active_link_booleans_test
6
- assert is_active_link?('/', true)
7
- refute is_active_link?('/', false)
8
- end
9
-
10
- def test_is_active_link_symbol_inclusive
11
- set_path('/root')
12
- assert is_active_link?('/root', :inclusive)
13
-
14
- set_path('/root?param=test')
15
- assert is_active_link?('/root', :inclusive)
16
-
17
- set_path('/root/child/sub-child')
18
- assert is_active_link?('/root', :inclusive)
19
-
20
- set_path('/other')
21
- refute is_active_link?('/root', :inclusive)
22
- end
23
-
24
- def test_is_active_link_symbol_inclusive_implied
25
- set_path('/root/child/sub-child')
26
- assert is_active_link?('/root')
27
- end
28
-
29
- def test_is_active_link_symbol_inclusive_similar_path
30
- set_path('/root/abc')
31
- refute is_active_link?('/root/a', :inclusive)
32
- end
33
-
34
- def test_is_active_link_symbol_inclusive_with_last_slash
35
- set_path('/root/abc')
36
- assert is_active_link?('/root/')
37
- end
38
-
39
- def test_is_active_link_symbol_inclusive_with_last_slash_and_similar_path
40
- set_path('/root_path')
41
- refute is_active_link?('/root/')
42
- end
43
-
44
- def test_is_active_link_symbol_inclusive_with_link_params
45
- set_path('/root?param=test')
46
- assert is_active_link?('/root?attr=example')
47
- end
48
-
49
- def test_is_active_link_symbol_exclusive
50
- set_path('/root')
51
- assert is_active_link?('/root', :exclusive)
52
-
53
- set_path('/root?param=test')
54
- assert is_active_link?('/root', :exclusive)
55
-
56
- set_path('/root/child')
57
- refute is_active_link?('/root', :exclusive)
58
- end
59
-
60
- def test_is_active_link_symbol_exclusive_with_link_params
61
- set_path('/root?param=test')
62
- assert is_active_link?('/root?attr=example', :exclusive)
63
- end
64
-
65
- def test_is_active_link_symbol_exact
66
- set_path('/root?param=test')
67
- assert is_active_link?('/root?param=test', :exact)
68
-
69
- set_path('/root?param=test')
70
- refute is_active_link?('/root?param=exact', :exact)
71
-
72
- set_path('/root')
73
- refute is_active_link?('/root?param=test', :exact)
74
-
75
- set_path('/root?param=test')
76
- refute is_active_link?('/root', :exact)
77
- end
78
-
79
- def test_is_active_link_regex
80
- set_path('/root')
81
- assert is_active_link?('/', /^\/root/)
82
-
83
- set_path('/root/child')
84
- assert is_active_link?('/', /^\/r/)
85
-
86
- set_path('/other')
87
- refute is_active_link?('/', /^\/r/)
88
- end
89
-
90
- def test_is_active_link_array
91
- params[:controller], params[:action] = 'controller', 'action'
92
-
93
- assert is_active_link?('/', [['controller'], ['action']])
94
- assert is_active_link?('/', [['controller'], ['action', 'action_b']])
95
- assert is_active_link?('/', [['controller', 'controller_b'], ['action']])
96
- assert is_active_link?('/', [['controller', 'controller_b'], ['action', 'action_b']])
97
- assert is_active_link?('/', ['controller', 'action'])
98
- assert is_active_link?('/', ['controller', ['action', 'action_b']])
99
- assert is_active_link?('/', [['controller', 'controller_b'], 'action'])
100
-
101
- refute is_active_link?('/', ['controller_a', 'action'])
102
- refute is_active_link?('/', ['controller', 'action_a'])
103
- end
104
-
105
- def test_is_active_link_array_with_hash
106
- params[:controller], params[:action] = 'controller', 'action'
107
-
108
- assert is_active_link?('/', [controller: :action])
109
- assert is_active_link?('/', ['controller' => 'action'])
110
-
111
- refute is_active_link?('/', [controller_b: :action])
112
- refute is_active_link?('/', [controller: :action_b])
113
- refute is_active_link?('/', [controller_b: :action_b])
114
-
115
- params[:controller], params[:action] = 'controller_b', 'action_b'
116
-
117
- assert is_active_link?('/', [controller: :action, controller_b: :action_b])
118
- end
119
-
120
- def test_is_active_link_hash
121
- params[:a] = 1
122
-
123
- assert is_active_link?('/', {a: 1})
124
- assert is_active_link?('/', {a: 1, b: nil})
125
-
126
- refute is_active_link?('/', {a: 1, b: 2})
127
- refute is_active_link?('/', {a: 2})
128
-
129
- params[:b] = 2
130
-
131
- assert is_active_link?('/', {a: 1, b: 2})
132
- assert is_active_link?('/', {a: 1, b: 2, c: nil})
133
-
134
- assert is_active_link?('/', {a: 1})
135
- assert is_active_link?('/', {b: 2})
136
- end
137
-
138
- def test_is_active_link_with_anchor
139
- set_path('/foo')
140
- assert is_active_link?('/foo#anchor', :exclusive)
141
- end
142
-
143
- def test_is_active_link_with_memoization
144
- set_path('/')
145
- assert is_active_link?('/', :exclusive)
146
-
147
- set_path('/other', false)
148
- assert is_active_link?('/', :exclusive)
149
- end
150
-
151
- def test_active_link_to_class
152
- set_path('/root')
153
- assert_equal 'active', active_link_to_class('/root')
154
- assert_equal 'on', active_link_to_class('/root', class_active: 'on')
155
-
156
- assert_equal '', active_link_to_class('/other')
157
- assert_equal 'off', active_link_to_class('/other', class_inactive: 'off')
158
- end
159
-
160
- def test_active_link_to
161
- set_path('/root')
162
- link = active_link_to('label', '/root')
163
- assert_html link, 'a.active[href="/root"]', 'label'
164
-
165
- link = active_link_to('label', '/other')
166
- assert_html link, 'a[href="/other"]', 'label'
167
- end
168
-
169
- def test_active_link_to_with_existing_class
170
- set_path('/root')
171
- link = active_link_to('label', '/root', class: 'current')
172
- assert_html link, 'a.current.active[href="/root"]', 'label'
173
-
174
- link = active_link_to('label', '/other', class: 'current')
175
- assert_html link, 'a.current[href="/other"]', 'label'
176
- end
177
-
178
- def test_active_link_to_with_custom_classes
179
- set_path('/root')
180
- link = active_link_to('label', '/root', class_active: 'on')
181
- assert_html link, 'a.on[href="/root"]', 'label'
182
-
183
- link = active_link_to('label', '/other', class_inactive: 'off')
184
- assert_html link, 'a.off[href="/other"]', 'label'
185
- end
186
-
187
- def test_active_link_to_with_wrap_tag
188
- set_path('/root')
189
- link = active_link_to('label', '/root', wrap_tag: :li)
190
- assert_html link, 'li.active a[href="/root"]', 'label'
191
-
192
- link = active_link_to('label', '/root', wrap_tag: :li, active_disable: true)
193
- assert_html link, 'li.active span', 'label'
194
-
195
- link = active_link_to('label', '/root', wrap_tag: :li, class: 'testing')
196
- assert_html link, 'li.active a.testing[href="/root"]', 'label'
197
- end
198
-
199
- def test_active_link_to_with_active_disable
200
- set_path('/root')
201
- link = active_link_to('label', '/root', active_disable: true)
202
- assert_html link, 'span.active', 'label'
203
- end
204
-
205
- def test_should_not_modify_passed_params
206
- set_path('/root')
207
- params = {class: 'testing', active: :inclusive}
208
- out = active_link_to 'label', '/root', params
209
- assert_html out, 'a.testing.active[href="/root"]', 'label'
210
- assert_equal ({class: 'testing', active: :inclusive }), params
211
- end
212
-
213
- def test_active_link_to_wrap_tag_class
214
- set_path('/root')
215
- link = active_link_to('label', '/root', wrap_tag: :li)
216
- assert_html link, 'li.active a[href="/root"]', 'label'
217
-
218
- link = active_link_to('label', '/other', wrap_tag: :li)
219
- assert_html link, 'li a[href="/other"]', 'label'
220
- end
221
-
222
- def test_active_link_to_with_aria
223
- set_path('/root')
224
- link = active_link_to('label', '/root')
225
- assert_html link, 'a.active[href="/root"][aria-current="page"]', 'label'
226
- end
227
-
228
- def test_active_link_to_with_utf8
229
- set_path('/äöü')
230
- link = active_link_to('label', '/äöü')
231
- assert_html link, 'a.active[href="/äöü"]', 'label'
232
- end
233
- end
data/test/test_helper.rb DELETED
@@ -1,41 +0,0 @@
1
- require 'bundler/setup'
2
- require 'minitest/autorun'
3
- require 'uri'
4
- require 'action_view'
5
- require 'active_link_to'
6
-
7
- class MiniTest::Test
8
-
9
- # need this to simulate requests that drive active_link_helper
10
- module FakeRequest
11
- class Request
12
- attr_accessor :original_fullpath
13
- end
14
- def request
15
- @request ||= Request.new
16
- end
17
- def params
18
- @params ||= {}
19
- end
20
- end
21
-
22
- ActiveLinkTo.send :include, FakeRequest
23
-
24
- include ActionView::Helpers::UrlHelper
25
- include ActionView::Helpers::TagHelper
26
- include ActiveLinkTo
27
-
28
- def set_path(path, purge_cache = true)
29
- request.original_fullpath = path
30
- if purge_cache && defined?(@is_active_link)
31
- remove_instance_variable(:@is_active_link)
32
- end
33
- end
34
-
35
- def assert_html(html, selector, value = nil)
36
- doc = Nokogiri::HTML(html)
37
- element = doc.at_css(selector)
38
- assert element, "No element found at: `#{selector}`"
39
- assert_equal value, element.text if value
40
- end
41
- end