Module: Rtype

Extended by:
Rtype
Included in:
Rtype
Defined in:
lib/rtype/legacy.rb,
lib/rtype/behavior.rb,
lib/rtype/behavior/and.rb,
lib/rtype/behavior/not.rb,
lib/rtype/behavior/xor.rb,
lib/rtype/behavior/base.rb,
lib/rtype/legacy/version.rb,
lib/rtype/type_signature.rb,
lib/rtype/rtype_component.rb,
lib/rtype/behavior/nilable.rb,
lib/rtype/method_annotator.rb,
lib/rtype/return_type_error.rb,
lib/rtype/behavior/typed_set.rb,
lib/rtype/argument_type_error.rb,
lib/rtype/behavior/typed_hash.rb,
lib/rtype/behavior/float_check.rb,
lib/rtype/behavior/typed_array.rb,
lib/rtype/type_signature_error.rb,
lib/rtype/behavior/integer_check.rb,
lib/rtype/behavior/numeric_check.rb

Defined Under Namespace

Modules: Behavior, Legacy, MethodAnnotator Classes: ArgumentTypeError, ReturnTypeError, RtypeComponent, TypeSignature, TypeSignatureError

Constant Summary collapse

@@type_signatures =

This is just ‘information’ Any change of this doesn’t affect type checking

Hash.new

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.and(*args) ⇒ Object



21
22
23
# File 'lib/rtype/behavior/and.rb', line 21

def self.and(*args)
	Behavior::And[*args]
end

Instance Method Details

#arg_message(idx) ⇒ String

Returns:

  • (String)


142
143
144
# File 'lib/rtype/legacy.rb', line 142

def arg_message(idx)
	"for #{ordinalize_number(idx+1)} argument:"
end

#arg_type_error_message(idx, expected, value) ⇒ String

Returns A error message.

Parameters:

  • idx (Integer)
  • expected

    A type behavior

  • value

Returns:

  • (String)

    A error message

Raises:

  • (ArgumentError)

    If expected is invalid



137
138
139
# File 'lib/rtype/legacy.rb', line 137

def arg_type_error_message(idx, expected, value)
	"#{arg_message(idx)}\n" + type_error_message(expected, value)
end

#assert_arguments_type(expected_args, args) ⇒ void

This method returns an undefined value.

Validates arguments

Parameters:

  • expected_args (Array)

    A type signature for non-keyword arguments

  • args (Array)

Raises:



326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/rtype/legacy.rb', line 326

def assert_arguments_type(expected_args, args)
	e_len = expected_args.length
	# `length.times` is faster than `each_with_index`
	args.length.times do |i|
		break if i >= e_len
		expected = expected_args[i]
		value = args[i]
		unless valid?(expected, value)
			raise ArgumentTypeError, "#{arg_message(i)}\n" + type_error_message(expected, value)
		end
	end
	nil
end

#assert_return_type(expected, result) ⇒ Object



350
351
352
353
354
355
# File 'lib/rtype/legacy.rb', line 350

def assert_return_type(expected, result)
	unless valid?(expected, result)
		raise ReturnTypeError, "for return:\n" + type_error_message(expected, result)
	end
	nil
end

#assert_valid_argument_type_sig_element(sig) ⇒ Object

Checks the type behavior is valid

Parameters:

  • sig

    A type behavior

Raises:



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/rtype/legacy.rb', line 248

def assert_valid_argument_type_sig_element(sig)
	case sig
	when Rtype::Behavior::Base
	when Module
	when Symbol
	when Regexp
	when Range
	when Array
		sig.each do |e|
			assert_valid_argument_type_sig_element(e)
		end
	when Hash
		sig.each_value do |e|
			assert_valid_argument_type_sig_element(e)
		end
	when Proc
	when true
	when false
	when nil
	else
		raise TypeSignatureError, "Invalid type signature: Unknown type behavior #{sig}"
	end
end

#assert_valid_arguments_type_sig(sig) ⇒ Object

Checks the arguments type signature is valid

