module T::Props::GeneratedCodeValidation
def self.assert_equal(expected, actual)
def self.assert_equal(expected, actual) al rror.new("Expected #{expected}, got #{actual}")
def self.self_class_decorator
def self.self_class_decorator or ||= s(:send, s(:send, s(:self), :class), :decorator).freeze
def self.validate_deserialize(source)
def self.validate_deserialize(source) parsed = parse(source) # def %<name>(hash) # ... # end assert_equal(:def, parsed.type) name, args, body = parsed.children assert_equal(:__t_props_generated_deserialize, name) assert_equal(s(:args, s(:arg, :hash)), args) assert_equal(:begin, body.type) init, *prop_clauses, ret = body.children # found = %<prop_count> # ... # found assert_equal(:lvasgn, init.type) init_name, init_val = init.children assert_equal(:found, init_name) assert_equal(:int, init_val.type) assert_equal(s(:lvar, :found), ret) prop_clauses.each_with_index do |clause, i| if i % 2 == 0 validate_deserialize_hash_read(clause) else validate_deserialize_ivar_set(clause) end end end
def self.validate_deserialize_handle_nil(node)
def self.validate_deserialize_handle_nil(node) :str, :sym, :int, :float, :true, :false, :nil safe arg = node.children _missing_from_deserialize(%<prop>) equired_prop_missing_from_deserialize, method) ym, arg.type) self_class_decorator corator.raise_nil_deserialize_error(%<serialized_form>) aise_nil_deserialize_error, method) tr, arg.type) default corator.props_with_defaults.fetch(%<prop>).default end, receiver.type) inner_method, inner_arg = receiver.children _class_decorator, :props_with_defaults), r, etch, inner_method) ym, inner_arg.type) nError.new("Unexpected receiver in nil handler: #{node.inspect}") rror.new("Unexpected nil handler: #{node.inspect}")
def self.validate_deserialize_hash_read(clause)
def self.validate_deserialize_hash_read(clause) alized_form>s] n, clause.type) children name) val.type) rg = val.children r, :hash), receiver) ethod) arg.type)
def self.validate_deserialize_ivar_set(clause)
def self.validate_deserialize_ivar_set(clause) = if val.nil? ss hash.key?(%<serialized_form>s) l>s n, clause.type) l = clause.children _a?(Symbol) rror.new("Unexpected ivar: #{ivar_name}") eser_val.type) else_body = deser_val.children d, s(:lvar, :val), :nil?), condition) , if_body.type) e_nil = if_body.children pdate_found.type) und_if_body, found_else_body = update_found.children found_condition.type) rg = found_condition.children r, :hash), receiver) method) arg.type) ound_if_body) asgn, s(:lvasgn, :found), :-, s(:int, 1)), found_else_body) e_handle_nil(handle_nil) de_effects(else_body, whitelisted_methods_for_deserialize)
def self.validate_lack_of_side_effects(node, whitelisted_methods_by_receiver_type)
def self.validate_lack_of_side_effects(node, whitelisted_methods_by_receiver_type) ause we'll have validated what method has been called :str, :sym, :int, :float, :true, :false, :nil, :self lf are ok ivar instance variables & arguments is ok ren.all? {|c| c.is_a?(Symbol)} nError.new("Unexpected child for #{node.type}: #{node.inspect}") :block, :begin, :if read-only if their contents are read-only h {|c| validate_lack_of_side_effects(c, whitelisted_methods_by_receiver_type) if c} er so check a whitelist *args = node.children e == :send r r.type _of_side_effects(receiver, whitelisted_methods_by_receiver_type) _methods_by_receiver_type[key]&.include?(method) ionError.new("Unexpected method #{method} called on #{receiver.inspect}") | f_side_effects(arg, whitelisted_methods_by_receiver_type) rror.new("Unexpected node type #{node.type}: #{node.inspect}")
def self.validate_serialize(source)
def self.validate_serialize(source) parsed = parse(source) # def %<name>(strict) # ... # end assert_equal(:def, parsed.type) name, args, body = parsed.children assert_equal(:__t_props_generated_serialize, name) assert_equal(s(:args, s(:arg, :strict)), args) assert_equal(:begin, body.type) init, *prop_clauses, ret = body.children # h = {} # ... # h assert_equal(s(:lvasgn, :h, s(:hash)), init) assert_equal(s(:lvar, :h), ret) prop_clauses.each do |clause| validate_serialize_clause(clause) end end
def self.validate_serialize_clause(clause)
def self.validate_serialize_clause(clause) lause.type) else_body = clause.children y>.nil? condition.type) condition.children receiver.type) method) issing_from_serialize(%<prop>) if strict if_body.type) on, if_strict_body, if_strict_else = if_body.children var, :strict), if_strict_condition) d, if_strict_body.type) r, on_strict_method, on_strict_arg = if_strict_body.children on_strict_receiver) uired_prop_missing_from_serialize, on_strict_method) , on_strict_arg.type) if_strict_else) rm>] = ... else_body.type) _key, h_val = else_body.children r, :h), receiver) method) h_key.type) de_effects(h_val, whitelisted_methods_for_serialize)
def self.whitelisted_methods_for_deserialize
def self.whitelisted_methods_for_deserialize s_for_deserialize ||= { ap transform_values transform_keys each_with_object nil? []=}, rialize from_hash deep_clone_object},
def self.whitelisted_methods_for_serialize
def self.whitelisted_methods_for_serialize s_for_serialize ||= { ap transform_values transform_keys each_with_object nil? []= serialize}, ap transform_values transform_keys each_with_object serialize}, ked_serialize deep_clone_object},