Module: Module::DbC

Defined in:
lib/module/dbc.rb

Defined Under Namespace

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

Constant Summary collapse

DbCOptArg =
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)

Options Hash (options):

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

    same as :precondition

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

    same as :postcondition

  • :return (Proc, #===)

    same as :postcondition

  • :invariant (Proc)

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