envalit 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9a43f0111d8c9a7a9a472808e4e44ab866772c41459eb1779ed1dec6f945470a
4
+ data.tar.gz: faa3025386293f3e5a93ff189204353c15442a400bcc17c14fdce28e30ed8bf9
5
+ SHA512:
6
+ metadata.gz: 95abf06a5c7e809dcb97a89a6efefd81095baa42e118a5ce0a0aa474a2bebd8a0eeaf94002c17b1de113dc3770c29dc3851701ddd1562aa357833efe8b6a6c0d
7
+ data.tar.gz: c2700ee464c75219a4f32831180742b642cda50cb5c875ace9afd24e055ab6c8643421de6349466a8f3d5fc87e628ca4c3e678fde00206b08d511b3bbef21e5b
data/.mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "3.4.2"
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,50 @@
1
+ # AllCops
2
+ AllCops:
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+ TargetRubyVersion: 3.0
6
+
7
+ # Style/FrozenStringLiteralComment
8
+ Style/FrozenStringLiteralComment:
9
+ Enabled: true
10
+ EnforcedStyle: always
11
+
12
+ # Layout/LineLength
13
+ Layout/LineLength:
14
+ Max: 120
15
+
16
+ # Naming/FileName
17
+ Naming/FileName:
18
+ Enabled: true
19
+ Exclude:
20
+ - 'spec/**/*'
21
+ - 'test/**/*'
22
+
23
+ # Layout/IndentationWidth
24
+ Layout/IndentationWidth:
25
+ Width: 2
26
+
27
+ # Style/StringLiterals
28
+ Style/StringLiterals:
29
+ EnforcedStyle: double_quotes
30
+
31
+ # Lint/UselessAssignment
32
+ Lint/UselessAssignment:
33
+ Enabled: true
34
+
35
+ # Metrics/AbcSize
36
+ Metrics/AbcSize:
37
+ Max: 100
38
+
39
+ # Metrics/BlockLength
40
+ Metrics/BlockLength:
41
+ Exclude:
42
+ - 'spec/**/*.rb'
43
+
44
+ # Metrics/MethodLength
45
+ Metrics/MethodLength:
46
+ Max: 100
47
+
48
+ # Naming/AccessorMethodName
49
+ Naming/AccessorMethodName:
50
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
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
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2024-04-08
11
+
12
+ ### Added
13
+ - Initial release
14
+ - Environment variable validation with type checking (string, integer, boolean, float)
15
+ - Support for required/optional variables
16
+ - Support for strict validation mode
17
+ - Support for default values
18
+ - Support for variable descriptions
19
+ - Automatic .env file loading
20
+ - Rails generator for easy setup
21
+ - Colored error messages for better visibility
22
+ - Helpful error messages with fix suggestions
23
+ - Integration with dotenv for .env file handling
24
+
25
+ [Unreleased]: https://github.com/bugloper/envalit/compare/v0.1.0...HEAD
26
+ [0.1.0]: https://github.com/bugloper/envalit/releases/tag/v0.1.0
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ gem "pry"
8
+ gem "rake", "~> 13.0"
9
+ gem "rspec", "~> 3.0"
10
+ gem "rubocop"
11
+ gem "ruby-lsp", "~> 0.23.6"
12
+ gem "webmock"
data/Gemfile.lock ADDED
@@ -0,0 +1,117 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ envalit (0.1.0)
5
+ dotenv (~> 3.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.8.7)
11
+ public_suffix (>= 2.0.2, < 7.0)
12
+ ast (2.4.2)
13
+ bigdecimal (3.1.9)
14
+ coderay (1.1.3)
15
+ crack (1.0.0)
16
+ bigdecimal
17
+ rexml
18
+ diff-lcs (1.6.0)
19
+ dotenv (3.1.7)
20
+ hashdiff (1.1.2)
21
+ json (2.10.2)
22
+ language_server-protocol (3.17.0.4)
23
+ lint_roller (1.1.0)
24
+ logger (1.6.6)
25
+ method_source (1.1.0)
26
+ parallel (1.26.3)
27
+ parser (3.3.7.1)
28
+ ast (~> 2.4.1)
29
+ racc
30
+ prism (1.3.0)
31
+ pry (0.15.2)
32
+ coderay (~> 1.1)
33
+ method_source (~> 1.0)
34
+ public_suffix (6.0.1)
35
+ racc (1.8.1)
36
+ rainbow (3.1.1)
37
+ rake (13.2.1)
38
+ rbs (3.8.1)
39
+ logger
40
+ regexp_parser (2.10.0)
41
+ rexml (3.4.1)
42
+ rspec (3.13.0)
43
+ rspec-core (~> 3.13.0)
44
+ rspec-expectations (~> 3.13.0)
45
+ rspec-mocks (~> 3.13.0)
46
+ rspec-core (3.13.3)
47
+ rspec-support (~> 3.13.0)
48
+ rspec-expectations (3.13.3)
49
+ diff-lcs (>= 1.2.0, < 2.0)
50
+ rspec-support (~> 3.13.0)
51
+ rspec-mocks (3.13.2)
52
+ diff-lcs (>= 1.2.0, < 2.0)
53
+ rspec-support (~> 3.13.0)
54
+ rspec-support (3.13.2)
55
+ rubocop (1.74.0)
56
+ json (~> 2.3)
57
+ language_server-protocol (~> 3.17.0.2)
58
+ lint_roller (~> 1.1.0)
59
+ parallel (~> 1.10)
60
+ parser (>= 3.3.0.2)
61
+ rainbow (>= 2.2.2, < 4.0)
62
+ regexp_parser (>= 2.9.3, < 3.0)
63
+ rubocop-ast (>= 1.38.0, < 2.0)
64
+ ruby-progressbar (~> 1.7)
65
+ unicode-display_width (>= 2.4.0, < 4.0)
66
+ rubocop-ast (1.38.1)
67
+ parser (>= 3.3.1.0)
68
+ rubocop-capybara (2.22.1)
69
+ lint_roller (~> 1.1)
70
+ rubocop (~> 1.72, >= 1.72.1)
71
+ rubocop-factory_bot (2.27.1)
72
+ lint_roller (~> 1.1)
73
+ rubocop (~> 1.72, >= 1.72.1)
74
+ rubocop-rake (0.7.1)
75
+ lint_roller (~> 1.1)
76
+ rubocop (>= 1.72.1)
77
+ rubocop-rspec (2.31.0)
78
+ rubocop (~> 1.40)
79
+ rubocop-capybara (~> 2.17)
80
+ rubocop-factory_bot (~> 2.22)
81
+ rubocop-rspec_rails (~> 2.28)
82
+ rubocop-rspec_rails (2.29.1)
83
+ rubocop (~> 1.61)
84
+ ruby-lsp (0.23.11)
85
+ language_server-protocol (~> 3.17.0)
86
+ prism (>= 1.2, < 2.0)
87
+ rbs (>= 3, < 4)
88
+ sorbet-runtime (>= 0.5.10782)
89
+ ruby-progressbar (1.13.0)
90
+ sorbet-runtime (0.5.11930)
91
+ unicode-display_width (3.1.4)
92
+ unicode-emoji (~> 4.0, >= 4.0.4)
93
+ unicode-emoji (4.0.4)
94
+ webmock (3.25.1)
95
+ addressable (>= 2.8.0)
96
+ crack (>= 0.3.2)
97
+ hashdiff (>= 0.4.0, < 2.0.0)
98
+ yard (0.9.37)
99
+
100
+ PLATFORMS
101
+ arm64-darwin-24
102
+ ruby
103
+
104
+ DEPENDENCIES
105
+ envalit!
106
+ pry
107
+ rake (~> 13.0)
108
+ rspec (~> 3.0)
109
+ rubocop
110
+ rubocop-rake (~> 0.6)
111
+ rubocop-rspec (~> 2.26)
112
+ ruby-lsp (~> 0.23.6)
113
+ webmock
114
+ yard (~> 0.9)
115
+
116
+ BUNDLED WITH
117
+ 2.6.5
data/README.md ADDED
@@ -0,0 +1,192 @@
1
+ # Envalit
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/envalit.svg)](https://badge.fury.io/rb/envalit)
4
+ [![Build Status](https://github.com/bugloper/envalit/workflows/Ruby%20Setup/badge.svg)](https://github.com/bugloper/envalit/actions)
5
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ Envalit is a powerful Ruby gem for managing and validating environment variables in your applications. It provides a flexible way to ensure all required environment variables are present and correctly typed, with options for warnings or strict validation.
8
+
9
+ ## Features
10
+
11
+ - 🔍 **Type Validation**: Support for string, integer, boolean, and float types
12
+ - 🚨 **Validation Modes**: Choose between warning or strict error modes
13
+ - 📝 **Default Values**: Set fallback values for optional variables
14
+ - 📚 **Documentation**: Add descriptions to document your environment variables
15
+ - 🌈 **Colored Output**: Clear, colorized error messages for better visibility
16
+ - 🚀 **Rails Integration**: Easy setup with Rails generator
17
+ - 📁 **Dotenv Integration**: Automatic loading of `.env` files
18
+ - 💡 **Helpful Errors**: Clear error messages with fix suggestions
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ ```ruby
25
+ gem 'envalit'
26
+ ```
27
+
28
+ And then execute:
29
+
30
+ ```bash
31
+ $ bundle install
32
+ ```
33
+
34
+ Or install it yourself as:
35
+
36
+ ```bash
37
+ $ gem install envalit
38
+ ```
39
+
40
+ ### Rails Setup
41
+
42
+ If you're using Rails, you can use our generator to quickly set up your environment configuration:
43
+
44
+ ```bash
45
+ $ rails generate envalit:install
46
+ ```
47
+
48
+ This will:
49
+ 1. Create `config/initializers/envalit.rb` with example configurations
50
+ 2. Create `.env.example` with sample environment variables
51
+
52
+ ## Usage
53
+
54
+ ### Basic Configuration
55
+
56
+ ```ruby
57
+ require 'envalit'
58
+
59
+ Envalit.configure do |config|
60
+ # Required variable with type validation
61
+ config.register "DATABASE_URL",
62
+ required: true,
63
+ strict: true,
64
+ description: "PostgreSQL connection URL"
65
+
66
+ # Optional variable with default value
67
+ config.register "PORT",
68
+ type: :integer,
69
+ default: 3000,
70
+ description: "Application port number"
71
+
72
+ # Boolean flag
73
+ config.register "DEBUG_MODE",
74
+ type: :boolean,
75
+ default: false,
76
+ description: "Enable debug mode"
77
+ end
78
+
79
+ # Normal validation (warns about missing variables)
80
+ Envalit.validate
81
+
82
+ # Strict validation (raises errors for missing variables)
83
+ Envalit.validate!
84
+ ```
85
+
86
+ ### Validation Modes
87
+
88
+ Envalit provides two validation modes:
89
+
90
+ 1. **Normal Mode** (`validate`):
91
+ - Warns about missing required variables
92
+ - Raises errors only for variables marked as `strict: true`
93
+ - Good for development environments
94
+
95
+ ```ruby
96
+ Envalit.validate # Prints warnings but doesn't halt execution
97
+ ```
98
+
99
+ 2. **Strict Mode** (`validate!`):
100
+ - Raises errors for any missing required variables
101
+ - Ignores the `strict` setting
102
+ - Recommended for production environments
103
+
104
+ ```ruby
105
+ Envalit.validate! # Raises ValidationError if any required variables are missing
106
+ ```
107
+
108
+ ### Type Validation
109
+
110
+ Envalit supports multiple data types:
111
+
112
+ ```ruby
113
+ Envalit.configure do |config|
114
+ # String (default)
115
+ config.register "API_KEY",
116
+ required: true
117
+
118
+ # Integer
119
+ config.register "PORT",
120
+ type: :integer,
121
+ default: 3000
122
+
123
+ # Boolean
124
+ config.register "CACHE_ENABLED",
125
+ type: :boolean,
126
+ default: true
127
+
128
+ # Float
129
+ config.register "TIMEOUT",
130
+ type: :float,
131
+ required: true,
132
+ default: 5.5
133
+ end
134
+ ```
135
+
136
+ ### Rails Integration
137
+
138
+ In your Rails application, create an initializer:
139
+
140
+ ```ruby
141
+ # config/initializers/envalit.rb
142
+ Envalit.configure do |config|
143
+ # Critical Variables
144
+ config.register "SECRET_KEY_BASE",
145
+ required: true,
146
+ strict: true
147
+
148
+ # Optional Settings
149
+ config.register "CACHE_TTL",
150
+ type: :integer,
151
+ default: 3600,
152
+ description: "Cache time-to-live in seconds"
153
+ end
154
+
155
+ # Validate based on environment
156
+ if Rails.env.production?
157
+ Envalit.validate! # Strict validation in production
158
+ else
159
+ Envalit.validate # Normal validation in development/test
160
+ end
161
+ ```
162
+
163
+ ### Error Messages
164
+
165
+ Envalit provides clear, colorized error messages:
166
+
167
+ ```
168
+ Missing required environment variables:
169
+ - DATABASE_URL
170
+ Type: string
171
+ Description: PostgreSQL connection URL
172
+
173
+ To fix this:
174
+ 1. Create a .env file in your project root if it doesn't exist
175
+ 2. Copy values from .env.example to your .env file:
176
+ cp .env.example .env
177
+ 3. Update the values in your .env file with your actual configuration
178
+ ```
179
+
180
+ ## Development
181
+
182
+ 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.
183
+
184
+ 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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
185
+
186
+ ## Contributing
187
+
188
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bugloper/envalit. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](CODE_OF_CONDUCT.md).
189
+
190
+ ## License
191
+
192
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ desc "Run the test suite and code style checks"
11
+ task default: %i[spec rubocop]
12
+
13
+ desc "Prepare for release"
14
+ task :prepare_release do
15
+ puts "\n== Checking git status =="
16
+ status = `git status --porcelain`
17
+ if status.empty?
18
+ puts "Working directory is clean"
19
+ else
20
+ abort "Error: There are uncommitted changes. Please commit or stash them first."
21
+ end
22
+
23
+ puts "\n== Running tests =="
24
+ Rake::Task["spec"].invoke
25
+
26
+ puts "\n== Running RuboCop =="
27
+ Rake::Task["rubocop"].invoke
28
+
29
+ puts "\n== Checking version =="
30
+ version = Envalit::VERSION
31
+ puts "Current version: #{version}"
32
+
33
+ puts "\n== Checking CHANGELOG.md =="
34
+ changelog = File.read("CHANGELOG.md")
35
+ abort "Error: Version #{version} not found in CHANGELOG.md" unless changelog.include?(version)
36
+ puts "CHANGELOG.md contains version #{version}"
37
+
38
+ puts "\nAll checks passed! You can now run 'rake release'"
39
+ end
40
+
41
+ # Override the release task to run checks first
42
+ Rake::Task["release"].enhance(["prepare_release"])
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "envalid"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ require "irb"
11
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/envalit.gemspec ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/envalit/version"
4
+
5
+ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
6
+ spec.name = "envalit"
7
+ spec.version = Envalit::VERSION
8
+ spec.authors = ["bugloper"]
9
+ spec.email = ["bugloper@gmail.com"]
10
+
11
+ spec.summary = "A simple Ruby gem for validating environment variables"
12
+ spec.description = "Envalit provides a straightforward way to ensure all required environment variables are present, with options to warn or crash when they're missing."
13
+ spec.homepage = "https://github.com/bugloper/envalit"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.6.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/bugloper/envalit"
19
+ spec.metadata["changelog_uri"] = "https://github.com/bugloper/envalit/blob/main/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ # Dependencies
33
+ spec.add_dependency "dotenv", "~> 3.1"
34
+
35
+ # Development dependencies
36
+ spec.add_development_dependency "rake", "~> 13.0"
37
+ spec.add_development_dependency "rspec", "~> 3.12"
38
+ spec.add_development_dependency "rubocop", "~> 1.60"
39
+ spec.add_development_dependency "rubocop-rake", "~> 0.6"
40
+ spec.add_development_dependency "rubocop-rspec", "~> 2.26"
41
+ spec.add_development_dependency "yard", "~> 0.9"
42
+
43
+ # For more information and examples about making a new gem, check out our
44
+ # guide at: https://bundler.io/guides/creating_gem.html
45
+ spec.metadata["rubygems_mfa_required"] = "false"
46
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module Envalit
6
+ module Generators
7
+ # Generator for installing Envalit configuration files in a Ruby/Rails application.
8
+ #
9
+ # This generator creates:
10
+ # - An initializer file with example environment variable configurations
11
+ # - A .env.example file with sample environment variable values
12
+ #
13
+ # @example Installing via Rails generator
14
+ # rails generate envalit:install
15
+ #
16
+ # @example Installing via Rake task
17
+ # rake envalit:install
18
+ #
19
+ # The generated files provide a starting point for:
20
+ # - Configuring required environment variables
21
+ # - Setting up type validations
22
+ # - Defining default values
23
+ # - Documenting environment requirements
24
+ class InstallGenerator < Rails::Generators::Base
25
+ source_root File.expand_path("templates", __dir__)
26
+ desc "Creates an Envalit initializer for your application"
27
+
28
+ # Copies the Envalit initializer template to the application.
29
+ #
30
+ # Creates a new initializer file at config/initializers/envalit.rb
31
+ # with example configurations for common environment variables.
32
+ #
33
+ # @return [void]
34
+ def copy_initializer
35
+ template "envalit.rb", "config/initializers/envalit.rb"
36
+ end
37
+
38
+ # Copies the example environment file template.
39
+ #
40
+ # Creates a .env.example file in the application root
41
+ # with sample values matching the initializer configuration.
42
+ #
43
+ # @return [void]
44
+ def copy_example_env
45
+ template "example.env", ".env.example"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Envalit Configuration
4
+ # This file contains the configuration for your environment variables.
5
+ # You can specify requirements, types, and other validations for each variable.
6
+
7
+ Envalit.configure do |config|
8
+ # # Database Configuration
9
+ # config.register "DATABASE_URL",
10
+ # required: true,
11
+ # strict: true, # Will raise an error if missing
12
+ # description: "PostgreSQL connection URL"
13
+
14
+ # # Application Settings
15
+ # config.register "APP_HOST",
16
+ # required: true,
17
+ # default: "localhost",
18
+ # description: "Application host name"
19
+
20
+ # config.register "PORT",
21
+ # required: true,
22
+ # type: :integer,
23
+ # default: 3000,
24
+ # description: "Port number for the application"
25
+
26
+ # # API Keys and Secrets
27
+ # config.register "SECRET_KEY_BASE",
28
+ # required: true,
29
+ # strict: true,
30
+ # description: "Rails secret key base"
31
+
32
+ # config.register "API_KEY",
33
+ # required: false, # Optional variable
34
+ # description: "External API key"
35
+
36
+ # # Feature Flags
37
+ # config.register "ENABLE_FEATURE_X",
38
+ # type: :boolean,
39
+ # default: false,
40
+ # description: "Enable experimental feature X"
41
+
42
+ # # Email Configuration
43
+ # config.register "SMTP_SERVER",
44
+ # required: true,
45
+ # description: "SMTP server hostname"
46
+
47
+ # config.register "SMTP_PORT",
48
+ # required: true,
49
+ # type: :integer,
50
+ # default: 587,
51
+ # description: "SMTP server port"
52
+
53
+ # # Cache Configuration
54
+ # config.register "REDIS_URL",
55
+ # required: false,
56
+ # default: "redis://localhost:6379/0",
57
+ # description: "Redis connection URL"
58
+
59
+ # Add your own environment variables here
60
+ # Example:
61
+ # config.register "YOUR_ENV_VAR",
62
+ # required: true|false,
63
+ # strict: true|false,
64
+ # type: :string|:integer|:boolean|:float,
65
+ # default: "default_value",
66
+ # description: "Description of the variable"
67
+ end
68
+
69
+ # Validate environment variables based on environment
70
+ if Rails.env.production?
71
+ # In production, use validate! to ensure all required variables are present
72
+ Envalit.validate!
73
+ else
74
+ # In development and test, use validate to warn about missing variables
75
+ Envalit.validate
76
+ end
@@ -0,0 +1,23 @@
1
+ # Database Configuration
2
+ DATABASE_URL=postgres://username:password@localhost:5432/database_name
3
+
4
+ # Application Settings
5
+ APP_HOST=localhost
6
+ PORT=3000
7
+
8
+ # API Keys and Secrets
9
+ SECRET_KEY_BASE=your_secret_key_base_here
10
+ API_KEY=your_api_key_here
11
+
12
+ # Feature Flags
13
+ ENABLE_FEATURE_X=false
14
+
15
+ # Email Configuration
16
+ SMTP_SERVER=smtp.example.com
17
+ SMTP_PORT=587
18
+
19
+ # Cache Configuration
20
+ REDIS_URL=redis://localhost:6379/0
21
+
22
+ # Add your own environment variables here
23
+ # YOUR_ENV_VAR=value
@@ -0,0 +1,204 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dotenv"
4
+
5
+ module Envalit
6
+ # The Loader class handles environment variable registration, validation, and type checking.
7
+ #
8
+ # This class is responsible for:
9
+ # - Managing the schema of environment variables
10
+ # - Loading variables from .env files
11
+ # - Validating variable presence and types
12
+ # - Handling default values
13
+ # - Providing warnings or errors for missing variables
14
+ #
15
+ # @example Basic usage with type validation
16
+ # loader = Loader.new(Rails.root)
17
+ # loader.register("PORT", type: :integer, default: 3000)
18
+ # loader.register("DEBUG", type: :boolean, default: false)
19
+ # loader.validate
20
+ #
21
+ # @example Strict validation with required variables
22
+ # loader = Loader.new(Dir.pwd)
23
+ # loader.register("API_KEY", required: true, strict: true)
24
+ # loader.register("API_URL", required: true)
25
+ # # Will raise ValidationError if API_KEY is missing
26
+ # # Will warn if API_URL is missing
27
+ # loader.validate
28
+ #
29
+ # @api private
30
+ class Loader
31
+ # Valid types for environment variables
32
+ VALID_TYPES = %i[string integer boolean float].freeze
33
+
34
+ # ANSI color codes for error formatting
35
+ ERROR_COLOR = "\e[1;91m" # bright red and bold
36
+ RESET_COLOR = "\e[0m"
37
+ HIGHLIGHT_COLOR = "\e[1m" # bold
38
+
39
+ # Initializes a new Loader instance.
40
+ #
41
+ # @param app_root [String] The root directory path where .env files are located
42
+ # @param app_root [String, nil] The root directory path where .env files are located. Defaults to Dir.pwd
43
+ def initialize(app_root = Dir.pwd)
44
+ @app_root = app_root
45
+ @schema = {}
46
+ @dotenv_loaded = false
47
+ end
48
+
49
+ # Registers an environment variable with validation options.
50
+ #
51
+ # @param key [String] The environment variable name
52
+ # @param options [Hash] The validation options
53
+ # @option options [Boolean] :required Whether the variable is required
54
+ # @option options [Boolean] :strict Raise error instead of warning for missing required variables
55
+ # @option options [Symbol] :type The variable type (:string, :integer, :boolean, :float)
56
+ # @option options [Object] :default The default value if variable is not set
57
+ # @option options [String] :description Description of the variable's purpose
58
+ #
59
+ # @raise [ArgumentError] If an invalid type is specified
60
+ # @return [void]
61
+ def register(key, options = {})
62
+ validate_options(options)
63
+ set_default_value(key, options[:default]) if options.key?(:default)
64
+ @schema[key] = options
65
+ end
66
+
67
+ # Validates all registered environment variables.
68
+ #
69
+ # This method:
70
+ # - Loads variables from .env file if not already loaded
71
+ # - Checks for missing required variables
72
+ # - Validates variable types
73
+ # - Raises errors for strict violations
74
+ # - Warns about non-strict violations
75
+ #
76
+ # @param strict [Boolean] Whether to enforce strict mode for all required variables
77
+ # @raise [ValidationError] If a strict required variable is missing
78
+ # @raise [ValidationError] If a variable's value doesn't match its specified type
79
+ # @return [void]
80
+ def validate(strict: false)
81
+ load_dotenv unless @dotenv_loaded
82
+ check_missing_variables(strict)
83
+ check_invalid_types
84
+ end
85
+
86
+ # Validates all registered environment variables in strict mode.
87
+ # All missing required variables will raise an error, regardless of their strict setting.
88
+ #
89
+ # @raise [ValidationError] If any required variable is missing
90
+ # @return [void]
91
+ def validate!
92
+ validate(strict: true)
93
+ end
94
+
95
+ # Loads environment variables from a .env file.
96
+ #
97
+ # @return [void]
98
+ def load
99
+ load_dotenv
100
+ end
101
+
102
+ private
103
+
104
+ # Validates the options passed to register.
105
+ #
106
+ # @param options [Hash] The options to validate
107
+ # @raise [ArgumentError] If an invalid type is specified
108
+ # @return [void]
109
+ def validate_options(options)
110
+ type = options[:type]
111
+ return unless type && !VALID_TYPES.include?(type)
112
+
113
+ raise ArgumentError,
114
+ "#{ERROR_COLOR}Invalid type: #{type}. Valid types are: #{VALID_TYPES.join(', ')}#{RESET_COLOR}"
115
+ end
116
+
117
+ # Sets the default value for an environment variable if it's not already set.
118
+ #
119
+ # @param key [String] The environment variable name
120
+ # @param default [Object] The default value
121
+ # @return [void]
122
+ def set_default_value(key, default)
123
+ return if ENV.key?(key)
124
+
125
+ case default
126
+ when true, false
127
+ default.to_s
128
+ end
129
+ ENV[key] = default.to_s
130
+ end
131
+
132
+ # Checks for missing required variables and handles them according to their strict setting.
133
+ #
134
+ # @param strict [Boolean] Whether to enforce strict mode for all required variables
135
+ # @return [void]
136
+ def check_missing_variables(strict = false) # rubocop:disable Style/OptionalBooleanParameter
137
+ missing_vars = @schema.select { |key, opts| opts[:required] && ENV[key].nil? }
138
+ return if missing_vars.empty?
139
+
140
+ message = "#{ERROR_COLOR}Missing required environment variables:#{RESET_COLOR}\n"
141
+ missing_vars.each do |key, opts|
142
+ message += "#{HIGHLIGHT_COLOR} - #{key}#{RESET_COLOR}\n"
143
+ message += " Type: #{opts[:type]}\n" if opts[:type]
144
+ message += " Description: #{opts[:description]}\n" if opts[:description]
145
+ end
146
+
147
+ message += "\n#{HIGHLIGHT_COLOR}To fix this:#{RESET_COLOR}\n"
148
+ message += "1. Create a .env file in your project root if it doesn't exist\n"
149
+
150
+ if File.exist?(".env.example")
151
+ message += "2. Copy values from .env.example to your .env file:\n"
152
+ message += " #{HIGHLIGHT_COLOR}cp .env.example .env#{RESET_COLOR}\n"
153
+ message += "3. Update the values in your .env file with your actual configuration"
154
+ else
155
+ message += "2. Add the missing variables to your .env file:\n"
156
+ missing_vars.each_key do |key|
157
+ message += " #{HIGHLIGHT_COLOR}#{key}=your_#{key.downcase}_here#{RESET_COLOR}\n"
158
+ end
159
+ end
160
+
161
+ raise ValidationError, message if strict || missing_vars.any? { |_, opts| opts[:strict] }
162
+
163
+ warn message
164
+ end
165
+
166
+ # Validates the types of all environment variables against their schema.
167
+ #
168
+ # @raise [ValidationError] If a variable's value doesn't match its specified type
169
+ # @return [void]
170
+ def check_invalid_types
171
+ invalid_vars = @schema.select do |key, opts|
172
+ next false if ENV[key].nil?
173
+
174
+ case opts[:type]
175
+ when :integer
176
+ !ENV[key].match?(/\A-?\d+\z/)
177
+ when :float
178
+ !ENV[key].match?(/\A-?\d*\.?\d+\z/)
179
+ when :boolean
180
+ !%w[true false].include?(ENV[key].downcase)
181
+ else
182
+ false
183
+ end
184
+ end
185
+
186
+ return if invalid_vars.empty?
187
+
188
+ key, opts = invalid_vars.first
189
+ raise ValidationError, "#{ERROR_COLOR}Invalid type for #{key}: expected #{opts[:type]}#{RESET_COLOR}"
190
+ end
191
+
192
+ # Loads environment variables from a .env file.
193
+ #
194
+ # @return [void]
195
+ def load_dotenv
196
+ dotenv_path = File.join(@app_root, ".env")
197
+ Dotenv.load(dotenv_path) if File.exist?(dotenv_path)
198
+ @dotenv_loaded = true
199
+ end
200
+ end
201
+
202
+ # Error raised when environment variable validation fails
203
+ class ValidationError < StandardError; end
204
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module Envalit
6
+ class Railtie < Rails::Railtie # rubocop:disable Style/Documentation
7
+ generators do
8
+ require_relative "generators/install_generator"
9
+ Rails::Generators.hide_namespaces "envalit"
10
+ Rails::Generators::Base.include Envalit::Generators
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envalit
4
+ VERSION = "0.1.0"
5
+ end
data/lib/envalit.rb ADDED
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "envalit/version"
4
+ require_relative "envalit/loader"
5
+ require_relative "envalit/railtie" if defined?(Rails)
6
+
7
+ # Envalit is a Ruby gem for managing and validating environment variables.
8
+ #
9
+ # It provides a simple and flexible way to:
10
+ # - Register environment variables with validation rules
11
+ # - Set default values for optional variables
12
+ # - Validate variable types (string, integer, boolean, float)
13
+ # - Control validation behavior (warnings vs. strict errors)
14
+ # - Load variables from .env files
15
+ #
16
+ # @example Basic usage
17
+ # Envalit.configure do |config|
18
+ # config.register "DATABASE_URL",
19
+ # required: true,
20
+ # strict: true
21
+ #
22
+ # config.register "PORT",
23
+ # type: :integer,
24
+ # default: 3000
25
+ # end
26
+ #
27
+ # Envalit.validate # Validates all registered variables
28
+ #
29
+ # @example Type validation
30
+ # Envalit.configure do |config|
31
+ # config.register "DEBUG_MODE",
32
+ # type: :boolean,
33
+ # default: false
34
+ #
35
+ # config.register "API_TIMEOUT",
36
+ # type: :float,
37
+ # required: true
38
+ # end
39
+ #
40
+ # @see Envalit::Loader for detailed implementation
41
+ module Envalit
42
+ class << self
43
+ # Configures Envalit with the given block.
44
+ #
45
+ # @yield [self] Yields self for configuration
46
+ # @return [void]
47
+ def configure
48
+ @loader ||= Loader.new(Dir.pwd)
49
+ yield(self)
50
+ end
51
+
52
+ # Registers an environment variable with validation options.
53
+ #
54
+ # @param key [String] The environment variable name
55
+ # @param options [Hash] The validation options
56
+ # @option options [Boolean] :required Whether the variable is required
57
+ # @option options [Boolean] :strict Raise error instead of warning for missing required variables
58
+ # @option options [Symbol] :type The variable type (:string, :integer, :boolean, :float)
59
+ # @option options [Object] :default The default value if variable is not set
60
+ # @option options [String] :description Description of the variable's purpose
61
+ # @return [void]
62
+ def register(key, options = {})
63
+ @loader.register(key, options)
64
+ end
65
+
66
+ # Validates all registered environment variables.
67
+ # Missing required variables will trigger warnings unless they are marked as strict.
68
+ #
69
+ # @raise [ValidationError] If a strict required variable is missing
70
+ # @return [void]
71
+ def validate
72
+ @loader.validate
73
+ end
74
+
75
+ # Validates all registered environment variables in strict mode.
76
+ # All missing required variables will raise an error, regardless of their strict setting.
77
+ #
78
+ # @raise [ValidationError] If any required variable is missing
79
+ # @return [void]
80
+ def validate!
81
+ @loader.validate!
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,26 @@
1
+ ## Describe your changes
2
+ Please include a detailed summary of the changes and the related issue. Also include any relevant context. List any dependencies that are required for this change.
3
+
4
+ ## Related issue number
5
+ Mention the related issue number (e.g., "Fixes #123").
6
+
7
+ ## Checklist before requesting a review
8
+ - [ ] I have performed a self-review of my code
9
+ - [ ] Ran code linter and addressed any issues.
10
+ - [ ] My code follows the style guidelines of this project
11
+ - [ ] I have commented my code, particularly in hard-to-understand areas
12
+ - [ ] I have made corresponding changes to the documentation
13
+ - [ ] I have added tests that prove my fix is effective or that my feature works
14
+ - [ ] New and existing unit tests pass locally with my changes
15
+
16
+ ## Type of change
17
+ _You may remove the options that are no relevant._
18
+
19
+ - [ ] Bug fix (non-breaking change which fixes an issue)
20
+ - [ ] New feature (non-breaking change which adds functionality)
21
+ - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
22
+ - [ ] This change requires a documentation update
23
+ - [ ] Code style update (formatting, local variables)
24
+ - [ ] Refactoring (no functional changes, no API changes)
25
+ - [ ] Build & CI Related Changes
26
+ - [ ] Others (Please describe)
data/sig/envalid.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Envalid
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: envalit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - bugloper
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-04-08 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: dotenv
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rspec
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.12'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.12'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rubocop
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.60'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.60'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rubocop-rake
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.6'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.6'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rubocop-rspec
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.26'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.26'
96
+ - !ruby/object:Gem::Dependency
97
+ name: yard
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '0.9'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.9'
110
+ description: Envalit provides a straightforward way to ensure all required environment
111
+ variables are present, with options to warn or crash when they're missing.
112
+ email:
113
+ - bugloper@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".mise.toml"
119
+ - ".rspec"
120
+ - ".rubocop.yml"
121
+ - ".ruby-version"
122
+ - CHANGELOG.md
123
+ - Gemfile
124
+ - Gemfile.lock
125
+ - README.md
126
+ - Rakefile
127
+ - bin/console
128
+ - bin/setup
129
+ - envalit.gemspec
130
+ - lib/envalit.rb
131
+ - lib/envalit/generators/install_generator.rb
132
+ - lib/envalit/generators/templates/envalit.rb
133
+ - lib/envalit/generators/templates/example.env
134
+ - lib/envalit/loader.rb
135
+ - lib/envalit/railtie.rb
136
+ - lib/envalit/version.rb
137
+ - pull_request_template.md
138
+ - sig/envalid.rbs
139
+ homepage: https://github.com/bugloper/envalit
140
+ licenses:
141
+ - MIT
142
+ metadata:
143
+ homepage_uri: https://github.com/bugloper/envalit
144
+ source_code_uri: https://github.com/bugloper/envalit
145
+ changelog_uri: https://github.com/bugloper/envalit/blob/main/CHANGELOG.md
146
+ rubygems_mfa_required: 'false'
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 2.6.0
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubygems_version: 3.6.6
162
+ specification_version: 4
163
+ summary: A simple Ruby gem for validating environment variables
164
+ test_files: []