email_digest 1.0.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.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/.vscode/settings.json +3 -0
  3. data/ANSWERS_TO_YOUR_QUESTIONS.md +361 -0
  4. data/CHANGELOG.md +14 -0
  5. data/COMPLETE_SETUP_INSTRUCTIONS.md +298 -0
  6. data/CUSTOMIZATION_GUIDE.md +264 -0
  7. data/FAQ.md +133 -0
  8. data/LICENSE.txt +21 -0
  9. data/QUICK_START.md +62 -0
  10. data/README.md +253 -0
  11. data/REPOSITORY_READY.md +146 -0
  12. data/RUBYGEMS_PUBLISHING.md +272 -0
  13. data/SETUP_SEPARATE_GEM_REPO.md +131 -0
  14. data/email_digest.gemspec +52 -0
  15. data/lib/email_digest/concerns/digestable.rb +57 -0
  16. data/lib/email_digest/configuration.rb +40 -0
  17. data/lib/email_digest/generators/email_digest/install/install_generator.rb +50 -0
  18. data/lib/email_digest/generators/email_digest/install/templates/README +16 -0
  19. data/lib/email_digest/generators/email_digest/install/templates/create_email_digest_tables.rb +77 -0
  20. data/lib/email_digest/generators/email_digest/install/templates/email_digest.rb +25 -0
  21. data/lib/email_digest/models/digest_item.rb +49 -0
  22. data/lib/email_digest/models/digest_preference.rb +106 -0
  23. data/lib/email_digest/railtie.rb +9 -0
  24. data/lib/email_digest/services/digest_collector.rb +38 -0
  25. data/lib/email_digest/services/digest_scheduler.rb +55 -0
  26. data/lib/email_digest/services/digest_summarizer.rb +135 -0
  27. data/lib/email_digest/version.rb +5 -0
  28. data/lib/email_digest/workers/digest_processor_worker.rb +64 -0
  29. data/lib/email_digest/workers/digest_scheduler_worker.rb +26 -0
  30. data/lib/email_digest/workers/digest_sender_worker.rb +48 -0
  31. data/lib/email_digest.rb +37 -0
  32. metadata +241 -0
