meta_tags-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +3 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +21 -0
  7. data/CHANGELOG.md +135 -0
  8. data/Gemfile +13 -0
  9. data/MIT-LICENSE +22 -0
  10. data/README.md +627 -0
  11. data/Rakefile +28 -0
  12. data/lib/meta_tags-rails.rb +37 -0
  13. data/lib/meta_tags-rails/configuration.rb +21 -0
  14. data/lib/meta_tags-rails/content_tag.rb +14 -0
  15. data/lib/meta_tags-rails/controller_helper.rb +44 -0
  16. data/lib/meta_tags-rails/meta_tags_collection.rb +176 -0
  17. data/lib/meta_tags-rails/renderer.rb +253 -0
  18. data/lib/meta_tags-rails/tag.rb +25 -0
  19. data/lib/meta_tags-rails/text_normalizer.rb +148 -0
  20. data/lib/meta_tags-rails/version.rb +4 -0
  21. data/lib/meta_tags-rails/view_helper.rb +205 -0
  22. data/meta-tags.gemspec +30 -0
  23. data/spec/configuration_spec.rb +14 -0
  24. data/spec/controller_helper_spec.rb +42 -0
  25. data/spec/spec_helper.rb +84 -0
  26. data/spec/text_normalizer/normalize_title_spec.rb +43 -0
  27. data/spec/text_normalizer/truncate_array_spec.rb +60 -0
  28. data/spec/view_helper/charset_spec.rb +16 -0
  29. data/spec/view_helper/custom_spec.rb +67 -0
  30. data/spec/view_helper/description_spec.rb +61 -0
  31. data/spec/view_helper/icon_spec.rb +42 -0
  32. data/spec/view_helper/keywords_spec.rb +58 -0
  33. data/spec/view_helper/links_spec.rb +125 -0
  34. data/spec/view_helper/module_spec.rb +41 -0
  35. data/spec/view_helper/noindex_spec.rb +107 -0
  36. data/spec/view_helper/open_graph_spec.rb +86 -0
  37. data/spec/view_helper/open_search_spec.rb +33 -0
  38. data/spec/view_helper/refresh_spec.rb +32 -0
  39. data/spec/view_helper/title_spec.rb +155 -0
  40. data/spec/view_helper/twitter_spec.rb +31 -0
  41. data/spec/view_helper_spec.rb +57 -0
  42. metadata +172 -0
