page_structured_data 1.0.4 → 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: f54fe0fb4f902e3b2c795720a871f085b2ce05489f06f16239cb92549c4961aa
4
- data.tar.gz: a41c5888a2bdcad023a91546ffd40d7756c4909a86edf567579960929d9c7d6f
3
+ metadata.gz: 5edbf7a0036c6b78d602900b3910cdeb8ee5a16920b47ac9ddaf2411a90f68c9
4
+ data.tar.gz: ae1930791919d1fecd18c525a5b01eb3bb782caf197604461bb17d882d508fd2
5
5
  SHA512:
6
- metadata.gz: dbd5383be779c9c23302693f05685d606f40e82de5bc5bf75461a60d53ad0aa3db14f50446cbf6cbefe50c8c04925accdb4323f7734892093cbc2a1818083a97
7
- data.tar.gz: 8103d194f775fea6308c8ce8defa7dfd6c8fe341c61dcfbd92dc873577c0a18be26292280ddfa5579ff10838826d73b7331081358cc1567e2960e41b9dff135f
6
+ metadata.gz: 5f116fb5b5a52658001b8a39fd5820885a8aa71bd0403d901c0f316b0f0541470d9274d55e67f1ee16d53400dcb31aba40364b60e6a1fed3574d7871679c78b0
7
+ data.tar.gz: 23d1d8e077b2b3780b7826a892b7a1636814941e0fbd339f8421a905d5b1d3d4bb6191da0cc529db428c8534da1f3818818da1048d11b7d876a26d32b8b85f45
data/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ 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
+
7
20
  ## 1.0.4 - 2026-05-06
8
21
 
9
22
  - Replace the bundled Slim meta tags partial with ERB so applications are not required to use Slim.
data/README.md CHANGED
@@ -17,8 +17,10 @@ It helps Rails applications render:
17
17
 
18
18
  ## Requirements
19
19
 
20
- - Rails 7.0 or newer
21
- - 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.
22
24
 
23
25
  ## Installation
24
26
 
@@ -43,12 +45,15 @@ Configure application-wide defaults in an initializer:
43
45
  Rails.application.config.after_initialize do
44
46
  PageStructuredData.config do |config|
45
47
  config.base_app_name = "AwesomestApp"
48
+ config.render_default_breadcrumb_json_ld = true
46
49
  end
47
50
  end
48
51
  ```
49
52
 
50
53
  `base_app_name` is appended to generated page titles.
51
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
+
52
57
  For example:
53
58
 
54
59
  ```ruby
@@ -125,7 +130,7 @@ Pass the breadcrumbs into the page object:
125
130
 
126
131
  This renders `BreadcrumbList` JSON-LD similar to Google's breadcrumb structured data format.
127
132
 
128
- 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`.
129
134
 
130
135
  ## Article Page Types
131
136
 
@@ -196,6 +201,7 @@ PageStructuredData::Breadcrumbs.new(
196
201
  Important methods:
197
202
 
198
203
  - `titles`: returns breadcrumb titles.
204
+ - `to_h(current_page_title:)`: returns a structured hash for `BreadcrumbList` JSON-LD.
199
205
  - `json_ld(current_page_title:)`: returns a `BreadcrumbList` JSON-LD script tag.
200
206
 
201
207
  ### Article Page Types
@@ -222,6 +228,11 @@ PageStructuredData::PageTypes::NewsArticle.new(
222
228
 
223
229
  `authors` should be an array of hashes with `:name` and `:url` keys.
224
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
+
225
236
  ## Development
226
237
 
227
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
@@ -1,3 +1,3 @@
1
1
  module PageStructuredData
2
- VERSION = "1.0.4"
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.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jey Geethan
@@ -14,6 +14,9 @@ dependencies:
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
17
20
  - - ">="
18
21
  - !ruby/object:Gem::Version
19
22
  version: 7.0.0
@@ -21,6 +24,9 @@ dependencies:
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '7.0'
24
30
  - - ">="
25
31
  - !ruby/object:Gem::Version
26
32
  version: 7.0.0
@@ -47,6 +53,7 @@ files:
47
53
  - app/src/page_structured_data/anchors.rb
48
54
  - app/src/page_structured_data/breadcrumbs.rb
49
55
  - app/src/page_structured_data/page.rb
56
+ - app/src/page_structured_data/page_types/article.rb
50
57
  - app/src/page_structured_data/page_types/blog_posting.rb
51
58
  - app/src/page_structured_data/page_types/news_article.rb
52
59
  - app/views/layouts/page_structured_data/application.html.erb
@@ -75,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
75
82
  requirements:
76
83
  - - ">="
77
84
  - !ruby/object:Gem::Version
78
- version: 2.3.0
85
+ version: 2.7.0
79
86
  required_rubygems_version: !ruby/object:Gem::Requirement
80
87
  requirements:
81
88
  - - ">="