page_structured_data 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7c3d0a5a1b15c977f7fbad8c98b6f65aa60873e4e320b05eeb1ef9ecb103cf2
4
- data.tar.gz: c9e1370c39548ca404bf508e02da8f80680c7ba9cc43450e541ba688b7fe00f9
3
+ metadata.gz: 5edbf7a0036c6b78d602900b3910cdeb8ee5a16920b47ac9ddaf2411a90f68c9
4
+ data.tar.gz: ae1930791919d1fecd18c525a5b01eb3bb782caf197604461bb17d882d508fd2
5
5
  SHA512:
6
- metadata.gz: 9a6762f1fac05f0c3fd7fa3d20f0aa1b815834becdff134a6850496c35789852f3b8b59f23541a537409c81e79f1934d16603edf83e558b4a41ab422de197064
7
- data.tar.gz: 286d821c75af661708819f6cdd36b47f7e49eb4da42e0743bfa0b80270b851674d693dbc9f1a573d36482077ef7e2ec786ebc6ff5df804d4b622564ecfec3a18
6
+ metadata.gz: 5f116fb5b5a52658001b8a39fd5820885a8aa71bd0403d901c0f316b0f0541470d9274d55e67f1ee16d53400dcb31aba40364b60e6a1fed3574d7871679c78b0
7
+ data.tar.gz: 23d1d8e077b2b3780b7826a892b7a1636814941e0fbd339f8421a905d5b1d3d4bb6191da0cc529db428c8534da1f3818818da1048d11b7d876a26d32b8b85f45
data/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@ All notable changes to this project are documented here.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 1.0.5 - 2026-05-06
8
+
9
+ - Add tests for HTML escaping in rendered meta tags.
10
+ - Add tests for script-breaking content in JSON-LD output.
11
+ - Add broader JSON-LD escaping coverage for breadcrumbs and article data.
12
+ - Extract shared article JSON-LD behavior for `BlogPosting` and `NewsArticle`.
13
+ - Add `to_h` schema hash APIs for breadcrumbs and article page types.
14
+ - Add tests for pages that render both breadcrumb and page type JSON-LD.
15
+ - Align the gemspec Ruby requirement with the Rails 7 baseline.
16
+ - Add GitHub Actions CI for tests, require verification, and gem build verification.
17
+ - Constrain the Rails dependency to Rails 7.x, matching the tested support baseline.
18
+ - Add `render_default_breadcrumb_json_ld` config to opt out of current-page-only breadcrumb JSON-LD.
19
+
20
+ ## 1.0.4 - 2026-05-06
21
+
22
+ - Replace the bundled Slim meta tags partial with ERB so applications are not required to use Slim.
23
+ - Remove the Slim runtime dependency.
24
+ - Add view-rendering tests for the meta tags partial.
25
+
7
26
  ## 1.0.3 - 2026-05-06
8
27
 
9
28
  - Improve RubyGems metadata, documentation links, and public README presentation.
data/README.md CHANGED
@@ -17,9 +17,10 @@ It helps Rails applications render:
17
17
 
18
18
  ## Requirements
19
19
 
20
- - Rails 7.0 or newer
21
- - Slim 4.1 or newer
22
- - A Ruby version supported by your Rails version
20
+ - Rails 7.x
21
+ - Ruby 2.7 or newer
22
+
23
+ Rails 7.0 requires Ruby 2.7 or newer, so this gem follows that same baseline. Rails 8 is not declared as supported yet; add CI coverage before widening the Rails dependency.
23
24
 
24
25
  ## Installation
25
26
 
@@ -44,12 +45,15 @@ Configure application-wide defaults in an initializer:
44
45
  Rails.application.config.after_initialize do
45
46
  PageStructuredData.config do |config|
46
47
  config.base_app_name = "AwesomestApp"
48
+ config.render_default_breadcrumb_json_ld = true
47
49
  end
48
50
  end
49
51
  ```
50
52
 
51
53
  `base_app_name` is appended to generated page titles.
52
54
 
55
+ `render_default_breadcrumb_json_ld` controls whether pages without an explicit breadcrumb render current-page-only breadcrumb JSON-LD. It defaults to `true` for backward compatibility. Set it to `false` if you only want breadcrumb JSON-LD when a `PageStructuredData::Breadcrumbs` object is passed to the page.
56
+
53
57
  For example:
54
58
 
55
59
  ```ruby
