better_seo 0.1.0 → 0.4.0

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: c9636cfad8403d7c6f0433fd5a0434b0fb46b4a51a4e1076ed6a348f81185b1f
4
- data.tar.gz: 9a7fa5ea86498ef3c77ee6adb69c40ccd63739879fe7574cbaef70503c87bb3d
3
+ metadata.gz: 21564a3e273f4c6274fcafaddc9dc0b9e5e36524c1ca2a548ae48e455490034f
4
+ data.tar.gz: d82e2faf6d565f8be930ca24e9c3af7b60de23c8ed02dbcc0d14390c6725580b
5
5
  SHA512:
6
- metadata.gz: 364c805e5bf4da2d5b738727a8786b44f62ea621396d3b307985b54e0141f9f4c48ff58c1d9964b2df972976f78312893d1d603bd7e5e01f06c57340c3e59d71
7
- data.tar.gz: fe9f49347a0ce696876b1e946151a77fa2a8b1f637a24b2bcbdf9f88437e94c9a59af1850161d9a43883867634b44540f866efb624fc282b39c28a2ea27806f8
6
+ metadata.gz: 656e243f281d61d4afac21dfdd2f18be27659ae695bc5d6770146fc7e234135a21e221847157d75bb50b1d41d2798094e87868fc8d91cac1eee0fe38e651c6eb
7
+ data.tar.gz: b65f741d51b2b192c2456356081ad908145d68f93d37e64c6ba5d45c3ae838820120d7c852592dd60d1f3da54e2bf21e88316bede5c2e9971d0af24d2cecbe50
data/CHANGELOG.md CHANGED
@@ -1,5 +1,66 @@
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.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
1
8
  ## [Unreleased]
2
9
 
3
- ## [0.1.0] - 2025-10-05
10
+ ## [0.4.0] - 2025-01-23
11
+
12
+ ### Added
13
+ - Rails view helpers for easy integration
14
+ - `seo_meta_tags` - Generate HTML meta tags
15
+ - `seo_open_graph_tags` - Generate Open Graph tags
16
+ - `seo_twitter_tags` - Generate Twitter Card tags
17
+ - `seo_tags` - Generate all SEO tags at once
18
+ - Support for both hash configuration and DSL blocks in helpers
19
+ - Automatic HTML safety with `raw` helper
20
+ - Controller integration patterns and examples
21
+ - Complete Rails integration documentation
22
+
23
+ ### Test Coverage
24
+ - 286 tests passing
25
+ - 100% code coverage (562/562 lines)
26
+
27
+ ## [0.3.0] - 2025-01-23
28
+
29
+ ### Added
30
+ - HTML Generators for converting DSL to HTML tags
31
+ - `MetaTagsGenerator` - Converts meta tags DSL to HTML
32
+ - `OpenGraphGenerator` - Converts Open Graph DSL to HTML
33
+ - `TwitterCardsGenerator` - Converts Twitter Cards DSL to HTML
34
+ - HTML entity escaping for security (XSS prevention)
35
+
36
+ ### Test Coverage
37
+ - 271 tests passing
38
+ - 100% code coverage (505/505 lines)
39
+
40
+ ## [0.2.0] - 2025-01-22
41
+
42
+ ### Added
43
+ - DSL Builders for creating SEO configurations
44
+ - `DSL::MetaTags` - For HTML meta tags
45
+ - `DSL::OpenGraph` - For Open Graph protocol
46
+ - `DSL::TwitterCards` - For Twitter Cards
47
+ - Fluent interface with method chaining
48
+ - Automatic validation for all DSL builders
49
+
50
+ ### Test Coverage
51
+ - 175 tests passing
52
+ - 100% code coverage (327/327 lines)
53
+
54
+ ## [0.1.0] - 2025-01-22
55
+
56
+ ### Added
57
+ - Core configuration system with singleton pattern
58
+ - Nested configuration objects
59
+ - Feature flags for enabling/disabling modules
60
+ - Validation with detailed error messages
61
+ - i18n support with multiple locales
62
+ - Custom error classes
4
63
 
