Module: Module::DbC

Defined in:
lib/module/dbc.rb

Defined Under Namespace

Classes: Error, InvariantConditionError, PostConditionError, PostInvariantConditionError, PreConditionError, PreInvariantConditionError

Constant Summary collapse

DbCOptArg =

Returns:

  • (Class)
OptionalArgument.define {
  opt :precondition,
      condition: Proc,
      aliases: [:pre]

  opt :postcondition,
      condition: OR(AND(Proc, ->v{v.arity == 1}), CAN(:===)),
      aliases: [:post, :return]

  opt :invariant,
      condition: Proc
}

Instance Method Summary collapse

Instance Method Details

#dbc(origin, options = {}) ⇒ self (private)

Parameters:

  • origin (Symbol, String, #to_sym)
  • options (Hash) (defaults to: {})

Options Hash (options):

  • :precondition (Proc)
  • :pre (Proc)

    same as :precondition

  • :postcondition (Proc, #===)
  • :post (Proc, #===)

    same as :postcondition

  • :return (Proc, #===)

    same as :postcondition

  • :invariant (Proc)

Returns:

  • (self)

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/module/dbc.rb', line 42

def dbc(origin, options={})
  origin = origin.to_sym
  opts = DbCOptArg.parse options
  
  @_dbc_prependable ||= ( prepend(prependable = Module.new); prependable )

  @_dbc_prependable.module_exec do
    define_method origin do |*args, &block|
      if opts.pre?
        unless instance_exec(*args, &opts.pre)
          raise PreConditionError, "pre-conditon is invalid: (args: #{args.join ','})"
        end
      end

      if opts.invariant?
        unless instance_exec(&opts.invariant)
          raise PreInvariantConditionError, "invariant-conditon is invalid"
        end
      end

      ret = super(*args, &block)

      if opts.invariant?
        unless instance_exec(&opts.invariant)
          raise PostInvariantConditionError, "invariant-conditon is invalid"
        end
      end

      if opts.post?
        if opts.post.kind_of?(Proc)
          unless instance_exec(ret, &opts.post)
            raise PostConditionError, "post-conditon is invalid: (return: #{ret})"
          end
        else
          unless opts.post === ret
            raise PostConditionError, "invalid return value: (return: #{ret}, expected: #{opts.post})"
          end
        end
      end

      ret
    end
  end

  # For readability on ancestors
  unless const_defined? :DbCPrpendable
    const_set :DbCPrpendable, @_dbc_prependable
    private_constant :DbCPrpendable
  end

  self
end