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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +252 -0
- data/data/schema_org_v30.json +20081 -0
- data/lib/generators/structured_data/install/install_generator.rb +17 -0
- data/lib/generators/structured_data/install/templates/structured_data.rb +15 -0
- data/lib/ruby-structured-data.rb +3 -0
- data/lib/ruby_structured_data.rb +4 -0
- data/lib/structured_data/compiler/parser.rb +120 -0
- data/lib/structured_data/compiler/terms.rb +24 -0
- data/lib/structured_data/compiler/uri_helper.rb +66 -0
- data/lib/structured_data/compiler/vocabulary.rb +115 -0
- data/lib/structured_data/compiler.rb +68 -0
- data/lib/structured_data/configuration.rb +19 -0
- data/lib/structured_data/document.rb +99 -0
- data/lib/structured_data/enum.rb +64 -0
- data/lib/structured_data/error.rb +19 -0
- data/lib/structured_data/list.rb +46 -0
- data/lib/structured_data/node.rb +133 -0
- data/lib/structured_data/rails/helper.rb +38 -0
- data/lib/structured_data/rails/railtie.rb +22 -0
- data/lib/structured_data/rails/registry.rb +124 -0
- data/lib/structured_data/rails/renderer.rb +20 -0
- data/lib/structured_data/rails.rb +6 -0
- data/lib/structured_data/reference.rb +46 -0
- data/lib/structured_data/serializer.rb +44 -0
- data/lib/structured_data/validator/context.rb +30 -0
- data/lib/structured_data/validator/diagnostic.rb +45 -0
- data/lib/structured_data/validator/node_validator.rb +131 -0
- data/lib/structured_data/validator/range_checker.rb +83 -0
- data/lib/structured_data/validator/result.rb +37 -0
- data/lib/structured_data/validator.rb +76 -0
- data/lib/structured_data/values.rb +148 -0
- data/lib/structured_data/version.rb +5 -0
- data/lib/structured_data/vocabulary/data_loader.rb +25 -0
- data/lib/structured_data/vocabulary/hierarchy.rb +32 -0
- data/lib/structured_data/vocabulary/registry.rb +90 -0
- data/lib/structured_data/vocabulary.rb +136 -0
- data/lib/structured_data.rb +84 -0
- 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).
|