allow redefinition of methods
This commit is contained in:
@@ -51,18 +51,26 @@ module HasAuxTable
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Main DSL method for defining auxiliary tables
|
# Main DSL method for defining auxiliary tables
|
||||||
sig { params(aux_name: T.any(String, Symbol)).returns(AuxTableConfig) }
|
sig do
|
||||||
def aux_table(aux_name)
|
params(
|
||||||
|
aux_name: T.any(String, Symbol),
|
||||||
|
allow_redefining: T.nilable(T.any(Symbol, T::Array[Symbol]))
|
||||||
|
).returns(AuxTableConfig)
|
||||||
|
end
|
||||||
|
def aux_table(aux_name, allow_redefining: nil)
|
||||||
@aux_table_configs ||=
|
@aux_table_configs ||=
|
||||||
T.let({}, T.nilable(T::Hash[Symbol, AuxTableConfig]))
|
T.let({}, T.nilable(T::Hash[Symbol, AuxTableConfig]))
|
||||||
|
|
||||||
|
allow_redefining = [allow_redefining].flatten.compact
|
||||||
|
|
||||||
aux_name = aux_name.to_sym
|
aux_name = aux_name.to_sym
|
||||||
if @aux_table_configs.key?(aux_name)
|
if @aux_table_configs.key?(aux_name)
|
||||||
Kernel.raise ArgumentError,
|
Kernel.raise ArgumentError,
|
||||||
"Auxiliary '#{aux_name}' on #{self.name} (table '#{self.table_name}') already exists"
|
"Auxiliary '#{aux_name}' on #{self.name} (table '#{self.table_name}') already exists"
|
||||||
end
|
end
|
||||||
|
|
||||||
@aux_table_configs[aux_name] = config = generate_aux_config(aux_name)
|
@aux_table_configs[aux_name] = config =
|
||||||
|
generate_aux_config(aux_name, allow_redefining)
|
||||||
setup_attribute_types_hook!(config)
|
setup_attribute_types_hook!(config)
|
||||||
setup_load_schema_hook!(config)
|
setup_load_schema_hook!(config)
|
||||||
setup_initialize_hook!(config)
|
setup_initialize_hook!(config)
|
||||||
@@ -85,8 +93,12 @@ module HasAuxTable
|
|||||||
private
|
private
|
||||||
|
|
||||||
# Generate auxiliary model class dynamically
|
# Generate auxiliary model class dynamically
|
||||||
sig { params(aux_name: Symbol).returns(AuxTableConfig) }
|
sig do
|
||||||
def generate_aux_config(aux_name)
|
params(aux_name: Symbol, allow_redefining: T::Array[Symbol]).returns(
|
||||||
|
AuxTableConfig
|
||||||
|
)
|
||||||
|
end
|
||||||
|
def generate_aux_config(aux_name, allow_redefining)
|
||||||
main_class = T.cast(self, T.class_of(ActiveRecord::Base))
|
main_class = T.cast(self, T.class_of(ActiveRecord::Base))
|
||||||
main_table = main_class.table_name
|
main_table = main_class.table_name
|
||||||
|
|
||||||
@@ -108,7 +120,8 @@ module HasAuxTable
|
|||||||
AuxTableConfig.from_models(
|
AuxTableConfig.from_models(
|
||||||
main_class:,
|
main_class:,
|
||||||
aux_class:,
|
aux_class:,
|
||||||
aux_association_name:
|
aux_association_name:,
|
||||||
|
allow_redefining:
|
||||||
)
|
)
|
||||||
|
|
||||||
# Define the association back to the specific STI subclass
|
# Define the association back to the specific STI subclass
|
||||||
@@ -217,7 +230,8 @@ module HasAuxTable
|
|||||||
# Generate attribute accessors for each auxiliary column
|
# Generate attribute accessors for each auxiliary column
|
||||||
config.aux.columns_hash.each do |column_name, column|
|
config.aux.columns_hash.each do |column_name, column|
|
||||||
column_name = column_name.to_sym
|
column_name = column_name.to_sym
|
||||||
if self.method_defined?(column_name.to_sym)
|
if self.method_defined?(column_name.to_sym) &&
|
||||||
|
!config.allow_redefining.include?(column_name.to_sym)
|
||||||
raise "invariant: method #{column_name} already defined"
|
raise "invariant: method #{column_name} already defined"
|
||||||
end
|
end
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -9,15 +9,21 @@ module HasAuxTable
|
|||||||
const :aux_association_name, Symbol
|
const :aux_association_name, Symbol
|
||||||
const :main, ModelClassHelper
|
const :main, ModelClassHelper
|
||||||
const :aux, ModelClassHelper
|
const :aux, ModelClassHelper
|
||||||
|
const :allow_redefining, T::Array[Symbol]
|
||||||
sig do
|
sig do
|
||||||
params(
|
params(
|
||||||
main_class: T.class_of(ActiveRecord::Base),
|
main_class: T.class_of(ActiveRecord::Base),
|
||||||
aux_class: T.class_of(ActiveRecord::Base),
|
aux_class: T.class_of(ActiveRecord::Base),
|
||||||
aux_association_name: Symbol
|
aux_association_name: Symbol,
|
||||||
|
allow_redefining: T::Array[Symbol]
|
||||||
).returns(AuxTableConfig)
|
).returns(AuxTableConfig)
|
||||||
end
|
end
|
||||||
def self.from_models(main_class:, aux_class:, aux_association_name:)
|
def self.from_models(
|
||||||
|
main_class:,
|
||||||
|
aux_class:,
|
||||||
|
aux_association_name:,
|
||||||
|
allow_redefining: []
|
||||||
|
)
|
||||||
primary_key = aux_class.primary_key
|
primary_key = aux_class.primary_key
|
||||||
aux_rejected_column_names = [
|
aux_rejected_column_names = [
|
||||||
primary_key,
|
primary_key,
|
||||||
@@ -37,7 +43,8 @@ module HasAuxTable
|
|||||||
ModelClassHelper.new(
|
ModelClassHelper.new(
|
||||||
klass: aux_class,
|
klass: aux_class,
|
||||||
rejected_column_names: aux_rejected_column_names
|
rejected_column_names: aux_rejected_column_names
|
||||||
)
|
),
|
||||||
|
allow_redefining:
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1182,4 +1182,57 @@ RSpec.describe HasAuxTable do
|
|||||||
expect(patient.doctors.count).to eq(1)
|
expect(patient.doctors.count).to eq(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "allowing redefining of methods" do
|
||||||
|
it "allows method redefining with `allow_method_redefinition`" do
|
||||||
|
ActiveRecord::Schema.define do
|
||||||
|
create_base_table :test_model2s do |t|
|
||||||
|
t.string :on_base
|
||||||
|
t.create_aux :specific do |t|
|
||||||
|
t.string :on_aux
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestModel2 < ActiveRecord::Base
|
||||||
|
include HasAuxTable
|
||||||
|
|
||||||
|
def on_base
|
||||||
|
"on_base #{super} #{id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
expect {
|
||||||
|
class TestModel2A < TestModel2
|
||||||
|
aux_table :specific, allow_redefining: :on_base
|
||||||
|
def on_base
|
||||||
|
"2a_on_base_override #{super}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_aux
|
||||||
|
"2a_on_aux_override #{super}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}.not_to raise_error
|
||||||
|
|
||||||
|
expect {
|
||||||
|
class TestModel2B < TestModel2
|
||||||
|
aux_table :specific, allow_redefining: :on_base
|
||||||
|
end
|
||||||
|
}.not_to raise_error
|
||||||
|
|
||||||
|
base_model = TestModel2.create!(on_base: "base")
|
||||||
|
expect(base_model.on_base).to eq("on_base base #{base_model.id}")
|
||||||
|
|
||||||
|
specific_a = TestModel2A.create!(on_base: "2a_base", on_aux: "2a_aux")
|
||||||
|
expect(specific_a.on_base).to eq(
|
||||||
|
"2a_on_base_override on_base 2a_base #{specific_a.id}"
|
||||||
|
)
|
||||||
|
expect(specific_a.on_aux).to eq("2a_on_aux_override 2a_aux")
|
||||||
|
|
||||||
|
specific_b = TestModel2B.create!(on_base: "2b_base", on_aux: "2b_aux")
|
||||||
|
expect(specific_b.on_base).to eq("on_base 2b_base #{specific_b.id}")
|
||||||
|
expect(specific_b.on_aux).to eq("2b_aux")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user