From 30dc01e80f48e635580e4197328e881d553e9fcb Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 12 Nov 2024 17:35:09 +0100 Subject: [PATCH] Validate configuration --- lib/hotsheet.rb | 5 +- lib/hotsheet/configuration.rb | 40 ++++++++++++++-- spec/lib/configuration_spec.rb | 83 ++++++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 12 deletions(-) diff --git a/lib/hotsheet.rb b/lib/hotsheet.rb index 34dc027..3a58651 100644 --- a/lib/hotsheet.rb +++ b/lib/hotsheet.rb @@ -15,9 +15,8 @@ def configuration @configuration ||= Configuration.new end - def configure - @configuration = Configuration.new - yield configuration + def configure(&block) + @configuration = Configuration.new.tap(&block) end def models diff --git a/lib/hotsheet/configuration.rb b/lib/hotsheet/configuration.rb index d8f88fd..b8f7fcd 100644 --- a/lib/hotsheet/configuration.rb +++ b/lib/hotsheet/configuration.rb @@ -10,14 +10,46 @@ def initialize self.models = {} end - def model(name, &block) - model_config = ModelConfig.new - yield model_config if block + def model(name) + model_config = ModelConfig.new(name).tap do |config| + yield(config) + Rails.application.config.to_prepare { config.validate! } + end models[name.to_s] = model_config end class ModelConfig - attr_accessor :included_attributes, :excluded_attributes + attr_accessor :included_attributes, :excluded_attributes, :model_name + + def initialize(model_name) + @model_name = model_name + @included_attributes = [] + @excluded_attributes = [] + end + + def validate! + ensure_only_one_attribute_set + validate_attribute_existence + end + + private + + def ensure_only_one_attribute_set + return unless included_attributes.any? && excluded_attributes.any? + + raise "Can only specify either included or excluded attributes for '#{model_name}'" + end + + def validate_attribute_existence + model_class = model_name.to_s.constantize + all_attributes = model_class.column_names + + (included_attributes + excluded_attributes).each do |attr| + unless all_attributes.include?(attr.to_s) + raise "Attribute '#{attr}' doesn't exist on model '#{model_name}'" + end + end + end end end end diff --git a/spec/lib/configuration_spec.rb b/spec/lib/configuration_spec.rb index 744c701..ee65579 100644 --- a/spec/lib/configuration_spec.rb +++ b/spec/lib/configuration_spec.rb @@ -6,21 +6,20 @@ subject(:config) { Hotsheet.configuration } context "without model configuration" do - before { Hotsheet.configure {} } # rubocop:disable Lint/EmptyBlock + before { Hotsheet.configure {} } # reset configuration it "does NOT have any configured model" do expect(config.models).to eq({}) end end - context "with a model configuration" do + context "with a valid model configuration" do let(:model_config) { config.models["Author"] } before do Hotsheet.configure do |config| config.model :Author do |model| model.included_attributes = %i[name birthdate] - model.excluded_attributes = %i[created_at] end end end @@ -30,10 +29,84 @@ expect(config.models["Author"]).to be_a Hotsheet::Configuration::ModelConfig end - it "has included and excluded attributes" do + it "has included attributes set correctly" do expect(model_config).to be_a Hotsheet::Configuration::ModelConfig expect(model_config.included_attributes).to eq %i[name birthdate] - expect(model_config.excluded_attributes).to eq %i[created_at] + end + end + + describe "Hotsheet::Configuration::ModelConfig" do + subject(:model_config) { Hotsheet::Configuration::ModelConfig.new("Author") } + + let(:model_class) do + Class.new do + def self.name + "Author" + end + + def self.column_names + %w[id name birthdate created_at updated_at] + end + end + end + + before do + stub_const("Author", model_class) + end + + context "when only included attributes are specified" do + before { model_config.included_attributes = %i[name birthdate] } + + it "validates without errors" do + expect { model_config.validate! }.not_to raise_error + end + end + + context "when only excluded attributes are specified" do + before { model_config.excluded_attributes = %i[created_at updated_at] } + + it "validates without errors" do + expect { model_config.validate! }.not_to raise_error + end + end + + context "when both included and excluded attributes are specified" do + before do + model_config.included_attributes = %i[name birthdate] + model_config.excluded_attributes = %i[created_at] + end + + it "raises an error" do + expect do + model_config.validate! + end.to raise_error("Can only specify either included or excluded attributes for 'Author'") + end + end + + context "when included attributes contain a non-existent attribute" do + before { model_config.included_attributes = %i[name non_existent_attribute] } + + it "raises an error indicating the attribute does not exist" do + expect do + model_config.validate! + end.to raise_error("Attribute 'non_existent_attribute' doesn't exist on model 'Author'") + end + end + + context "when excluded attributes contain a non-existent attribute" do + before { model_config.excluded_attributes = %i[non_existent_attribute] } + + it "raises an error indicating the attribute does not exist" do + expect do + model_config.validate! + end.to raise_error("Attribute 'non_existent_attribute' doesn't exist on model 'Author'") + end + end + + context "when no included or excluded attributes are specified" do + it "validates without errors" do + expect { model_config.validate! }.not_to raise_error + end end end end