Module: TSpec

Defined in:
lib/tspec.rb,
lib/tspec/core.rb,
lib/tspec/version.rb,
lib/tspec/type_error.rb

Defined Under Namespace

Classes: ArgumentTypeError, NotFoundArgumentNameError, ReturnValueTypeError

Constant Summary collapse

HOOK_EVENT =
%i(call return c_call c_return line)
DEFINE_METHOD_SYMBOLS =
%i(method_added singleton_method_added define_method instance_method method)
VERSION =
'0.5.0'

Class Method Summary collapse

Class Method Details

.check_type(tp) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/tspec/core.rb', line 100

def check_type(tp)
  key = "#{tp.defined_class}::#{tp.method_id}"

  if types = @method_arguments_type_table[key]
    arguments = tp.binding.local_variables

    types.each do |name, type|
      name = arguments.first if name == type.__id__

      unless arguments.include?(name)
        @type_error_flag = true
        raise NotFoundArgumentNameError, "undefined arguments `#{name}' for #{key}"
      end

      value = tp.binding.local_variable_get(name)

      unless value_type_check(value, *type)
        @type_error_flag = true
        if type.instance_of?(Array)
          raise ArgumentTypeError, "##{tp.method_id} '#{name}' variable should be #{type.map(&:inspect).join(' or ')}, but actual '#{value.inspect}' - #{value.class}"
        else
          raise ArgumentTypeError, "##{tp.method_id} '#{name}' variable should be #{type.inspect}, but actual '#{value.inspect}' - #{value.class}"
        end
      end
    end
  end
end

.get_keys(tp, btp) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/tspec/core.rb', line 61

def get_keys(tp, btp)
  ctx = tp.binding
  keys = []

  if %i(instance_method method).include?(btp[:method_id])
    keys << "#{tp.self.owner}::#{tp.self.name}"
  else
    if btp[:method_id] == :singleton_method_added
      klass = btp[:self].singleton_class

      if @module_function_flags[btp[:self]]
        keys << "#{btp[:self]}::#{ctx.receiver}"
      end
    else
      klass = btp[:self]
    end

    keys << "#{klass}::#{ctx.receiver}"
  end

  keys
end

.regist_receive_type(keys, types, type) ⇒ Object



90
91
92
93
94
95
96
97
98
# File 'lib/tspec/core.rb', line 90

def regist_receive_type(keys, types, type)
  keys.each do |key|
    @method_arguments_type_table[key] = types

    if @method_arguments_type_table[key].empty?
      @method_arguments_type_table[key] = { type.__id__ => type }
    end
  end
end

.regist_return_type(keys, types) ⇒ Object



84
85
86
87
88
# File 'lib/tspec/core.rb', line 84

def regist_return_type(keys, types)
  keys.each do |key|
    @method_return_type_table[key] = types
  end
end

.regist_type(method_id, ctx, keys) ⇒ Object



50
51
52
53
54
55
56
57
58
59
# File 'lib/tspec/core.rb', line 50

def regist_type(method_id, ctx, keys)
  types = ctx.local_variable_get(:types)

  case method_id
    when :return
      regist_return_type(keys, types)
    when :receive
      regist_receive_type(keys, types, ctx.local_variable_get(:type))
  end
end

.value_type_check(value, *types) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/tspec/core.rb', line 34

def value_type_check(value, *types)
  types.any? do |type|
    if type.instance_of?(Array)
      return false unless value.instance_of?(Array)

      value.all? do |v|
        type.any? do |t|
          value_type_check(v, t)
        end
      end
    else
      value.instance_of?(type)
    end
  end
end