-
-
Save v-kolesnikov/2aec064ecf292cdf6faa93a4eaaf71c5 to your computer and use it in GitHub Desktop.
ENV validation POC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'dry-validation' | |
class EnvValidation | |
class ENV | |
def inspect | |
ivs = instance_variables.each { |v| "#{v}=#{instance_variable_get(v)}" }.join(', ') | |
"ENV[#{ivs}]" | |
end | |
def to_s | |
"ENV[#{instance_variables.length} values]" | |
end | |
def method_missing(name, *) | |
raise RuntimeError, "Unknown env variable: #{name}" | |
end | |
def merge(kv) | |
dup.tap do |copy| | |
copy.instance_exec do | |
kv.each do |k, v| | |
instance_variable_set(:"@#{k}", v) | |
end | |
end | |
end | |
end | |
end | |
class Result | |
attr_reader :env, :errors | |
def initialize(env, errors) | |
@env = env | |
@errors = errors | |
end | |
def success? | |
@errors.nil? | |
end | |
end | |
class Schema | |
attr_reader :keys, :schema, :defaults | |
def initialize(keys, schema, defaults) | |
@keys = keys | |
@schema = schema | |
@defaults = defaults | |
@struct = Class.new(ENV) do | |
attr_reader *keys | |
singleton_class.send(:define_method, :keys) { keys } | |
define_method(:initialize) do |values| | |
keys.each do |key| | |
instance_variable_set(:"@#{key}", values.fetch(key) { | |
raise "#{key.inspect} not found in #{values.inspect}" | |
}) | |
end | |
end | |
end | |
end | |
def call(values) | |
result = @schema.call(values) | |
if result.success? | |
Result.new(@struct.new(**defaults, **result.to_h), nil) | |
else | |
Result.new(nil, result.messages(full: true).values.flatten(1)) | |
end | |
end | |
end | |
class DSL | |
def call(&block) | |
dsl = self | |
@defaults = {} | |
@keys = [] | |
schema = Dry::Validation.Form do | |
form = self | |
dsl.instance_exec do | |
@form = form | |
instance_exec(&block) | |
end | |
end | |
Schema.new(@keys, schema, @defaults) | |
end | |
def var(name, type: :str, required: true, **other) | |
@keys << name | |
type_predicate = :"#{type}?" | |
if other.key?(:default) | |
@defaults[name] = other[:default] | |
@form.optional(name).filled(type_predicate) | |
elsif required | |
@form.required(name).filled(type_predicate) | |
else | |
@defaults[name] = nil | |
@form.optional(name).filled(type_predicate) | |
end | |
end | |
end | |
class Env | |
def initialize(schema, value) | |
@schema = schema | |
@value = value | |
end | |
end | |
def initialize(&block) | |
@schema = DSL.new.call(&block) | |
end | |
def call(values) | |
@schema.call(values.to_h) | |
end | |
alias_method :[], :call | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative './env_validation' | |
schema = EnvValidation.new do | |
var :IMPRINT_DATABASE_URL, type: :str | |
var :IMPRINT_PRINT_TASK_RESULTS, type: :str, default: '/tmp/imprint/print_tasks' | |
var :IMPRINT_REDIS_PROVIDER, type: :str, default: 'redis://127.0.0.1:6379' | |
var :IMPRINT_SIDEKIQ_TIMEOUT, type: :int, default: 5 | |
var :IMPRINT_PRINT_TASK_MAIL_FROM, type: :str, required: false | |
var :IMPRINT_PRINT_TASK_MAIL_TO, type: :str | |
var :IMPRINT_PRINT_RESULT_HTTP, type: :str, required: false | |
var :IMPRINT_CLEAN_TMP_TIMEOUT, type: :int, default: 1 | |
var :IMPRINT_SMTP_ADDRESS, type: :str, required: false | |
var :IMPRINT_SMTP_PORT, type: :int, required: false | |
var :IMPRINT_SMTP_DOMAIN, type: :str, required: false | |
var :IMPRINT_SMTP_ADDRESS, type: :str, required: false | |
var :IMPRINT_SMTP_USERNAME, type: :str, required: false | |
var :IMPRINT_SMTP_PASSWORD, type: :str, required: false | |
var :WEB_SESSIONS_SECRET, type: :str | |
end | |
result = schema[ENV] | |
if result.success? | |
Imprint = Module.new | |
Imprint::Env = result.env | |
Imprint::Env.class.keys.each do |key| | |
ENV.delete(key.to_s) | |
end | |
else | |
raise RuntimeError, "Environment misconfigured: #{result.errors.join(', ')}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment