active_link_to 1.0.5 → 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: d0d98b57bf4abf67586e2eb4121f6fdd0b435b2e
4
- data.tar.gz: 7c59ffc37c74c76e97fa7d0d67918f2a91e6ecea
2
+ SHA256:
3
+ metadata.gz: 23739b476611e406b4da34c0597867fa72eaf5e218d736732a44b2acfc9bf425
4
+ data.tar.gz: 3edfd60e459ba7b00ea7943cada4db37ac4c94ba23c91768098d62770ed19a2a
5
5
  SHA512:
6
- metadata.gz: bd29e30982524b635daba3fdfd64df45d4bc91c000d3c5946d00cde1732a2a791e548d74b6b204935aebad5c4d06150e42faa0eb40e4a19ee381dd8b30205fe4
7
- data.tar.gz: 432188f6449e92a6fa822d8feecb516ee47afee975243fd66de33f57eb4245de934ed942ecf3d062a6680f6c0450d15c30a410bcd86173b343aec9575d53f364
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
@@ -36,6 +43,28 @@ Here's a list of available options that can be used as the `:active` value
36
43
  * Hash -> { param_a: 1, param_b: 2 }
37
44
  ```
38
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
+
39
68
  ## More Examples
40
69
  Most of the functionality of `active_link_to` depends on the current
41
70
  url. Specifically, `request.original_fullpath` value. We covered the basic example
@@ -150,4 +179,4 @@ active_link_to_class(users_path, active: :inclusive)
150
179
 
151
180
  ### Copyright
152
181
 
153
- 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,52 +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
- name = block_given? ? capture(&block) : args.shift
14
- options = args.shift || {}
15
+ name = block_given? ? capture(&block) : args.shift
16
+ options = args.shift || {}
15
17
  html_options = args.shift || {}
16
-
18
+
17
19
  url = url_for(options)
18
20
 
19
- active_options = { }
20
- link_options = { }
21
+ active_options = {}
22
+ link_options = {}
21
23
  html_options.each do |k, v|
22
- 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)
23
25
  active_options[k] = v
24
26
  else
25
27
  link_options[k] = v
26
28
  end
27
29
  end
28
30
 
29
- css_class = link_options.delete(:class).to_s + ' '
31
+ css_class = link_options.delete(:class).to_s
30
32
 
31
- wrap_tag = active_options[:wrap_tag].present? ? active_options[:wrap_tag] : nil
32
- 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
33
46
 
34
47
  if wrap_tag.present?
35
- wrap_class << active_link_to_class(url, active_options)
48
+ wrap_class = "#{wrap_class} #{active_link_to_class(url, active_options)}"
36
49
  wrap_class.strip!
37
50
  else
38
- css_class << active_link_to_class(url, active_options)
51
+ css_class = "#{css_class} #{active_link_to_class(url, active_options)}"
39
52
  css_class.strip!
40
53
  end
41
54
 
42
55
  link_options[:class] = css_class if css_class.present?
43
- 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])
44
57
 
45
- link = if active_options[:active_disable] === true && is_active_link?(url, active_options[:active])
46
- content_tag(:span, name, link_options)
47
- else
48
- link_to(name, url, link_options)
49
- 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
50
71
 
51
72
  wrap_tag ? content_tag(wrap_tag, link, class: (wrap_class if wrap_class.present?)) : link
52
73
  end
@@ -57,9 +78,9 @@ module ActiveLinkTo
57
78
  #
58
79
  def active_link_to_class(url, options = {})
59
80
  if is_active_link?(url, options[:active])
60
- options[:class_active] || 'active'
81
+ options[:class_active] || ActiveLinkTo.configuration.class_active
61
82
  else
62
- options[:class_inactive] || ''
83
+ options[:class_inactive] || ActiveLinkTo.configuration.class_inactive
63
84
  end
64
85
  end
65
86
 
@@ -78,32 +99,48 @@ module ActiveLinkTo
78
99
  # is_active_link?('/root', ['users', ['show', 'edit']])
79
100
  #
80
101
  def is_active_link?(url, condition = nil)
102
+ return false if request.nil?
103
+
81
104
  @is_active_link ||= {}
82
105
  @is_active_link[[url, condition]] ||= begin
83
106
  original_url = url
84
- url = Addressable::URI::parse(url).path
85
- path = request.original_fullpath
107
+ url = Addressable::URI.parse(url).path
108
+ path = request.original_fullpath
109
+
86
110
  case condition
87
111
  when :inclusive, nil
88
- !path.match(/^#{Regexp.escape(url).chomp('/')}(\/.*|\?.*)?$/).blank?
112
+ !path.match(%r{^#{Regexp.escape(url).chomp('/')}(/.*|\?.*)?$}).blank?
113
+
89
114
  when :exclusive
90
- !path.match(/^#{Regexp.escape(url)}\/?(\?.*)?$/).blank?
115
+ !path.match(%r{^#{Regexp.escape(url)}/?(\?.*)?$}).blank?
116
+
91
117
  when :exact
92
118
  path == original_url
119
+
93
120
  when Regexp
94
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
95
126
  when Array
96
- controllers = [*condition[0]]
97
- actions = [*condition[1]]
98
- (controllers.blank? || controllers.member?(params[:controller])) &&
99
- (actions.blank? || actions.member?(params[:action])) ||
100
- controllers.any? do |controller, action|
101
- 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])
102
136
  end
137
+
103
138
  when TrueClass
104
139
  true
140
+
105
141
  when FalseClass
106
142
  false
143
+
107
144
  when Hash
108
145
  condition.all? do |key, value|
109
146
  params[key].to_s == value.to_s
@@ -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.5"
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.5
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-08-29 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.6.11
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