ruby-structured-data 0.1.1

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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +36 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +252 -0
  5. data/data/schema_org_v30.json +20081 -0
  6. data/lib/generators/structured_data/install/install_generator.rb +17 -0
  7. data/lib/generators/structured_data/install/templates/structured_data.rb +15 -0
  8. data/lib/ruby-structured-data.rb +3 -0
  9. data/lib/ruby_structured_data.rb +4 -0
  10. data/lib/structured_data/compiler/parser.rb +120 -0
  11. data/lib/structured_data/compiler/terms.rb +24 -0
  12. data/lib/structured_data/compiler/uri_helper.rb +66 -0
  13. data/lib/structured_data/compiler/vocabulary.rb +115 -0
  14. data/lib/structured_data/compiler.rb +68 -0
  15. data/lib/structured_data/configuration.rb +19 -0
  16. data/lib/structured_data/document.rb +99 -0
  17. data/lib/structured_data/enum.rb +64 -0
  18. data/lib/structured_data/error.rb +19 -0
  19. data/lib/structured_data/list.rb +46 -0
  20. data/lib/structured_data/node.rb +133 -0
  21. data/lib/structured_data/rails/helper.rb +38 -0
  22. data/lib/structured_data/rails/railtie.rb +22 -0
  23. data/lib/structured_data/rails/registry.rb +124 -0
  24. data/lib/structured_data/rails/renderer.rb +20 -0
  25. data/lib/structured_data/rails.rb +6 -0
  26. data/lib/structured_data/reference.rb +46 -0
  27. data/lib/structured_data/serializer.rb +44 -0
  28. data/lib/structured_data/validator/context.rb +30 -0
  29. data/lib/structured_data/validator/diagnostic.rb +45 -0
  30. data/lib/structured_data/validator/node_validator.rb +131 -0
  31. data/lib/structured_data/validator/range_checker.rb +83 -0
  32. data/lib/structured_data/validator/result.rb +37 -0
  33. data/lib/structured_data/validator.rb +76 -0
  34. data/lib/structured_data/values.rb +148 -0
  35. data/lib/structured_data/version.rb +5 -0
  36. data/lib/structured_data/vocabulary/data_loader.rb +25 -0
  37. data/lib/structured_data/vocabulary/hierarchy.rb +32 -0
  38. data/lib/structured_data/vocabulary/registry.rb +90 -0
  39. data/lib/structured_data/vocabulary.rb +136 -0
  40. data/lib/structured_data.rb +84 -0
  41. metadata +252 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9ca854a07f1a996cea65258754927d5e5509cb5bb2f7c618ebb8f0819e30af67
