/
type_lookup.rb
101 lines (91 loc) · 2.38 KB
/
type_lookup.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
94
95
96
97
98
99
100
101
module Virtus
# A module that adds type lookup to a class
module TypeLookup
TYPE_FORMAT = /\A(?:[A-Z]\w*)\z/.freeze
# Returns a descendant based on a name or class
#
# @example
# MyClass.determine_type('String') # => MyClass::String
#
# @param [Class, #to_s] class_or_name
# name of a class or a class itself
#
# @return [Class]
# a descendant
#
# @return [nil]
# nil if the type cannot be determined by the class_or_name
#
# @api public
def determine_type(class_or_name)
case class_or_name
when singleton_class
determine_type_from_descendant(class_or_name)
when Class
determine_type_from_primitive(class_or_name)
else
determine_type_from_string(class_or_name.to_s)
end
end
# Return the default primitive supported
#
# @return [Class]
#
# @api private
def primitive
raise NotImplementedError, "#{self}.primitive must be implemented"
end
private
# Return the class given a descendant
#
# @param [Class] descendant
#
# @return [Class]
#
# @api private
def determine_type_from_descendant(descendant)
descendant if descendant < self
end
# Return the class given a primitive
#
# @param [Class] primitive
#
# @return [Class]
#
# @return [nil]
# nil if the type cannot be determined by the primitive
#
# @api private
def determine_type_from_primitive(primitive)
type = nil
descendants.reverse_each do |descendant|
descendant_primitive = descendant.primitive
next unless primitive <= descendant_primitive
type = descendant if type.nil? || type.primitive > descendant_primitive
end
type
end
# Return the class given a string
#
# @param [String] string
#
# @return [Class]
#
# @return [nil]
# nil if the type cannot be determined by the string
#
# @api private
def determine_type_from_string(string)
if string =~ TYPE_FORMAT && const_defined?(string, false)
const_get(string, false)
end
end
if RUBY_VERSION < '1.9' || RUBY_ENGINE == 'rbx'
def determine_type_from_string(string)
if string =~ TYPE_FORMAT && const_defined?(string)
const_get(string)
end
end
end
end # module TypeLookup
end # module Virtus