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)
  # This guarantees that the type will remain as T.untyped for attributes in the following form:
  # attribute :name
  # This is because for a generic attribute with no specified type, ActiveModel::Type::Value.new is returned
  return "T.untyped" if attribute_type_value.instance_of?(ActiveModel::Type::Value)
  type = case attribute_type_value
  when ActiveModel::Type::Boolean
    "T::Boolean"
  when ActiveModel::Type::Date
    "::Date"
  when ActiveModel::Type::DateTime, ActiveModel::Type::Time
    "::Time"
  when ActiveModel::Type::Decimal
    "::BigDecimal"
  when ActiveModel::Type::Float
    "::Float"
  when ActiveModel::Type::Integer
    "::Integer"
  when ActiveModel::Type::String
    "::String"
  else
    attribute_type_value.class.name.to_s
  end
  as_nilable_type(type)
end