4
+ data.tar.gz: 798d276145c4da10bfe5df55c3d153a4a9a31d410cf7ea7030aa4d0688df9222
5
+ SHA512:
6
+ metadata.gz: ca9a62dcf4ab94efd21949cb88e24c300383f614a079ae0018b899898adf965540b8d7f4e1c32c9bb4405310d549387934c9f76c473f0b821d9b855f4e14246e
7
+ data.tar.gz: a73e49d892971809a478bc8b65b0d690040569870818ce950ea976faa029bfbd7699afa2ac72cc43aa11aa721f5f3953367cfcd84fd1b7cd2669eb286ff5a983
data/CHANGELOG.md ADDED
@@ -0,0 +1,36 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.1] - 2026-09-14
11
+
12
+ ### Changed
13
+
14
+ - Rails integration loads automatically from the default `gem "ruby-structured-data"` require. The Railtie registers when Rails is present; framework-only usage requires no extra setup.
15
+
16
+ ## [0.1.0] - 2026-09-11
17
+
18
+ ### Added
19
+
20
+ - Framework-neutral core Schema.org JSON-LD authoring DSL (`StructuredData.node`, `StructuredData.document`, `StructuredData.ref`, `StructuredData.list`, `StructuredData.enum`, `StructuredData.url`, `StructuredData.text`).
21
+ - Embedded Schema.org vocabulary definition supporting types, properties, multiple inheritance, domain/range metadata, and enumerations.
22
+ - Offline metadata-driven validator supporting `:schema_org`, `:strict`, and `:none` validation modes with DidYouMean suggestions and superseded term detection.
23
+ - Fast, HTML-safe JSON-LD serialization neutralizing `</script>` tags and unicode line/paragraph separators.
24
+ - Vocabulary compiler CLI / Rake task (`bundle exec rake schemaorg:update`) to build vocabulary data from upstream Schema.org JSON-LD definitions.
25
+ - Optional Rails integration:
26
+ - `StructuredData::Rails::Railtie` configuring Railtie options and view helper loading.
27
+ - `StructuredData::Rails::Registry` for mapping controller/action endpoints to structured data builders.
28
+ - `StructuredData::Rails::Renderer` for generating `ActiveSupport::SafeBuffer` JSON-LD `<script>` tags.
29
+ - `StructuredData::Rails::Helper#structured_data_tag` for view rendering.
30
+ - `rails generate structured_data:install` generator creating `config/initializers/structured_data.rb`.
31
+ - GitHub Actions CI workflow with Ruby 3.4 matrix, RuboCop, Reek, Bundler Audit, and 100% line/branch RSpec coverage.
32
+ - GitHub Actions Release workflow publishing gems to RubyGems.
33
+
34
+ [Unreleased]: https://github.com/develoz-com/ruby-structured-data/compare/v0.1.1...HEAD
35
+ [0.1.1]: https://github.com/develoz-com/ruby-structured-data/compare/v0.1.0...v0.1.1
36
+ [0.1.0]: https://github.com/develoz-com/ruby-structured-data/releases/tag/v0.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mauricio Zaffari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,252 @@
1
+ # Ruby Structured Data (`ruby-structured-data`)
2
+
3
+ Framework-neutral Ruby gem for authoring, validating, and rendering [Schema.org](https://schema.org) JSON-LD structured data with metadata-driven validation and seamless Rails integration.
4
+
5
+ ## Features
6
+
7
+ - **Fluent DSL**: Expressive API for authoring nodes, documents, graphs, enums, lists, and references.
8
+ - **Embedded Schema.org Vocabulary**: Built-in vocabulary supporting Schema.org types, properties, inheritance, and enumerations.
9
+ - **Diagnostics & Validation**: Fast, metadata-driven validation with three modes (`:schema_org`, `:strict`, `:none`) featuring DidYouMean suggestions and superseded term checks.
10
+ - **XSS-Safe Serialization**: HTML-safe JSON-LD serialization neutralizing `</script>` breakouts and unicode line/paragraph separators.
11
+ - **Rails Integration**: View helper (`structured_data_tag`), page builder registry (`StructuredData::Rails::Registry`), Railtie configuration, and generator (`rails generate structured_data:install`).
12
+ - **100% Test Coverage**: Full line and branch test coverage enforced via SimpleCov.
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ Add the gem to your application's `Gemfile`:
19
+
20
+ ```ruby
21
+ gem "ruby-structured-data"
22
+ ```
23
+
24
+ Then execute:
25
+
26
+ ```bash
27
+ bundle install
28
+ ```
29
+
30
+ Or install it directly:
31
+
32
+ ```bash
33
+ gem install ruby-structured-data
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Quickstart
39
+
40
+ ### Authoring Nodes
41
+
42
+ Create Schema.org entities using `StructuredData.node`:
43
+
44
+ ```ruby
45
+ require "ruby-structured-data"
46
+
47
+ person = StructuredData.node("Person",
48
+ id: "https://example.com/people/alice",
49
+ name: "Alice Smith",
50
+ job_title: "Software Engineer",
51
+ url: "https://example.com/alice"
52
+ )
53
+
54
+ # You can also use a block for structured composition:
55
+ organization = StructuredData.node("Organization", id: "https://example.com/#org") do |org|
56
+ org.set(:name, "Acme Corp")
57
+ org.set(:url, "https://example.com")
58
+ org.set(:founder, person)
59
+ end
60
+ ```
61
+
62
+ ### Documents & Graphs
63
+
64
+ Wrap nodes in a `StructuredData.document`. By default, a document with a single node renders as a single entity with `@context`. Multiple nodes or documents explicitly initialized with `graph: true` render within an `@graph` array:
65
+
66
+ ```ruby
67
+ # Single entity document
68
+ doc = StructuredData.document(organization)
69
+ puts StructuredData.dump(doc, pretty: true)
70
+ # => {
71
+ # "@context": "https://schema.org",
72
+ # "@type": "Organization",
73
+ # "@id": "https://example.com/#org",
74
+ # "name": "Acme Corp",
75
+ # "url": "https://example.com",
76
+ # "founder": {
77
+ # "@type": "Person",
78
+ # ...
79
+ # }
80
+ # }
81
+
82
+ # Explicit @graph document
83
+ graph_doc = StructuredData.document(organization, person, graph: true)
84
+ puts StructuredData.dump(graph_doc, pretty: true)
85
+ # => {
86
+ # "@context": "https://schema.org",
87
+ # "@graph": [
88
+ # { "@type": "Organization", ... },
89
+ # { "@type": "Person", ... }
90
+ # ]
91
+ # }
92
+ ```
93
+
94
+ ### Value Helpers
95
+
96
+ - `StructuredData.ref("https://example.com/people/alice")`: Creates an entity reference (`{ "@id": "..." }`).
97
+ - `StructuredData.list("Item 1", "Item 2")`: Wraps ordered items in an `@list`.
98
+ - `StructuredData.enum("InStock", "ItemAvailability")`: Generates a Schema.org enumeration URI.
99
+ - `StructuredData.url("https://example.com")`: Validated URL wrapper.
100
+ - `StructuredData.text("Sample text")`: Text value wrapper.
101
+
102
+ ---
103
+
104
+ ## Schema.org Validation
105
+
106
+ `StructuredData.validate` validates nodes or documents against Schema.org metadata without making network requests.
107
+
108
+ ### Modes
109
+
110
+ - `:schema_org` (default): Checks unknown types/properties, warns on superseded terms, and flags incompatible ranges.
111
+ - `:strict`: Treats warnings as errors (such as domain mismatches or superseded terms).
112
+ - `:none`: Bypasses schema validation.
113
+
114
+ ```ruby
115
+ # Validating a node
116
+ result = StructuredData.validate(person, mode: :schema_org)
117
+
118
+ if result.valid?
119
+ puts "Valid Schema.org data!"
120
+ else
121
+ result.errors.each { |err| puts "[ERROR] #{err.message}" }
122
+ result.warnings.each { |warn| puts "[WARNING] #{warn.message}" }
123
+ end
124
+
125
+ # Or raise a ValidationError when invalid:
126
+ StructuredData.validate!(person)
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Rails Integration
132
+
133
+ ### 1. Install Generator
134
+
135
+ Run the generator to install the initializer:
136
+
137
+ ```bash
138
+ bin/rails generate structured_data:install
139
+ ```
140
+
141
+ This creates `config/initializers/structured_data.rb`:
142
+
143
+ ```ruby
144
+ # frozen_string_literal: true
145
+
146
+ StructuredData.configure do |config|
147
+ # Validation mode: :strict, :schema_org (default), or :none
148
+ config.validation_mode = :schema_org
149
+
150
+ # Output pretty formatted JSON-LD
151
+ config.pretty = Rails.env.development?
152
+ end
153
+
154
+ # Register controller/action structured data builders:
155
+ # StructuredData::Rails::Registry.register("landing#index", LandingPageBuilder)
156
+ # StructuredData::Rails::Registry.register("products#show") do |context|
157
+ # StructuredData.node("Product", name: context.product.name)
158
+ # end
159
+ ```
160
+
161
+ ### 2. Registry & Builders
162
+
163
+ Register structured data builders for specific controller actions:
164
+
165
+ ```ruby
166
+ # Using a block
167
+ StructuredData::Rails::Registry.register("products#show") do |view_context|
168
+ product = view_context.assigns["product"]
169
+ StructuredData.node("Product",
170
+ name: product.name,
171
+ description: product.description,
172
+ sku: product.sku
173
+ )
174
+ end
175
+
176
+ # Or using a dedicated builder class
177
+ class LandingPageBuilder
178
+ def self.build(view_context)
179
+ StructuredData.document(
180
+ StructuredData.node("WebSite",
181
+ name: "Acme",
182
+ url: "https://example.com"
183
+ )
184
+ )
185
+ end
186
+ end
187
+
188
+ StructuredData::Rails::Registry.register("landing#index", LandingPageBuilder)
189
+ ```
190
+
191
+ ### 3. View Helper (`structured_data_tag`)
192
+
193
+ Render the JSON-LD script tag in your layout or view template (e.g. `app/views/layouts/application.html.erb`):
194
+
195
+ ```erb
196
+ <head>
197
+ <%= structured_data_tag %>
198
+ </head>
199
+ ```
200
+
201
+ When called without arguments, `structured_data_tag` automatically looks up the registered builder matching `controller_path#action_name`.
202
+
203
+ You can also pass an explicit node or document:
204
+
205
+ ```erb
206
+ <%= structured_data_tag(@article_schema) %>
207
+ ```
208
+
209
+ Output is marked `html_safe` and wrapped in:
210
+
211
+ ```html
212
+ <script type="application/ld+json">
213
+ {"@context":"https://schema.org","@type":"Product","name":"Widget"}
214
+ </script>
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Updating Vocabulary
220
+
221
+ The embedded vocabulary definitions can be re-compiled from upstream Schema.org releases using the compiler:
222
+
223
+ ```bash
224
+ bundle exec rake schemaorg:update
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Development
230
+
231
+ Clone the repository and install dependencies:
232
+
233
+ ```bash
234
+ git clone https://github.com/develoz-com/ruby-structured-data.git
235
+ cd ruby-structured-data
236
+ bundle install
237
+ ```
238
+
239
+ Run test suite and quality checks:
240
+
241
+ ```bash
242
+ bundle exec rspec # Run test suite
243
+ bundle exec rubocop # Run RuboCop linter
244
+ bundle exec reek # Run Reek code smell detector
245
+ bin/ci # Run complete CI pipeline (RuboCop, Reek, RSpec, Bundler Audit)
246
+ ```
247
+
248
+ ---
249
+
250
+ ## License
251
+
252
+ This project is available as open source under the terms of the [MIT License](LICENSE.txt).