data/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # EmailDigest
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/email_digest.svg)](https://badge.fury.io/rb/email_digest)
4
+ [![Build Status](https://github.com/yourusername/email_digest/workflows/CI/badge.svg)](https://github.com/yourusername/email_digest/actions)
5
+
6
+ A flexible, production-ready email digest system for Rails applications. EmailDigest allows you to collect, summarize, and send batched email notifications to users with customizable schedules, priority-based processing, and multi-tenant support.
7
+
8
+ ## Features
9
+
10
+ - ✅ **Multiple Digest Types**: Support for different types of digests (notifications, time logs, etc.)
11
+ - ✅ **Flexible Scheduling**: Daily, weekly, or custom schedules with timezone support
12
+ - ✅ **Priority-Based Processing**: High-priority items are highlighted in digests
13
+ - ✅ **Smart Summarization**: Automatic grouping and summarization of digest items
14
+ - ✅ **Multi-Tenant Support**: Full support for multi-tenant applications
15
+ - ✅ **PostgreSQL**: Built on PostgreSQL with proper indexes and constraints
16
+ - ✅ **Sidekiq Integration**: Asynchronous processing with Sidekiq
17
+ - ✅ **Production Ready**: Includes error handling, logging, and monitoring hooks
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'email_digest'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```bash
30
+ $ bundle install
31
+ ```
32
+
33
+ Or install it yourself as:
34
+
35
+ ```bash
36
+ $ gem install email_digest
37
+ ```
38
+
39
+ ## Setup
40
+
41
+ ### 1. Run the Install Generator
42
+
43
+ ```bash
44
+ rails generate email_digest:install
45
+ ```
46
+
47
+ This will:
48
+ - Create `config/initializers/email_digest.rb`
49
+ - Create a migration for the digest tables
50
+ - Add the email_digest queue to your Sidekiq configuration
51
+ - Add the scheduler cron job to your Sidekiq cron schedule
52
+
53
+ ### 2. Run the Migration
54
+
55
+ ```bash
56
+ rails db:migrate
57
+ ```
58
+
59
+ ### 3. Configure EmailDigest
60
+
61
+ Edit `config/initializers/email_digest.rb`:
62
+
63
+ ```ruby
64
+ EmailDigest.configure do |config|
65
+ # Default settings
66
+ config.default_frequency = :daily
67
+ config.default_time = '09:00'
68
+ config.default_timezone = 'UTC'
69
+ config.queue_name = :email_digest
70
+ config.max_items_per_digest = 50
71
+ config.enable_summarization = true
72
+ config.mailer_class = 'UserMailer'
73
+ config.mailer_method = 'digest_email'
74
+ config.organization_class = 'Organization'
75
+ config.user_class = 'User'
76
+
77
+ # Register digest types
78
+ config.register_digest_type(:time_log_notifications, {
79
+ mailer_method: 'time_log_digest_email'
80
+ })
81
+
82
+ config.register_digest_type(:mentor_supervisor_notifications, {
83
+ mailer_method: 'mentor_supervisor_digest_email'
84
+ })
85
+ end
86
+ ```
87
+
88
+ ### 4. Create Mailer Methods
89
+
90
+ Add digest email methods to your mailer (e.g., `app/mailers/user_mailer.rb`):
91
+
92
+ ```ruby
93
+ class UserMailer < ActionMailer::Base
94
+ def digest_email(user, summary, digest_type)
95
+ @user = user
96
+ @summary = summary.with_indifferent_access
97
+ @digest_type = digest_type
98
+ attach_logo
99
+
100
+ I18n.with_locale(@user.default_language) do
101
+ mail(
102
+ to: @user.email,
103
+ from: 'no-reply@example.com',
104
+ subject: @summary[:subject] || 'Notifications Digest',
105
+ content_type: 'text/html'
106
+ ) do |format|
107
+ format.html { render 'digest_email' }
108
+ end
109
+ end
110
+ end
111
+ end
112
+ ```
113
+
114
+ ### 5. Create Email Templates
115
+
116
+ Create email templates in `app/views/user_mailer/`:
117
+
118
+ ```erb
119
+ <!-- app/views/user_mailer/digest_email.html.erb -->
120
+ <div style="background-color: #F5F5F5; padding: 20px;">
121
+ <div style="background-color: #FFFFFF; padding: 20px; max-width: 600px; margin: 0 auto;">
122
+ <h1><%= @summary[:subject] %></h1>
123
+ <p><%= @summary[:summary] %></p>
124
+
125
+ <% if @summary[:grouped_items].present? %>
126
+ <% @summary[:grouped_items].each do |group_key, items| %>
127
+ <h2><%= group_key.to_s.humanize %> (<%= items.size %>)</h2>
128
+ <% items.each do |item| %>
129
+ <div style="margin: 10px 0; padding: 10px; border-left: 3px solid #007BFF;">
130
+ <h3><%= item[:subject] %></h3>
131
+ <p><%= truncate(item[:body], length: 200) %></p>
132
+ </div>
133
+ <% end %>
134
+ <% end %>
135
+ <% end %>
136
+ </div>
137
+ </div>
138
+ ```
139
+
140
+ ## Usage
141
+
142
+ ### Adding Items to Digests
143
+
144
+ #### Option 1: Using the Digestable Concern
145
+
146
+ Include the concern in your models:
147
+
148
+ ```ruby
149
+ class TimeLog < ActiveRecord::Base
150
+ include EmailDigest::Concerns::Digestable
151
+
152
+ digestable :time_log_notifications
153
+ end
154
+ ```
155
+
156
+ Then add items to digests:
157
+
158
+ ```ruby
159
+ time_log = TimeLog.find(1)
160
+ time_log.add_to_digest(
161
+ user,
162
+ :submission_received,
163
+ subject: "New Time Log Submission",
164
+ body: "A new time log has been submitted for review.",
165
+ priority: 5,
166
+ metadata: { time_log_id: time_log.id }
167
+ )
168
+ ```
169
+
170
+ #### Option 2: Direct Creation
171
+
172
+ ```ruby
173
+ EmailDigest::Models::DigestItem.create_for_user(
174
+ user,
175
+ :time_log_notifications,
176
+ :submission_received,
177
+ subject: "New Time Log Submission",
178
+ body: "A new time log has been submitted for review.",
179
+ priority: 5,
180
+ source_id: time_log.id.to_s,
181
+ source_type: 'TimeLog',
182
+ metadata: { time_log_id: time_log.id }
183
+ )
184
+ ```
185
+
186
+ ### Managing User Preferences
187
+
188
+ ```ruby
189
+ # Get or create a preference
190
+ preference = EmailDigest::Models::DigestPreference.for_user_and_type(
191
+ user,
192
+ :time_log_notifications,
193
+ user.organization
194
+ )
195
+
196
+ # Update preference
197
+ preference.update(
198
+ frequency: 'weekly',
199
+ day_of_week: 1, # Monday
200
+ time: '10:00',
201
+ timezone: 'America/New_York',
202
+ enabled: true
203
+ )
204
+
205
+ # Disable digest
206
+ preference.update(enabled: false)
207
+ ```
208
+
209
+ ## Configuration Options
210
+
211
+ | Option | Default | Description |
212
+ |--------|---------|-------------|
213
+ | `default_frequency` | `:daily` | Default digest frequency |
214
+ | `default_time` | `'09:00'` | Default send time (HH:MM) |
215
+ | `default_timezone` | `'UTC'` | Default timezone |
216
+ | `queue_name` | `:email_digest` | Sidekiq queue name |
217
+ | `max_items_per_digest` | `50` | Maximum items per digest |
218
+ | `enable_summarization` | `true` | Enable smart summarization |
219
+ | `mailer_class` | `'UserMailer'` | Mailer class name |
220
+ | `mailer_method` | `'digest_email'` | Default mailer method |
221
+ | `organization_class` | `'Organization'` | Organization model class |
222
+ | `user_class` | `'User'` | User model class |
223
+
224
+ ## Requirements
225
+
226
+ - Rails >= 6.0, < 8.0
227
+ - PostgreSQL >= 10.0
228
+ - Sidekiq >= 5.0
229
+ - Sidekiq Cron >= 1.0
230
+
231
+ ## Development
232
+
233
+ After checking out the repo, run:
234
+
235
+ ```bash
236
+ bundle install
237
+ rails db:create db:migrate
238
+ rspec
239
+ ```
240
+
241
+ ## Contributing
242
+
243
+ Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/email_digest.
244
+
245
+ ## License
246
+
247
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
248
+
249
+ ## Support
250
+
251
+ For issues, questions, or contributions, please visit:
252
+ - [GitHub Issues](https://github.com/yourusername/email_digest/issues)
253
+ - [Documentation](https://github.com/yourusername/email_digest/wiki)
@@ -0,0 +1,146 @@
1
+ # ✅ EmailDigest Gem Repository - Ready!
2
+
3
+ ## Location
4
+
5
+ Your gem repository is now at:
6
+ ```
7
+ /Users/rosharma/workspace/email_digest
8
+ ```
9
+
10
+ This is parallel to your main application at:
11
+ ```
12
+ /Users/rosharma/workspace/sll-la/eportfolio
13
+ ```
14
+
15
+ ## What's Included
16
+
17
+ ✅ Complete gem structure with all source files
18
+ ✅ Generator for easy installation
19
+ ✅ Gemspec ready for RubyGems
20
+ ✅ Complete documentation
21
+ ✅ Publishing guides
22
+
23
+ ## Next Steps
24
+
25
+ ### 1. Initialize Git (if needed)
26
+
27
+ ```bash
28
+ cd /Users/rosharma/workspace/email_digest
29
+ git init
30
+ git add .
31
+ git commit -m "Initial commit: EmailDigest gem v1.0.0"
32
+ ```
33
+
34
+ ### 2. Update Gemspec Metadata
35
+
36
+ Edit `email_digest.gemspec` and update:
37
+ - `spec.authors` - Your name
38
+ - `spec.email` - Your email
39
+ - `spec.homepage` - Your GitHub repo URL
40
+ - `spec.metadata` URLs - Your repository URLs
41
+
42
+ ### 3. Create GitHub Repository
43
+
44
+ ```bash
45
+ # Create repo on GitHub, then:
46
+ git remote add origin https://github.com/yourusername/email_digest.git
47
+ git branch -M main
48
+ git push -u origin main
49
+ ```
50
+
51
+ ### 4. Publish to RubyGems
52
+
53
+ ```bash
54
+ # Create account at https://rubygems.org
55
+ gem signin
56
+ gem build email_digest.gemspec
57
+ gem push email_digest-1.0.0.gem
58
+ ```
59
+
60
+ ### 5. Use in Your Application
61
+
62
+ In your main app's `Gemfile` (`/Users/rosharma/workspace/sll-la/eportfolio/Gemfile`):
63
+
64
+ ```ruby
65
+ # Option 1: Local path (for development)
66
+ gem 'email_digest', path: '../../email_digest'
67
+
68
+ # Option 2: From GitHub (after pushing)
69
+ gem 'email_digest', git: 'https://github.com/yourusername/email_digest.git'
70
+
71
+ # Option 3: From RubyGems (after publishing)
72
+ gem 'email_digest'
73
+ ```
74
+
75
+ Then:
76
+
77
+ ```bash
78
+ cd /Users/rosharma/workspace/sll-la/eportfolio
79
+ bundle install
80
+ rails generate email_digest:install
81
+ rails db:migrate
82
+ ```
83
+
84
+ ## File Structure
85
+
86
+ ```
87
+ email_digest/
88
+ ├── email_digest.gemspec # Gem specification
89
+ ├── README.md # Main documentation
90
+ ├── LICENSE.txt # MIT License
91
+ ├── CHANGELOG.md # Version history
92
+ ├── QUICK_START.md # Quick setup guide
93
+ ├── RUBYGEMS_PUBLISHING.md # Publishing guide
94
+ ├── COMPLETE_SETUP_INSTRUCTIONS.md # Detailed setup
95
+ └── lib/
96
+ ├── email_digest.rb # Main entry point
97
+ └── email_digest/
98
+ ├── version.rb
99
+ ├── configuration.rb
100
+ ├── railtie.rb
101
+ ├── models/
102
+ │ ├── digest_item.rb
103
+ │ └── digest_preference.rb
104
+ ├── services/
105
+ │ ├── digest_collector.rb
106
+ │ ├── digest_summarizer.rb
107
+ │ └── digest_scheduler.rb
108
+ ├── workers/
109
+ │ ├── digest_processor_worker.rb
110
+ │ ├── digest_sender_worker.rb
111
+ │ └── digest_scheduler_worker.rb
112
+ ├── concerns/
113
+ │ └── digestable.rb
114
+ └── generators/
115
+ └── email_digest/
116
+ └── install/
117
+ ├── install_generator.rb
118
+ └── templates/
119
+ ├── email_digest.rb
120
+ ├── create_email_digest_tables.rb
121
+ └── README
122
+ ```
123
+
124
+ ## Important Notes
125
+
126
+ ✅ **Separate Repository** - Completely independent from your main app
127
+ ✅ **Ready to Publish** - All files configured for RubyGems
128
+ ✅ **No Disruption** - Your main app continues to work normally
129
+ ✅ **Easy Integration** - Just add to Gemfile when ready
130
+
131
+ ## Documentation
132
+
133
+ - `QUICK_START.md` - 5-minute setup guide
134
+ - `COMPLETE_SETUP_INSTRUCTIONS.md` - Detailed step-by-step
135
+ - `RUBYGEMS_PUBLISHING.md` - Complete publishing guide
136
+ - `README.md` - Full usage documentation
137
+
138
+ ## Status
139
+
140
+ 🎉 **Your gem repository is ready!**
141
+
142
+ You can now:
143
+ 1. Initialize git and push to GitHub
144
+ 2. Update gemspec metadata
145
+ 3. Publish to RubyGems
146
+ 4. Use in your application via Gemfile
@@ -0,0 +1,272 @@
1
+ # Publishing EmailDigest to RubyGems
2
+
3
+ Complete guide for publishing and maintaining your gem on RubyGems.
4
+
5
+ ## Prerequisites
6
+
7
+ 1. **Create RubyGems Account**
8
+ - Go to https://rubygems.org
9
+ - Sign up for a free account
10
+ - Verify your email
11
+
12
+ 2. **Get API Key**
13
+ - Go to https://rubygems.org/profile/edit
14
+ - Scroll to "API Access"
15
+ - Create a new API key
16
+ - Copy the key (you'll use it once)
17
+
18
+ ## Initial Setup
19
+
20
+ ### 1. Configure RubyGems Credentials
21
+
22
+ ```bash
23
+ # Set your credentials (one-time setup)
24
+ gem signin
25
+ # Enter your RubyGems username and password
26
+ # This creates ~/.gem/credentials
27
+ ```
28
+
29
+ Or manually create `~/.gem/credentials`:
30
+
31
+ ```yaml
32
+ ---
33
+ :rubygems_api_key: YOUR_API_KEY_HERE
34
+ ```
35
+
36
+ ### 2. Update Gemspec
37
+
38
+ Make sure `email_digest.gemspec` has correct metadata:
39
+
40
+ ```ruby
41
+ spec.name = 'email_digest'
42
+ spec.version = EmailDigest::VERSION
43
+ spec.authors = ['Your Name'] # Update this
44
+ spec.email = ['your.email@example.com'] # Update this
45
+ spec.homepage = 'https://github.com/yourusername/email_digest' # Update this
46
+ ```
47
+
48
+ ## Publishing Process
49
+
50
+ ### Step 1: Prepare Your Gem
51
+
52
+ ```bash
53
+ # Make sure you're in the gem directory
54
+ cd ~/workspace/email_digest
55
+
56
+ # Check your files
57
+ git status
58
+
59
+ # Update version if needed (in lib/email_digest/version.rb)
60
+ # Update CHANGELOG.md
61
+
62
+ # Commit changes
63
+ git add .
64
+ git commit -m "Prepare for release v1.0.0"
65
+ ```
66
+
67
+ ### Step 2: Build the Gem
68
+
69
+ ```bash
70
+ # Build the gem
71
+ gem build email_digest.gemspec
72
+
73
+ # This creates: email_digest-1.0.0.gem
74
+ # Verify the file was created
75
+ ls -lh *.gem
76
+ ```
77
+
78
+ ### Step 3: Test Locally (Optional but Recommended)
79
+
80
+ ```bash
81
+ # Install locally to test
82
+ gem install ./email_digest-1.0.0.gem
83
+
84
+ # Or test in a Rails app
85
+ # In Gemfile: gem 'email_digest', path: '../email_digest'
86
+ ```
87
+
88
+ ### Step 4: Push to GitHub
89
+
90
+ ```bash
91
+ # Tag the release
92
+ git tag -a v1.0.0 -m "Release version 1.0.0"
93
+ git push origin main
94
+ git push origin v1.0.0
95
+ ```
96
+
97
+ ### Step 5: Publish to RubyGems
98
+
99
+ ```bash
100
+ # Push to RubyGems
101
+ gem push email_digest-1.0.0.gem
102
+
103
+ # You'll see:
104
+ # Pushing gem to https://rubygems.org...
105
+ # Successfully registered gem: email_digest
106
+ ```
107
+
108
+ ### Step 6: Verify Publication
109
+
110
+ ```bash
111
+ # Check on RubyGems
112
+ # Visit: https://rubygems.org/gems/email_digest
113
+
114
+ # Or via command line
115
+ gem search email_digest
116
+ gem info email_digest
117
+ ```
118
+
119
+ ## Updating the Gem
120
+
121
+ ### For Bug Fixes (Patch Version: 1.0.0 → 1.0.1)
122
+
123
+ ```bash
124
+ # 1. Update version
125
+ # In lib/email_digest/version.rb: VERSION = '1.0.1'
126
+
127
+ # 2. Update CHANGELOG.md
128
+
129
+ # 3. Commit
130
+ git add .
131
+ git commit -m "Bump version to 1.0.1"
132
+
133
+ # 4. Tag
134
+ git tag -a v1.0.1 -m "Version 1.0.1"
135
+ git push origin main
136
+ git push origin v1.0.1
137
+
138
+ # 5. Build and push
139
+ gem build email_digest.gemspec
140
+ gem push email_digest-1.0.1.gem
141
+ ```
142
+
143
+ ### For New Features (Minor Version: 1.0.0 → 1.1.0)
144
+
145
+ ```bash
146
+ # Same process, but update to 1.1.0
147
+ ```
148
+
149
+ ### For Breaking Changes (Major Version: 1.0.0 → 2.0.0)
150
+
151
+ ```bash
152
+ # Same process, but update to 2.0.0
153
+ # Make sure to document breaking changes in CHANGELOG
154
+ ```
155
+
156
+ ## Versioning Guidelines
157
+
158
+ Follow [Semantic Versioning](https://semver.org/):
159
+
160
+ - **MAJOR** (1.0.0 → 2.0.0): Incompatible API changes
161
+ - **MINOR** (1.0.0 → 1.1.0): New functionality, backwards compatible
162
+ - **PATCH** (1.0.0 → 1.0.1): Bug fixes, backwards compatible
163
+
164
+ ## Best Practices
165
+
166
+ ### Before Publishing
167
+
168
+ - [ ] Update version number
169
+ - [ ] Update CHANGELOG.md
170
+ - [ ] Run tests (if you have them)
171
+ - [ ] Test installation in a clean environment
172
+ - [ ] Test generator: `rails generate email_digest:install`
173
+ - [ ] Verify all dependencies are correct
174
+ - [ ] Check gemspec metadata
175
+
176
+ ### After Publishing
177
+
178
+ - [ ] Verify gem appears on RubyGems.org
179
+ - [ ] Test installation: `gem install email_digest`
180
+ - [ ] Test in a fresh Rails app
181
+ - [ ] Update GitHub release notes
182
+ - [ ] Announce on relevant channels (if applicable)
183
+
184
+ ## Troubleshooting
185
+
186
+ ### "You have already pushed this version"
187
+
188
+ If you try to push the same version twice:
189
+
190
+ ```bash
191
+ # Update version and try again
192
+ # Or yank the version first (if needed)
193
+ gem yank email_digest -v 1.0.0
194
+ ```
195
+
196
+ ### "Authentication required"
197
+
198
+ ```bash
199
+ # Re-authenticate
200
+ gem signin
201
+ ```
202
+
203
+ ### "Invalid gemspec"
204
+
205
+ ```bash
206
+ # Validate your gemspec
207
+ gem spec email_digest.gemspec
208
+
209
+ # Check for syntax errors
210
+ ruby -c email_digest.gemspec
211
+ ```
212
+
213
+ ## Yanking a Version (Removing)
214
+
215
+ If you need to remove a published version:
216
+
217
+ ```bash
218
+ # Yank a specific version
219
+ gem yank email_digest -v 1.0.0
220
+
221
+ # Note: This doesn't delete it, just marks it as yanked
222
+ # Users who already installed it can still use it
223
+ ```
224
+
225
+ ## Using Your Published Gem
226
+
227
+ Once published, others can use it:
228
+
229
+ ```ruby
230
+ # In Gemfile
231
+ gem 'email_digest'
232
+
233
+ # Then
234
+ bundle install
235
+ rails generate email_digest:install
236
+ rails db:migrate
237
+ ```
238
+
239
+ ## Maintenance
240
+
241
+ ### Regular Updates
242
+
243
+ - Keep dependencies updated
244
+ - Monitor for security vulnerabilities
245
+ - Respond to issues on GitHub
246
+ - Update documentation as needed
247
+
248
+ ### Release Checklist Template
249
+
250
+ ```markdown
251
+ ## Release Checklist
252
+
253
+ - [ ] Update version in lib/email_digest/version.rb
254
+ - [ ] Update CHANGELOG.md
255
+ - [ ] Run tests
256
+ - [ ] Update README if needed
257
+ - [ ] Commit changes
258
+ - [ ] Create git tag
259
+ - [ ] Build gem
260
+ - [ ] Test gem installation
261
+ - [ ] Push to GitHub
262
+ - [ ] Publish to RubyGems
263
+ - [ ] Verify on RubyGems.org
264
+ - [ ] Create GitHub release
265
+ ```
266
+
267
+ ## Resources
268
+
269
+ - RubyGems: https://rubygems.org
270
+ - RubyGems Guides: https://guides.rubygems.org
271
+ - Semantic Versioning: https://semver.org
272
+ - Bundler Best Practices: https://bundler.io/v2.0/guides/creating_gem.html