-
Notifications
You must be signed in to change notification settings - Fork 0
/
typed_variable.rb
129 lines (104 loc) · 2.78 KB
/
typed_variable.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
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
127
128
129
class TypedVariable
include ContractErrors
extend AttrPublicReadPrivateWrite
attr_accessor :value, :on_change
attr_public_read_private_write :type
def initialize(type, value = nil, on_change: nil, **options)
self.type = type
self.value = value || type.default_value
self.on_change = on_change
end
def self.create(type, value = nil, on_change: nil, **options)
type = Type.create(type)
options[:on_change] = on_change
if type.mapping?
MappingType.new(type, value, **options)
elsif type.array?
ArrayType.new(type, value, **options)
elsif type.contract?
ContractType.new(type, value, **options)
else
new(type, value, **options)
end
end
def self.create_or_validate(type, value = nil, on_change: nil)
if value.is_a?(TypedVariable)
unless Type.create(type).can_be_assigned_from?(value.type)
raise VariableTypeError.new("invalid #{type}: #{value.inspect}")
end
value = value.value
end
create(type, value, on_change: on_change)
end
def as_json(args = {})
serialize
end
def serialize
value
end
def to_s
if value.is_a?(String) || value.is_a?(Integer)
value.to_s
else
raise "No string conversion"
end
end
def deserialize(serialized_value)
self.value = serialized_value
end
def value=(new_value)
new_value = type.check_and_normalize_literal(new_value)
if @value != new_value
on_change&.call
if new_value.respond_to?(:on_change=)
new_value.on_change = on_change
end
@value = new_value
end
end
def method_missing(name, *args, &block)
if value.respond_to?(name)
result = value.send(name, *args, &block)
if result.class == value.class
begin
result = type.check_and_normalize_literal(result)
rescue ContractErrors::VariableTypeError => e
if type.is_uint?
result = TypedVariable.create(:uint256, result)
else
raise
end
end
end
result
if name.to_s.end_with?("=") && !%w[>= <=].include?(name.to_s[-2..])
self.value = result if type.is_value_type?
self
else
result
end
else
super
end
end
def respond_to_missing?(name, include_private = false)
value.respond_to?(name, include_private) || super
end
def !=(other)
!(self == other)
end
def ==(other)
if other.is_a?(self.class)
return false unless type.values_can_be_compared?(other.type)
return value == other.value
else
return value == TypedVariable.create(type, other).value
end
end
def hash
[value, type].hash
end
def eql?(other)
hash == other.hash
end
end