Verifly v0.2

Build Status

This gem consists of several dependent components, which all could be used standalone. The most important one is Verifier, but understanding Applicator and ApplicatorWithOptions helps understand its API. The least important one, ClassBuilder, is only used in private APIs, but its own API is public


$ gem install verifly

and then in code

require 'verifly'



Abstract =
  extend Verifly::ClassBuilder::Mixin

  class WithString < self
    def self.build_class(x)
      self if x.is_a?(String)

  Generic =

  self.buildable_classes = [WithString, Generic]
  # or, vice versa
  def self.buildable_classes
    [WithString, Generic]
end"foo") # =>"foo") # =>"foo")

or see lib/verifier/applicator.rb

Why don't just use Uber::Builder? (Uber is cool, you should try it) There are two reasons: firstly, it is an unnecessary dependency. We dont want npm hell, do we? Uber::Builder realy does not do much work, it's just a pattern. Secondly, this implementation looks more clear to me, because children are deciding whether they will handle arguments, not parents.

So to use it, you have to:

  1. Write some classes with duck type .class_builder(*args)

  2. Invoke[<%= array_of_classes %>]).call(*args)

  3. ????


It's simple and clear, but not very sugary. So, otherwise, you may do following:

  1. Write an abstract class

  2. Extend Verifly::ClassBuilder::Mixin

  3. Inherit from the abstract class in different implementations

  4. If some implementations have common ancestors (not including the abstract class), you can implement common ancestor's .build_class in terms of super (i.e. def self.build_class(x); super if x.is_a?(String); end)

  5. Change .build_class of other classes like self if .... Don't change default implementation's .build_class

  6. Setup .buildable_classes on the abstract class, mentioning only direct chldren if you done step 4

  7. Optionally redefine .build in abstract class, if you want to separate build_class and constructor params

  8. Use .build instead of new


Applicator is designed to wrap applications of applicable objects around some binding in some context


object = :bar), object, {}) # => :bar'foo', object, {}) # => :bar'context', object, {}) # => {}> { foo }, object, {}) # => :bar>(context) { context[foo] }, object, bar: :baz) # => :baz, object, {}) # => true

foo = :bar, binding, {}) # => :bar'', binding, {}) # => :bar

Applicator is good, but in most cases ApplicatorWithOptions would be a better option.


ApplicatorWithOptions is an applicator with options. The options are if: and unless:. Same as in ActiveModel::Validations, they are applied to the same binding. Main action is executed only if if: evaluates to truthy and unless: evaluates to falsey.

See examples:, if: -> { true }).call(binding, {}) # => foo, if: -> (context) { context[:bar] })
  .call(binding, { bar: true }) # => foo, if: { bar: true }).call(binding, :bar) # => foo, unless: -> { true })
  .call(binding, {}) # => nil, unless: -> (context) { context[:bar] })
  .call(binding, { bar: true }) # => foo, unless: { bar: true })
  .call(binding, :bar) # => nil


The last, but the most interesting component is Verifier. Verifiers use ApplciatorWithOptions to execute generic procedures. Procedures should call message! if they want to yield something. Note that you should implement message! by yourself (in terms of super)

class MyVerifier < Verifly::Verifier
  Message =
  verify :foo, if: { foo: true }


  def message!(text)
    super { }

  def foo
    message!('Something is wrong') if Fixnum != Bignum

In addition to Applicator's power, you also can nest your verifiers to split the logic

class MyVerifier < Verifly::Verifier
  Message =
  verify_with ChildVerifier, if: -> (context) { cotnext[:foo] }


  def message!(text)
    super { }

class ChildVerifier < MyVerifier
  verify %q(message!("it's alive!"))