e.g. ‘[Integer]`, `“value”` are valid (the second is keyword argument signature and ignored in rtype-legacy). `Integer` is invalid.

Parameters:

  • sig

    A arguments type signature

Raises:



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/rtype/legacy.rb', line 223

def assert_valid_arguments_type_sig(sig)
	if sig.is_a?(Array)
		sig = sig.dup
		if sig.last.is_a?(Hash)
			kwargs = sig.pop
		else
			kwargs = {}
		end
		sig.each { |e| assert_valid_argument_type_sig_element(e) }
		unless kwargs.empty?
			raise TypeSignatureError, "Invalid type signature: keyword arguments must be empty"
		end
	elsif sig.is_a?(Hash)
		unless kwargs.empty?
			raise TypeSignatureError, "Invalid type signature: keyword arguments must be empty"
		end
	else
		raise TypeSignatureError, "Invalid type signature: arguments type signature is neither array nor hash"
	end
end

#assert_valid_return_type_sig(sig) ⇒ Object



273
274
275
# File 'lib/rtype/legacy.rb', line 273

def assert_valid_return_type_sig(sig)
	assert_valid_argument_type_sig_element(sig)
end

#assert_valid_type_sig(sig) ⇒ Object

Checks the type signature is valid

e.g. ‘[Integer] => Any` is valid. `[Integer]` or `Any` are invalid

Parameters:

  • sig

    A type signature

Raises:



204
205
206
207
208
209
210
211
212
213
# File 'lib/rtype/legacy.rb', line 204

def assert_valid_type_sig(sig)
	unless sig.is_a?(Hash)
		raise TypeSignatureError, "Invalid type signature: type signature is not hash"
	end
	if sig.empty?
		raise TypeSignatureError, "Invalid type signature: type signature is empty hash"
	end
	assert_valid_arguments_type_sig(sig.first[0])
	assert_valid_return_type_sig(sig.first[1])
end

#define_typed_accessor(owner, name, type_behavior, singleton) ⇒ void

This method returns an undefined value.