5
- - Initial release
64
+ ### Test Coverage
65
+ - 74 tests passing
66
+ - 100% code coverage (179/179 lines)
data/README.md CHANGED
@@ -1,38 +1,710 @@
1
1
  # BetterSeo
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ A comprehensive SEO gem for Ruby and Rails applications. BetterSeo provides a clean, fluent DSL for managing meta tags, Open Graph, Twitter Cards, structured data, sitemaps, and more.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/better_seo`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ [![Tests](https://img.shields.io/badge/tests-286%20passing-brightgreen)](https://github.com/yourusername/better_seo)
6
+ [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/yourusername/better_seo)
7
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.0.0-red)](https://www.ruby-lang.org)
8
+ [![Rails](https://img.shields.io/badge/rails-%3E%3D%206.1-red)](https://rubyonrails.org)
9
+
10
+ ## Features
11
+
12
+ ### ✅ Implemented (v0.2.0)
13
+
14
+ - **Core Configuration System**
15
+ - Singleton configuration with block-style setup
16
+ - Nested configuration objects
17
+ - Feature flags for enabling/disabling modules
18
+ - Validation with detailed error messages
19
+ - i18n support with multiple locales
20
+
21
+ - **DSL Builders**
22
+ - **Meta Tags DSL**: title, description, keywords, author, canonical, robots, viewport, charset
23
+ - **Open Graph DSL**: Complete OG protocol support including articles, images, videos, audio
24
+ - **Twitter Cards DSL**: All card types (summary, summary_large_image, app, player)
25
+ - Fluent interface with method chaining
26
+ - Automatic validation (title/description length, required fields)
27
+
28
+ - **HTML Generators**
29
+ - **MetaTagsGenerator**: Converts DSL to HTML meta tags
30
+ - **OpenGraphGenerator**: Converts DSL to Open Graph meta tags
31
+ - **TwitterCardsGenerator**: Converts DSL to Twitter Card meta tags
32
+ - HTML entity escaping for security
33
+ - Integration with DSL builders
34
+
35
+ - **Rails Integration**
36
+ - **View Helpers**: `seo_meta_tags`, `seo_open_graph_tags`, `seo_twitter_tags`, `seo_tags`
37
+ - Support for hash configuration and DSL blocks
38
+ - Automatic HTML safety with `raw` helper
39
+ - Integration with global configuration defaults
40
+
41
+ ### 🚧 Planned
42
+
43
+ - **Advanced Generators** (v0.5.0)
44
+ - Schema.org JSON-LD generator
45
+ - Breadcrumbs generator
46
+ - AMP HTML generator
47
+
48
+ - **Advanced Rails Integration** (v0.5.0)
49
+ - Controller helpers for setting page SEO
50
+ - Railtie for automatic initialization
51
+ - Generator for initializer file
52
+
53
+ - **Sitemap Generation** (v0.5.0)
54
+ - XML sitemap builder
55
+ - Automatic Rails routes integration
56
+ - Multi-language sitemap support
57
+ - Sitemap index for large sites
58
+
59
+ - **Advanced Features** (v0.6.0+)
60
+ - robots.txt generator
61
+ - Image optimization with WebP conversion
62
+ - Structured data builders (Organization, Person, Product, etc.)
63
+ - SEO validators and recommendations
6
64
 
7
65
  ## Installation
8
66
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
67
+ Add this line to your application's Gemfile:
10
68
 
11
- Install the gem and add to the application's Gemfile by executing:
69
+ ```ruby
70
+ gem 'better_seo'
71
+ ```
72
+
73
+ And then execute:
12
74
 
13
75
  ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
76
+ bundle install
15
77
  ```
16
78
 
17
- If bundler is not being used to manage dependencies, install the gem by executing:
79
+ Or install it yourself as:
18
80
 
19
81
  ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
