diff --git a/lib/sorbet-rails/model_plugins/active_record_attribute.rb b/lib/sorbet-rails/model_plugins/active_record_attribute.rb index 6d45cc5f..3d548ca9 100644 --- a/lib/sorbet-rails/model_plugins/active_record_attribute.rb +++ b/lib/sorbet-rails/model_plugins/active_record_attribute.rb @@ -12,28 +12,38 @@ def generate(root) model_class_rbi = root.create_class(self.model_class_name) model_class_rbi.create_include(attribute_module_name) + model_defined_enums = @model_class.defined_enums + model_defined_aliases = @model_class.send(:attribute_aliases) + column_names = columns_hash.keys + aliases_hash = model_class_columns_to_aliases(column_names, model_defined_aliases) + attributes_and_aliases_hash = model_class_attributes_and_aliases(columns_hash, aliases_hash) + + attributes_and_aliases_hash.sort.each do |attribute_name, column_def| + column_name = column_def.name - columns_hash.sort.each do |column_name, column_def| if model_defined_enums.has_key?(column_name) generate_enum_methods( - root, - model_class_rbi, - attribute_module_rbi, - model_defined_enums, - column_name, - column_def, + root: root, + model_class_rbi: model_class_rbi, + attribute_module_rbi: attribute_module_rbi, + model_defined_enums: model_defined_enums, + attribute_name: attribute_name, + column_name: column_name.presence || attribute_name, + column_def: column_def, ) elsif serialization_coder_for_column(column_name) next # handled by the ActiveRecordSerializedAttribute plugin else column_type = type_for_column_def(column_def) + attribute_module_rbi.create_method( - column_name.to_s, + attribute_name.to_s, return_type: column_type.to_s, ) + attribute_module_rbi.create_method( - "#{column_name}=", + "#{attribute_name}=", parameters: [ Parameter.new("value", type: value_type_for_attr_writer(column_type)) ], @@ -42,29 +52,33 @@ def generate(root) end attribute_module_rbi.create_method( - "#{column_name}?", + "#{attribute_name}?", return_type: "T::Boolean", ) end end + private + sig { params( root: Parlour::RbiGenerator::Namespace, model_class_rbi: Parlour::RbiGenerator::Namespace, attribute_module_rbi: Parlour::RbiGenerator::Namespace, model_defined_enums: T::Hash[String, T::Hash[String, T.untyped]], + attribute_name: String, column_name: String, column_def: T.untyped, ).void } def generate_enum_methods( - root, - model_class_rbi, - attribute_module_rbi, - model_defined_enums, - column_name, - column_def + root:, + model_class_rbi:, + attribute_module_rbi:, + model_defined_enums:, + attribute_name:, + column_name:, + column_def: ) should_skip_setter_getter = false nilable_column = nilable_column?(column_def) @@ -91,11 +105,11 @@ def generate_enum_methods( # add directly to model_class_rbi because they are included # by sorbet's hidden.rbi model_class_rbi.create_method( - "typed_#{column_name}", + "typed_#{attribute_name}", return_type: assignable_type, ) model_class_rbi.create_method( - "typed_#{column_name}=", + "typed_#{attribute_name}=", parameters: [ Parameter.new("value", type: assignable_type) ], @@ -112,11 +126,11 @@ def generate_enum_methods( return_type = "T.nilable(#{return_type})" if nilable_column attribute_module_rbi.create_method( - column_name.to_s, + attribute_name.to_s, return_type: return_type, ) attribute_module_rbi.create_method( - "#{column_name}=", + "#{attribute_name}=", parameters: [ Parameter.new("value", type: assignable_type) ], diff --git a/lib/sorbet-rails/model_plugins/active_record_serialized_attribute.rb b/lib/sorbet-rails/model_plugins/active_record_serialized_attribute.rb index 9b7c7577..7b172c8e 100644 --- a/lib/sorbet-rails/model_plugins/active_record_serialized_attribute.rb +++ b/lib/sorbet-rails/model_plugins/active_record_serialized_attribute.rb @@ -13,7 +13,13 @@ def generate(root) model_class_rbi = root.create_class(self.model_class_name) model_class_rbi.create_include(serialize_module_name) - columns_hash.sort.each do |column_name, column_def| + model_defined_aliases = @model_class.send(:attribute_aliases) + column_names = columns_hash.keys + aliases_hash = model_class_columns_to_aliases(column_names, model_defined_aliases) + attributes_and_aliases_hash = model_class_attributes_and_aliases(columns_hash, aliases_hash) + + attributes_and_aliases_hash.sort.each do |attribute_name, column_def| + column_name = column_def.name || attribute_name serialization_coder = serialization_coder_for_column(column_name) next unless serialization_coder @@ -21,12 +27,12 @@ def generate(root) attr_type = attr_types_for_coder(serialization_coder) serialize_module_rbi.create_method( - column_name.to_s, + attribute_name.to_s, return_type: ColumnType.new(base_type: attr_type, nilable: nilable).to_s, ) serialize_module_rbi.create_method( - "#{column_name}=", + "#{attribute_name}=", parameters: [ Parameter.new('value', type: ColumnType.new(base_type: attr_type, nilable: nilable).to_s) ], @@ -34,7 +40,7 @@ def generate(root) ) serialize_module_rbi.create_method( - "#{column_name}?", + "#{attribute_name}?", return_type: 'T::Boolean', ) end diff --git a/lib/sorbet-rails/model_plugins/base.rb b/lib/sorbet-rails/model_plugins/base.rb index 8800c363..8e246726 100644 --- a/lib/sorbet-rails/model_plugins/base.rb +++ b/lib/sorbet-rails/model_plugins/base.rb @@ -30,6 +30,8 @@ def initialize(model_class, available_classes) @available_classes = T.let(available_classes, T::Set[String]) end + private + sig { params(column_name: String).returns(T.nilable(Class)) } def serialization_coder_for_column(column_name) column_type = @model_class.type_for_attribute(column_name) @@ -44,5 +46,43 @@ def serialization_coder_for_column(column_name) Object end end + + sig { + params(column_names: T::Array[String], aliases: T::Hash[String, String]) + .returns(T::Hash[String, T::Array[String]]) + } + def model_class_columns_to_aliases(column_names, aliases) + column_names.each_with_object({}) do |column_name, columns_to_aliases| + direct_aliases = aliases.select do |_alias_name, attribute_name| + attribute_name == column_name + end.keys + all_aliases = direct_aliases.flat_map do |direct_alias_name| + recursive_keys_for_value(aliases, direct_alias_name).push(direct_alias_name) + end + + columns_to_aliases[column_name] = all_aliases unless all_aliases.empty? + end + end + + sig { params(hash: T::Hash[String, String], initial_value: String).returns(T::Array[String]) } + def recursive_keys_for_value(hash, initial_value) + initial_keys = hash.select { |_key, value| value == initial_value }.keys + initial_keys.flat_map { |key| [key].concat(recursive_keys_for_value(hash, key)) } + end + + sig { + params( + columns_hash: T::Hash[String, T.untyped], + aliases_hash: T::Hash[String, T::Array[String]], + ).returns(T::Hash[String, T.untyped]) + } + def model_class_attributes_and_aliases(columns_hash, aliases_hash) + columns_hash + .each_with_object({}) do |(column_name, column_def), attributes_and_aliases| + [column_name].concat(aliases_hash[column_name] || []).each do |attribute_name| + attributes_and_aliases[attribute_name] = column_def + end + end + end end end diff --git a/spec/generators/rails-template.rb b/spec/generators/rails-template.rb index a8e79395..fff98c44 100644 --- a/spec/generators/rails-template.rb +++ b/spec/generators/rails-template.rb @@ -92,6 +92,9 @@ class SpellBook < ApplicationRecord dark_art: 999, } + alias_attribute :title, :name + alias_attribute :book_category, :book_type + scope :recent, -> { where('created_at > ?', 1.month.ago) } end RUBY @@ -179,6 +182,8 @@ class Professor; end serialize :pets, Array serialize :patronus_characteristics, JSON + alias_attribute :ordinary_wizarding_level_results, :owl_results + has_one :wand has_many :spell_books # habtm which is optional at the db level diff --git a/spec/generators/sorbet_test_cases.rb b/spec/generators/sorbet_test_cases.rb index 27df2767..b8f04ace 100644 --- a/spec/generators/sorbet_test_cases.rb +++ b/spec/generators/sorbet_test_cases.rb @@ -8,6 +8,17 @@ # -- model columns T.assert_type!(wizard.name, T.nilable(String)) +spell_book = wizard.spell_books.first! +T.assert_type!(spell_book, SpellBook) + +# -- alias attributes +T.assert_type!(spell_book.title, String) # standard alias attribute +T.assert_type!(spell_book.book_category, String) # enum alias attribute +T.assert_type!( + wizard.ordinary_wizarding_level_results, # serialized alias attribute + T.nilable(T::Hash[T.untyped, T.untyped]) +) + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -157,7 +168,6 @@ T.assert_type!(Wizard.all.empty?, T::Boolean) # Finder methods -- CollectionProxy -spell_book = wizard.spell_books.first! spell_books = wizard.spell_books T.assert_type!(spell_books.exists?(name: 'Fantastic Beasts'), T::Boolean) T.assert_type!(spell_books.find(spell_book.id), SpellBook) diff --git a/spec/support/v5.2/app/models/spell_book.rb b/spec/support/v5.2/app/models/spell_book.rb index ab2fb0e0..0462a0c7 100644 --- a/spec/support/v5.2/app/models/spell_book.rb +++ b/spec/support/v5.2/app/models/spell_book.rb @@ -14,5 +14,8 @@ class SpellBook < ApplicationRecord dark_art: 999, } + alias_attribute :title, :name + alias_attribute :book_category, :book_type + scope :recent, -> { where('created_at > ?', 1.month.ago) } end diff --git a/spec/support/v5.2/app/models/wizard.rb b/spec/support/v5.2/app/models/wizard.rb index 703a76aa..3b90ffa1 100644 --- a/spec/support/v5.2/app/models/wizard.rb +++ b/spec/support/v5.2/app/models/wizard.rb @@ -52,6 +52,8 @@ class Professor; end serialize :pets, Array serialize :patronus_characteristics, JSON + alias_attribute :ordinary_wizarding_level_results, :owl_results + has_one :wand has_many :spell_books # habtm which is optional at the db level diff --git a/spec/support/v5.2/sorbet_test_cases.rb b/spec/support/v5.2/sorbet_test_cases.rb index b46e810f..711044e8 100644 --- a/spec/support/v5.2/sorbet_test_cases.rb +++ b/spec/support/v5.2/sorbet_test_cases.rb @@ -8,6 +8,17 @@ # -- model columns T.assert_type!(wizard.name, T.nilable(String)) +spell_book = wizard.spell_books.first! +T.assert_type!(spell_book, SpellBook) + +# -- alias attributes +T.assert_type!(spell_book.title, String) # standard alias attribute +T.assert_type!(spell_book.book_category, String) # enum alias attribute +T.assert_type!( + wizard.ordinary_wizarding_level_results, # serialized alias attribute + T.nilable(T::Hash[T.untyped, T.untyped]) +) + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -161,7 +172,6 @@ T.assert_type!(Wizard.all.empty?, T::Boolean) # Finder methods -- CollectionProxy -spell_book = wizard.spell_books.first! spell_books = wizard.spell_books T.assert_type!(spell_books.exists?(name: 'Fantastic Beasts'), T::Boolean) T.assert_type!(spell_books.find(spell_book.id), SpellBook) diff --git a/spec/support/v6.0/app/models/spell_book.rb b/spec/support/v6.0/app/models/spell_book.rb index efe838aa..b0c6c951 100644 --- a/spec/support/v6.0/app/models/spell_book.rb +++ b/spec/support/v6.0/app/models/spell_book.rb @@ -14,5 +14,8 @@ class SpellBook < ApplicationRecord dark_art: 999, } + alias_attribute :title, :name + alias_attribute :book_category, :book_type + scope :recent, -> { where('created_at > ?', 1.month.ago) } end diff --git a/spec/support/v6.0/app/models/wizard.rb b/spec/support/v6.0/app/models/wizard.rb index 33b5f8c5..c1fff751 100644 --- a/spec/support/v6.0/app/models/wizard.rb +++ b/spec/support/v6.0/app/models/wizard.rb @@ -52,6 +52,8 @@ class Professor; end serialize :pets, Array serialize :patronus_characteristics, JSON + alias_attribute :ordinary_wizarding_level_results, :owl_results + has_one :wand has_many :spell_books # habtm which is optional at the db level diff --git a/spec/support/v6.0/sorbet_test_cases.rb b/spec/support/v6.0/sorbet_test_cases.rb index b46e810f..711044e8 100644 --- a/spec/support/v6.0/sorbet_test_cases.rb +++ b/spec/support/v6.0/sorbet_test_cases.rb @@ -8,6 +8,17 @@ # -- model columns T.assert_type!(wizard.name, T.nilable(String)) +spell_book = wizard.spell_books.first! +T.assert_type!(spell_book, SpellBook) + +# -- alias attributes +T.assert_type!(spell_book.title, String) # standard alias attribute +T.assert_type!(spell_book.book_category, String) # enum alias attribute +T.assert_type!( + wizard.ordinary_wizarding_level_results, # serialized alias attribute + T.nilable(T::Hash[T.untyped, T.untyped]) +) + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -161,7 +172,6 @@ T.assert_type!(Wizard.all.empty?, T::Boolean) # Finder methods -- CollectionProxy -spell_book = wizard.spell_books.first! spell_books = wizard.spell_books T.assert_type!(spell_books.exists?(name: 'Fantastic Beasts'), T::Boolean) T.assert_type!(spell_books.find(spell_book.id), SpellBook) diff --git a/spec/support/v6.1/app/models/spell_book.rb b/spec/support/v6.1/app/models/spell_book.rb index efe838aa..b0c6c951 100644 --- a/spec/support/v6.1/app/models/spell_book.rb +++ b/spec/support/v6.1/app/models/spell_book.rb @@ -14,5 +14,8 @@ class SpellBook < ApplicationRecord dark_art: 999, } + alias_attribute :title, :name + alias_attribute :book_category, :book_type + scope :recent, -> { where('created_at > ?', 1.month.ago) } end diff --git a/spec/support/v6.1/app/models/wizard.rb b/spec/support/v6.1/app/models/wizard.rb index 33b5f8c5..c1fff751 100644 --- a/spec/support/v6.1/app/models/wizard.rb +++ b/spec/support/v6.1/app/models/wizard.rb @@ -52,6 +52,8 @@ class Professor; end serialize :pets, Array serialize :patronus_characteristics, JSON + alias_attribute :ordinary_wizarding_level_results, :owl_results + has_one :wand has_many :spell_books # habtm which is optional at the db level diff --git a/spec/support/v6.1/sorbet_test_cases.rb b/spec/support/v6.1/sorbet_test_cases.rb index 63f90832..6600601f 100644 --- a/spec/support/v6.1/sorbet_test_cases.rb +++ b/spec/support/v6.1/sorbet_test_cases.rb @@ -8,6 +8,17 @@ # -- model columns T.assert_type!(wizard.name, T.nilable(String)) +spell_book = wizard.spell_books.first! +T.assert_type!(spell_book, SpellBook) + +# -- alias attributes +T.assert_type!(spell_book.title, String) # standard alias attribute +T.assert_type!(spell_book.book_category, String) # enum alias attribute +T.assert_type!( + wizard.ordinary_wizarding_level_results, # serialized alias attribute + T.nilable(T::Hash[T.untyped, T.untyped]) +) + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -163,7 +174,6 @@ T.assert_type!(Wizard.all.empty?, T::Boolean) # Finder methods -- CollectionProxy -spell_book = wizard.spell_books.first! spell_books = wizard.spell_books T.assert_type!(spell_books.exists?(name: 'Fantastic Beasts'), T::Boolean) T.assert_type!(spell_books.find(spell_book.id), SpellBook) diff --git a/spec/support/v7.0/app/models/spell_book.rb b/spec/support/v7.0/app/models/spell_book.rb index ab2fb0e0..0462a0c7 100644 --- a/spec/support/v7.0/app/models/spell_book.rb +++ b/spec/support/v7.0/app/models/spell_book.rb @@ -14,5 +14,8 @@ class SpellBook < ApplicationRecord dark_art: 999, } + alias_attribute :title, :name + alias_attribute :book_category, :book_type + scope :recent, -> { where('created_at > ?', 1.month.ago) } end diff --git a/spec/support/v7.0/app/models/wizard.rb b/spec/support/v7.0/app/models/wizard.rb index c4ff4e6d..2bbebe64 100644 --- a/spec/support/v7.0/app/models/wizard.rb +++ b/spec/support/v7.0/app/models/wizard.rb @@ -52,6 +52,8 @@ class Professor; end serialize :pets, Array serialize :patronus_characteristics, JSON + alias_attribute :ordinary_wizarding_level_results, :owl_results + has_one :wand has_many :spell_books # habtm which is optional at the db level @@ -61,5 +63,4 @@ class Professor; end belongs_to :school, optional: true scope :recent, -> { where('created_at > ?', 1.month.ago) } - end diff --git a/spec/support/v7.0/sorbet_test_cases.rb b/spec/support/v7.0/sorbet_test_cases.rb index 0d9ffb72..c6ac18c5 100644 --- a/spec/support/v7.0/sorbet_test_cases.rb +++ b/spec/support/v7.0/sorbet_test_cases.rb @@ -8,6 +8,17 @@ # -- model columns T.assert_type!(wizard.name, T.nilable(String)) +spell_book = wizard.spell_books.first! +T.assert_type!(spell_book, SpellBook) + +# -- alias attributes +T.assert_type!(spell_book.title, String) # standard alias attribute +T.assert_type!(spell_book.book_category, String) # enum alias attribute +T.assert_type!( + wizard.ordinary_wizarding_level_results, # serialized alias attribute + T.nilable(T::Hash[T.untyped, T.untyped]) +) + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -162,7 +173,6 @@ T.assert_type!(Wizard.all.empty?, T::Boolean) # Finder methods -- CollectionProxy -spell_book = wizard.spell_books.first! spell_books = wizard.spell_books T.assert_type!(spell_books.exists?(name: 'Fantastic Beasts'), T::Boolean) T.assert_type!(spell_books.find(spell_book.id), SpellBook) diff --git a/spec/test_data/v5.2/expected_spell_book.rbi b/spec/test_data/v5.2/expected_spell_book.rbi index 34baa213..ad5e502e 100644 --- a/spec/test_data/v5.2/expected_spell_book.rbi +++ b/spec/test_data/v5.2/expected_spell_book.rbi @@ -28,6 +28,15 @@ module SpellBook::ActiveRelation_WhereNot end module SpellBook::GeneratedAttributeMethods + sig { returns(String) } + def book_category; end + + sig { params(value: T.any(Integer, String, Symbol)).void } + def book_category=(value); end + + sig { returns(T::Boolean) } + def book_category?; end + sig { returns(String) } def book_type; end @@ -55,6 +64,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def name?; end + sig { returns(String) } + def title; end + + sig { params(value: T.any(String, Symbol)).void } + def title=(value); end + + sig { returns(T::Boolean) } + def title?; end + sig { returns(Integer) } def wizard_id; end @@ -134,6 +152,12 @@ class SpellBook < ApplicationRecord sig { params(args: T.untyped).returns(SpellBook::ActiveRecord_Relation) } def self.unclassified(*args); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + sig { returns(SpellBook::BookType) } def typed_book_type; end diff --git a/spec/test_data/v5.2/expected_squib.rbi b/spec/test_data/v5.2/expected_squib.rbi index 5bf3b92d..01023e39 100644 --- a/spec/test_data/v5.2/expected_squib.rbi +++ b/spec/test_data/v5.2/expected_squib.rbi @@ -121,6 +121,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v5.2/expected_wizard.rbi b/spec/test_data/v5.2/expected_wizard.rbi index 90202f24..02aa9d6f 100644 --- a/spec/test_data/v5.2/expected_wizard.rbi +++ b/spec/test_data/v5.2/expected_wizard.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi b/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi index 3b2f4868..c443329c 100644 --- a/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v6.0/expected_spell_book.rbi b/spec/test_data/v6.0/expected_spell_book.rbi index 121a89dc..5c568abb 100644 --- a/spec/test_data/v6.0/expected_spell_book.rbi +++ b/spec/test_data/v6.0/expected_spell_book.rbi @@ -28,6 +28,15 @@ module SpellBook::ActiveRelation_WhereNot end module SpellBook::GeneratedAttributeMethods + sig { returns(String) } + def book_category; end + + sig { params(value: T.any(Integer, String, Symbol)).void } + def book_category=(value); end + + sig { returns(T::Boolean) } + def book_category?; end + sig { returns(String) } def book_type; end @@ -55,6 +64,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def name?; end + sig { returns(String) } + def title; end + + sig { params(value: T.any(String, Symbol)).void } + def title=(value); end + + sig { returns(T::Boolean) } + def title?; end + sig { returns(Integer) } def wizard_id; end @@ -143,6 +161,12 @@ class SpellBook < ApplicationRecord sig { params(args: T.untyped).returns(SpellBook::ActiveRecord_Relation) } def self.unclassified(*args); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + sig { returns(SpellBook::BookType) } def typed_book_type; end diff --git a/spec/test_data/v6.0/expected_squib.rbi b/spec/test_data/v6.0/expected_squib.rbi index 79c00a7e..9403b533 100644 --- a/spec/test_data/v6.0/expected_squib.rbi +++ b/spec/test_data/v6.0/expected_squib.rbi @@ -121,6 +121,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v6.0/expected_wizard.rbi b/spec/test_data/v6.0/expected_wizard.rbi index bc1fbc52..2f3db3d0 100644 --- a/spec/test_data/v6.0/expected_wizard.rbi +++ b/spec/test_data/v6.0/expected_wizard.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi b/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi index 814ca593..0afde797 100644 --- a/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v6.1/expected_spell_book.rbi b/spec/test_data/v6.1/expected_spell_book.rbi index d00eb8bb..c76008e1 100644 --- a/spec/test_data/v6.1/expected_spell_book.rbi +++ b/spec/test_data/v6.1/expected_spell_book.rbi @@ -28,6 +28,15 @@ module SpellBook::ActiveRelation_WhereNot end module SpellBook::GeneratedAttributeMethods + sig { returns(String) } + def book_category; end + + sig { params(value: T.any(Integer, String, Symbol)).void } + def book_category=(value); end + + sig { returns(T::Boolean) } + def book_category?; end + sig { returns(String) } def book_type; end @@ -55,6 +64,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def name?; end + sig { returns(String) } + def title; end + + sig { params(value: T.any(String, Symbol)).void } + def title=(value); end + + sig { returns(T::Boolean) } + def title?; end + sig { returns(Integer) } def wizard_id; end @@ -143,6 +161,12 @@ class SpellBook < ApplicationRecord sig { params(args: T.untyped).returns(SpellBook::ActiveRecord_Relation) } def self.unclassified(*args); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + sig { returns(SpellBook::BookType) } def typed_book_type; end diff --git a/spec/test_data/v6.1/expected_squib.rbi b/spec/test_data/v6.1/expected_squib.rbi index fbac8d3f..22f86eb1 100644 --- a/spec/test_data/v6.1/expected_squib.rbi +++ b/spec/test_data/v6.1/expected_squib.rbi @@ -121,6 +121,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v6.1/expected_wizard.rbi b/spec/test_data/v6.1/expected_wizard.rbi index 3884877c..89387162 100644 --- a/spec/test_data/v6.1/expected_wizard.rbi +++ b/spec/test_data/v6.1/expected_wizard.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v6.1/expected_wizard_wo_spellbook.rbi b/spec/test_data/v6.1/expected_wizard_wo_spellbook.rbi index db2b31c5..efacf42a 100644 --- a/spec/test_data/v6.1/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v6.1/expected_wizard_wo_spellbook.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v7.0/expected_spell_book.rbi b/spec/test_data/v7.0/expected_spell_book.rbi index 5148e68c..2297bbdb 100644 --- a/spec/test_data/v7.0/expected_spell_book.rbi +++ b/spec/test_data/v7.0/expected_spell_book.rbi @@ -28,6 +28,15 @@ module SpellBook::ActiveRelation_WhereNot end module SpellBook::GeneratedAttributeMethods + sig { returns(String) } + def book_category; end + + sig { params(value: T.any(Integer, String, Symbol)).void } + def book_category=(value); end + + sig { returns(T::Boolean) } + def book_category?; end + sig { returns(String) } def book_type; end @@ -55,6 +64,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def name?; end + sig { returns(String) } + def title; end + + sig { params(value: T.any(String, Symbol)).void } + def title=(value); end + + sig { returns(T::Boolean) } + def title?; end + sig { returns(Integer) } def wizard_id; end @@ -143,6 +161,12 @@ class SpellBook < ApplicationRecord sig { params(args: T.untyped).returns(SpellBook::ActiveRecord_Relation) } def self.unclassified(*args); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + sig { returns(SpellBook::BookType) } def typed_book_type; end diff --git a/spec/test_data/v7.0/expected_squib.rbi b/spec/test_data/v7.0/expected_squib.rbi index e4baa46b..b13023da 100644 --- a/spec/test_data/v7.0/expected_squib.rbi +++ b/spec/test_data/v7.0/expected_squib.rbi @@ -121,6 +121,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v7.0/expected_wizard.rbi b/spec/test_data/v7.0/expected_wizard.rbi index 189f89bc..3a50930a 100644 --- a/spec/test_data/v7.0/expected_wizard.rbi +++ b/spec/test_data/v7.0/expected_wizard.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end diff --git a/spec/test_data/v7.0/expected_wizard_wo_spellbook.rbi b/spec/test_data/v7.0/expected_wizard_wo_spellbook.rbi index ae2fac1f..52e21b06 100644 --- a/spec/test_data/v7.0/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v7.0/expected_wizard_wo_spellbook.rbi @@ -121,6 +121,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def newt_subjects?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } + def ordinary_wizarding_level_results; end + + sig { params(value: T.nilable(T::Hash[T.untyped, T.untyped])).void } + def ordinary_wizarding_level_results=(value); end + + sig { returns(T::Boolean) } + def ordinary_wizarding_level_results?; end + sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) } def owl_results; end