class Tapioca::Dsl::Compilers::ActiveModelAttributes

~~~
end
def name=(name); end
sig { params(name: T.nilable(::String)).returns(T.nilable(::String)) }
def name; end
sig { returns(T.nilable(::String)) }
class Shop
# typed: true
~~~rbi
this compiler will produce an RBI file with the following content:
~~~
end
attribute :name, :string
include ActiveModel::Attributes
class Shop
~~~rb
For example, with the following class:
classes that use [‘ActiveModel::Attributes`](edgeapi.rubyonrails.org/classes/ActiveModel/Attributes/ClassMethods.html).
`Tapioca::Dsl::Compilers::ActiveModelAttributes` decorates RBI files for all

def attribute_methods_for_constant

def attribute_methods_for_constant
  patterns = if constant.respond_to?(:attribute_method_patterns)
    # https://github.com/rails/rails/pull/44367
    constant.attribute_method_patterns
  else
    T.unsafe(constant).attribute_method_matchers
  end
  patterns.flat_map do |pattern|
    constant.attribute_types.filter_map do |name, value|
      next unless handle_method_pattern?(pattern)
      [pattern.method_name(name), type_for(value)]
    end
  end
end

def decorate

def decorate
  attribute_methods = attribute_methods_for_constant
  return if attribute_methods.empty?
  root.create_path(constant) do |klass|
    attribute_methods.each do |method, attribute_type|
      generate_method(klass, method, attribute_type)
    end
  end
end

def gather_constants

def gather_constants
  all_classes.grep(::ActiveModel::Attributes::ClassMethods)
end

def generate_method(klass, method, type)

def generate_method(klass, method, type)
  if method.end_with?("=")
    parameter = create_param("value", type: type)
    klass.create_method(
      method,
      parameters: [parameter],
      return_type: type,
    )
  else
    klass.create_method(method, return_type: type)
  end
end

def handle_method_pattern?(pattern)

def handle_method_pattern?(pattern)
  target = if pattern.respond_to?(:method_missing_target)
    # Pre-Rails 6.0, the field is named "method_missing_target"
    T.unsafe(pattern).method_missing_target
  elsif pattern.respond_to?(:target)
    # Rails 6.0+ has renamed the field to "target"
    pattern.target
  else
    # https://github.com/rails/rails/pull/44367/files
    T.unsafe(pattern).proxy_target
  end
  HANDLED_METHOD_TARGETS.include?(target.to_s)
end

def type_for(attribute_type_value)

def type_for(attribute_type_value)
  case attribute_type_value
  when ActiveModel::Type::Boolean
    as_nilable_type("T::Boolean")
  when ActiveModel::Type::Date
    as_nilable_type("::Date")
  when ActiveModel::Type::DateTime, ActiveModel::Type::Time
    as_nilable_type("::Time")
  when ActiveModel::Type::Decimal
    as_nilable_type("::BigDecimal")
  when ActiveModel::Type::Float
    as_nilable_type("::Float")
  when ActiveModel::Type::Integer
    as_nilable_type("::Integer")
  when ActiveModel::Type::String
    as_nilable_type("::String")
  else
    type = Helpers::ActiveModelTypeHelper.type_for(attribute_type_value)
    type = as_nilable_type(type) if Helpers::ActiveModelTypeHelper.assume_nilable?(attribute_type_value)
    type
  end
end