class T::Props::Decorator
def model_inherited(child)
def model_inherited(child) child.extend(T::Props::ClassMethods) child = T.cast(child, T.all(Module, T::Props::ClassMethods)) child.plugins.concat(decorated_class.plugins) decorated_class.plugins.each do |mod| # NB: apply_class_methods must not be an instance method on the decorator itself, # otherwise we'd have to call child.decorator here, which would create the decorator # before any `decorator_class` override has a chance to take effect (see the comment below). T::Props::Plugin::Private.apply_class_methods(mod, child) end props.each do |name, rules| copied_rules = rules.dup # NB: Calling `child.decorator` here is a timb bomb that's going to give someone a really bad # time. Any class that defines props and also overrides the `decorator_class` method is going # to reach this line before its override take effect, turning it into a no-op. child.decorator.add_prop_definition(name, copied_rules) # It's a bit tricky to support `prop_get` hooks added by plugins without # sacrificing the `attr_reader` fast path or clobbering customized getters # defined manually on a child. # # To make this work, we _do_ clobber getters defined on the child, but only if: # (a) it's needed in order to support a `prop_get` hook, and # (b) it's safe because the getter was defined by this file. # unless rules[:without_accessors] if child.decorator.method(:prop_get).owner != method(:prop_get).owner && child.instance_method(name).source_location&.first == __FILE__ child.send(:define_method, name) do T.unsafe(self.class).decorator.prop_get(self, name, rules) end end unless rules[:immutable] if child.decorator.method(:prop_set).owner != method(:prop_set).owner && child.instance_method("#{name}=").source_location&.first == __FILE__ child.send(:define_method, "#{name}=") do |val| T.unsafe(self.class).decorator.prop_set(self, name, val, rules) end end end end end end