lib/tapioca/compilers/dsl/smart_properties.rb in tapioca-0.4.27 vs lib/tapioca/compilers/dsl/smart_properties.rb in tapioca-0.5.0
- old
+ new
@@ -1,10 +1,8 @@
# typed: strict
# frozen_string_literal: true
-require "parlour"
-
begin
require "smart_properties"
rescue LoadError
# means SmartProperties is not installed,
# so let's not even define the generator.
@@ -53,61 +51,53 @@
# def published?; end
#
# sig { params(published: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
# def published=(published); end
#
- # ssig { returns(T.nilable(T::Boolean)) }
+ # sig { returns(T.nilable(T::Boolean)) }
# def enabled; end
#
# sig { params(enabled: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
# def enabled=(enabled); end
# end
# ~~~
class SmartProperties < Base
extend T::Sig
- sig do
- override
- .params(
- root: Parlour::RbiGenerator::Namespace,
- constant: T.class_of(::SmartProperties)
- )
- .void
- end
+ sig { override.params(root: RBI::Tree, constant: T.class_of(::SmartProperties)).void }
def decorate(root, constant)
properties = T.let(
T.unsafe(constant).properties,
::SmartProperties::PropertyCollection
)
return if properties.keys.empty?
instance_methods = constant.instance_methods(false).map(&:to_s).to_set
- root.path(constant) do |k|
+ root.create_path(constant) do |k|
properties.values.each do |property|
generate_methods_for_property(k, property) do |method_name|
!instance_methods.include?(method_name.to_sym)
end
end
end
end
sig { override.returns(T::Enumerable[Module]) }
def gather_constants
- classes = T.cast(ObjectSpace.each_object(Class), T::Enumerable[Class])
- classes.select do |c|
+ all_classes.select do |c|
c < ::SmartProperties
end.reject do |c|
- c.name.nil? || c == ::SmartProperties::Validations::Ancestor
+ name_of(c).nil? || c == ::SmartProperties::Validations::Ancestor
end
end
private
sig do
params(
- klass: Parlour::RbiGenerator::Namespace,
+ klass: RBI::Scope,
property: ::SmartProperties::Property,
block: T.proc.params(arg: String).returns(T::Boolean)
).void
end
def generate_methods_for_property(klass, property, &block)
@@ -117,11 +107,11 @@
name = property.name.to_s
method_name = "#{name}="
klass.create_method(
method_name,
- parameters: [Parlour::RbiGenerator::Parameter.new(name, type: type)],
+ parameters: [create_param(name, type: type)],
return_type: type
) if block.call(method_name)
end
klass.create_method(property.reader.to_s, return_type: type) if block.call(property.reader.to_s)
@@ -132,41 +122,39 @@
[false, true],
].freeze, T::Array[[T::Boolean, T::Boolean]])
sig { params(property: ::SmartProperties::Property).returns(String) }
def type_for(property)
- converter = property.converter
+ converter, accepter, required = property.to_h.fetch_values(
+ :converter,
+ :accepter,
+ :required,
+ )
+
return "T.untyped" if converter
- accepter = property.accepter
-
type = if accepter.nil? || accepter.respond_to?(:to_proc)
"T.untyped"
elsif accepter == Array
"T::Array[T.untyped]"
elsif BOOLEANS.include?(accepter)
"T::Boolean"
elsif Array(accepter).all? { |a| a.is_a?(Module) }
accepters = Array(accepter)
- types = accepters.map { |mod| name_of(mod) }.join(', ')
+ types = accepters.map { |mod| T.must(qualified_name_of(mod)) }.join(", ")
types = "T.any(#{types})" if accepters.size > 1
types
else
"T.untyped"
end
- required_attr = property.instance_variable_get(:@required)
- required = !required_attr.is_a?(Proc) && !!required_attr
- property_required = type == "T.untyped" || required
- type = "T.nilable(#{type})" unless property_required
+ # Early return for "T.untyped", nothing more to do.
+ return type if type == "T.untyped"
- type
- end
+ might_be_optional = Proc === required || !required
+ type = "T.nilable(#{type})" if might_be_optional
- sig { params(type: Module).returns(String) }
- def name_of(type)
- name = Module.instance_method(:name).bind(type).call
- name.start_with?("::") ? name : "::#{name}"
+ type
end
end
end
end
end