├── script
├── test
├── release
├── bootstrap
├── cibuild
└── fmt
├── .rspec
├── spec
├── fixtures
│ ├── _layouts
│ │ └── layout.html
│ ├── _authors
│ │ └── kansaichris.md
│ ├── tags
│ │ └── how we work.md
│ ├── one_redirect_to_path.md
│ ├── one_redirect_from.md
│ ├── one_redirect_to_url.md
│ ├── _articles
│ │ ├── redirect-somewhere-else-plz.html
│ │ ├── redirect-me-plz.md
│ │ └── redirect-somewhere-else-im-a-permalink.html
│ ├── _posts
│ │ └── 2014-01-03-redirect-me-plz.md
│ ├── multiple_redirect_froms.md
│ └── multiple_redirect_tos.md
├── jekyll_redirect_from
│ ├── context_spec.rb
│ ├── layout_spec.rb
│ ├── redirectable_spec.rb
│ ├── generator_spec.rb
│ └── redirect_page_spec.rb
├── spec_helper.rb
└── integrations_spec.rb
├── lib
├── jekyll-redirect-from
│ ├── version.rb
│ ├── page_without_a_file.rb
│ ├── context.rb
│ ├── redirect.html
│ ├── layout.rb
│ ├── redirectable.rb
│ ├── generator.rb
│ └── redirect_page.rb
└── jekyll-redirect-from.rb
├── Rakefile
├── Gemfile
├── .gitignore
├── .rubocop.yml
├── .rubocop_todo.yml
├── jekyll-redirect-from.gemspec
├── LICENSE.txt
├── .github
└── workflows
│ └── ci.yml
├── README.md
└── History.markdown
/script/test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | bundle exec rspec $@
3 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --format progress
3 | --require spec_helper
4 | --order random
5 |
--------------------------------------------------------------------------------
/script/release:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | script/cibuild
4 | bundle exec rake release
5 |
--------------------------------------------------------------------------------
/script/bootstrap:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | set -e
3 |
4 | bundle install -j8 || bundle install
5 |
--------------------------------------------------------------------------------
/spec/fixtures/_layouts/layout.html:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | LAYOUT INCLUDED
5 |
6 | {{ content }}
7 |
--------------------------------------------------------------------------------
/spec/fixtures/_authors/kansaichris.md:
--------------------------------------------------------------------------------
1 | ---
2 | redirect_from: /kansaichris/
3 | ---
4 |
5 | Hi.
6 |
--------------------------------------------------------------------------------
/script/cibuild:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | set -e
3 |
4 | script/test
5 | script/fmt
6 | bundle exec rake build
7 |
--------------------------------------------------------------------------------
/spec/fixtures/tags/how we work.md:
--------------------------------------------------------------------------------
1 | ---
2 | redirect_to: "/tags/how-we-work/"
3 | permalink: "/tags/how we work/"
4 | ---
5 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module JekyllRedirectFrom
4 | VERSION = "0.16.0"
5 | end
6 |
--------------------------------------------------------------------------------
/spec/fixtures/one_redirect_to_path.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: I am going somewhere external
3 | redirect_to: /foo
4 | ---
5 |
6 | Redirecting elsewhere.
7 |
--------------------------------------------------------------------------------
/spec/fixtures/one_redirect_from.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: I only have one redirect path
3 | redirect_from: some/other/path
4 | ---
5 |
6 | One redirect url
7 |
--------------------------------------------------------------------------------
/spec/fixtures/one_redirect_to_url.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: I am going somewhere external
3 | redirect_to: https://www.github.com
4 | ---
5 |
6 | Redirecting elsewhere.
7 |
--------------------------------------------------------------------------------
/spec/fixtures/_articles/redirect-somewhere-else-plz.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Please redirect away from me, sir.
3 | redirect_to: "http://www.zombo.com"
4 | ---
5 |
6 | Boo.
7 |
--------------------------------------------------------------------------------
/spec/fixtures/_articles/redirect-me-plz.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Please redirect me, sir.
3 | redirect_from: /articles/23128432159832/mary-had-a-little-lamb
4 | ---
5 |
6 | Yay.
7 |
--------------------------------------------------------------------------------
/spec/fixtures/_posts/2014-01-03-redirect-me-plz.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Please redirect me, sir.
3 | redirect_from: /posts/23128432159832/mary-had-a-little-lamb
4 | ---
5 |
6 | Yay.
7 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "bundler/gem_tasks"
4 | require "rspec/core/rake_task"
5 |
6 | RSpec::Core::RakeTask.new(:spec)
7 |
8 | task :default => :spec
9 |
--------------------------------------------------------------------------------
/spec/fixtures/_articles/redirect-somewhere-else-im-a-permalink.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Please redirect away from me and my permalink.
3 | permalink: /tags/our projects/
4 | redirect_to: /tags/our-projects/
5 | ---
6 |
7 | Bye.
8 |
--------------------------------------------------------------------------------
/spec/fixtures/multiple_redirect_froms.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: I have lots of redirect urls
3 | redirect_from:
4 | - help
5 | - contact
6 | - let-there/be/light-he-said
7 | - /geepers/mccreepin
8 | ---
9 |
10 | Lots of redirect urls
11 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/page_without_a_file.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module JekyllRedirectFrom
4 | class PageWithoutAFile < Jekyll::Page
5 | def read_yaml(*)
6 | @data ||= {}
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/fixtures/multiple_redirect_tos.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: I have lots of redirect to urls
3 | redirect_to:
4 | - https://www.jekyllrb.com
5 | - https://www.github.com
6 | - https://www.twitter.com
7 | ---
8 |
9 | Lots of redirect to urls.
10 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 | gemspec
5 |
6 | gem "github-pages" if ENV["GH_PAGES"]
7 | gem "jekyll", ENV["JEKYLL_VERSION"] if ENV["JEKYLL_VERSION"]
8 | gem "kramdown-parser-gfm" if ENV["JEKYLL_VERSION"] == "~> 3.9"
9 |
--------------------------------------------------------------------------------
/script/fmt:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo "RuboCop $(bundle exec rubocop --version)"
5 | bundle exec rubocop -D -E $@
6 | success=$?
7 | if ((success != 0)); then
8 | echo -e "\nTry running \`script/fmt -a\` to automatically fix errors"
9 | fi
10 | exit $success
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle
4 | .config
5 | .yardoc
6 | Gemfile.lock
7 | InstalledFiles
8 | _yardoc
9 | coverage
10 | doc/
11 | lib/bundler/man
12 | pkg
13 | rdoc
14 | spec/reports
15 | spec/fixtures/.jekyll-metadata
16 | spec/fixtures/.jekyll-cache
17 | test/tmp
18 | test/version_tmp
19 | tmp
20 | vendor/bundle
21 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/context.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module JekyllRedirectFrom
4 | # Stubbed LiquidContext to support relative_url and absolute_url helpers
5 | class Context
6 | attr_reader :site
7 |
8 | def initialize(site)
9 | @site = site
10 | end
11 |
12 | def registers
13 | { :site => site }
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/jekyll_redirect_from/context_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe JekyllRedirectFrom::Context do
4 | subject { described_class.new(site) }
5 |
6 | it "stores the site" do
7 | expect(subject.site).to be_a(Jekyll::Site)
8 | end
9 |
10 | it "returns the register" do
11 | expect(subject.registers).to have_key(:site)
12 | expect(subject.registers[:site]).to be_a(Jekyll::Site)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Redirecting…
5 |
6 |
7 |
8 |
9 | Redirecting…
10 | Click here if you are not redirected.
11 |
12 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/layout.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module JekyllRedirectFrom
4 | # A stubbed layout for our default redirect template
5 | # We cannot use the standard Layout class because of site.in_source_dir
6 | class Layout < Jekyll::Layout
7 | def initialize(site)
8 | @site = site
9 | @base = __dir__
10 | @name = "redirect.html"
11 | @path = File.expand_path(@name, @base)
12 | @relative_path = "_layouts/redirect.html"
13 |
14 | self.data = {}
15 | self.ext = "html"
16 | self.content = File.read(@path)
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "jekyll"
4 | require "jekyll-redirect-from/version"
5 | require "jekyll-redirect-from/generator"
6 |
7 | module JekyllRedirectFrom
8 | # Jekyll classes which should be redirectable
9 | CLASSES = [Jekyll::Page, Jekyll::Document].freeze
10 |
11 | autoload :Context, "jekyll-redirect-from/context"
12 | autoload :RedirectPage, "jekyll-redirect-from/redirect_page"
13 | autoload :Redirectable, "jekyll-redirect-from/redirectable"
14 | autoload :Layout, "jekyll-redirect-from/layout"
15 | autoload :PageWithoutAFile, "jekyll-redirect-from/page_without_a_file"
16 | end
17 |
18 | JekyllRedirectFrom::CLASSES.each do |klass|
19 | klass.send :include, JekyllRedirectFrom::Redirectable
20 | end
21 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/redirectable.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module JekyllRedirectFrom
4 | # Module which can be mixed in to documents (and pages) to provide
5 | # redirect_to and redirect_from helpers
6 | module Redirectable
7 | # Returns a string representing the relative path or URL
8 | # to which the document should be redirected
9 | def redirect_to
10 | meta_data = to_liquid["redirect_to"]
11 | meta_data.is_a?(Array) ? meta_data.compact.first : meta_data
12 | end
13 |
14 | # Returns an array representing the relative paths to other
15 | # documents which should be redirected to this document
16 | def redirect_from
17 | meta_data = to_liquid["redirect_from"]
18 | meta_data.is_a?(Array) ? meta_data.compact : [meta_data].compact
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/spec/jekyll_redirect_from/layout_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe JekyllRedirectFrom::Layout do
4 | subject { described_class.new(@site) }
5 |
6 | it "exposes the site" do
7 | expect(subject.site).to eql(@site)
8 | end
9 |
10 | it "exposes the name" do
11 | expect(subject.name).to eql("redirect.html")
12 | end
13 |
14 | it "exposes the path" do
15 | expected = File.expand_path "../../lib/jekyll-redirect-from/redirect.html", __dir__
16 | expect(subject.path).to eql(expected)
17 | end
18 |
19 | it "exposes the relative path" do
20 | expect(subject.relative_path).to eql("_layouts/redirect.html")
21 | end
22 |
23 | it "exposes the ext" do
24 | expect(subject.ext).to eql("html")
25 | end
26 |
27 | it "exposes data" do
28 | expect(subject.data).to eql({})
29 | end
30 |
31 | it "exposes content" do
32 | expect(subject.content).to match("Redirecting...")
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | inherit_from: .rubocop_todo.yml
2 |
3 | require: rubocop-jekyll
4 |
5 | inherit_gem:
6 | rubocop-jekyll: .rubocop.yml
7 |
8 | AllCops:
9 | TargetRubyVersion: 2.5
10 | SuggestExtensions: false
11 | Exclude:
12 | - vendor/**/*
13 |
14 | Layout/LineEndStringConcatenationIndentation:
15 | Enabled: true
16 |
17 | Lint/EmptyInPattern:
18 | Enabled: false
19 |
20 | Naming/InclusiveLanguage:
21 | Enabled: false
22 | Naming/MemoizedInstanceVariableName:
23 | Exclude:
24 | - 'lib/jekyll-redirect-from/page_without_a_file.rb'
25 |
26 | Performance/MapCompact:
27 | Enabled: true
28 | Performance/RedundantEqualityComparisonBlock:
29 | Enabled: true
30 | Performance/RedundantSplitRegexpArgument:
31 | Enabled: true
32 |
33 | Style/ConcatArrayLiterals:
34 | Exclude:
35 | - 'jekyll-redirect-from.gemspec'
36 | Style/InPatternThen:
37 | Enabled: false
38 | Style/MultilineInPatternThen:
39 | Enabled: false
40 | Style/QuotedSymbols:
41 | Enabled: true
42 |
--------------------------------------------------------------------------------
/.rubocop_todo.yml:
--------------------------------------------------------------------------------
1 | # This configuration was generated by
2 | # `rubocop --auto-gen-config`
3 | # on 2021-09-17 12:49:45 UTC using RuboCop version 1.18.4.
4 | # The point is for the user to remove these configuration records
5 | # one by one as the offenses are removed from the code base.
6 | # Note that changes in the inspected code, or installation of new
7 | # versions of RuboCop, may require this file to be generated again.
8 |
9 | # Offense count: 3
10 | # Cop supports --auto-correct.
11 | # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
12 | # URISchemes: http, https
13 | Layout/LineLength:
14 | Max: 105
15 |
16 | # Offense count: 2
17 | # Configuration parameters: AllowedMethods.
18 | # AllowedMethods: enums
19 | Lint/ConstantDefinitionInBlock:
20 | Exclude:
21 | - 'spec/jekyll_redirect_from/generator_spec.rb'
22 |
23 | # Offense count: 2
24 | # Configuration parameters: AllowComments, AllowEmptyLambdas.
25 | Lint/EmptyBlock:
26 | Exclude:
27 | - 'spec/jekyll_redirect_from/generator_spec.rb'
28 |
--------------------------------------------------------------------------------
/jekyll-redirect-from.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative "lib/jekyll-redirect-from/version"
4 |
5 | Gem::Specification.new do |spec|
6 | spec.name = "jekyll-redirect-from"
7 | spec.version = JekyllRedirectFrom::VERSION
8 | spec.authors = ["Parker Moore"]
9 | spec.email = ["parkrmoore@gmail.com"]
10 | spec.summary = "Seamlessly specify multiple redirection URLs for your pages and posts"
11 | spec.homepage = "https://github.com/jekyll/jekyll-redirect-from"
12 | spec.license = "MIT"
13 |
14 | spec.files = `git ls-files lib`.split("\n").concat(%w(LICENSE.txt README.md History.markdown))
15 | spec.require_paths = ["lib"]
16 |
17 | spec.required_ruby_version = ">= 2.5.0"
18 |
19 | spec.add_runtime_dependency "jekyll", ">= 3.3", "< 5.0"
20 |
21 | spec.add_development_dependency "bundler"
22 | spec.add_development_dependency "jekyll-sitemap", "~> 1.0"
23 | spec.add_development_dependency "rake", "~> 13.0"
24 | spec.add_development_dependency "rspec", "~> 3.5"
25 | spec.add_development_dependency "rubocop-jekyll", "~> 0.13.0"
26 | end
27 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-present Parker Moore and jekyll-redirect-from contributors
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "jekyll"
4 | require File.expand_path("lib/jekyll-redirect-from.rb")
5 |
6 | RSpec.configure do |config|
7 | config.run_all_when_everything_filtered = true
8 | config.filter_run :focus
9 |
10 | config.expect_with :rspec do |c|
11 | c.syntax = :expect
12 | end
13 |
14 | config.before(:each) do
15 | Jekyll.logger.log_level = :error
16 | dest_path.rmtree if dest_path.exist?
17 | site.reset
18 | end
19 |
20 | config.after(:each) do
21 | dest_path.rmtree if dest_path.exist?
22 | end
23 |
24 | def fixtures_path
25 | Pathname.new(__dir__).join("fixtures")
26 | end
27 |
28 | def dest_path
29 | Pathname.new(site.dest)
30 | end
31 |
32 | def dest_dir(*paths)
33 | dest_path.join(*paths)
34 | end
35 |
36 | def config
37 | Jekyll.configuration(
38 | "source" => fixtures_path.to_s,
39 | "destination" => fixtures_path.join("_site").to_s,
40 | "collections" => {
41 | "articles" => { "output" => true },
42 | "authors" => {},
43 | },
44 | "url" => "http://jekyllrb.com",
45 | "plugins" => %w(jekyll-redirect-from jekyll-sitemap),
46 | "defaults" => [{
47 | "scope" => { "path" => "" },
48 | "values" => { "layout" => "layout" },
49 | }]
50 | )
51 | end
52 |
53 | def site
54 | @site ||= Jekyll::Site.new(config)
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Continuous Integration
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches:
9 | - master
10 |
11 | jobs:
12 | ci:
13 | if: "!contains(github.event.commits[0].message, '[ci skip]')"
14 | name: 'Ruby ${{ matrix.ruby_version }}'
15 | runs-on: 'ubuntu-latest'
16 |
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | ruby_version:
21 | - "2.7"
22 | - "3.0"
23 | - "3.3"
24 | steps:
25 | - uses: actions/checkout@v4
26 | with:
27 | fetch-depth: 5
28 | - name: "Set up Ruby ${{ matrix.ruby_version }}"
29 | uses: ruby/setup-ruby@v1
30 | with:
31 | ruby-version: ${{ matrix.ruby_version }}
32 | bundler-cache: true
33 | - name: Execute tests
34 | run: bash script/test
35 | - name: Check Style Offenses
36 | run: bash script/fmt
37 | - name: Test gem build
38 | run: bundle exec gem build jekyll-redirect-from.gemspec
39 | - name: Test gem install
40 | run: bundle exec gem install jekyll-redirect-from --local --verbose
41 |
42 | ghp:
43 | if: "!contains(github.event.commits[0].message, '[ci skip]')"
44 | name: Ruby 3.3 with GitHub Pages Gem
45 | runs-on: 'ubuntu-latest'
46 | env:
47 | GH_PAGES: true
48 | strategy:
49 | fail-fast: false
50 | steps:
51 | - uses: actions/checkout@v4
52 | with:
53 | fetch-depth: 5
54 | - name: "Set up Ruby 3.3"
55 | uses: ruby/setup-ruby@v1
56 | with:
57 | ruby-version: 3.3
58 | bundler-cache: true
59 | - name: Execute tests
60 | run: bash script/test
61 |
--------------------------------------------------------------------------------
/spec/jekyll_redirect_from/redirectable_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class RedirectableTestHelper
4 | include JekyllRedirectFrom::Redirectable
5 | attr_reader :to_liquid
6 |
7 | def initialize(data)
8 | @to_liquid = data
9 | end
10 | end
11 |
12 | RSpec.describe JekyllRedirectFrom::Redirectable do
13 | let(:data) { "" }
14 | subject { RedirectableTestHelper.new(data) }
15 |
16 | context "with strings" do
17 | let(:data) { { "redirect_from" => "/foo", "redirect_to" => "/bar" } }
18 |
19 | it "returns redirect_from" do
20 | expect(subject.redirect_from).to eql(["/foo"])
21 | end
22 |
23 | it "returns redirect_to" do
24 | expect(subject.redirect_to).to eql("/bar")
25 | end
26 | end
27 |
28 | context "with arrays" do
29 | let(:data) { { "redirect_from" => ["/foo"], "redirect_to" => ["/bar"] } }
30 |
31 | it "returns redirect_from" do
32 | expect(subject.redirect_from).to eql(["/foo"])
33 | end
34 |
35 | it "returns redirect_to" do
36 | expect(subject.redirect_to).to eql("/bar")
37 | end
38 | end
39 |
40 | context "with fields missing" do
41 | let(:data) { {} }
42 |
43 | it "returns an empty array for redirect_from" do
44 | expect(subject.redirect_from).to eql([])
45 | end
46 |
47 | it "returns nil for redirect_to" do
48 | expect(subject.redirect_to).to be_nil
49 | end
50 | end
51 |
52 | context "with nils" do
53 | let(:data) { { "redirect_from" => nil, "redirect_to" => nil } }
54 |
55 | it "returns an empty array for redirect_from" do
56 | expect(subject.redirect_from).to eql([])
57 | end
58 |
59 | it "returns nil for redirect_to" do
60 | expect(subject.redirect_to).to be_nil
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/generator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module JekyllRedirectFrom
4 | class Generator < Jekyll::Generator
5 | safe true
6 | attr_reader :site, :redirects
7 |
8 | def generate(site)
9 | @site = site
10 | @redirects = {}
11 |
12 | # Inject our layout, unless the user has already specified a redirect layout'
13 | unless site.layouts.key?("redirect")
14 | site.layouts["redirect"] = JekyllRedirectFrom::Layout.new(site)
15 | end
16 |
17 | # Must duplicate pages to modify while in loop
18 | (site.docs_to_write + site.pages.dup).each do |doc|
19 | next unless redirectable_document?(doc)
20 |
21 | generate_redirect_from(doc)
22 | generate_redirect_to(doc)
23 | end
24 |
25 | generate_redirects_json if generate_redirects_json?
26 | end
27 |
28 | private
29 |
30 | # For every `redirect_from` entry, generate a redirect page
31 | def generate_redirect_from(doc)
32 | doc.redirect_from.each do |path|
33 | page = RedirectPage.redirect_from(doc, path)
34 | doc.site.pages << page
35 | redirects[page.redirect_from] = page.redirect_to
36 | end
37 | end
38 |
39 | def generate_redirect_to(doc)
40 | return unless doc.redirect_to
41 |
42 | page = RedirectPage.redirect_to(doc, doc.redirect_to)
43 | doc.data.merge!(page.data)
44 | doc.content = doc.output = page.output
45 | redirects[page.redirect_from] = page.redirect_to
46 | end
47 |
48 | def generate_redirects_json
49 | return if File.exist? site.in_source_dir("redirects.json")
50 |
51 | page = PageWithoutAFile.new(site, "", "", "redirects.json")
52 | page.content = redirects.to_json
53 | page.data["layout"] = nil
54 | site.pages << page
55 | end
56 |
57 | def redirectable_document?(doc)
58 | doc.is_a?(Jekyll::Document) || doc.is_a?(Jekyll::Page)
59 | end
60 |
61 | def generate_redirects_json?
62 | site.config.dig("redirect_from", "json") != false
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/lib/jekyll-redirect-from/redirect_page.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module JekyllRedirectFrom
4 | # Specialty page which implements the redirect path logic
5 | class RedirectPage < Jekyll::Page
6 | # Use Jekyll's native absolute_url filter
7 | include Jekyll::Filters::URLFilters
8 |
9 | DEFAULT_DATA = {
10 | "sitemap" => false,
11 | "layout" => "redirect",
12 | }.freeze
13 |
14 | # Creates a new RedirectPage instance from a source path and redirect path
15 | #
16 | # site - The Site object
17 | # from - the (URL) path, relative to the site root to redirect from
18 | # to - the relative path or URL which the page should redirect to
19 | def self.from_paths(site, from, to)
20 | page = RedirectPage.new(site, site.source, "", "redirect.html")
21 | page.set_paths(from, to)
22 | page
23 | end
24 |
25 | # Creates a new RedirectPage instance from the path to the given doc
26 | def self.redirect_from(doc, path)
27 | RedirectPage.from_paths(doc.site, path, doc.url)
28 | end
29 |
30 | # Creates a new RedirectPage instance from the doc to the given path
31 | def self.redirect_to(doc, path)
32 | RedirectPage.from_paths(doc.site, doc.url, path)
33 | end
34 |
35 | # Overwrite the default read_yaml method since the file doesn't exist
36 | def read_yaml(_base, _name, _opts = {})
37 | self.content = self.output = ""
38 | self.data ||= DEFAULT_DATA.dup
39 | end
40 |
41 | # Helper function to set the appropriate path metadata
42 | #
43 | # from - the relative path to the redirect page
44 | # to - the relative path or absolute URL to the redirect target
45 | def set_paths(from, to)
46 | @context ||= context
47 | from = ensure_leading_slash(from)
48 | data.merge!(
49 | "permalink" => from,
50 | "redirect" => {
51 | "from" => from,
52 | "to" => %r!^https?://!.match?(to) ? to : absolute_url(to),
53 | }
54 | )
55 | end
56 |
57 | def redirect_from
58 | data["redirect"]["from"] if data["redirect"]
59 | end
60 |
61 | def redirect_to
62 | data["redirect"]["to"] if data["redirect"]
63 | end
64 |
65 | private
66 |
67 | def context
68 | JekyllRedirectFrom::Context.new(site)
69 | end
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/spec/integrations_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe "JekyllRedirectFrom integration tests" do
4 | before { site.process }
5 | let(:relative_path) { "" }
6 | let(:path) { dest_dir(relative_path) }
7 | let(:contents) { File.read(path) }
8 |
9 | context "pages" do
10 | context "single redirect from" do
11 | let(:relative_path) { "some/other/path.html" }
12 |
13 | it "exists in the built site" do
14 | expect(path).to exist
15 | expect(contents).to match("http://jekyllrb.com/one_redirect_from.html")
16 | end
17 | end
18 |
19 | context "multiple redirect froms" do
20 | ["help", "contact", "let-there/be/light-he-said", "geepers/mccreepin"].each do |redirect|
21 | context "the #{redirect} redirect" do
22 | let(:relative_path) { "#{redirect}.html" }
23 |
24 | it "exists in the built site" do
25 | expect(path).to exist
26 | expect(contents).to match("http://jekyllrb.com/multiple_redirect_froms.html")
27 | end
28 | end
29 | end
30 | end
31 |
32 | context "a redirect to URL" do
33 | let(:relative_path) { "one_redirect_to_url.html" }
34 |
35 | it "exists in the built site" do
36 | expect(path).to exist
37 | expect(contents).to match("https://www.github.com")
38 | end
39 | end
40 |
41 | context "a redirect to path" do
42 | let(:relative_path) { "one_redirect_to_path.html" }
43 |
44 | it "exists in the built site" do
45 | expect(path).to exist
46 | expect(contents).to match("http://jekyllrb.com/foo")
47 | end
48 | end
49 | end
50 |
51 | context "documents" do
52 | context "a single redirect from" do
53 | let(:relative_path) { "articles/23128432159832/mary-had-a-little-lamb.html" }
54 |
55 | it "exists in the built site" do
56 | expect(path).to exist
57 | expect(contents).to match("http://jekyllrb.com/articles/redirect-me-plz.html")
58 | end
59 | end
60 |
61 | context "redirect to" do
62 | let(:relative_path) { "articles/redirect-somewhere-else-plz.html" }
63 |
64 | it "exists in the built site" do
65 | expect(path).to exist
66 | expect(contents).to match("http://www.zombo.com")
67 | end
68 | end
69 |
70 | context "with a permalink" do
71 | let(:relative_path) { "tags/our projects/index.html" }
72 |
73 | it "exists in the built site" do
74 | expect(path).to exist
75 | expect(contents).to match("http://jekyllrb.com/tags/our-projects/")
76 | end
77 | end
78 | end
79 |
80 | context "sitemap" do
81 | let(:relative_path) { "sitemap.xml" }
82 |
83 | it "doesn't contain redirects" do
84 | expect(contents).to_not be_nil
85 | expect(contents).to_not match("redirect_to")
86 | end
87 | end
88 | end
89 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JekyllRedirectFrom
2 |
3 | Give your Jekyll posts and pages multiple URLs.
4 |
5 | When importing your posts and pages from, say, Tumblr, it's annoying and
6 | impractical to create new pages in the proper subdirectories so they, e.g.
7 | `/post/123456789/my-slug-that-is-often-incompl`, redirect to the new post URL.
8 |
9 | Instead of dealing with maintaining those pages for redirection, let
10 | `jekyll-redirect-from` handle it for you.
11 |
12 | [](https://github.com/jekyll/jekyll-redirect-from/actions/workflows/ci.yml)
13 |
14 | ## How it Works
15 |
16 | Redirects are performed by serving an HTML file with an HTTP-REFRESH meta
17 | tag which points to your destination. No `.htaccess` file, nginx conf, xml
18 | file, or anything else will be generated. It simply creates HTML files.
19 |
20 | ## Installation
21 |
22 | Add this line to your application's Gemfile:
23 |
24 | gem 'jekyll-redirect-from'
25 |
26 | And then execute:
27 |
28 | $ bundle
29 |
30 | Or install it yourself as:
31 |
32 | $ gem install jekyll-redirect-from
33 |
34 | Once it's installed into your environment, add it to your `_config.yml`:
35 |
36 | ```yaml
37 | plugins:
38 | - jekyll-redirect-from
39 | ```
40 |
41 | 💡 If you are using a Jekyll version less than 3.5.0, use the `gems` key instead of `plugins`.
42 |
43 | If you're using Jekyll in `safe` mode to mimic GitHub Pages, make sure to
44 | add jekyll-redirect-from to your whitelist:
45 |
46 | ```yaml
47 | whitelist:
48 | - jekyll-redirect-from
49 | ```
50 |
51 | Then run `jekyll --safe` like normal.
52 |
53 | ## Usage
54 |
55 | The objective of this gem is to allow an author to specify multiple URLs for a
56 | page, such that the alternative URLs redirect to the new Jekyll URL.
57 |
58 | To use it, simply add the array to the YAML front-matter of your page or post:
59 |
60 | ```yaml
61 | title: My amazing post
62 | redirect_from:
63 | - /post/123456789/
64 | - /post/123456789/my-amazing-post/
65 | ```
66 |
67 | Redirects including a trailing slash will generate a corresponding subdirectory containing an `index.html`, while redirects without a trailing slash will generate a corresponding `filename` without an extension, and without a subdirectory.
68 |
69 | For example...
70 |
71 | ```yaml
72 | redirect_from:
73 | - /post/123456789/my-amazing-post
74 | ```
75 |
76 | ...will generate the following page in the destination:
77 |
78 | ```text
79 | /post/123456789/my-amazing-post
80 | ```
81 |
82 | While...
83 |
84 | ```yaml
85 | redirect_from:
86 | - /post/123456789/my-amazing-post/
87 | ```
88 |
89 | ...will generate the following page in the destination:
90 |
91 | ```text
92 | /post/123456789/my-amazing-post/index.html
93 | ```
94 |
95 | These pages will contain an HTTP-REFRESH meta tag which redirect to your URL.
96 |
97 | You can also specify just **one url** like this:
98 |
99 | ```yaml
100 | title: My other awesome post
101 | redirect_from: /post/123456798/
102 | ```
103 |
104 | ### Prefix
105 |
106 | If `site.url` is set, its value, together with `site.baseurl`, is used as a prefix for the redirect url automatically. This is useful for scenarios where a site isn't available from the domain root, so the redirects point to the correct path. If `site.url` is not set, only `site.baseurl` is used, if set.
107 |
108 | **_Note_**: If you are hosting your Jekyll site on [GitHub Pages](https://pages.github.com/), and `site.url` is not set, the prefix is set to the pages domain name i.e. http://example.github.io/project or a custom CNAME.
109 |
110 | ### Redirect To
111 |
112 | Sometimes, you may want to redirect a site page to a totally different website. This plugin also supports that with the `redirect_to` key:
113 |
114 | ```yaml
115 | title: My amazing post
116 | redirect_to: http://www.github.com
117 | ```
118 |
119 | **Note**: Using `redirect_to` or `redirect_from` with collections will only work with files which are output to HTML, such as `.md`, `.textile`, `.html` etc.
120 |
121 | ## Customizing the redirect template
122 |
123 | If you want to customize the redirect template, you can. Simply create a layout in your site's `_layouts` directory called `redirect.html`.
124 |
125 | Your layout will get the following variables:
126 |
127 | * `page.redirect.from` - the relative path to the redirect page
128 | * `page.redirect.to` - the absolute URL (where available) to the target page
129 |
130 | ## Configuration
131 |
132 | You can configure this plugin in `_config.yml` by adding to the `redirect_from` key.
133 |
134 | ### Disabling `redirects.json`
135 |
136 | By default, a file called `redirects.json`, which can be used for automated testing or to implement server-side redirects, will be included in the output. To exclude it from the output, set the `json` key to `false`:
137 |
138 | ```yml
139 | redirect_from:
140 | json: false
141 | ```
142 |
143 | ## Contributing
144 |
145 | 1. Fork it
146 | 2. Create your feature branch (`git checkout -b my-new-feature`)
147 | 3. Commit your changes (`git commit -am 'Add some feature'`)
148 | 4. Push to the branch (`git push origin my-new-feature`)
149 | 5. Create new Pull Request
150 |
--------------------------------------------------------------------------------
/History.markdown:
--------------------------------------------------------------------------------
1 | ## HEAD
2 |
3 | ### styles
4 |
5 | * style: Style/SpecialGlobalVars (#216)
6 |
7 | ### Development Fixes
8 |
9 | * fix Gemfile to correctly install jekyll 3.9 (#224)
10 | * Refactor specs for RedirectPage (#222)
11 | * Lock to RuboCop v1.18.x (#242)
12 | * Clean up gemspec (#243)
13 | * Bump versions in CI workflow (#273)
14 |
15 | ### Bug Fixes
16 |
17 | * Refactor Redirectable mixin to reduce allocations (#241)
18 |
19 | ## 0.16.0 / 2020-01-26
20 |
21 | ### Minor Enhancements
22 |
23 | * Allows generation of `redirects.json` to be disabled (#207)
24 | * Allow redirects from and for subclasses of page and document (#204)
25 |
26 | ### Bug Fixes
27 |
28 | * Use `Hash#key?` instead of `Hash#keys.any?` (#201)
29 |
30 | ### Development Fixes
31 |
32 | * Target Ruby 2.4
33 | * Stop testing with backwards-compatible site config (#211)
34 |
35 | ### Documentation
36 |
37 | * Simplifies YAML for `redirect_to` (#185)
38 |
39 | ## 0.15.0 / 2019-03-23
40 |
41 | ### Development Fixes
42 |
43 | * chore(deps): rubocop-jekyll 0.3 (#187)
44 |
45 | ### Bug Fixes
46 |
47 | * Allow testing and using with Jekyll 4.x (#196)
48 |
49 | ## 0.14.0 / 2018-06-29
50 |
51 | ### Minor Enhancements
52 |
53 | * Run javascript at first to avoid splash (#158)
54 |
55 | ### Development Fixes
56 |
57 | * Use Rubocop 0.57
58 | * Target Ruby 2.3
59 | * Test against Ruby 2.5 (#173)
60 |
61 | ## 0.13.0 / 2017-12-03
62 |
63 | * Test against same version of Ruby that GitHub Pages uses (#132)
64 |
65 | ### Development Fixes
66 |
67 | * Rubocop (#141)
68 | * Fix tests for jekyll 3.5.x (#160)
69 | * Rubocop: autocorrect (#165)
70 |
71 | ### Minor Enhancements
72 |
73 | * HTML encode ellipsis (#142)
74 | * Added no-index to template (#152)
75 | * Define path with __dir__ (#161)
76 |
77 | ### Major Enhancements
78 |
79 | * Create redirects.json file (#147)
80 |
81 | ### Documentation
82 |
83 | * Update README.md (#167)
84 |
85 | ## 0.12.1 / 2017-01-12
86 |
87 | ### Development Fixes
88 |
89 | * Stop testing Ruby 1.9 (#133)
90 |
91 | ### Minor Enhancements
92 |
93 | * Use send to monkey patch to support Ruby < 2.2.0 (#136)
94 | * set `page.output` to empty string instead of nil (#137)
95 |
96 | ## 0.12.0 / 2017-01-02
97 |
98 | ### Major Enhancements
99 |
100 | * Support for custom redirect templates
101 | * Use Jekyll's `absolute_url` filter to generate canonical URLs (now respecting `baseurl`)
102 | * Rely more heavily on Jekyll's native Page, permalink, and extension handling logic
103 |
104 | ### Minor Enhancementse
105 |
106 | * redirect_to Pages should not have a layout. (#115)
107 | * Require Jekyll >= 3.3
108 |
109 | ### Development Enhancements
110 |
111 | * Push redirect logic to the redirect page model (#131)
112 | * Add Rubocop and enforce Jekyll coding standards
113 | * Tests no longer build and write the entire site between each example
114 | * Removed all the `is_*`? and `has_*`? helpers from the generator
115 |
116 | ## 0.11.0 / 2016-07-06
117 |
118 | * Redirect page should not have any layout (#106)
119 | * Include absolute path in canonical url (#109)
120 | * Add tag and language (#100)
121 | * Ensure redirect_to links produce an HTML file. (#111)
122 |
123 | ## 0.10.0 / 2016-03-16
124 |
125 | * Ensure output extension is assigned (#96)
126 |
127 | ## 0.9.1 / 2015-12-11
128 |
129 | * Enforce double-quote strings to pass htmlhint (#83)
130 | * Stringify all values coming from `site.github` (#89)
131 |
132 | ## 0.9.0 / 2015-10-28
133 |
134 | * Support Jekyll 3 stable (#76)
135 | * Test against Jekyll 3, 2, and GitHub Pages (#72)
136 |
137 | ## 0.8.0 / 2015-05-20
138 |
139 | * Exclude redirect pages from sitemap (#69)
140 |
141 | ## 0.7.0 / 2015-03-16
142 |
143 | * Remove spaces in redirect page (#62)
144 | * Only parse through documents/pages/posts (#56)
145 | * Simplified `has_alt_urls?` and `has_redirect_to_url?` conditions (#52)
146 | * Add support for Jekyll 3. (#59)
147 |
148 | ## 0.6.2 / 2014-09-12
149 |
150 | * Fixed error where `redirect_to` `Document`s were not being output properly (#46)
151 |
152 | ## 0.6.1 / 2014-09-08
153 |
154 | * Fixed error when the `site.github` config key is not a `Hash` (#43)
155 |
156 | ## 0.6.0 / 2014-08-22
157 |
158 | * Support redirecting to/from collection documents (#40)
159 |
160 | ## 0.5.0 / 2014-08-10
161 |
162 | ### Minor Enhancements
163 |
164 | * Support `redirect_to` property (#32)
165 | * Automatically prefix redirects with the `baseurl` or GitHub URL. (#26)
166 |
167 | ### Bug Fixes
168 |
169 | * Remove unnecessary `Array#flatten` (#34)
170 |
171 | ### Development Fixes
172 |
173 | * Use `be_truthy` instead of `be_true`. (#33)
174 |
175 | ## 0.4.0 / 2014-05-06
176 |
177 | ### Major Enhancements
178 |
179 | * Upgrade to Jekyll 2.0 (#27)
180 |
181 | ### Minor Enhancements
182 |
183 | * Shorten resulting HTML to make redirects quicker (#20)
184 |
185 | ### Development Fixes
186 |
187 | * Use SVG Travis badge in README (#21)
188 |
189 | ## 0.3.1 / 2014-01-22
190 |
191 | ### Bug Fixes
192 |
193 | * Add `safe true` to the `Jekyll::Generator` so it can be run in safe mode (#12)
194 |
195 | ## 0.3.0 / 2014-01-15
196 |
197 | ### Major Enhancements
198 |
199 | * `redirect_from` items are now proper permalinks rooted in site source (#8)
200 |
201 | ### Development Fixes
202 |
203 | * Add forgotten `s` to `gems` in README.md (#7)
204 |
205 | ## 0.2.0 / 2014-01-04
206 |
207 | ### Minor Enhancements
208 |
209 | * Allow user to set one or many `redirect_from` URLs
210 | * Rename from `jekyll-alt-urls` to `jekyll-redirect-from` (props to @benbalter)
211 | * Namespace now its own module: `JekyllRedirectFrom` (#3)
212 |
213 | ### Development Fixes
214 |
215 | * Add history file
216 | * Add specs (#3)
217 | * Add TravisCI badge (#4)
218 |
219 | ## 0.1.0 / 2013-12-15
220 |
221 | * Birthday!
222 |
--------------------------------------------------------------------------------
/spec/jekyll_redirect_from/generator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe JekyllRedirectFrom::Generator do
4 | before(:each) do
5 | site.read
6 | site.generate
7 | site.render
8 | site.write
9 | end
10 |
11 | context "layouts" do
12 | context "a site with a redirect layout" do
13 | before { site.layouts["redirect"] = "foo" }
14 |
15 | it "doesn't inject the layout" do
16 | expect(site.layouts["redirect"]).to eql("foo")
17 | end
18 | end
19 |
20 | context "a site without a redirect layout" do
21 | it "injects the layout" do
22 | expect(site.layouts["redirect"]).to be_a(JekyllRedirectFrom::Layout)
23 | end
24 | end
25 | end
26 |
27 | context "redirect froms" do
28 | context "pages" do
29 | context "a page with a single redirect" do
30 | let(:page) { site.pages.find { |p| p.url == "/some/other/path" } }
31 |
32 | it "creates the redirect" do
33 | expect(page).to_not be_nil
34 | expect(page.output).to match("http://jekyllrb.com/one_redirect_from.html")
35 | end
36 | end
37 |
38 | context "a page with multiple redirects" do
39 | let(:redirects) do
40 | ["/help", "/contact", "/let-there/be/light-he-said", "/geepers/mccreepin"]
41 | end
42 |
43 | it "creates all the redirects" do
44 | redirects.each do |url|
45 | page = site.pages.find { |p| p.url == url }
46 | expect(page).to_not be_nil
47 | expect(page.output).to match("http://jekyllrb.com/multiple_redirect_froms.html")
48 | end
49 | end
50 | end
51 | end
52 |
53 | context "documents" do
54 | let(:page) { site.pages.find { |p| p.url == "/articles/23128432159832/mary-had-a-little-lamb" } }
55 |
56 | it "redirects" do
57 | expect(page).to_not be_nil
58 | expect(page.output).to match("http://jekyllrb.com/articles/redirect-me-plz.html")
59 | end
60 | end
61 | end
62 |
63 | context "redirect tos" do
64 | context "pages" do
65 | context "a single redirect to" do
66 | let(:page) { site.pages.find { |p| p.url == "/one_redirect_to_url.html" } }
67 |
68 | it "redirects" do
69 | expect(page.output).to match("https://www.github.com")
70 | end
71 | end
72 |
73 | context "multiple redirect tos" do
74 | let(:page) { site.pages.find { |p| p.url == "/multiple_redirect_tos.html" } }
75 |
76 | it "redirects to the first entry" do
77 | expect(page.output).to match("https://www.jekyllrb.com")
78 | end
79 | end
80 | end
81 |
82 | context "documents" do
83 | let(:doc) { site.documents.find { |p| p.url == "/articles/redirect-somewhere-else-plz.html" } }
84 |
85 | it "redirects" do
86 | expect(doc.output).to match("http://www.zombo.com")
87 | end
88 | end
89 | end
90 |
91 | context "redirects.json" do
92 | let(:path) { dest_dir("redirects.json") }
93 | let(:contents) { File.read(path) }
94 | let(:redirects) { JSON.parse(contents) }
95 | let(:domain) { "http://jekyllrb.com" }
96 |
97 | it "creates the redirects file" do
98 | expect(path).to exist
99 | end
100 |
101 | it "contains redirects" do
102 | expect(redirects.count).to eql(13)
103 | end
104 |
105 | it "contains single redirects tos" do
106 | expect(redirects.keys).to include "/one_redirect_to_path.html"
107 | expect(redirects["/one_redirect_to_path.html"]).to eql("#{domain}/foo")
108 | end
109 |
110 | it "contains multiple redirect tos" do
111 | expect(redirects.keys).to include "/multiple_redirect_tos.html"
112 | expect(redirects["/multiple_redirect_tos.html"]).to eql("https://www.jekyllrb.com")
113 | end
114 |
115 | it "contains single redirect froms" do
116 | expect(redirects.keys).to include "/some/other/path"
117 | expect(redirects["/some/other/path"]).to eql("#{domain}/one_redirect_from.html")
118 | end
119 |
120 | it "contains multiple redirect froms" do
121 | expect(redirects.keys).to include "/help"
122 | expect(redirects["/help"]).to eql("#{domain}/multiple_redirect_froms.html")
123 |
124 | expect(redirects.keys).to include "/contact"
125 | expect(redirects["/contact"]).to eql("#{domain}/multiple_redirect_froms.html")
126 | end
127 |
128 | context "with a user-supplied redirects.json" do
129 | let(:source_path) { File.join fixtures_path, "redirects.json" }
130 | before do
131 | File.write source_path, { "foo" => "bar" }.to_json
132 | site.reset
133 | site.read
134 | site.generate
135 | site.render
136 | site.write
137 | end
138 |
139 | after do
140 | FileUtils.rm_f source_path
141 | end
142 |
143 | it "doesn't overwrite redirects.json" do
144 | expect(path).to exist
145 | expect(redirects).to eql("foo" => "bar")
146 | end
147 | end
148 |
149 | context "when explicitly disabled" do
150 | let(:site) { Jekyll::Site.new(config.merge("redirect_from" => { "json" => false })) }
151 |
152 | it "does not create the redirects file" do
153 | expect(path).to_not exist
154 | end
155 | end
156 | end
157 |
158 | context "redirectable_document?" do
159 | let(:generator) { JekyllRedirectFrom::Generator.new }
160 |
161 | it "accepts subclasses of Jekyll::Document" do
162 | SubclassOfJekyllDocument = Class.new(Jekyll::Document) { define_method(:initialize) {} }
163 | expect(generator.send(:redirectable_document?, SubclassOfJekyllDocument.new)).to be_truthy
164 | end
165 |
166 | it "accepts subclasses of Jekyll::Page" do
167 | SubclassOfJekyllPage = Class.new(Jekyll::Page) { define_method(:initialize) {} }
168 | expect(generator.send(:redirectable_document?, SubclassOfJekyllPage.new)).to be_truthy
169 | end
170 | end
171 | end
172 |
--------------------------------------------------------------------------------
/spec/jekyll_redirect_from/redirect_page_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe JekyllRedirectFrom::RedirectPage do
4 | let(:site_url) { site.config["url"] }
5 | before { site.read }
6 |
7 | shared_examples "a redirect page" do
8 | context "being a page" do
9 | before { page.read_yaml(nil, nil, nil) }
10 |
11 | it "returns no content" do
12 | expect(page.content).to eql("")
13 | end
14 |
15 | it "returns no output" do
16 | expect(page.output).to eql("")
17 | end
18 |
19 | it "sets default data" do
20 | expect(page.to_liquid["layout"]).to eql("redirect")
21 | expect(page.to_liquid["sitemap"]).to be_falsey
22 | end
23 |
24 | it "sets the paths" do
25 | expect(page.to_liquid["permalink"]).to eql(from)
26 | expect(page.to_liquid).to have_key("redirect")
27 | expect(page.to_liquid["redirect"]["from"]).to eql(from)
28 | expect(page.to_liquid["redirect"]["to"]).to eql("#{site_url}#{to}")
29 | end
30 |
31 | it "sets the permalink" do
32 | expect(page.to_liquid["permalink"]).to eql(from)
33 | end
34 |
35 | it "sets redirect metadata" do
36 | expect(page.to_liquid).to have_key("redirect")
37 | expect(page.to_liquid["redirect"]["from"]).to eql(from)
38 | expect(page.to_liquid["redirect"]["to"]).to eql("#{site_url}#{to}")
39 | end
40 | end
41 |
42 | context "generating" do
43 | before { site.generate }
44 | let(:output) { Jekyll::Renderer.new(site, page, site.site_payload).run }
45 |
46 | it "renders the template" do
47 | expect(output).to_not be_nil
48 | expect(output.to_s).to_not be_empty
49 | end
50 |
51 | it "contains the meta refresh tag" do
52 | expect(output).to match("")
53 | end
54 |
55 | it "contains the javascript redirect" do
56 | expect(output).to match("")
57 | end
58 |
59 | it "contains canonical link in header" do
60 | expect(output).to match("")
61 | end
62 |
63 | it "contains the clickable link" do
64 | expect(output).to match("Click here if you are not redirected.")
65 | end
66 | end
67 | end
68 |
69 | context "redirecting to" do
70 | let(:to) { "/bar" }
71 | let(:doc) { site.documents.first }
72 | subject(:page) { described_class.redirect_to(doc, to) }
73 | let(:from) { doc.url }
74 |
75 | it_behaves_like "a redirect page"
76 |
77 | context "a relative path" do
78 | let(:to) { "/bar" }
79 |
80 | it "redirects" do
81 | expect(page.to_liquid["permalink"]).to eql("/2014/01/03/redirect-me-plz.html")
82 | expect(page.to_liquid).to have_key("redirect")
83 | expect(page.to_liquid["redirect"]["to"]).to eql("#{site_url}#{to}")
84 | expect(page.to_liquid["redirect"]["from"]).to eql("/2014/01/03/redirect-me-plz.html")
85 | end
86 |
87 | context "with no leading slash" do
88 | let(:to) { "bar" }
89 |
90 | it "redirects" do
91 | expect(page.to_liquid).to have_key("redirect")
92 | expect(page.to_liquid["redirect"]["to"]).to eql("#{site_url}/#{to}")
93 | end
94 | end
95 |
96 | context "with a trailing slash" do
97 | let(:to) { "/bar/" }
98 |
99 | it "redirects" do
100 | expect(page.to_liquid).to have_key("redirect")
101 | expect(page.to_liquid["redirect"]["to"]).to eql("#{site_url}#{to}")
102 | end
103 | end
104 | end
105 |
106 | context "an absolute URL" do
107 | let(:to) { "https://foo.invalid" }
108 |
109 | it "redirects" do
110 | expect(page.to_liquid["permalink"]).to eql("/2014/01/03/redirect-me-plz.html")
111 | expect(page.to_liquid).to have_key("redirect")
112 | expect(page.to_liquid["redirect"]["to"]).to eql("https://foo.invalid")
113 | expect(page.to_liquid["redirect"]["from"]).to eql("/2014/01/03/redirect-me-plz.html")
114 | end
115 | end
116 | end
117 |
118 | context "redirecting from" do
119 | let(:from) { "/foo" }
120 | let(:doc) { site.documents.first }
121 | subject(:page) { described_class.redirect_from(doc, from) }
122 | let(:to) { doc.url }
123 |
124 | it_behaves_like "a redirect page"
125 |
126 | it "sets liquid data for the page" do
127 | expect(page.to_liquid["permalink"]).to eql(from)
128 | expect(page.to_liquid).to have_key("redirect")
129 | expect(page.to_liquid["redirect"]["from"]).to eql(from)
130 | expected = "http://jekyllrb.com/2014/01/03/redirect-me-plz.html"
131 | expect(page.to_liquid["redirect"]["to"]).to eql(expected)
132 | end
133 |
134 | context "when redirect from has no extension" do
135 | let(:from) { "/foo" }
136 |
137 | it "adds .html" do
138 | expected = File.expand_path "foo.html", site.dest
139 | expect(page.destination("/")).to eql(expected)
140 | end
141 | end
142 |
143 | context "when redirect from is a directory" do
144 | let(:from) { "/foo/" }
145 |
146 | it "knows to add the index.html" do
147 | expected = File.expand_path "foo/index.html", site.dest
148 | expect(page.destination("/")).to eql(expected)
149 | end
150 |
151 | it "uses HTML" do
152 | expect(page.output_ext).to eql(".html")
153 | end
154 | end
155 |
156 | context "when redirect from is an HTML file" do
157 | let(:from) { "/foo.html" }
158 |
159 | it "adds .html" do
160 | expected = File.expand_path "foo.html", site.dest
161 | expect(page.destination("/")).to eql(expected)
162 | end
163 | end
164 |
165 | context "when redirect from is another extension" do
166 | let(:from) { "/foo.htm" }
167 |
168 | it "doesn't add .html" do
169 | expected = File.expand_path "foo.htm", site.dest
170 | expect(page.destination("/")).to eql(expected)
171 | end
172 |
173 | it "honors the extension" do
174 | expect(page.output_ext).to eql(".htm")
175 | end
176 | end
177 |
178 | context "when redirect from has no leading slash" do
179 | let(:from) { "foo" }
180 |
181 | it "adds the slash" do
182 | expected = File.expand_path "foo.html", site.dest
183 | expect(page.destination("/")).to eql(expected)
184 | end
185 |
186 | it "uses HTML" do
187 | expect(page.output_ext).to eql(".html")
188 | end
189 | end
190 | end
191 | end
192 |
--------------------------------------------------------------------------------