# encoding: utf-8 require "transproc" require_relative "assertion/transprocs/inflector" require_relative "assertion/transprocs/list" require_relative "assertion/invalid_error" require_relative "assertion/attributes" require_relative "assertion/messages" require_relative "assertion/state" require_relative "assertion/base" require_relative "assertion/inversion" require_relative "assertion/inverter" require_relative "assertion/guard" # The module allows declaring assertions (assertions) about various objects, # and apply (validate) them to concrete data. # # @example # # config/locales/en.yml # # --- # # en: # # assertion: # # adult: # # right: "%{name} is an adult (age %{age})" # # wrong: "%{name} is a child (age %{age})" # # Adult = Assertion.about :name, :age do # age >= 18 # end # # joe = { name: 'Joe', age: 13 } # Adult[joe].validate! # # => #<Assertion::InvalidError @messages=["Joe is a child (age 13)"]> # # jane = { name: 'Jane', age: 22 } # Adult.not[jane].validate! # # => #<Assertion::InvalidError @messages=["Jane is an adult (age 22)"] # # @api public # module Assertion # Builds the subclass of `Assertion::Base` with predefined `attributes` # and implementation of the `#check` method. # # @example # IsMan = Assertion.about :age, :gender do # (age >= 18) && (gender == :male) # end # # # This is the same as: # class IsMan < Assertion::Base # attribute :age, :gender # # def check # (age >= 18) && (gender == :male) # end # end # # @param [Symbol, Array<Symbol>] attributes # The list of attributes for the new assertion # @param [Proc] block # The content for the `check` method # # @return [Class] The specific assertion class # def self.about(*attributes, &block) klass = Class.new(Base) klass.public_send(:attribute, attributes) klass.__send__(:define_method, :check, &block) if block_given? klass end # Builds the subclass of `Assertion::Guard` with given attribute # (alias for the `object`) and implementation of the `#state` method. # # @example # VoterOnly = Assertion.guards :user do # IsAdult[user.attributes] & IsCitizen[user.attributes] # end # # # This is the same as: # class VoterOnly < Assertion::Guard # alias_method :user, :object # # def state # IsAdult[user.attributes] & IsCitizen[user.attributes] # end # end # # @param [Symbol] attribute # The alias for the `object` attribute # @param [Proc] block # The content for the `state` method # # @return [Class] The specific guard class # def self.guards(attribute = nil, &block) klass = Class.new(Guard) klass.public_send(:attribute, attribute) if attribute klass.__send__(:define_method, :state, &block) if block_given? klass end end # module Assertion