Project

typero

0.0
Low commit activity in last 3 years
No release in over a year
Simple and fast ruby type system. Enforce types as Array, Email, Boolean for ruby class instances
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

 Project Readme

Typero - custom types and schema validations

Typero is lib for custom types and schema validations.

Instead of haveing DB schema, you can model your data on real types and geneate db_schema, forms, API validators and other based on given types.

Errors are localized

UserSchema = Typero do
  name       max: 100
  email      :email
  interests  Set[:label]
  location   :point
end

UserSchema.rules           # rules hash
UserSchema.db_schema       # generate DB schema
UserSchema.validate @user  # validate data

You can test single value

good_email = 'DUX@Net.hr'

# will convert email to 'dux@net.hr' (lowercase)
# but it will not raise error
Typero.set :email, good_email

bad_email = 'duxnet.hr'

# raises TypeError
Typero.set :email, bad_email

# will capture error if block provided
Typero.set(:email, bad_email) { |e| @error = e.message }

Schema example

# we can say
UserSchema = Typero do
  # default type is String
  name    min: 3 # default type is String

  # unique info
  email   :email, unique: 'Email is allready registred'

  # min and max length can be defined for numbers and strings
  speed   :float, min:10, max:200

  # use values to define all possible values for a property
  eyes    default: 'blue', values: %w(brown blue green)

  # array type can be defined for any value
  # duplicates are false by defult
  emails  Array[:email], duplicates: true, max_length: 5
  emails  Set[:email]

  # manualy set field and value for protected fields
  set :set, String

  # non required fields are defined by ?
  name? # same as "name required: false"

  # meta attributes can accept any value
  name meta: { foo: :bar, baz: 113 } # ok
  name foo: :bar # ArgumentError

  # you can set custome filed names and error messages
  # @object.sallary = 500 # erorr - 'Plata min is 1000 (500 given)'
  sallary  Integer, name: 'Plata', min: 1000, meta: { en: { min_value_error: 'min is %s (%s given)'} }
  # or without locale prefix
  sallary  Integer, name: 'Plata', min: 1000, meta: { min_value_error: 'min is %s (%s given)' }
end

Installation

to install

gem install typero

or in Gemfile

gem 'typero'

and to use

require 'typero'

Usage

Can be used in plain, ActiveRecord (adapter missing) or Sequel classes.

Can be used as schema validator for custom implementations

schema = Typero do
  email   :email, req: true
  integer :age,   min: 18, max: 150 #, min_error: "Minimal allowed age is 18 years."
end

# or

schema = Typero do
  set :email, req: true, type: :email
  set :age, Integer, min: 18, max: 150
end

schema.validate({ email:'dux@net.hr', age:'40' }) # {}
schema.validate({ email:'duxnet.hr', age:'16' })  # {:email=>"Email is missing @", :age=>"Age min is 18, got 16"}

You can define schemas in many ways

# as a instance
schema = Typero.new { user_name }

# as a instance, shorter
schema = Typero { user_name }

# via cached schema
Typero(:user) { user_name }
schema = Typero(:user)

# via class schema
# Typero(:user) will return UserSchema if one present
UserSchema = Typero do { user_name }
schema = Typero(:user)
UserSchema.validate(@user)
schema.validate(@user)

Nested schemas

# create model
UserSchema = Typero.schema User do
  name
  email  :email
  avatar? :url
end

# reference by model
Typero.schema :api1 do
  # root params
  bar
  foo Integer

  # if hash matches schema, you can filter it on schema
  # user model: UserSchema
  # user schema: UserSchema
  user UserSchema

  # or dynamic declaration
  user do
    name
    email :email
    avatar? :url
  end
end

Advanced - bulk type define and function access

Types can be assigned in a bulk, you just neeed to pass a block and end type with "!"

Example numberos booleans with default false + integers

Notice that any attribute can be a function. If it is, it will be evaluated at runtime inside the scope of given object.

Typero.schema :bulk do
  integer! do
    org_id        req: proc { I18n.t('org.required') }
    prroduct_id?
  do

  false! do
    is_active
    is_locked
  end
end

Built in types

Create custom type

We will create custom type named :label

class Typero::LabelType < Typero::Type
  # default value for blank? == true values
  def default
    nil
  end

  def set
    value do |data|
      data.to_s.gsub(/[^\w\-]/,'')[0,30].downcase
    end
  end

  def validate
    # allow only strnings
    raise TypeError.neew("having unallowed characters") unless @value =~ /^\w+$/
    true
  end
end

Errors

If you want to overload errors or add new languages.

Typero::Type.error :en, :min_length_error, 'minimun lenght is %s, you have defined %s'

Built in errors

ERRORS = {
  en: {
    min_length_error: 'min lenght is %s, you have %s',
    max_length_error: 'max lenght is %s, you have %s',
    min_value_error: 'min is %s, got %s',
    max_value_error: 'max is %s, got %s',
    unallowed_characters_error: 'is having unallowed characters',
    not_in_range: 'Value in not in allowed range (%s)',
    unsupported_boolean: 'Unsupported boolean param value: %s',
    min_date: 'Minimal allowed date is %s',
    max_date: 'Maximal allowed date is %s',
    not_8_chars_error: 'is not having at least 8 characters',
    missing_monkey_error: 'is missing @',
    not_hash_type_error: 'value is not hash type',
    image_not_starting_error: 'URL is not starting with http',
    image_not_image_format: 'URL is not ending with jpg, jpeg, gif, png, svg, webp',
    locale_bad_format: 'Locale "%s" is in bad format (should be xx or xx-xx)',
    not_an_oib_error: 'not in an OIB format',
    invalid_time_zone: 'Invalid time zone',
    url_not_starting_error: 'URL is not starting with http or https',
  }
}