@@ -126,7 +130,7 @@ Pass the breadcrumbs into the page object:
126
130
 
127
131
  This renders `BreadcrumbList` JSON-LD similar to Google's breadcrumb structured data format.
128
132
 
129
- Current compatibility note: when no breadcrumb object is passed, `PageStructuredData::Page` still creates an empty breadcrumb trail for the current page. This is existing behavior and should be considered part of the current public API.
133
+ Current compatibility note: when no breadcrumb object is passed, `PageStructuredData::Page` renders current-page-only breadcrumb JSON-LD by default. To opt out, set `config.render_default_breadcrumb_json_ld = false`.
130
134
 
131
135
  ## Article Page Types
132
136
 
@@ -197,6 +201,7 @@ PageStructuredData::Breadcrumbs.new(
197
201
  Important methods:
198
202
 
199
203
  - `titles`: returns breadcrumb titles.
204
+ - `to_h(current_page_title:)`: returns a structured hash for `BreadcrumbList` JSON-LD.
200
205
  - `json_ld(current_page_title:)`: returns a `BreadcrumbList` JSON-LD script tag.
201
206
 
202
207
  ### Article Page Types
@@ -223,6 +228,11 @@ PageStructuredData::PageTypes::NewsArticle.new(
223
228
 
224
229
  `authors` should be an array of hashes with `:name` and `:url` keys.
225
230
 
231
+ Important methods:
232
+
233
+ - `to_h`: returns a structured hash for article JSON-LD.
234
+ - `json_ld`: returns an article JSON-LD script tag.
235
+
226
236
  ## Development
227
237
 
228
238
  Run the test suite:
@@ -13,15 +13,28 @@ module PageStructuredData
13
13
  hierarchy.pluck(:title)
14
14
  end
15
15
 
16
- def json_ld(current_page_title:) # rubocop:disable Metrics/MethodLength
17
- node = {
16
+ def to_h(current_page_title:) # rubocop:disable Metrics/MethodLength
17
+ {
18
18
  '@context': 'https://schema.org',
19
19
  '@type': 'BreadcrumbList',
20
- 'itemListElement': [],
21
- }.with_indifferent_access
20
+ 'itemListElement': item_list_elements(current_page_title: current_page_title),
21
+ }
22
+ end
23
+
24
+ def json_ld(current_page_title:)
25
+ %(
26
+ <script type="application/ld+json">
27
+ #{to_h(current_page_title: current_page_title).to_json}
28
+ </script>
29
+ )
30
+ end
22
31
 
32
+ private
33
+
34
+ def item_list_elements(current_page_title:)
23
35
  items = []
24
36
  count = 0
37
+
25
38
  @hierarchy.each do |page|
26
39
  items << {
27
40
  '@type': 'ListItem',
@@ -36,14 +49,6 @@ module PageStructuredData
36
49
  position: (count += 1),
37
50
  name: current_page_title,
38
51
  }
39
-
40
- node['itemListElement'] = items
41
-
42
- %(
43
- <script type="application/ld+json">
44
- #{node.to_json}
45
- </script>
46
- )
47
52
  end
48
53
  end
49
54
  end
@@ -13,8 +13,6 @@ module PageStructuredData
13
13
  @extra_title = extra_title
14
14
  @breadcrumb = breadcrumb
15
15
  @page_type = page_type
16
-
17
- @breadcrumb = Breadcrumbs.new if breadcrumb.blank?
18
16
  end
19
17
 
20
18
  def title_with_hierarchies
@@ -33,13 +31,20 @@ module PageStructuredData
33
31
 
34
32
  def json_lds
35
33
  output = []
36
- output << breadcrumb.json_ld(current_page_title: title) if breadcrumb.present?
34
+ output << breadcrumb_json_ld if (breadcrumb_json_ld = self.breadcrumb_json_ld).present?
37
35
  output << page_type.json_ld if page_type.present?
38
36
  output.join
39
37
  end
40
38
 
41
39
  private
42
40
 
41
+ def breadcrumb_json_ld
42
+ return breadcrumb.json_ld(current_page_title: title) if breadcrumb.present?
43
+ return unless PageStructuredData.render_default_breadcrumb_json_ld
44
+
45
+ Breadcrumbs.new.json_ld(current_page_title: title)
46
+ end
47
+
43
48
  def base_app_name
44
49
  PageStructuredData.base_app_name
45
50
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PageStructuredData
4
+ module PageTypes
5
+ # Shared structured data for schema.org article-like page types.
6
+ class Article
7
+ attr_reader :headline, :images, :published_at, :updated_at, :authors
8
+
9
+ def initialize(headline:, published_at:, updated_at:, images: [], authors: [])
10
+ @headline = headline
11
+ @images = images
12
+ @published_at = published_at
13
+ @updated_at = updated_at
14
+ @authors = authors
15
+ end
16
+
17
+ def to_h
18
+ {
19
+ '@context': 'https://schema.org',
20
+ '@type': schema_type,
21
+ headline: headline,
22
+ image: images,
23
+ datePublished: published_at,
24
+ dateModified: updated_at,
25
+ author: authors.map do |author|
26
+ {
27
+ '@type': 'Person',
28
+ name: author[:name],
29
+ url: author[:url],
30
+ }
31
+ end,
32
+ }
33
+ end
34
+
35
+ def json_ld
36
+ %(
37
+ <script type="application/ld+json">
38
+ #{to_h.to_json}
39
+ </script>
40
+ )
41
+ end
42
+
43
+ private
44
+
45
+ def schema_type
46
+ raise NotImplementedError, "#{self.class.name} must define #schema_type"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -3,43 +3,11 @@
3
3
  module PageStructuredData
4
4
  module PageTypes
5
5
  # Basic page metadata for any page
6
- class BlogPosting
7
- attr_reader :headline, :images, :published_at, :updated_at, :authors
6
+ class BlogPosting < Article
7
+ private
8
8
 
9
- def initialize(headline:, published_at:, updated_at:, images: [], authors: [])
10
- @headline = headline
11
- @images = images
12
- @published_at = published_at
13
- @updated_at = updated_at
14
- @authors = authors
15
- end
16
-
17
- def json_ld # rubocop:disable Metrics/MethodLength
18
- node = {
19
- '@context': 'https://schema.org',
20
- '@type': 'BlogPosting',
21
- }
22
-
23
- node[:headline] = headline
24
- node[:image] = images
25
- node[:datePublished] = published_at
26
- node[:dateModified] = updated_at
27
-
28
- author_hash = authors.map do |author|
29
- {
30
- '@type': 'Person',
31
- name: author[:name],
32
- url: author[:url],
33
- }
34
- end
35
-
36
- node[:author] = author_hash
37
-
38
- %(
39
- <script type="application/ld+json">
40
- #{node.to_json}
41
- </script>
42
- )
9
+ def schema_type
10
+ 'BlogPosting'
43
11
  end
44
12
  end
45
13
  end
@@ -3,43 +3,11 @@
3
3
  module PageStructuredData
4
4
  module PageTypes
5
5
  # Basic page metadata for any page
6
- class NewsArticle
7
- attr_reader :headline, :images, :published_at, :updated_at, :authors
6
+ class NewsArticle < Article
7
+ private
8
8
 
9
- def initialize(headline:, published_at:, updated_at:, images: [], authors: [])
10
- @headline = headline
11
- @images = images
12
- @published_at = published_at
13
- @updated_at = updated_at
14
- @authors = authors
15
- end
16
-
17
- def json_ld # rubocop:disable Metrics/MethodLength
18
- node = {
19
- '@context': 'https://schema.org',
20
- '@type': 'NewsArticle',
21
- }
22
-
23
- node[:headline] = headline
24
- node[:image] = images
25
- node[:datePublished] = published_at
26
- node[:dateModified] = updated_at
27
-
28
- author_hash = authors.map do |author|
29
- {
30
- '@type': 'Person',
31
- name: author[:name],
32
- url: author[:url],
33
- }
34
- end
35
-
36
- node[:author] = author_hash
37
-
38
- %(
39
- <script type="application/ld+json">
40
- #{node.to_json}
41
- </script>
42
- )
9
+ def schema_type
10
+ 'NewsArticle'
43
11
  end
44
12
  end
45
13
  end
@@ -0,0 +1,22 @@
1
+ <% default_image_url = local_assigns[:default_image_url] %>
2
+
3
+ <% title = page&.page_title %>
4
+ <% description = page&.description %>
5
+ <% image = page&.image || default_image_url || nil %>
6
+
7
+ <title><%= title %></title>
8
+
9
+ <meta name="title" content="<%= title %>">
10
+ <meta name="description" content="<%= description %>">
11
+ <meta name="image" content="<%= image %>">
12
+
13
+ <meta property="og:title" content="<%= title %>">
14
+ <meta property="og:description" content="<%= description %>">
15
+ <meta property="og:image" content="<%= image %>">
16
+
17
+ <meta property="twitter:card" content="summary_large_image">
18
+ <meta property="twitter:title" content="<%= title %>">
19
+ <meta property="twitter:description" content="<%= description %>">
20
+ <meta property="twitter:image" content="<%= image %>">
21
+
22
+ <%= page&.json_lds&.html_safe %>
@@ -1,3 +1,3 @@
1
1
  module PageStructuredData
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -4,9 +4,16 @@ require "page_structured_data/engine"
4
4
  module PageStructuredData
5
5
  class << self
6
6
  attr_accessor :base_app_name
7
+ attr_writer :render_default_breadcrumb_json_ld
7
8
 
8
9
  def config
9
10
  yield self
10
11
  end
12
+
13
+ def render_default_breadcrumb_json_ld
14
+ return true if @render_default_breadcrumb_json_ld.nil?
15
+
16
+ @render_default_breadcrumb_json_ld
17
+ end
11
18
  end
12
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: page_structured_data
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jey Geethan
@@ -14,30 +14,22 @@ dependencies:
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 7.0.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
19
+ version: '7.0'
24
20
  - - ">="
25
21
  - !ruby/object:Gem::Version
26
22
  version: 7.0.0
27
- - !ruby/object:Gem::Dependency
28
- name: slim
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 4.1.0
34
23
  type: :runtime
35
24
  prerelease: false
36
25
  version_requirements: !ruby/object:Gem::Requirement
37
26
  requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '7.0'
38
30
  - - ">="
39
31
  - !ruby/object:Gem::Version
40
- version: 4.1.0
32
+ version: 7.0.0
41
33
  description: PageStructuredData gives Rails applications a small page object and view
42
34
  partial for rendering page titles, basic meta tags, Open Graph tags, Twitter card
43
35
  tags, breadcrumb JSON-LD, and article JSON-LD.
@@ -61,10 +53,11 @@ files:
61
53
  - app/src/page_structured_data/anchors.rb
62
54
  - app/src/page_structured_data/breadcrumbs.rb
63
55
  - app/src/page_structured_data/page.rb
56
+ - app/src/page_structured_data/page_types/article.rb
64
57
  - app/src/page_structured_data/page_types/blog_posting.rb
65
58
  - app/src/page_structured_data/page_types/news_article.rb
66
59
  - app/views/layouts/page_structured_data/application.html.erb
67
- - app/views/page_structured_data/_meta_tags.html.slim
60
+ - app/views/page_structured_data/_meta_tags.html.erb
68
61
  - config/routes.rb
69
62
  - lib/page_structured_data.rb
70
63
  - lib/page_structured_data/engine.rb
@@ -89,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
89
82
  requirements:
90
83
  - - ">="
91
84
  - !ruby/object:Gem::Version
92
- version: 2.3.0
85
+ version: 2.7.0
93
86
  required_rubygems_version: !ruby/object:Gem::Requirement
94
87
  requirements:
95
88
  - - ">="
@@ -1,22 +0,0 @@
1
- - default_image_url = local_assigns[:default_image_url]
2
-
3
- - title = page&.page_title
4
- - description = page&.description
5
- - image = page&.image || default_image_url || nil
6
-
7
- title = title
8
-
9
- meta{name="title" content=title}
10
- meta{name="description" content=description}
11
- meta{name="image" content=image}
12
-
13
- meta{property="og:title" content=title}
14
- meta{property="og:description" content=description}
15
- meta{property="og:image" content=image}
16
-
17
- meta{property="twitter:card" content="summary_large_image"}
18
- meta{property="twitter:title" content=title}
19
- meta{property="twitter:description" content=description}
20
- meta{property="twitter:image" content=image}
21
-
22
- = page&.json_lds&.html_safe