Parameters:

  • owner

    Owner of the accessor

  • name (#to_sym)
  • type_behavior

    A type behavior. e.g. Integer

  • singleton (Boolean)

    Whether the method is singleton method

Raises:



89
90
91
92
# File 'lib/rtype/legacy.rb', line 89

def define_typed_accessor(owner, name, type_behavior, singleton)
	define_typed_reader(owner, name, type_behavior, singleton)
	define_typed_writer(owner, name, type_behavior, singleton)
end

#define_typed_method(owner, method_name, type_sig_info, singleton) ⇒ void

This method returns an undefined value.

Makes the method typed

Parameters:

  • owner

    Owner of the method

  • method_name (#to_sym)
  • type_sig_info (Hash)

    A type signature. e.g. ‘[Integer, Float] => Float`

  • singleton (Boolean)

    Whether the method is singleton method

Raises:

  • (ArgumentError)

    If method_name is nil, keyword argument signature is not empty, or singleton is not a boolean

  • (TypeSignatureError)

    If type_sig_info is invalid



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
# File 'lib/rtype/legacy.rb', line 47

def define_typed_method(owner, method_name, type_sig_info, singleton)
	method_name = method_name.to_sym
	raise ArgumentError, "method_name is nil" if method_name.nil?
	raise ArgumentError, "singleton must be a boolean" unless singleton.is_a?(Boolean)
	assert_valid_type_sig(type_sig_info)

	el = type_sig_info.first
	arg_sig = el[0]
	return_sig = el[1]

	if arg_sig.is_a?(Array)
		expected_args = arg_sig.dup
		if expected_args.last.is_a?(Hash)
			kwargs = expected_args.pop
			# empty kwargs signature
		else
			# empty kwargs signature
		end
	elsif arg_sig.is_a?(Hash)
		# empty kwargs signature
		expected_args = []
	end

	sig = TypeSignature.new
	sig.argument_type = arg_sig
	sig.return_type = return_sig
	unless @@type_signatures.key?(owner)
		@@type_signatures[owner] = {}
	end
	@@type_signatures[owner][method_name] = sig

	redefine_method_to_typed(owner, method_name, expected_args, return_sig, singleton)
end

#define_typed_reader(owner, name, type_behavior, singleton) ⇒ void

This method returns an undefined value.

Parameters:

  • owner

    Owner of the getter

  • name (#to_sym)
  • type_behavior

    A type behavior. e.g. Integer

  • singleton (Boolean)

    Whether the method is singleton method

Raises:



102
103
104
105
106
# File 'lib/rtype/legacy.rb', line 102

def define_typed_reader(owner, name, type_behavior, singleton)
	raise ArgumentError, "name is nil" if name.nil?
	valid?(type_behavior, nil)
	define_typed_method owner, name.to_sym, {[] => type_behavior}, singleton
end

#define_typed_writer(owner, name, type_behavior, singleton) ⇒ void

This method returns an undefined value.

Parameters:

  • owner

    Owner of the setter

  • name (#to_sym)
  • type_behavior

    A type behavior. e.g. Integer

  • singleton (Boolean)

    Whether the method is singleton method

Raises:



116
117
118
119
120
# File 'lib/rtype/legacy.rb', line 116

def define_typed_writer(owner, name, type_behavior, singleton)
	raise ArgumentError, "name is nil" if name.nil?
	valid?(type_behavior, nil)
	define_typed_method owner, :"#{name.to_sym}=", {[type_behavior] => Any}, singleton
end

#nilable(*args) ⇒ Object



18
19
20
# File 'lib/rtype/behavior/nilable.rb', line 18

def nilable(*args)
	Behavior::Nilable[*args]
end

#not(*args) ⇒ Object



21
22
23
# File 'lib/rtype/behavior/not.rb', line 21

def not(*args)
	Behavior::Not[*args]
end

#type_error_message(expected, value) ⇒ String

Note:

This method doesn’t check the value is valid

Returns a error message for the pair of type behavior and value

Parameters:

  • expected

    A type behavior

  • value

Returns:

  • (String)

    error message

Raises:



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/rtype/legacy.rb', line 154

def type_error_message(expected, value)
	case expected
	when Rtype::Behavior::Base
		expected.error_message(value)
	when Module
		"Expected #{value.inspect} to be a #{expected}"
	when Symbol
		"Expected #{value.inspect} to respond to :#{expected}"
	when Regexp
		"Expected stringified #{value.inspect} to match regexp #{expected.inspect}"
	when Range
		"Expected #{value.inspect} to be included in range #{expected.inspect}"
	when Array
		arr = expected.map { |e| type_error_message(e, value) }
		arr.join("\nOR ")
	when Hash
		if value.is_a?(Hash)
			arr = []
			expected.each do |k, v|
				if v.is_a?(Array) || v.is_a?(Hash)
					arr << "- #{k} : {\n" + type_error_message(v, value[k]) + "\n}"
				else
					arr << "- #{k} : " + type_error_message(v, value[k])
				end
			end
			"Expected #{value.inspect} to be a hash with #{expected.length} elements:\n" + arr.join("\n")
		else
			"Expected #{value.inspect} to be a hash"
		end
	when Proc
		"Expected #{value.inspect} to return a truthy value for proc #{expected}"
	when true
		"Expected #{value.inspect} to be a truthy value"
	when false
		"Expected #{value.inspect} to be a falsy value"
	when nil # for return
		"Expected #{value.inspect} to be nil"
	else
		raise TypeSignatureError, "Invalid type behavior #{expected}"
	end
end

#type_signaturesHash

Note:

type_signatures[method_name]

This is just ‘information’ Any change of this doesn’t affect type checking

Returns:



127
128
129
# File 'lib/rtype/legacy.rb', line 127

def type_signatures
	@@type_signatures
end

#valid?(expected, value) ⇒ Boolean

Checks the value is valid for the type behavior

Parameters:

  • expected

    A type behavior

  • value

Returns:

Raises:



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/rtype/legacy.rb', line 285

def valid?(expected, value)
	case expected
	when Module
		value.is_a? expected
	when Symbol
		value.respond_to? expected
	when Regexp
		!!(expected =~ value.to_s)
	when Range
		expected.include?(value)
	when Hash
		return false unless value.is_a?(Hash)
		return false unless expected.keys == value.keys
		expected.all? { |k, v| valid?(v, value[k]) }
	when Array
		expected.any? { |e| valid?(e, value) }
	when Proc
		!!expected.call(value)
	when true
		!!value
	when false
		!value
	when Rtype::Behavior::Base
		expected.valid? value
	when nil
		value.nil?
	else
		raise TypeSignatureError, "Invalid type signature: Unknown type behavior #{expected}"
	end
end

#xor(*args) ⇒ Object



22
23
24
# File 'lib/rtype/behavior/xor.rb', line 22

def xor(*args)
	Behavior::Xor[*args]
end