Skip to content

Instantly share code, notes, and snippets.

@coop
Last active March 26, 2016 14:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save coop/4a035a609fffa74eb4ac to your computer and use it in GitHub Desktop.
Save coop/4a035a609fffa74eb4ac to your computer and use it in GitHub Desktop.

Inferring Schemas From Structs

This is a really quick and dirty example of how you can infer a form schema from a dry-type Struct or Value and how you might use it in a HTTP controller.

require "rspec"
require "json"
require "dry-types"
require "dry-validation"
module Types
include Dry::Types.module
RegionCode = Types::Strict::String.constrained(
format: /\A(au|nz|uk|ie)\z/,
)
end
class OpenSettlement < Dry::Types::Value
attribute :region_code, Types::RegionCode
attribute :period_ending_on, Types::Strict::Date
end
class CommandsController
attr_reader :payload
def initialize(payload)
@payload = payload
end
def call
payload_validator.call(payload).messages
end
private
def payload_validator
command_present = !(command.nil? || command == "")
validator = arg_validator if command_present
@payload_validator ||= Dry::Validation.Form do
key(:command).required
if command_present
key(:args).schema(validator)
else
key(:args).maybe(:hash?)
end
end
end
def arg_validator
arg_validators[command_klass]
end
def arg_validators
@arg_validators ||= Hash.new do |hash, key|
hash[key] = Dry::Validation.Form do
key.schema.each do |attribute, type|
key(attribute).required(type)
end
end
end
end
def command_klass
@command_klass ||= Object.const_get(payload[:command])
end
def command
payload[:command]
end
def args
payload[:args]
end
end
RSpec.describe "command enqueuing" do
it "errors with an empty payload" do
payload = {}
controller = CommandsController.new(payload)
errors = controller.call
expect(errors).to eq(
command: ["is missing"],
args: ["is missing"],
)
end
it "errors when command is missing from payload" do
payload = {
args: {},
}
controller = CommandsController.new(payload)
errors = controller.call
expect(errors).to eq(
command: ["is missing"],
)
end
it "errors with an invalid set of args" do
payload = {
command: "OpenSettlement",
args: {
region_code: "au",
},
}
controller = CommandsController.new(payload)
errors = controller.call
expect(errors).to eq(
args: {
period_ending_on: ["is missing"],
},
)
end
it "validates correct params" do
payload = {
command: "OpenSettlement",
args: {
region_code: "au",
period_ending_on: "2016-03-31",
},
}
controller = CommandsController.new(payload)
errors = controller.call
expect(errors).to be_empty
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment