diff --git a/lib/sorbet-rails/model_plugins/active_record_attribute.rb b/lib/sorbet-rails/model_plugins/active_record_attribute.rb index 6d45cc5f..6eb72007 100644 --- a/lib/sorbet-rails/model_plugins/active_record_attribute.rb +++ b/lib/sorbet-rails/model_plugins/active_record_attribute.rb @@ -1,5 +1,7 @@ # typed: strict + require ('sorbet-rails/model_plugins/base') + class SorbetRails::ModelPlugins::ActiveRecordAttribute < SorbetRails::ModelPlugins::Base sig { override.params(root: Parlour::RbiGenerator::Namespace).void } @@ -12,28 +14,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 = T.unsafe(@model_class).attribute_aliases + aliases_hash = model_class_columns_to_aliases(model_defined_aliases) + attributes_and_aliases_hash = model_class_attributes_and_aliases(columns_hash, aliases_hash) - columns_hash.sort.each do |column_name, column_def| - if model_defined_enums.has_key?(column_name) + attributes_and_aliases_hash.each do |attribute_name, column_def| + if model_defined_enums.key?(attribute_name) || + ((column_name = model_defined_aliases[attribute_name]).present? && model_defined_enums.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) + elsif serialization_coder_for_column(attribute_name) || + ((column_name = model_defined_aliases[attribute_name]).present? && + 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 +54,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 +107,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 +128,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..e13507c1 100644 --- a/lib/sorbet-rails/model_plugins/active_record_serialized_attribute.rb +++ b/lib/sorbet-rails/model_plugins/active_record_serialized_attribute.rb @@ -13,6 +13,9 @@ def generate(root) model_class_rbi = root.create_class(self.model_class_name) model_class_rbi.create_include(serialize_module_name) + model_defined_aliases = T.unsafe(@model_class).attribute_aliases + aliases_hash = model_class_columns_to_aliases(model_defined_aliases) + columns_hash.sort.each do |column_name, column_def| serialization_coder = serialization_coder_for_column(column_name) next unless serialization_coder @@ -20,23 +23,25 @@ def generate(root) nilable = nilable_column?(column_def) attr_type = attr_types_for_coder(serialization_coder) - serialize_module_rbi.create_method( - column_name.to_s, - return_type: ColumnType.new(base_type: attr_type, nilable: nilable).to_s, - ) + [column_name].union(aliases_hash[column_name] || []).each do |attribute_name| + serialize_module_rbi.create_method( + attribute_name.to_s, + return_type: ColumnType.new(base_type: attr_type, nilable: nilable).to_s, + ) - serialize_module_rbi.create_method( - "#{column_name}=", - parameters: [ - Parameter.new('value', type: ColumnType.new(base_type: attr_type, nilable: nilable).to_s) - ], - return_type: nil, - ) + serialize_module_rbi.create_method( + "#{attribute_name}=", + parameters: [ + Parameter.new('value', type: ColumnType.new(base_type: attr_type, nilable: nilable).to_s) + ], + return_type: nil, + ) - serialize_module_rbi.create_method( - "#{column_name}?", - return_type: 'T::Boolean', - ) + serialize_module_rbi.create_method( + "#{attribute_name}?", + return_type: 'T::Boolean', + ) + end end end diff --git a/lib/sorbet-rails/model_plugins/base.rb b/lib/sorbet-rails/model_plugins/base.rb index 8800c363..04ae8bce 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,30 @@ def serialization_coder_for_column(column_name) Object end end + + sig { params(aliases: T::Hash[String, String]).returns(T::Hash[String, T::Array[String]]) } + def model_class_columns_to_aliases(aliases) + aliases.each_with_object({}) do |(alias_, column), hash| + hash[column] ||= [] + hash[column] << alias_ + end + 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 + .sort + .each_with_object({}) do |(column_name, column_def), hash| + attributes = [column_name].union(aliases_hash[column_name] || []) + attributes.each do |attribute_name| + hash[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..777ce7df 100644 --- a/spec/generators/sorbet_test_cases.rb +++ b/spec/generators/sorbet_test_cases.rb @@ -8,6 +8,14 @@ # -- 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, T::Hash[T.untyped, T.untyped]) # serialized alias attribute + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -157,7 +165,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..3544c5b1 100644 --- a/spec/support/v5.2/sorbet_test_cases.rb +++ b/spec/support/v5.2/sorbet_test_cases.rb @@ -8,6 +8,14 @@ # -- 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, T::Hash[T.untyped, T.untyped]) # serialized alias attribute + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -161,7 +169,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..3544c5b1 100644 --- a/spec/support/v6.0/sorbet_test_cases.rb +++ b/spec/support/v6.0/sorbet_test_cases.rb @@ -8,6 +8,14 @@ # -- 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, T::Hash[T.untyped, T.untyped]) # serialized alias attribute + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -161,7 +169,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..09e71ac2 100644 --- a/spec/support/v6.1/sorbet_test_cases.rb +++ b/spec/support/v6.1/sorbet_test_cases.rb @@ -8,6 +8,14 @@ # -- 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, T::Hash[T.untyped, T.untyped]) # serialized alias attribute + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -163,7 +171,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..58a89002 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 diff --git a/spec/support/v7.0/sorbet_test_cases.rb b/spec/support/v7.0/sorbet_test_cases.rb index 0d9ffb72..1a966bb3 100644 --- a/spec/support/v7.0/sorbet_test_cases.rb +++ b/spec/support/v7.0/sorbet_test_cases.rb @@ -8,6 +8,14 @@ # -- 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, T::Hash[T.untyped, T.untyped]) # serialized alias attribute + # -- time/date columns T.assert_type!(wizard.created_at, ActiveSupport::TimeWithZone) T.assert_type!(wand.broken_at, T.nilable(Time)) @@ -162,7 +170,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..cc608d85 100644 --- a/spec/test_data/v5.2/expected_spell_book.rbi +++ b/spec/test_data/v5.2/expected_spell_book.rbi @@ -37,6 +37,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def book_type?; end + 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(Integer) } def id; 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 @@ -140,6 +158,12 @@ class SpellBook < ApplicationRecord sig { params(value: SpellBook::BookType).void } def typed_book_type=(value); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + class BookType < T::Enum enums do Unclassified = new(%q{unclassified}) diff --git a/spec/test_data/v5.2/expected_squib.rbi b/spec/test_data/v5.2/expected_squib.rbi index 5bf3b92d..ebcbbc7c 100644 --- a/spec/test_data/v5.2/expected_squib.rbi +++ b/spec/test_data/v5.2/expected_squib.rbi @@ -130,6 +130,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; end diff --git a/spec/test_data/v5.2/expected_wizard.rbi b/spec/test_data/v5.2/expected_wizard.rbi index 90202f24..02ef8c28 100644 --- a/spec/test_data/v5.2/expected_wizard.rbi +++ b/spec/test_data/v5.2/expected_wizard.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; 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..e9e33591 100644 --- a/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v5.2/expected_wizard_wo_spellbook.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; 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..65568b0c 100644 --- a/spec/test_data/v6.0/expected_spell_book.rbi +++ b/spec/test_data/v6.0/expected_spell_book.rbi @@ -37,6 +37,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def book_type?; end + 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(Integer) } def id; 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 @@ -149,6 +167,12 @@ class SpellBook < ApplicationRecord sig { params(value: SpellBook::BookType).void } def typed_book_type=(value); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + class BookType < T::Enum enums do Unclassified = new(%q{unclassified}) diff --git a/spec/test_data/v6.0/expected_squib.rbi b/spec/test_data/v6.0/expected_squib.rbi index 79c00a7e..92e61517 100644 --- a/spec/test_data/v6.0/expected_squib.rbi +++ b/spec/test_data/v6.0/expected_squib.rbi @@ -130,6 +130,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; end diff --git a/spec/test_data/v6.0/expected_wizard.rbi b/spec/test_data/v6.0/expected_wizard.rbi index bc1fbc52..ddb49024 100644 --- a/spec/test_data/v6.0/expected_wizard.rbi +++ b/spec/test_data/v6.0/expected_wizard.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; 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..b46c2453 100644 --- a/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v6.0/expected_wizard_wo_spellbook.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; 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..d8f7ff5b 100644 --- a/spec/test_data/v6.1/expected_spell_book.rbi +++ b/spec/test_data/v6.1/expected_spell_book.rbi @@ -37,6 +37,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def book_type?; end + 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(Integer) } def id; 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 @@ -149,6 +167,12 @@ class SpellBook < ApplicationRecord sig { params(value: SpellBook::BookType).void } def typed_book_type=(value); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + class BookType < T::Enum enums do Unclassified = new(%q{unclassified}) diff --git a/spec/test_data/v6.1/expected_squib.rbi b/spec/test_data/v6.1/expected_squib.rbi index fbac8d3f..5404ad69 100644 --- a/spec/test_data/v6.1/expected_squib.rbi +++ b/spec/test_data/v6.1/expected_squib.rbi @@ -130,6 +130,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; end diff --git a/spec/test_data/v6.1/expected_wizard.rbi b/spec/test_data/v6.1/expected_wizard.rbi index 3884877c..e098aa2c 100644 --- a/spec/test_data/v6.1/expected_wizard.rbi +++ b/spec/test_data/v6.1/expected_wizard.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; 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..e806b011 100644 --- a/spec/test_data/v6.1/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v6.1/expected_wizard_wo_spellbook.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; 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..c8c39396 100644 --- a/spec/test_data/v7.0/expected_spell_book.rbi +++ b/spec/test_data/v7.0/expected_spell_book.rbi @@ -37,6 +37,15 @@ module SpellBook::GeneratedAttributeMethods sig { returns(T::Boolean) } def book_type?; end + 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(Integer) } def id; 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 @@ -149,6 +167,12 @@ class SpellBook < ApplicationRecord sig { params(value: SpellBook::BookType).void } def typed_book_type=(value); end + sig { returns(SpellBook::BookType) } + def typed_book_category; end + + sig { params(value: SpellBook::BookType).void } + def typed_book_category=(value); end + class BookType < T::Enum enums do Unclassified = new(%q{unclassified}) diff --git a/spec/test_data/v7.0/expected_squib.rbi b/spec/test_data/v7.0/expected_squib.rbi index e4baa46b..d1129216 100644 --- a/spec/test_data/v7.0/expected_squib.rbi +++ b/spec/test_data/v7.0/expected_squib.rbi @@ -130,6 +130,15 @@ module Squib::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; end diff --git a/spec/test_data/v7.0/expected_wizard.rbi b/spec/test_data/v7.0/expected_wizard.rbi index 189f89bc..19762fd9 100644 --- a/spec/test_data/v7.0/expected_wizard.rbi +++ b/spec/test_data/v7.0/expected_wizard.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; 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..b3baceaf 100644 --- a/spec/test_data/v7.0/expected_wizard_wo_spellbook.rbi +++ b/spec/test_data/v7.0/expected_wizard_wo_spellbook.rbi @@ -130,6 +130,15 @@ module Wizard::GeneratedSerializedAttributeMethods sig { returns(T::Boolean) } def owl_results?; 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(ActiveRecord::Coders::JSON)) } def patronus_characteristics; end