meta-tags 2.11.0 → 2.18.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,19 +5,19 @@
5
5
  [![Code Climate](https://codeclimate.com/github/kpumuk/meta-tags/badges/gpa.svg)](https://codeclimate.com/github/kpumuk/meta-tags)
6
6
  [![Test Coverage](https://codeclimate.com/github/kpumuk/meta-tags/badges/coverage.svg)](https://codeclimate.com/github/kpumuk/meta-tags/coverage)
7
7
  [![Gem Downloads](https://img.shields.io/gem/dt/meta-tags.svg)](https://badge.fury.io/rb/meta-tags)
8
- [![Changelog](https://img.shields.io/badge/Changelog-latest-blue.svg)](https://github.com/kpumuk/meta-tags/blob/master/CHANGELOG.md)
8
+ [![Changelog](https://img.shields.io/badge/Changelog-latest-blue.svg)](https://github.com/kpumuk/meta-tags/blob/main/CHANGELOG.md)
9
9
 
10
10
  Search Engine Optimization (SEO) plugin for Ruby on Rails applications.
11
11
 
12
12
  ## Ruby on Rails
13
13
 
14
- MetaTags master branch fully supports Ruby on Rails 4.2+, and is tested against all
15
- major Rails releases up to 5.1.
14
+ MetaTags main branch fully supports Ruby on Rails 5.1+, and is tested against all
15
+ major Rails releases up to 7.0.
16
16
 
17
- Ruby versions older than 2.2.0 are no longer officially supported.
17
+ Ruby versions older than 2.6 are no longer officially supported.
18
18
 
19
- _Please note_ that we are no longer support Ruby versions older than 2.2.0 and
20
- Ruby on Rails older than 4.2, because they [reached their End of Life](https://github.com/kpumuk/meta-tags/pull/143).
19
+ _Please note_ that we no longer support Ruby versions older than 2.6.0 and
20
+ Ruby on Rails older than 5.1, because they reached their [End of Life](https://endoflife.date/ruby).
21
21
 
22
22
  ## Installation
23
23
 
@@ -36,7 +36,7 @@ truncation have recommended values, you can change them to reflect your own
36
36
  preferences. Keywords are converted to lowercase by default, but this is also
37
37
  configurable.
38
38
 
39
- To overide the defaults, create an initializer
39
+ To override the defaults, create an initializer
40
40
  `config/initializers/meta_tags.rb` using the following command:
41
41
 
42
42
  ```bash
@@ -152,30 +152,30 @@ If you want to set the title and display another text, use this:
152
152
 
153
153
  Use these options to customize the title format:
154
154
 
155
- | Option | Description |
156
- | -------------- | ----------- |
157
- | `:site` | site title |
158
- | `:title` | page title |
159
- | `:description` | page description |
160
- | `:keywords` | page keywords |
161
- | `:charset` | page character set |
162
- | `:prefix` | text between site name and separator |
163
- | `:separator` | text used to separate website name from page title |
164
- | `:suffix` | text between separator and page title |
165
- | `:lowercase` | when true, the page name will be lowercase |
166
- | `:reverse` | when true, the page and site names will be reversed |
167
- | `:noindex` | add noindex meta tag; when true, 'robots' will be used, otherwise the string will be used |
168
- | `:index` | add index meta tag; when true, 'robots' will be used, otherwise the string will be used |
169
- | `:nofollow` | add nofollow meta tag; when true, 'robots' will be used, otherwise the string will be used |
170
- | `:follow` | add follow meta tag; when true, 'robots' will be used, otherwise the string will be used |
171
- | `:noarchive` | add noarchive meta tag; when true, 'robots' will be used, otherwise the string will be used |
172
- | `:canonical` | add canonical link tag |
173
- | `:prev` | add prev link tag |
174
- | `:next` | add next link tag |
175
- | `:image_src` | add image_src link tag |
176
- | `:og` | add Open Graph tags (Hash) |
177
- | `:twitter` | add Twitter tags (Hash) |
178
- | `:refresh` | refresh interval and optionally url to redirect to |
155
+ | Option | Description |
156
+ | -------------- | -------------------------------------------------------------------------------------------------------------------- |
157
+ | `:site` | site title |
158
+ | `:title` | page title |
159
+ | `:description` | page description |
160
+ | `:keywords` | page keywords |
161
+ | `:charset` | page character set |
162
+ | `:prefix` | text between site name and separator |
163
+ | `:separator` | text used to separate website name from page title |
164
+ | `:suffix` | text between separator and page title |
165
+ | `:lowercase` | when true, the page name will be lowercase |
166
+ | `:reverse` | when true, the page and site names will be reversed |
167
+ | `:noindex` | add noindex meta tag; when true, 'robots' will be used; accepts a string with a robot name, or an array of strings |
168
+ | `:index` | add index meta tag; when true, 'robots' will be used; accepts a string with a robot name, or an array of strings |
169
+ | `:nofollow` | add nofollow meta tag; when true, 'robots' will be used; accepts a string with a robot name, or an array of strings |
170
+ | `:follow` | add follow meta tag; when true, 'robots' will be used; accepts a string with a robot name, or an array of strings |
171
+ | `:noarchive` | add noarchive meta tag; when true, 'robots' will be used; accepts a string with a robot name, or an array of strings |
172
+ | `:canonical` | add canonical link tag |
173
+ | `:prev` | add prev link tag |
174
+ | `:next` | add next link tag |
175
+ | `:image_src` | add image_src link tag |
176
+ | `:og` | add Open Graph tags (Hash) |
177
+ | `:twitter` | add Twitter tags (Hash) |
178
+ | `:refresh` | refresh interval and optionally url to redirect to |
179
179
 
180
180
  And here are a few examples to give you ideas.
181
181
 
@@ -307,7 +307,7 @@ Recommended title tag length: up to <b>70 characters</b>, <b>10 words</b>.
307
307
 
308
308
  Further reading:
309
309
 
310
- * [Title Tag](https://moz.com/learn/seo/title-tag)
310
+ - [Title Tag](https://moz.com/learn/seo/title-tag)
311
311
 
312
312
  ### Description
313
313
 
@@ -325,8 +325,8 @@ Recommended description tag length: up to <b>300 characters</b>.
325
325
 
326
326
  Further reading:
327
327
 
328
- * [Meta Description](https://moz.com/learn/seo/meta-description)
329
- * [How Long Should Your Meta Description Be? (2018 Edition)](https://moz.com/blog/how-long-should-your-meta-description-be-2018)
328
+ - [Meta Description](https://moz.com/learn/seo/meta-description)
329
+ - [How Long Should Your Meta Description Be? (2018 Edition)](https://moz.com/blog/how-long-should-your-meta-description-be-2018)
330
330
 
331
331
  ### Keywords
332
332
 
@@ -360,8 +360,8 @@ This is useful for pages like login, password reset, privacy policy, etc.
360
360
 
361
361
  Further reading:
362
362
 
363
- * [Blocking Google](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=93708)
364
- * [Using meta tags to block access to your site](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=93710)
363
+ - [Blocking Google](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=93708)
364
+ - [Using meta tags to block access to your site](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=93710)
365
365
 
366
366
  ### Index
367
367
 
@@ -388,12 +388,12 @@ set_meta_tags nofollow: 'googlebot'
388
388
 
389
389
  Further reading:
390
390
 
391
- * [About rel="nofollow"](http://www.google.com/support/webmasters/bin/answer.py?answer=96569)
392
- * [Meta tags](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=79812)
391
+ - [About rel="nofollow"](http://www.google.com/support/webmasters/bin/answer.py?answer=96569)
392
+ - [Meta tags](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=79812)
393
393
 
394
394
  ### Follow
395
395
 
396
- Follow will work with Noindex meta tag
396
+ Follow will work with Noindex meta tag
397
397
 
398
398
  ```ruby
399
399
  set_meta_tags noindex: true, follow: true
@@ -409,6 +409,9 @@ Canonical link element tells a search engine what is the canonical or main URL
409
409
  for a content which have multiple URLs. The search engine will always return
410
410
  that URL, and link popularity and authority will be applied to that URL.
411
411
 
412
+ Note: If you like follow a hint of John Mueller that you shouldn't mix canonical with noindex, then you can
413
+ set `MetaTags.config.skip_canonical_links_on_noindex = true` and we'll handle it for you.
414
+
412
415
  ```ruby
413
416
  set_meta_tags canonical: "http://yoursite.com/canonical/url"
414
417
  # <link rel="canonical" href="http://yoursite.com/canonical/url">
@@ -416,8 +419,8 @@ set_meta_tags canonical: "http://yoursite.com/canonical/url"
416
419
 
417
420
  Further reading:
418
421
 
419
- * [About rel="canonical"](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=139394)
420
- * [Canonicalization](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=139066)
422
+ - [About rel="canonical"](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=139394)
423
+ - [Canonicalization](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=139066)
421
424
 
422
425
  ### Icon
423
426
 
@@ -440,9 +443,8 @@ set_meta_tags icon: [
440
443
 
441
444
  Further reading:
442
445
 
443
- * [Favicon](https://www.wikiwand.com/en/Favicon)
444
- * [Touch Icons](https://mathiasbynens.be/notes/touch-icons)
445
-
446
+ - [Favicon](https://www.wikiwand.com/en/Favicon)
447
+ - [Touch Icons](https://mathiasbynens.be/notes/touch-icons)
446
448
 
447
449
  ### Multi-regional and multilingual URLs, RSS and mobile links
448
450
 
@@ -471,9 +473,9 @@ set_meta_tags alternate: [
471
473
 
472
474
  Further reading:
473
475
 
474
- * [Multi-regional and multilingual sites](https://support.google.com/webmasters/answer/182192)
475
- * [About rel="alternate" hreflang="x"](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=189077)
476
- * [Separate URLs](https://developers.google.com/webmasters/mobile-sites/mobile-seo/configurations/separate-urls#annotation-in-the-html)
476
+ - [Multi-regional and multilingual sites](https://support.google.com/webmasters/answer/182192)
477
+ - [About rel="alternate" hreflang="x"](http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=189077)
478
+ - [Separate URLs](https://developers.google.com/webmasters/mobile-sites/mobile-seo/configurations/separate-urls#annotation-in-the-html)
477
479
 
478
480
  ### Pagination links
479
481
 
@@ -490,8 +492,8 @@ set_meta_tags next: "http://yoursite.com/url?page=3"
490
492
 
491
493
  Further reading:
492
494
 
493
- * [Pagination](http://support.google.com/webmasters/bin/answer.py?hl=en&answer=1663744)
494
- * [Pagination with rel="next" and rel="prev"](http://googlewebmastercentral.blogspot.ca/2011/09/pagination-with-relnext-and-relprev.html)
495
+ - [Pagination](http://support.google.com/webmasters/bin/answer.py?hl=en&answer=1663744)
496
+ - [Pagination with rel="next" and rel="prev"](http://googlewebmastercentral.blogspot.ca/2011/09/pagination-with-relnext-and-relprev.html)
495
497
 
496
498
  ### image_src links
497
499
 
@@ -518,8 +520,17 @@ set_meta_tags amphtml: url_for(format: :amp, only_path: false)
518
520
 
519
521
  To link back to normal version, use `canonical`.
520
522
 
521
- * [What Is AMP?](https://www.ampproject.org/learn/about-amp/)
522
- * [Make Your Page Discoverable](https://www.ampproject.org/docs/guides/discovery)
523
+ - [What Is AMP?](https://www.ampproject.org/learn/about-amp/)
524
+ - [Make Your Page Discoverable](https://www.ampproject.org/docs/guides/discovery)
525
+
526
+ ### Manifest links
527
+
528
+ ```ruby
529
+ set_meta_tags manifest: 'manifest.json'
530
+ # <link rel="manifest" href="manifest.json">
531
+ ```
532
+
533
+ - [What is manifest?](https://developer.mozilla.org/en-US/docs/Web/Manifest)
523
534
 
524
535
  ### Refresh interval and redirect URL
525
536
 
@@ -539,9 +550,8 @@ set_meta_tags refresh: '5;url=http://example.com'
539
550
 
540
551
  Further reading:
541
552
 
542
- * [Meta refresh](http://en.wikipedia.org/wiki/Meta_refresh)
543
- * [What is the Meta Refresh Tag](http://webdesign.about.com/od/metataglibraries/a/aa080300a.htm)
544
-
553
+ - [Meta refresh](http://en.wikipedia.org/wiki/Meta_refresh)
554
+ - [What is the Meta Refresh Tag](http://webdesign.about.com/od/metataglibraries/a/aa080300a.htm)
545
555
 
546
556
  ### Open Search
547
557
 
@@ -557,8 +567,8 @@ set_meta_tags open_search: {
557
567
 
558
568
  Further reading:
559
569
 
560
- * [OpenSearch specs](http://www.opensearch.org/Specifications/OpenSearch/1.1)
561
- * [OpenSearch wiki](http://en.wikipedia.org/wiki/OpenSearch)
570
+ - [OpenSearch specs](http://www.opensearch.org/Specifications/OpenSearch/1.1)
571
+ - [OpenSearch wiki](http://en.wikipedia.org/wiki/OpenSearch)
562
572
 
563
573
  ### Hashes
564
574
 
@@ -660,8 +670,8 @@ set_meta_tags article: {
660
670
 
661
671
  Further reading:
662
672
 
663
- * [Open Graph protocol](http://developers.facebook.com/docs/opengraph/)
664
- * [Must-Have Social Meta Tags for Twitter, Google+, Facebook and More](https://moz.com/blog/meta-data-templates-123)
673
+ - [Open Graph protocol](http://developers.facebook.com/docs/opengraph/)
674
+ - [Must-Have Social Meta Tags for Twitter, Google+, Facebook and More](https://moz.com/blog/meta-data-templates-123)
665
675
 
666
676
  ### Twitter Cards
667
677
 
@@ -696,9 +706,27 @@ set_meta_tags twitter: {
696
706
  # <meta name="twitter:image:height" content="100">
697
707
  ```
698
708
 
709
+ Special parameter `itemprop` can be used on a "anonymous" tag "\_" to generate "itemprop" HTML attribute:
710
+
711
+ ```ruby
712
+ set_meta_tags twitter: {
713
+ card: "photo",
714
+ image: {
715
+ _: "http://example.com/1.png",
716
+ width: 100,
717
+ height: 100,
718
+ itemprop: "image",
719
+ }
720
+ }
721
+ # <meta name="twitter:card" content="photo">
722
+ # <meta name="twitter:image" content="http://example.com/1.png" itemprop="image">
723
+ # <meta name="twitter:image:width" content="100">
724
+ # <meta name="twitter:image:height" content="100">
725
+ ```
726
+
699
727
  Further reading:
700
728
 
701
- * [Twitter Cards Documentation](https://dev.twitter.com/cards/)
729
+ - [Twitter Cards Documentation](https://dev.twitter.com/cards/)
702
730
 
703
731
  ### App Links
704
732
 
@@ -719,7 +747,7 @@ set_meta_tags al: {
719
747
 
720
748
  Further reading:
721
749
 
722
- * [App Links Documentation](https://developers.facebook.com/docs/applinks)
750
+ - [App Links Documentation](https://developers.facebook.com/docs/applinks)
723
751
 
724
752
  ### Custom meta tags
725
753
 
data/Rakefile CHANGED
@@ -16,3 +16,34 @@ task :circleci do
16
16
  config_path = File.expand_path('.circleci/config.yml', __dir__)
17
17
  File.write config_path, ERB.new(File.read(template_path)).result
18
18
  end
19
+
20
+ module SteepRunner
21
+ def self.run(*command)
22
+ require "steep"
23
+ require "steep/cli"
24
+
25
+ Steep::CLI.new(argv: command, stdout: $stdout, stderr: $stderr, stdin: $stdin).run
26
+ end
27
+ end
28
+
29
+ task :steep do
30
+ SteepRunner.run("check")
31
+ end
32
+
33
+ namespace :steep do
34
+ task :stats do
35
+ SteepRunner.run("stats", "--log-level=fatal")
36
+ end
37
+ end
38
+
39
+ namespace :rbs do
40
+ task :spec do
41
+ exec(
42
+ {
43
+ 'RBS_TEST_TARGET' => 'MetaTags::*',
44
+ 'RUBYOPT' => '-rrbs/test/setup',
45
+ },
46
+ 'bundle exec rspec',
47
+ )
48
+ end
49
+ end
data/Steepfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :lib do
4
+ signature "sig"
5
+
6
+ check "lib"
7
+ # check "Gemfile"
8
+
9
+ # We don't want to type check Rails/RSpec related code
10
+ # (because we don't have RBS files for it)
11
+ ignore "lib/meta_tags/railtie.rb"
12
+ ignore "lib/generators"
13
+
14
+ library "set"
15
+ end
data/certs/kpumuk.pem CHANGED
@@ -1,7 +1,7 @@
1
1
  -----BEGIN CERTIFICATE-----
2
2
  MIIDODCCAiCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhrcHVt
3
- dWsvREM9a3B1bXVrL0RDPWluZm8wHhcNMTgxMTE2MTgxOTIzWhcNMTkxMTE2MTgx
4
- OTIzWjAjMSEwHwYDVQQDDBhrcHVtdWsvREM9a3B1bXVrL0RDPWluZm8wggEiMA0G
3
+ dWsvREM9a3B1bXVrL0RDPWluZm8wHhcNMjIwNzA1MjIyODU4WhcNMjMwNzA1MjIy
4
+ ODU4WjAjMSEwHwYDVQQDDBhrcHVtdWsvREM9a3B1bXVrL0RDPWluZm8wggEiMA0G
5
5
  CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8NmK6GXPiE/q7PDbj7nNdw3pa8a6Q
6
6
  IDxLtc7kW95e1mh0TVgOE8kvGegGtRtjvhXVGTTFtZ+yMD/0DCfTM2oUQYk5oYpO
7
7
  ZGrCfbNIdZauf4WYsnJtKOTrRoqFMwpL5PlBDKczB2y5lUmQs2HIsjQ0Q21wdKyy
@@ -10,11 +10,11 @@ ZGrCfbNIdZauf4WYsnJtKOTrRoqFMwpL5PlBDKczB2y5lUmQs2HIsjQ0Q21wdKyy
10
10
  RryRTj5NVZbq9p1/WRc5zxD9QhAEPjRa5ikbd+eWebIDpAKI0hpyC/9bAgMBAAGj
11
11
  dzB1MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBT2uFRXNWDpVdbv
12
12
  +xBk8DAgJPGBPTAdBgNVHREEFjAUgRJrcHVtdWtAa3B1bXVrLmluZm8wHQYDVR0S
13
- BBYwFIESa3B1bXVrQGtwdW11ay5pbmZvMA0GCSqGSIb3DQEBCwUAA4IBAQB9bd46
14
- p2C6r49hmuxMrIFRi05MS0Nze6GvlYvF5mb2+KS9YCLWLFb1G+0zttX51qVdO3nc
15
- uw1O5ku+Up47jv5ClyguHinCntFCA5hupyYkbpnFuURZE3QIY6UZQyJ2xuIPFfnR
16
- Q8sXb5/btWSNhKXx29TL35SkEH5fzPA90DljUPGp3lLEK0+7FQk0OkRVumdyanEE
17
- LUchqnAWHnNCdQhEhsnbYhSvG0NE2uzMWeUd6uDONYsRFNRXaRwj8tykWgKZvIod
18
- j0ZkOZOMk6hzny9+AnYZ7eiUqp/XX7Hn+hqtl/AebKhbFapnTu0n7KcfM0oDaLUr
19
- Fc+FAHErSClMb7YN
13
+ BBYwFIESa3B1bXVrQGtwdW11ay5pbmZvMA0GCSqGSIb3DQEBCwUAA4IBAQBa5fMh
14
+ JcbhWBoP3kA32g3yM238fyJlre/ZeE6WIFxcuETff8AgPmk550qpAF/WBtP23X8Q
15
+ khIFv+bFiuBURvNbuFevs23to7NeNA7XMmEJqjB6fRzO/i/a3bkLG07u+o74MyXe
16
+ 3/VAxl4Ce+C3aLwXccsbD+Fe3kQ6ku4ceIh2WebBSkpG3WRANReEAf7lcOt4aGEt
17
+ nkYjyHgDz6/gYamK15XtOivglkTJDwAVGBzF9o6j5IQ9nXho8Vd2P+hiawx76CoT
18
+ ANVO3I4ZwTKD12DMFqjalLwbSVVO4wpuMO3tcAgO4q7Fqh2tXTXom/YYl0SFvmx4
19
+ evTPD0iY8lmGP3ZM
20
20
  -----END CERTIFICATE-----
@@ -33,6 +33,12 @@ module MetaTags
33
33
  # - an array of strings or symbols representing their names or name-prefixes.
34
34
  attr_reader :property_tags
35
35
 
36
+ # Configure whenever Meta-Tags should skip canonicals on pages with noindex: true
37
+ # "shouldn't mix noindex & rel=canonical comes from: they're very contradictory pieces of information for us."
38
+ # - John Mueller (Webmaster Trends Analyst at Google)
39
+ # https://www.reddit.com/r/TechSEO/comments/8yahdr/2_questions_about_the_canonical_tag/e2dey9i/
40
+ attr_accessor :skip_canonical_links_on_noindex
41
+
36
42
  # Initializes a new instance of Configuration class.
37
43
  def initialize
38
44
  reset_defaults!
@@ -77,6 +83,7 @@ module MetaTags
77
83
  @property_tags = default_property_tags.dup
78
84
  @open_meta_tags = true
79
85
  @minify_output = false
86
+ @skip_canonical_links_on_noindex = false
80
87
  end
81
88
  end
82
89
  end
@@ -15,9 +15,9 @@ module MetaTags
15
15
  # Processes the <tt>@page_title</tt>, <tt>@page_keywords</tt>, and
16
16
  # <tt>@page_description</tt> instance variables and calls +render+.
17
17
  def render(*args, &block)
18
- meta_tags[:title] = @page_title if @page_title
19
- meta_tags[:keywords] = @page_keywords if @page_keywords
20
- meta_tags[:description] = @page_description if @page_description
18
+ meta_tags[:title] = @page_title if defined?(@page_title) && @page_title
19
+ meta_tags[:keywords] = @page_keywords if defined?(@page_keywords) && @page_keywords
20
+ meta_tags[:description] = @page_description if defined?(@page_description) && @page_description
21
21
 
22
22
  super
23
23
  end
@@ -9,7 +9,7 @@ module MetaTags
9
9
  # Initializes a new instance of MetaTagsCollection.
10
10
  #
11
11
  def initialize
12
- @meta_tags = HashWithIndifferentAccess.new
12
+ @meta_tags = ActiveSupport::HashWithIndifferentAccess.new
13
13
  end
14
14
 
15
15
  # Returns meta tag value by name.
@@ -38,7 +38,13 @@ module MetaTags
38
38
  # @return [Hash] result of the merge.
39
39
  #
40
40
  def update(object = {})
41
- meta_tags = object.respond_to?(:to_meta_tags) ? object.to_meta_tags : object
41
+ meta_tags = if object.respond_to?(:to_meta_tags)
42
+ # @type var object: (_MetaTagish & Object)
43
+ object.to_meta_tags
44
+ else
45
+ # @type var object: Hash[String | Symbol, untyped]
46
+ object
47
+ end
42
48
  @meta_tags.deep_merge! normalize_open_graph(meta_tags)
43
49
  end
44
50
 
@@ -64,14 +70,16 @@ module MetaTags
64
70
  with_defaults(defaults) { extract_full_title }
65
71
  end
66
72
 
67
- # Constructs the title without site title (for normalized parameters).
73
+ # Constructs the title without site title (for normalized parameters). When title is empty,
74
+ # use the site title instead.
68
75
  #
69
76
  # @return [String] page title.
70
77
  #
71
78
  def page_title(defaults = {})
72
79
  old_site = @meta_tags[:site]
73
80
  @meta_tags[:site] = nil
74
- with_defaults(defaults) { extract_full_title }
81
+ full_title = with_defaults(defaults) { extract_full_title }
82
+ full_title.presence || old_site || ''
75
83
  ensure
76
84
  @meta_tags[:site] = old_site
77
85
  end
@@ -99,7 +107,7 @@ module MetaTags
99
107
  #
100
108
  def extract_full_title
101
109
  site_title = extract(:site) || ''
102
- title = extract_title || []
110
+ title = extract_title
103
111
  separator = extract_separator
104
112
  reverse = extract(:reverse) == true
105
113
 
@@ -112,8 +120,9 @@ module MetaTags
112
120
  #
113
121
  def extract_title
114
122
  title = extract(:title).presence
115
- return unless title
123
+ return [] unless title
116
124
 
125
+ # @type var title: Array[String]
117
126
  title = Array(title)
118
127
  return title.map(&:downcase) if extract(:lowercase) == true
119
128
 
@@ -142,28 +151,20 @@ module MetaTags
142
151
  #
143
152
  # @return [Hash<String,String>] noindex attributes.
144
153
  #
145
- def extract_noindex
146
- noindex_name, noindex_value = extract_noindex_attribute(:noindex)
147
- index_name, index_value = extract_noindex_attribute(:index)
148
-
149
- nofollow_name, nofollow_value = extract_noindex_attribute(:nofollow)
150
- follow_name, follow_value = extract_noindex_attribute(:follow)
151
-
152
- noindex_attributes = if noindex_name == follow_name && (noindex_value || follow_value)
153
- # noindex has higher priority than index and follow has higher priority than nofollow
154
- [
155
- [noindex_name, noindex_value || index_value],
156
- [follow_name, follow_value || nofollow_value],
157
- ]
158
- else
159
- [
160
- [index_name, index_value],
161
- [follow_name, follow_value],
162
- [noindex_name, noindex_value],
163
- [nofollow_name, nofollow_value],
164
- ]
165
- end
166
- append_noarchive_attribute group_attributes_by_key noindex_attributes
154
+ def extract_robots
155
+ result = Hash.new { |h, k| h[k] = [] }
156
+
157
+ [
158
+ # noindex has higher priority than index
159
+ [:noindex, :index],
160
+ # follow has higher priority than nofollow
161
+ [:follow, :nofollow],
162
+ :noarchive,
163
+ ].each do |attributes|
164
+ calculate_robots_attributes(result, attributes)
165
+ end
166
+
167
+ result.transform_values { |v| v.join(', ') }
167
168
  end
168
169
 
169
170
  protected
@@ -171,10 +172,10 @@ module MetaTags
171
172
  # Converts input hash to HashWithIndifferentAccess and renames :open_graph to :og.
172
173
  #
173
174
  # @param [Hash] meta_tags list of meta tags.
174
- # @return [HashWithIndifferentAccess] normalized meta tags list.
175
+ # @return [ActiveSupport::HashWithIndifferentAccess] normalized meta tags list.
175
176
  #
176
177
  def normalize_open_graph(meta_tags)
177
- meta_tags = meta_tags.kind_of?(HashWithIndifferentAccess) ? meta_tags.dup : meta_tags.with_indifferent_access
178
+ meta_tags = meta_tags.with_indifferent_access
178
179
  meta_tags[:og] = meta_tags.delete(:open_graph) if meta_tags.key?(:open_graph)
179
180
  meta_tags
180
181
  end
@@ -190,43 +191,37 @@ module MetaTags
190
191
  meta_tags[name] == false ? '' : (meta_tags[name] || default)
191
192
  end
192
193
 
193
- # Extracts noindex attribute name and value without deleting it from meta tags list.
194
+ # Extracts robots attribute (noindex, nofollow, etc) name and value.
194
195
  #
195
196
  # @param [String, Symbol] name noindex attribute name.
196
197
  # @return [Array<String>] pair of noindex attribute name and value.
197
198
  #
198
- def extract_noindex_attribute(name)
199
+ def extract_robots_attribute(name)
199
200
  noindex = extract(name)
200
- noindex_name = noindex.kind_of?(String) ? noindex : 'robots'
201
+ noindex_name = noindex.kind_of?(String) || noindex.kind_of?(Array) ? noindex : 'robots'
201
202
  noindex_value = noindex ? name.to_s : nil
202
203
 
203
204
  [ noindex_name, noindex_value ]
204
205
  end
205
206
 
206
- # Append noarchive attribute if it present.
207
- #
208
- # @param [Hash<String, String>] noindex noindex attributes.
209
- # @return [Hash<String, String>] modified noindex attributes.
210
- #
211
- def append_noarchive_attribute(noindex)
212
- noarchive_name, noarchive_value = extract_noindex_attribute :noarchive
213
- if noarchive_value
214
- if noindex[noarchive_name].blank?
215
- noindex[noarchive_name] = noarchive_value
216
- else
217
- noindex[noarchive_name] += ", #{noarchive_value}"
207
+ def calculate_robots_attributes(result, attributes)
208
+ processed = Set.new
209
+ Array(attributes).each do |attribute|
210
+ names, value = extract_robots_attribute(attribute)
211
+ next unless value
212
+
213
+ Array(names).each do |name|
214
+ apply_robots_value(result, name, value, processed)
218
215
  end
219
216
  end
220
- noindex
221
217
  end
222
218
 
223
- # Convert array of arrays to hashes and concatenate values
224
- #
225
- # @param [Array<Array>] attributes list of noindex keys and values
226
- # @return [Hash<String, String>] hash of grouped noindex keys and values
227
- #
228
- def group_attributes_by_key(attributes)
229
- Hash[attributes.group_by(&:first).map { |k, v| [k, v.map(&:last).tap(&:compact!).join(', ')] }]
219
+ def apply_robots_value(result, name, value, processed)
220
+ name = name.to_s
221
+ return if processed.include?(name)
222
+
223
+ result[name] << value
224
+ processed << name
230
225
  end
231
226
  end
232
227
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MetaTags
4
+ class Railtie < Rails::Railtie
5
+ initializer 'meta_tags.setup_action_controller' do
6
+ ActiveSupport.on_load :action_controller do
7
+ ActionController::Base.include MetaTags::ControllerHelper
8
+ end
9
+ end
10
+
11
+ initializer 'meta_tags.setup_action_view' do
12
+ ActiveSupport.on_load :action_view do
13
+ ActionView::Base.include MetaTags::ViewHelper
14
+ end
15
+ end
16
+ end
17
+ end