Может ли кто-нибудь еще помочь мне пройти один сценарий, связанный с переопределением ранее определенного метода?
У меня есть класс, который может получить Hash
для создания переменных экземпляра во время выполнения для каждого ключа пары Если значением является Hash
, то нам нужно создать экземпляр нового класса Config
и присвоить его переменной экземпляра в контексте, что зафиксировано в методе initialize
.
Кроме того, этот класс должен реагировать на разные методы, и если их нет, то нам нужно создавать их на лету. И это покрыто переопределением метода method_missing
и оценкой, является ли значение для данного метода Hash
, затем примените те же логики c, что и в инициализаторе.
class Config
def initialize(parameters = {})
raise ArgumentError.new unless parameters.is_a?(Hash)
parameters.each do |key, value|
raise ArgumentError.new unless key.is_a?(String) || key.is_a?(Symbol)
create_new_method_on_instance(key, value)
end
end
def method_missing(method_name, *args)
name = method_name.to_s.delete_suffix('=')
create_new_method_on_instance(name, args.first)
end
private
def create_new_method_on_instance(name, value)
singleton_class.send(:attr_accessor, name)
if value.is_a?(Hash)
instance_variable_set("@#{name}", Config.new(value))
else
instance_variable_set("@#{name}", value)
end
end
end
Все, что работает просто отлично, но проблема в том, что теперь мне нужно переопределить метод foo
на лету. Например, сначала создайте объект Config.new({foo => 23})
, который будет иметь переменную экземпляра foo
, затем я хочу передать новое значение (переназначить его), например, config.foo = {x: 23}
. Поскольку это новое значение - hash
, мне нужно перехватить его и применить тот же лог c, что и раньше, создать новый объект Config
с этим значением и присвоить его переменной экземпляра foo
.
Проблема здесь в том, что, поскольку метод foo
уже определен, я не могу перехватить его новое назначение в методе method_missing
, чтобы применить необходимые логики c. Кто-нибудь знает способ перехвата, когда мы вызываем метод setter динамически?
Тесты:
describe 'VerifiedConfig' do
it 'should return nil for non-existing config values' do
config = Config.new
expect(config.foo).to be_nil
expect(config.bar).to be_nil
end
it 'should allow assigning new simple config values' do
config = Config.new
config.foo = 13
config.bar = "foo-bar"
expect(config.foo).to eq(13)
expect(config.bar).to eq("foo-bar")
end
it 'should allow assigning hash values' do
config = Config.new
config.foo = {bar: {'baz' => 'x'}}
config.bar = {'foo' => {bar: [12, 13], baz: 14}}
expect(config.foo).to be_a(Config)
expect(config.foo.bar).to be_a(Config)
expect(config.foo.bar.baz).to eq('x')
expect(config.bar.foo.bar).to eq([12, 13])
expect(config.bar.foo.baz).to eq(14)
end
it 'should allow initialization through constructor' do
config = Config.new({'foo' => {bar: [12, 13], baz: 14}})
expect(config.foo.bar).to eq([12, 13])
expect(config.foo.baz).to eq(14)
end
it 'should override values' do
config = Config.new({'foo' => {bar: 'baz'}})
config.foo = 10
config.foo = {x: {y: 'z'}}
expect(config.foo.x.y).to eq('z')
end
it 'should raise an error when keys have illegal type' do
config = Config.new
expect {config.x = {14 => 15}}.to raise_error(ArgumentError)
end
it 'should not accept anything that Hash in the constructor' do
expect {Config.new(11)}.to raise_error(ArgumentError)
expect {Config.new('test')}.to raise_error(ArgumentError)
end
end
Это сценарий, который терпит неудачу:
it 'should override values' do
config = Config.new({'foo' => {bar: 'baz'}})
config.foo = 10
config.foo = {x: {y: 'z'}}
expect(config.foo.x.y).to eq('z')
end
ПРИМЕЧАНИЕ: Я не могу использовать OpenStruct