82
+ gem install better_seo
83
+ ```
84
+
85
+ ## Quick Start
86
+
87
+ ### 1. Configuration
88
+
89
+ Create an initializer (Rails) or configure at app startup:
90
+
91
+ ```ruby
92
+ # config/initializers/better_seo.rb
93
+ BetterSeo.configure do |config|
94
+ config.site_name = "My Awesome Site"
95
+ config.default_locale = :en
96
+ config.available_locales = [:en, :it, :fr]
97
+
98
+ # Configure defaults for meta tags
99
+ config.meta_tags.default_title = "My Awesome Site"
100
+ config.meta_tags.title_separator = " | "
101
+ config.meta_tags.append_site_name = true
102
+ config.meta_tags.default_description = "The best site on the internet"
103
+ config.meta_tags.default_keywords = ["awesome", "site", "seo"]
104
+
105
+ # Configure Open Graph defaults
106
+ config.open_graph.site_name = "My Awesome Site"
107
+ config.open_graph.default_type = "website"
108
+ config.open_graph.default_locale = "en_US"
109
+
110
+ # Configure Twitter Cards defaults
111
+ config.twitter.site = "@mysite"
112
+ config.twitter.creator = "@myhandle"
113
+ config.twitter.card_type = "summary_large_image"
114
+ end
115
+ ```
116
+
117
+ ### 2. Using DSL Builders
118
+
119
+ #### Meta Tags
120
+
121
+ ```ruby
122
+ meta = BetterSeo::DSL::MetaTags.new
123
+
124
+ meta.evaluate do
125
+ title "My Page Title"
126
+ description "This is an amazing page about Ruby and SEO"
127
+ keywords "ruby", "seo", "meta tags"
128
+ author "John Doe"
129
+ canonical "https://example.com/my-page"
130
+ robots index: true, follow: true, noarchive: true
131
+ viewport # uses default: "width=device-width, initial-scale=1.0"
132
+ charset # uses default: "UTF-8"
133
+ end
134
+
135
+ # Get the configuration
136
+ config = meta.build
137
+ # => {
138
+ # title: "My Page Title",
139
+ # description: "This is an amazing page...",
140
+ # keywords: ["ruby", "seo", "meta tags"],
141
+ # ...
142
+ # }
143
+ ```
144
+
145
+ #### Open Graph
146
+
147
+ ```ruby
148
+ og = BetterSeo::DSL::OpenGraph.new
149
+
150
+ og.evaluate do
151
+ title "My OG Title"
152
+ description "Description for social media"
153
+ type "article"
154
+ url "https://example.com/article"
155
+ image "https://example.com/image.jpg"
156
+ site_name "My Site"
157
+ locale "en_US"
158
+ locale_alternate "it_IT", "fr_FR"
159
+
160
+ # For article type
161
+ article do
162
+ author "John Doe"
163
+ published_time "2024-01-01T00:00:00Z"
164
+ modified_time "2024-01-02T00:00:00Z"
165
+ section "Technology"
166
+ tag "Ruby", "SEO", "OpenGraph"
167
+ end
168
+ end
169
+
170
+ config = og.build
171
+ ```
172
+
173
+ #### Twitter Cards
174
+
175
+ ```ruby
176
+ twitter = BetterSeo::DSL::TwitterCards.new
177
+
178
+ twitter.evaluate do
179
+ card "summary_large_image"
180
+ site "@mysite" # @ prefix added automatically
181
+ creator "myhandle" # @ prefix added automatically
182
+ title "Twitter Card Title"
183
+ description "Description for Twitter"
184
+ image "https://example.com/twitter-image.jpg"
185
+ image_alt "Image description for accessibility"
186
+ end
187
+
188
+ config = twitter.build
189
+ ```
190
+
191
+ #### Method Chaining
192
+
193
+ All DSL builders support fluent interface:
194
+
195
+ ```ruby
196
+ meta = BetterSeo::DSL::MetaTags.new
197
+ .title("Chained Title")
198
+ .description("Chained Description")
199
+ .keywords("ruby", "rails", "seo")
200
+ .author("Jane Doe")
201
+ .canonical("https://example.com/page")
202
+
203
+ og = BetterSeo::DSL::OpenGraph.new
204
+ .title("OG Title")
205
+ .type("article")
206
+ .url("https://example.com")
207
+ .image("https://example.com/og.jpg")
208
+
209
+ twitter = BetterSeo::DSL::TwitterCards.new
210
+ .card("summary_large_image")
211
+ .site("@mysite")
212
+ .title("Twitter Title")
213
+ .description("Twitter Description")
214
+ .image("https://example.com/twitter.jpg")
215
+ ```
216
+
217
+ ### 3. HTML Generation
218
+
219
+ Once you've built your SEO configuration with DSL builders, use generators to convert them to HTML tags:
220
+
221
+ #### Meta Tags Generator
222
+
223
+ ```ruby
224
+ # Build configuration with DSL
225
+ meta = BetterSeo::DSL::MetaTags.new
226
+ meta.title("My Page Title")
227
+ meta.description("Page description for SEO")
228
+ meta.keywords("ruby", "seo", "rails")
229
+ meta.canonical("https://example.com/page")
230
+ meta.robots(index: true, follow: true)
231
+
232
+ # Generate HTML tags
233
+ generator = BetterSeo::Generators::MetaTagsGenerator.new(meta.build)
234
+ html = generator.generate
235
+
236
+ # Output:
237
+ # <meta charset="UTF-8">
238
+ # <meta name="viewport" content="width=device-width, initial-scale=1.0">
239
+ # <title>My Page Title</title>
240
+ # <meta name="description" content="Page description for SEO">
241
+ # <meta name="keywords" content="ruby, seo, rails">
242
+ # <link rel="canonical" href="https://example.com/page">
243
+ # <meta name="robots" content="index, follow">
244
+ ```
245
+
246
+ #### Open Graph Generator
247
+
248
+ ```ruby
249
+ # Build configuration with DSL
250
+ og = BetterSeo::DSL::OpenGraph.new
251
+ og.title("Article Title")
252
+ og.type("article")
253
+ og.url("https://example.com/article")
254
+ og.image(url: "https://example.com/og.jpg", width: 1200, height: 630)
255
+
256
+ # Generate HTML tags
257
+ generator = BetterSeo::Generators::OpenGraphGenerator.new(og.build)
258
+ html = generator.generate
259
+
260
+ # Output:
261
+ # <meta property="og:title" content="Article Title">
262
+ # <meta property="og:type" content="article">
263
+ # <meta property="og:url" content="https://example.com/article">
264
+ # <meta property="og:image" content="https://example.com/og.jpg">
265
+ # <meta property="og:image:width" content="1200">
266
+ # <meta property="og:image:height" content="630">
267
+ ```
268
+
269
+ #### Twitter Cards Generator
270
+
271
+ ```ruby
272
+ # Build configuration with DSL
273
+ twitter = BetterSeo::DSL::TwitterCards.new
274
+ twitter.card("summary_large_image")
275
+ twitter.site("@mysite")
276
+ twitter.title("Twitter Card Title")
277
+ twitter.description("Description for Twitter")
278
+ twitter.image("https://example.com/twitter.jpg")
279
+
280
+ # Generate HTML tags
281
+ generator = BetterSeo::Generators::TwitterCardsGenerator.new(twitter.build)
282
+ html = generator.generate
283
+
284
+ # Output:
285
+ # <meta name="twitter:card" content="summary_large_image">
286
+ # <meta name="twitter:site" content="@mysite">
287
+ # <meta name="twitter:title" content="Twitter Card Title">
288
+ # <meta name="twitter:description" content="Description for Twitter">
289
+ # <meta name="twitter:image" content="https://example.com/twitter.jpg">
290
+ ```
291
+
292
+ #### Complete Example
293
+
294
+ ```ruby
295
+ # Build all SEO tags for a page
296
+ meta = BetterSeo::DSL::MetaTags.new.evaluate do
297
+ title "My Awesome Page"
298
+ description "This page is about Ruby SEO"
299
+ keywords "ruby", "seo", "meta tags"
300
+ end
301
+
302
+ og = BetterSeo::DSL::OpenGraph.new.evaluate do
303
+ title "My Awesome Page"
304
+ type "article"
305
+ url "https://example.com/page"
306
+ image "https://example.com/og.jpg"
307
+ end
308
+
309
+ twitter = BetterSeo::DSL::TwitterCards.new.evaluate do
310
+ card "summary_large_image"
311
+ site "@mysite"
312
+ title "My Awesome Page"
313
+ image "https://example.com/twitter.jpg"
314
+ end
315
+
316
+ # Generate all HTML
317
+ meta_html = BetterSeo::Generators::MetaTagsGenerator.new(meta.build).generate
318
+ og_html = BetterSeo::Generators::OpenGraphGenerator.new(og.build).generate
319
+ twitter_html = BetterSeo::Generators::TwitterCardsGenerator.new(twitter.build).generate
320
+
321
+ # Combine and render in your view
322
+ all_tags = [meta_html, og_html, twitter_html].join("\n")
323
+ ```
324
+
325
+ #### Security Features
326
+
327
+ All generators automatically escape HTML entities to prevent XSS attacks:
328
+
329
+ ```ruby
330
+ meta = BetterSeo::DSL::MetaTags.new
331
+ meta.title('Title with "quotes" & <script>alert("xss")</script>')
332
+
333
+ generator = BetterSeo::Generators::MetaTagsGenerator.new(meta.build)
334
+ html = generator.generate
335
+
336
+ # Output:
337
+ # <title>Title with &quot;quotes&quot; &amp; &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;</title>
338
+ # All dangerous characters are properly escaped
339
+ ```
340
+
341
+ ### 4. Validation
342
+
343
+ All DSL builders include automatic validation:
344
+
345
+ ```ruby
346
+ meta = BetterSeo::DSL::MetaTags.new
347
+ meta.title("A" * 80) # Too long (max 60 chars recommended)
348
+ meta.build
349
+ # => BetterSeo::ValidationError: Title too long (80 chars, max 60 recommended)
350
+
351
+ og = BetterSeo::DSL::OpenGraph.new
352
+ og.title("Title")
353
+ og.build
354
+ # => BetterSeo::ValidationError: og:type is required, og:image is required, og:url is required
355
+
356
+ twitter = BetterSeo::DSL::TwitterCards.new
357
+ twitter.card("invalid_type")
358
+ twitter.build
359
+ # => BetterSeo::ValidationError: Invalid card type: invalid_type. Valid types: summary, summary_large_image, app, player
360
+ ```
361
+
362
+ ### 5. Rails Integration
363
+
364
+ BetterSeo provides view helpers for easy integration in Rails applications.
365
+
366
+ #### Setup
367
+
368
+ Include the helpers in your `ApplicationHelper`:
369
+
370
+ ```ruby
371
+ # app/helpers/application_helper.rb
372
+ module ApplicationHelper
373
+ include BetterSeo::Rails::Helpers::SeoHelper
374
+ end
21
375
  ```
22
376
 
23
- ## Usage
377
+ Or include them globally in `ApplicationController`:
24
378
 
25
- TODO: Write usage instructions here
379
+ ```ruby
380
+ # app/controllers/application_controller.rb
381
+ class ApplicationController < ActionController::Base
382
+ helper BetterSeo::Rails::Helpers::SeoHelper
383
+ end
384
+ ```
385
+
386
+ #### Using View Helpers
387
+
388
+ ##### Single Tag Group Helpers
389
+
390
+ ```erb
391
+ <%# app/views/layouts/application.html.erb %>
392
+ <head>
393
+ <%= seo_meta_tags do |meta|
394
+ meta.title "My Page Title"
395
+ meta.description "Page description"
396
+ meta.keywords "ruby", "rails", "seo"
397
+ meta.canonical request.original_url
398
+ meta.robots index: true, follow: true
399
+ end %>
400
+
401
+ <%= seo_open_graph_tags do |og|
402
+ og.title "My Page Title"
403
+ og.type "website"
404
+ og.url request.original_url
405
+ og.image image_url("og-image.jpg")
406
+ og.site_name "My Site"
407
+ end %>
408
+
409
+ <%= seo_twitter_tags do |twitter|
410
+ twitter.card "summary_large_image"
411
+ twitter.site "@mysite"
412
+ twitter.title "My Page Title"
413
+ twitter.description "Page description"
414
+ twitter.image image_url("twitter-image.jpg")
415
+ end %>
416
+ </head>
417
+ ```
418
+
419
+ ##### All-in-One Helper
420
+
421
+ ```erb
422
+ <%# Generate all SEO tags at once %>
423
+ <head>
424
+ <%= seo_tags do |seo|
425
+ seo.meta do |meta|
426
+ meta.title @page_title || "Default Title"
427
+ meta.description @page_description
428
+ meta.keywords @page_keywords if @page_keywords
429
+ meta.canonical request.original_url
430
+ end
431
+
432
+ seo.og do |og|
433
+ og.title @page_title || "Default Title"
434
+ og.type "article"
435
+ og.url request.original_url
436
+ og.image @og_image || image_url("default-og.jpg")
437
+ end
438
+
439
+ seo.twitter do |twitter|
440
+ twitter.card "summary_large_image"
441
+ twitter.site "@mysite"
442
+ twitter.title @page_title || "Default Title"
443
+ twitter.image @twitter_image || image_url("default-twitter.jpg")
444
+ end
445
+ end %>
446
+ </head>
447
+ ```
448
+
449
+ #### Controller Integration
450
+
451
+ Set SEO data in your controllers:
452
+
453
+ ```ruby
454
+ class ArticlesController < ApplicationController
455
+ def show
456
+ @article = Article.find(params[:id])
457
+
458
+ # Set SEO variables for the view
459
+ @page_title = @article.title
460
+ @page_description = @article.excerpt
461
+ @page_keywords = @article.tags.pluck(:name)
462
+ @og_image = url_for(@article.cover_image) if @article.cover_image.attached?
463
+ end
464
+ end
465
+ ```
466
+
467
+ Then use them in your layout:
468
+
469
+ ```erb
470
+ <head>
471
+ <%= seo_tags do |seo|
472
+ seo.meta do |meta|
473
+ meta.title @page_title if @page_title
474
+ meta.description @page_description if @page_description
475
+ meta.keywords(*@page_keywords) if @page_keywords
476
+ meta.canonical request.original_url
477
+ end
478
+
479
+ seo.og do |og|
480
+ og.title @page_title || "Default Title"
481
+ og.type "article"
482
+ og.url request.original_url
483
+ og.image @og_image if @og_image
484
+ end
485
+
486
+ seo.twitter do |twitter|
487
+ twitter.card "summary_large_image"
488
+ twitter.title @page_title || "Default Title"
489
+ twitter.description @page_description if @page_description
490
+ end
491
+ end %>
492
+ </head>
493
+ ```
494
+
495
+ #### Hash Configuration
496
+
497
+ You can also pass hash configurations directly:
498
+
499
+ ```erb
500
+ <%= seo_meta_tags(
501
+ title: "My Page",
502
+ description: "Description",
503
+ keywords: ["ruby", "rails"]
504
+ ) %>
505
+
506
+ <%= seo_open_graph_tags(
507
+ title: "My Page",
508
+ type: "article",
509
+ url: request.original_url,
510
+ image: image_url("og.jpg")
511
+ ) %>
512
+
513
+ <%= seo_twitter_tags(
514
+ card: "summary",
515
+ title: "My Page",
516
+ description: "Description"
517
+ ) %>
518
+ ```
519
+
520
+ #### Partial Integration
521
+
522
+ Create reusable SEO partials:
523
+
524
+ ```erb
525
+ <%# app/views/shared/_seo.html.erb %>
526
+ <%= seo_tags do |seo|
527
+ seo.meta do |meta|
528
+ meta.title local_assigns[:title] || "Default Title"
529
+ meta.description local_assigns[:description]
530
+ meta.canonical request.original_url
531
+ end
532
+
533
+ seo.og do |og|
534
+ og.title local_assigns[:title] || "Default Title"
535
+ og.type local_assigns[:og_type] || "website"
536
+ og.url request.original_url
537
+ og.image local_assigns[:og_image] || image_url("default-og.jpg")
538
+ end
539
+
540
+ seo.twitter do |twitter|
541
+ twitter.card "summary_large_image"
542
+ twitter.title local_assigns[:title] || "Default Title"
543
+ end
544
+ end %>
545
+ ```
546
+
547
+ Then use it in your views:
548
+
549
+ ```erb
550
+ <%# app/views/articles/show.html.erb %>
551
+ <%= render "shared/seo",
552
+ title: @article.title,
553
+ description: @article.excerpt,
554
+ og_type: "article",
555
+ og_image: url_for(@article.cover_image) %>
556
+ ```
557
+
558
+ ## Configuration Reference
559
+
560
+ ### Global Configuration
561
+
562
+ ```ruby
563
+ BetterSeo.configure do |config|
564
+ # Site-wide settings
565
+ config.site_name = "My Site"
566
+ config.default_locale = :en
567
+ config.available_locales = [:en, :it, :fr, :de, :es]
568
+
569
+ # Meta tags configuration
570
+ config.meta_tags.default_title = "Default Title"
571
+ config.meta_tags.title_separator = " | "
572
+ config.meta_tags.append_site_name = true
573
+ config.meta_tags.default_description = "Default description"
574
+ config.meta_tags.default_keywords = ["keyword1", "keyword2"]
575
+ config.meta_tags.default_author = "Your Name"
576
+
577
+ # Open Graph configuration
578
+ config.open_graph.enabled = true
579
+ config.open_graph.site_name = "My Site"
580
+ config.open_graph.default_type = "website"
581
+ config.open_graph.default_locale = "en_US"
582
+ config.open_graph.default_image.url = "https://example.com/default-og.jpg"
583
+ config.open_graph.default_image.width = 1200
584
+ config.open_graph.default_image.height = 630
585
+
586
+ # Twitter Cards configuration
587
+ config.twitter.enabled = true
588
+ config.twitter.site = "@mysite"
589
+ config.twitter.creator = "@myhandle"
590
+ config.twitter.card_type = "summary_large_image"
591
+
592
+ # Structured Data configuration
593
+ config.structured_data.enabled = true
594
+ config.structured_data.organization = {
595
+ name: "My Organization",
596
+ url: "https://example.com"
597
+ }
598
+
599
+ # Sitemap configuration (planned)
600
+ config.sitemap.enabled = false
601
+ config.sitemap.host = "https://example.com"
602
+ config.sitemap.output_path = "public/sitemap.xml"
603
+
604
+ # Robots.txt configuration (planned)
605
+ config.robots.enabled = false
606
+ config.robots.output_path = "public/robots.txt"
607
+
608
+ # Image optimization configuration (planned)
609
+ config.images.enabled = false
610
+ config.images.webp.enabled = true
611
+ config.images.webp.quality = 80
612
+ end
613
+ ```
614
+
615
+ ### Checking Configuration
616
+
617
+ ```ruby
618
+ # Access configuration
619
+ BetterSeo.configuration.site_name
620
+ # => "My Site"
621
+
622
+ # Check if features are enabled
623
+ BetterSeo.enabled?(:open_graph)
624
+ # => true
625
+
626
+ BetterSeo.enabled?(:sitemap)
627
+ # => false
628
+
629
+ # Reset configuration (useful for testing)
630
+ BetterSeo.reset_configuration!
631
+ ```
26
632
 
27
633
  ## Development
28
634
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
635
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
636
+
637
+ ```bash
638
+ # Install dependencies
639
+ bundle install
640
+
641
+ # Run tests
642
+ bundle exec rspec
643
+
644
+ # Run tests with coverage
645
+ bundle exec rspec --format documentation
646
+
647
+ # Check code coverage
648
+ open coverage/index.html
649
+ ```
650
+
651
+ ### Running Tests
652
+
653
+ The gem uses RSpec with SimpleCov for test coverage. We maintain **100% code coverage**.
654
+
655
+ ```bash
656
+ # Run all tests
657
+ bundle exec rspec
658
+
659
+ # Run specific test file
660
+ bundle exec rspec spec/dsl/meta_tags_spec.rb
661
+
662
+ # Run with documentation format
663
+ bundle exec rspec --format documentation
664
+ ```
665
+
666
+ Current test statistics:
667
+ - **286 tests** passing
668
+ - **100% code coverage** (562/562 lines)
669
+ - **3 DSL builders** fully tested
670
+ - **3 HTML generators** fully tested
671
+ - **1 Rails view helper module** fully tested
672
+ - **1 core configuration system** fully tested
673
+
674
+ ## Architecture
30
675
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
676
+ ```
677
+ lib/better_seo/
678
+ ├── version.rb # Gem version
679
+ ├── errors.rb # Custom error classes
680
+ ├── configuration.rb # Main configuration class
681
+ ├── dsl/
682
+ │ ├── base.rb # Base DSL builder class
683
+ │ ├── meta_tags.rb # Meta tags DSL
684
+ │ ├── open_graph.rb # Open Graph DSL
685
+ │ └── twitter_cards.rb # Twitter Cards DSL
686
+ ├── generators/
687
+ │ ├── meta_tags_generator.rb # HTML meta tags generator
688
+ │ ├── open_graph_generator.rb # Open Graph tags generator
689
+ │ └── twitter_cards_generator.rb # Twitter Cards generator
690
+ ├── rails/
691
+ │ └── helpers/
692
+ │ └── seo_helper.rb # Rails view helpers
693
+ └── (planned)
694
+ ├── validators/ # SEO validators
695
+ └── sitemap/ # Sitemap generation
696
+ ```
32
697
 
33
698
  ## Contributing
34
699
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/better_seo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/better_seo/blob/main/CODE_OF_CONDUCT.md).
700
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/better_seo.
701
+
702
+ 1. Fork it
703
+ 2. Create your feature branch (`git checkout -b feature/my-new-feature`)
704
+ 3. Write tests (we maintain 100% coverage)
705
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
706
+ 5. Push to the branch (`git push origin feature/my-new-feature`)
707
+ 6. Create new Pull Request
36
708
 
37
709
  ## License
38
710
 
@@ -40,4 +712,18 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
712
 
41
713
  ## Code of Conduct
42
714
 
43
- Everyone interacting in the BetterSeo project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/better_seo/blob/main/CODE_OF_CONDUCT.md).
715
+ Everyone interacting in the BetterSeo project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/yourusername/better_seo/blob/main/CODE_OF_CONDUCT.md).
716
+
717
+ ## Roadmap
718
+
719
+ See [docs/00_OVERVIEW.md](docs/00_OVERVIEW.md) for the complete implementation roadmap.
720
+
721
+ ### Version History
722
+
723
+ - **v0.1.0** - Core configuration system
724
+ - **v0.2.0** - DSL builders (Meta Tags, Open Graph, Twitter Cards)
725
+ - **v0.3.0** - HTML generators (Meta Tags, Open Graph, Twitter Cards)
726
+ - **v0.4.0** - Rails view helpers integration ← **Current**
727
+ - **v0.5.0** - Sitemap generation (planned)
728
+ - **v0.6.0** - Advanced features (planned)
729
+ - **v1.0.0** - Stable release (planned)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BetterSeo
4
- VERSION = "0.1.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/better_seo.rb CHANGED
@@ -1,8 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support"
4
+ require "active_support/core_ext"
5
+
3
6
  require_relative "better_seo/version"
7
+ require_relative "better_seo/errors"
8
+ require_relative "better_seo/configuration"
9
+ require_relative "better_seo/dsl/base"
10
+ require_relative "better_seo/dsl/meta_tags"
11
+ require_relative "better_seo/dsl/open_graph"
12
+ require_relative "better_seo/dsl/twitter_cards"
13
+ require_relative "better_seo/generators/meta_tags_generator"
14
+ require_relative "better_seo/generators/open_graph_generator"
15
+ require_relative "better_seo/generators/twitter_cards_generator"
16
+ require_relative "better_seo/rails/helpers/seo_helper"
4
17
 
5
18
  module BetterSeo
6
- class Error < StandardError; end
7
- # Your code goes here...
19
+ class << self
20
+ # Accesso alla configurazione singleton
21
+ def configuration
22
+ @configuration ||= Configuration.new
23
+ end
24
+
25
+ # Block-style configuration
26
+ def configure
27
+ yield(configuration) if block_given?
28
+ configuration.validate! if block_given?
29
+ configuration
30
+ end
31
+
32
+ # Reset configuration (utile per test)
33
+ def reset_configuration!
34
+ @configuration = Configuration.new
35
+ end
36
+
37
+ # Shortcut per check feature enabled
38
+ def enabled?(feature)
39
+ configuration.public_send("#{feature}_enabled?")
40
+ rescue NoMethodError
41
+ false
42
+ end
43
+ end
8
44
  end
metadata CHANGED
@@ -1,17 +1,60 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_seo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - alessiobussolari
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-05 00:00:00.000000000 Z
12
- dependencies: []
13
- description: BetterSeo provides tools and utilities to enhance SEO capabilities in
14
- Ruby applications
11
+ date: 2025-10-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.22'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.22'
55
+ description: BetterSeo provides a clean, fluent DSL for managing meta tags, Open Graph,
56
+ Twitter Cards, and more. Features include automatic HTML generation, validation,
57
+ Rails view helpers, and 100% test coverage.
15
58
  email:
16
59
  - alessio@cosmic.tech
17
60
  executables: []
@@ -53,5 +96,5 @@ requirements: []
53
96
  rubygems_version: 3.5.11
54
97
  signing_key:
55
98
  specification_version: 4
56
- summary: A Ruby gem for better SEO functionality
99
+ summary: Comprehensive SEO gem for Ruby and Rails applications
57
100
  test_files: []