@@ -0,0 +1,25 @@
1
+ module MetaTags
2
+ # Represents an HTML meta tag with no content (<tag />).
3
+ class Tag
4
+ attr_reader :name, :attributes
5
+
6
+ # Initializes a new instance of Tag class.
7
+ #
8
+ # @param [String, Symbol] name HTML tag name
9
+ # @param [Hash] attributes list of HTML tag attributes
10
+ #
11
+ def initialize(name, attributes = {})
12
+ @name = name
13
+ @attributes = attributes
14
+ end
15
+
16
+ # Render tag into a Rails view.
17
+ #
18
+ # @param [ActionView::Base] view instance of a Rails view.
19
+ # @return [String] HTML string for the tag.
20
+ #
21
+ def render(view)
22
+ view.tag(name, attributes)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,148 @@
1
+ module MetaTags
2
+ # Module contains helpers that normalize text meta tag values.
3
+ module TextNormalizer
4
+ # Normalize title value.
5
+ #
6
+ # @param [String] site_title site title.
7
+ # @param [String, Array<String>] title title string.
8
+ # @param [String] separator a string to join title parts with.
9
+ # @param [true,false] reverse whether title should be reversed.
10
+ # @return [Array<String>] array of title parts with tags removed.
11
+ #
12
+ def self.normalize_title(site_title, title, separator, reverse = false)
13
+ title = Array(title).flatten.map(&method(:strip_tags))
14
+ title.reject!(&:blank?)
15
+ site_title = strip_tags(site_title)
16
+ separator = strip_tags(separator)
17
+
18
+ if MetaTags.config.title_limit
19
+ limit = MetaTags.config.title_limit - separator.length
20
+ if limit > site_title.length
21
+ title = truncate_array(title, limit - site_title.length, separator)
22
+ else
23
+ site_title = truncate(site_title, limit)
24
+ # Site title is too long, we have to skip page title
25
+ title = []
26
+ end
27
+ end
28
+
29
+ title.unshift(site_title) if site_title.present?
30
+ title.reverse! if reverse
31
+ safe_join(title, separator)
32
+ end
33
+
34
+ # Normalize description value.
35
+ #
36
+ # @param [String] description description string.
37
+ # @return [String] text with tags removed, squashed spaces, truncated
38
+ # to 200 characters.
39
+ #
40
+ def self.normalize_description(description)
41
+ return '' if description.blank?
42
+ description = cleanup_string(description)
43
+ truncate(description, MetaTags.config.description_limit)
44
+ end
45
+
46
+ # Normalize keywords value.
47
+ #
48
+ # @param [String, Array<String>] keywords list of keywords as a string or Array.
49
+ # @return [String] list of keywords joined with comma, with tags removed.
50
+ #
51
+ def self.normalize_keywords(keywords)
52
+ return '' if keywords.blank?
53
+ keywords = cleanup_strings(keywords).each(&:downcase!)
54
+ separator = strip_tags MetaTags.config.keywords_separator
55
+
56
+ keywords = truncate_array(keywords, MetaTags.config.keywords_limit, separator)
57
+ safe_join(keywords, separator)
58
+ end
59
+
60
+ # Easy way to get access to Rails helpers.
61
+ #
62
+ # @return [ActionView::Base] proxy object to access Rails helpers.
63
+ #
64
+ def self.helpers
65
+ ActionController::Base.helpers
66
+ end
67
+
68
+ # Strips all HTML tags from the +html+, including comments.
69
+ #
70
+ # @param [String] string HTML string.
71
+ # @return [String] string with no HTML tags.
72
+ #
73
+ def self.strip_tags(string)
74
+ ERB::Util.html_escape helpers.strip_tags(string)
75
+ end
76
+
77
+ # This method returns a html safe string similar to what <tt>Array#join</tt>
78
+ # would return. All items in the array, including the supplied separator, are
79
+ # html escaped unless they are html safe, and the returned string is marked
80
+ # as html safe.
81
+ #
82
+ # @param [Array<String>] array list of strings to join.
83
+ # @param [String] sep separator to join strings with.
84
+ # @return [String] input strings joined together using a given separator.
85
+ #
86
+ def self.safe_join(array, sep = $,)
87
+ helpers.safe_join(array, sep)
88
+ end
89
+
90
+ # Removes HTML tags and squashes down all the spaces.
91
+ #
92
+ # @param [String] string input string.
93
+ # @return [String] input string with no HTML tags and consequent white
94
+ # space characters squashed into a single space.
95
+ #
96
+ def self.cleanup_string(string)
97
+ strip_tags(string).gsub(/\s+/, ' ').strip.html_safe
98
+ end
99
+
100
+ # Cleans multiple strings up.
101
+ #
102
+ # @param [Array<String>] strings input strings.
103
+ # @return [Array<String>] clean strings.
104
+ # @see cleanup_string
105
+ #
106
+ def self.cleanup_strings(strings)
107
+ Array(strings).flatten.map(&method(:cleanup_string))
108
+ end
109
+
110
+ # Truncates a string to a specific limit.
111
+ #
112
+ # @param [String] string input strings.
113
+ # @param [Integer,nil] limit characters number to truncate to.
114
+ # @param [String] natural_separator natural separator to truncate at.
115
+ # @return [String] truncated string.
116
+ #
117
+ def self.truncate(string, limit = nil, natural_separator = ' ')
118
+ string = helpers.truncate(string, length: limit, separator: natural_separator, omission: '') if limit
119
+ string
120
+ end
121
+
122
+ # Truncates a string to a specific limit.
123
+ #
124
+ # @param [Array<String>] string_array input strings.
125
+ # @param [Integer,nil] limit characters number to truncate to.
126
+ # @param [String] separator separator that will be used to join array later.
127
+ # @param [String] natural_separator natural separator to truncate at.
128
+ # @return [String] truncated string.
129
+ #
130
+ def self.truncate_array(string_array, limit = nil, separator = '', natural_separator = ' ')
131
+ return string_array if limit.nil? || limit == 0
132
+ length = 0
133
+ result = []
134
+ string_array.each do |string|
135
+ limit_left = limit - length - (result.any? ? separator.length : 0)
136
+ if string.length > limit_left
137
+ result << truncate(string, limit_left, natural_separator)
138
+ break
139
+ end
140
+ length += (result.any? ? separator.length : 0) + string.length
141
+ result << string
142
+ # No more strings will fit
143
+ break if length + separator.length >= limit
144
+ end
145
+ result
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,4 @@
1
+ module MetaTags
2
+ # Gem version.
3
+ VERSION = '1.0.0'
4
+ end
@@ -0,0 +1,205 @@
1
+ module MetaTags
2
+ # Contains methods to use in views and helpers.
3
+ #
4
+ module ViewHelper
5
+ # Get meta tags for the page.
6
+ def meta_tags
7
+ @meta_tags ||= MetaTagsCollection.new
8
+ end
9
+
10
+ # Set meta tags for the page.
11
+ #
12
+ # Method could be used several times, and all options passed will
13
+ # be merged. If you will set the same property several times, last one
14
+ # will take precedence.
15
+ #
16
+ # Usually you will not call this method directly. Use {#title}, {#keywords},
17
+ # {#description} for your daily tasks.
18
+ #
19
+ # @param [Hash] meta_tags list of meta tags. See {#display_meta_tags}
20
+ # for allowed options.
21
+ #
22
+ # @example
23
+ # set_meta_tags title: 'Login Page', description: 'Here you can login'
24
+ # set_meta_tags keywords: 'authorization, login'
25
+ #
26
+ # @see #display_meta_tags
27
+ #
28
+ def set_meta_tags(meta_tags = {})
29
+ self.meta_tags.update(meta_tags)
30
+ end
31
+
32
+ # Set the page title and return it back.
33
+ #
34
+ # This method is best suited for use in helpers. It sets the page title
35
+ # and returns it (or +headline+ if specified).
36
+ #
37
+ # @param [nil, String, Array] title page title. When passed as an
38
+ # +Array+, parts will be joined using configured separator value
39
+ # (see {#display_meta_tags}). When nil, current title will be returned.
40
+ # @param [String] headline the value to return from method. Useful
41
+ # for using this method in views to set both page title
42
+ # and the content of heading tag.
43
+ # @return [String] returns +title+ value or +headline+ if passed.
44
+ #
45
+ # @example Set HTML title to "Please login", return "Please login"
46
+ # title 'Login Page'
47
+ # @example Set HTML title to "Login Page", return "Please login"
48
+ # title 'Login Page', 'Please login'
49
+ # @example Set title as array of strings
50
+ # title title: ['part1', 'part2'] # => "part1 | part2"
51
+ # @example Get current title
52
+ # title
53
+ #
54
+ # @see #display_meta_tags
55
+ #
56
+ def title(title = nil, headline = '')
57
+ set_meta_tags(title: title) unless title.nil?
58
+ headline.blank? ? meta_tags[:title] : headline
59
+ end
60
+
61
+ # Set the page keywords.
62
+ #
63
+ # @param [String, Array] keywords meta keywords to render in HEAD
64
+ # section of the HTML document.
65
+ # @return [String, Array] passed value.
66
+ #
67
+ # @example
68
+ # keywords 'keyword1, keyword2'
69
+ # keywords %w(keyword1 keyword2)
70
+ #
71
+ # @see #display_meta_tags
72
+ #
73
+ def keywords(keywords)
74
+ set_meta_tags(keywords: keywords)
75
+ keywords
76
+ end
77
+
78
+ # Set the page description.
79
+ #
80
+ # @param [String] description page description to be set in HEAD section of
81
+ # the HTML document. Please note, any HTML tags will be stripped
82
+ # from output string, and string will be truncated to 200
83
+ # characters.
84
+ # @return [String] passed value.
85
+ #
86
+ # @example
87
+ # description 'This is login page'
88
+ #
89
+ # @see #display_meta_tags
90
+ #
91
+ def description(description)
92
+ set_meta_tags(description: description)
93
+ description
94
+ end
95
+
96
+ # Set the noindex meta tag
97
+ #
98
+ # @param [Boolean, String] noindex a noindex value.
99
+ # @return [Boolean, String] passed value.
100
+ #
101
+ # @example
102
+ # noindex true
103
+ # noindex 'googlebot'
104
+ #
105
+ # @see #display_meta_tags
106
+ #
107
+ def noindex(noindex = true)
108
+ set_meta_tags(noindex: noindex)
109
+ noindex
110
+ end
111
+
112
+ # Set the nofollow meta tag
113
+ #
114
+ # @param [Boolean, String] nofollow a nofollow value.
115
+ # @return [Boolean, String] passed value.
116
+ #
117
+ # @example
118
+ # nofollow true
119
+ # nofollow 'googlebot'
120
+ #
121
+ # @see #display_meta_tags
122
+ #
123
+ def nofollow(nofollow = true)
124
+ set_meta_tags(nofollow: nofollow)
125
+ nofollow
126
+ end
127
+
128
+ # Set the refresh meta tag
129
+ #
130
+ # @param [Integer, String] refresh a refresh value.
131
+ # @return [Integer, String] passed value.
132
+ #
133
+ # @example
134
+ # refresh 5
135
+ # refresh "5;url=http://www.example.com/"
136
+ #
137
+ # @see #display_meta_tags
138
+ #
139
+ def refresh(refresh)
140
+ set_meta_tags(refresh: refresh)
141
+ refresh
142
+ end
143
+
144
+ # Set default meta tag values and display meta tags. This method
145
+ # should be used in layout file.
146
+ #
147
+ # @param [Hash] defaults default meta tag values.
148
+ # @option default [String] :site (nil) site title;
149
+ # @option default [String] :title ("") page title;
150
+ # @option default [String] :description (nil) page description;
151
+ # @option default [String] :keywords (nil) page keywords;
152
+ # @option default [String, Boolean] :prefix (" ") text between site name and separator; when +false+, no prefix will be rendered;
153
+ # @option default [String] :separator ("|") text used to separate website name from page title;
154
+ # @option default [String, Boolean] :suffix (" ") text between separator and page title; when +false+, no suffix will be rendered;
155
+ # @option default [Boolean] :lowercase (false) when true, the page title will be lowercase;
156
+ # @option default [Boolean] :reverse (false) when true, the page and site names will be reversed;
157
+ # @option default [Boolean, String] :noindex (false) add noindex meta tag; when true, 'robots' will be used, otherwise the string will be used;
158
+ # @option default [Boolean, String] :nofollow (false) add nofollow meta tag; when true, 'robots' will be used, otherwise the string will be used;
159
+ # @option default [String] :canonical (nil) add canonical link tag.
160
+ # @option default [Hash] :alternate ({}) add alternate link tag.
161
+ # @option default [String] :prev (nil) add prev link tag;
162
+ # @option default [String] :next (nil) add next link tag.
163
+ # @option default [String] :author (nil) add author link tag;
164
+ # @option default [String] :publisher (nil) add publisher link tag.
165
+ # @option default [String, Integer] :refresh (nil) meta refresh tag;
166
+ # @option default [Hash] :open_graph ({}) add Open Graph meta tags.
167
+ # @option default [Hash] :open_search ({}) add Open Search link tag.
168
+ # @return [String] HTML meta tags to render in HEAD section of the
169
+ # HTML document.
170
+ #
171
+ # @example
172
+ # <head>
173
+ # <%= display_meta_tags site: 'My website' %>
174
+ # </head>
175
+ #
176
+ def display_meta_tags(defaults = {})
177
+ self.meta_tags.with_defaults(defaults) { Renderer.new(meta_tags).render(self) }
178
+ end
179
+
180
+ # Returns full page title as a string without surrounding <title> tag.
181
+ #
182
+ # The only case when you may need this helper is when you use pjax. This means
183
+ # that your layout file (with display_meta_tags helper) will not be rendered,
184
+ # so you have to pass default arguments like site title in here. You probably
185
+ # want to define helper with default options to minimize code duplication.
186
+ #
187
+ # @param [Hash] defaults list of meta tags.
188
+ # @option default [String] :site (nil) site title;
189
+ # @option default [String] :title ("") page title;
190
+ # @option default [String, Boolean] :prefix (" ") text between site name and separator; when +false+, no prefix will be rendered;
191
+ # @option default [String] :separator ("|") text used to separate website name from page title;
192
+ # @option default [String, Boolean] :suffix (" ") text between separator and page title; when +false+, no suffix will be rendered;
193
+ # @option default [Boolean] :lowercase (false) when true, the page name will be lowercase;
194
+ # @option default [Boolean] :reverse (false) when true, the page and site names will be reversed;
195
+ #
196
+ # @example
197
+ # <div data-page-container="true" title="<%= display_title title: 'My Page', site: 'PJAX Site' %>">
198
+ #
199
+ def display_title(defaults = {})
200
+ @meta_tags.full_title(defaults)
201
+ end
202
+
203
+ # safe_helper :display_meta_tags if defined?(:safe_helper)
204
+ end
205
+ end
data/meta-tags.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'meta_tags-rails/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'meta_tags-rails'
7
+ s.version = MetaTags::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.license = "MIT"
10
+ s.authors = ['Dmytro Shteflyuk', 'Yves Siegrist']
11
+ s.email = ['Elektron1c97@gmail.com']
12
+ s.homepage = 'http://github.com/Elektron1c97/meta_tags-rails'
13
+ s.summary = %q{Collection of SEO helpers for Ruby on Rails.}
14
+ s.description = %q{Search Engine Optimization (SEO) plugin for Ruby on Rails applications.}
15
+
16
+ s.add_dependency 'actionpack', '>= 3.0.0'
17
+
18
+ s.add_development_dependency 'rake'
19
+ s.add_development_dependency 'rspec', '~> 3.3.0'
20
+ s.add_development_dependency 'rspec-html-matchers'
21
+ s.add_development_dependency 'yard'
22
+ s.add_development_dependency 'bluecloth'
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.extra_rdoc_files = ['README.md', 'CHANGELOG.md']
28
+ s.rdoc_options = ['--charset=UTF-8']
29
+ s.require_paths = ['lib']
30
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetaTags::Configuration do
4
+ it 'should be returned by MetaTags.config' do
5
+ expect(MetaTags.config).to be_instance_of(MetaTags::Configuration)
6
+ end
7
+
8
+ it 'should be yielded by MetaTags.configure' do
9
+ MetaTags.configure do |c|
10
+ expect(c).to be_instance_of(MetaTags::Configuration)
11
+ expect(c).to be(MetaTags.config)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ class MetaTagsController < ActionController::Base
4
+ attr_reader :rendered
5
+
6
+ def render_without_meta_tags
7
+ @rendered = true
8
+ end
9
+
10
+ def index
11
+ @page_title = 'title'
12
+ @page_keywords = 'key1, key2, key3'
13
+ @page_description = 'description'
14
+ render
15
+ end
16
+
17
+ public :set_meta_tags, :meta_tags
18
+ end
19
+
20
+ describe MetaTags::ControllerHelper do
21
+ subject { MetaTagsController.new }
22
+
23
+ context 'module' do
24
+ it 'should be mixed into ActionController::Base' do
25
+ expect(ActionController::Base.included_modules).to include(MetaTags::ControllerHelper)
26
+ end
27
+
28
+ it 'should respond to "set_meta_tags" helper' do
29
+ expect(subject).to respond_to(:set_meta_tags)
30
+ end
31
+ end
32
+
33
+ describe '.render' do
34
+ it 'should set meta tags from instance variables' do
35
+ subject.index
36
+ expect(subject.rendered).to be_truthy
37
+ expect(subject.meta_tags.meta_tags).to eq('title' => 'title', 'keywords' => 'key1, key2, key3', 'description' => 'description')
38
+ end
39
+ end
40
+
41
+ it_behaves_like '.set_meta_tags'
42
+ end