Class: Tapioca::Dsl::Compilers::Shrine

Inherits:
Tapioca::Dsl::Compiler
  • Object
show all
Includes:
RBIHelper
Defined in:
lib/tapioca/dsl/compilers/shrine.rb

Overview

‘Tapioca::Dsl::Compilers::Shrine` decorates RBI files for classes that include a `Shrine::Attachment` module provided by the `shrine` gem. github.com/shrinerb/shrine

For example, with the following model: ~~~rb class Photo < ActiveRecord::Base

include ImageUploader::Attachment(:image)

end ~~~

This compiler will generate the following RBI: ~~~rbi class Photo

include ShrineGeneratedMethods
extend ShrineGeneratedClassMethods

module ShrineGeneratedClassMethods
  sig { params(options: T.untyped).returns(::Shrine::Attacher) }
  def image_attacher(**options); end
end

module ShrineGeneratedMethods
  sig { returns(T.nilable(::Shrine::UploadedFile)) }
  def image; end

  sig { params(value: T.untyped).returns(T.untyped) }
  def image=(value); end

  sig { params(options: T.untyped).returns(T.nilable(::Shrine::Attacher)) }
  def image_attacher(**options); end

  sig { returns(T::Boolean) }
  def image_changed?; end

  sig { params(args: T.untyped, options: T.untyped).returns(T.nilable(String)) }
  def image_url(*args, **options); end
end

end ~~~

Constant Summary collapse

InstanceMethodModuleName =
"ShrineGeneratedMethods"
ClassMethodModuleName =
"ShrineGeneratedClassMethods"
ConstantType =
type_member { { fixed: T.class_of(Object) } }

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.gather_constantsObject



60
61
62
63
64
# File 'lib/tapioca/dsl/compilers/shrine.rb', line 60

def gather_constants
  all_classes.select do |klass|
    klass.ancestors.any? { |ancestor| ancestor.is_a?(::Shrine::Attachment) }
  end
end

Instance Method Details

#decorateObject

: -> void



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
# File 'lib/tapioca/dsl/compilers/shrine.rb', line 69

def decorate
  attachments = shrine_attachments(constant)
  return if attachments.empty?

  root.create_path(constant) do |klass|
    instance_module = RBI::Module.new(InstanceMethodModuleName)
    class_module = RBI::Module.new(ClassMethodModuleName)

    attachments.each do |attachment|
      name = attachment.attachment_name

      # Filter to methods that follow shrine's naming convention (<name> or <name>= or <name>_*).
      # This excludes method overrides like `reload` from the ActiveRecord plugin.
      attachment.instance_methods(false).sort
        .filter { |m| m == name || m == :"#{name}=" || m.start_with?("#{name}_") }
        .each do |method_name|
        method_obj = attachment.instance_method(method_name)
        instance_module.create_method(
          method_name.to_s,
          parameters: compile_parameters(method_obj),
          return_type: return_type_for(name, method_name),
        )
      end

      # Class method from entity plugin:
      #   .<name>_attacher - returns a class-level attacher instance
      next unless constant.respond_to?(:"#{name}_attacher")

      class_method_obj = constant.method(:"#{name}_attacher")
      class_module.create_method(
        "#{name}_attacher",
        parameters: compile_parameters(class_method_obj),
        return_type: "::Shrine::Attacher",
      )
    end

    klass << instance_module
    klass.create_include(InstanceMethodModuleName)
    klass << class_module
    klass.create_extend(ClassMethodModuleName)
  end
end