From 67c3d4dff582bb7602f2cd12b2807544ac584fa5 Mon Sep 17 00:00:00 2001 From: Nathaniel Watts Date: Thu, 6 Feb 2025 12:59:07 -0600 Subject: [PATCH] Fix issue introduced by YARD's global #log method [The YARD gem adds a global `#log` method](https://github.com/lsegal/yard/blob/efb33b5411f54ae491c10ce5cd227fa49b985fde/lib/yard/globals.rb#L20-L22), which becomes a problem if a Factory needs to declare a `log` attribute. Ex: ```ruby FactoryBot.define :event do # This would originally call out to YARD's global log method, # instead of defining the attribute on the factory log end ``` This commit adds `FactoryBot::DefinitionProxy#log` to ensure that if defining a `log` attribute, it'll correctly get passed to the necessary methods through `method_missing`, and therefore added as an attribute to the factory. --- lib/factory_bot/definition_proxy.rb | 11 +++++++++++ spec/factory_bot/definition_proxy_spec.rb | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/factory_bot/definition_proxy.rb b/lib/factory_bot/definition_proxy.rb index a27c33f2..d8b20e17 100644 --- a/lib/factory_bot/definition_proxy.rb +++ b/lib/factory_bot/definition_proxy.rb @@ -103,6 +103,17 @@ def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondTo end end + # The YARD gem adds a global `log` method that prevents FactoryBot from being able + # to declare attributes / associations called `log`. + # + # This overrides that method, and instead passes the arguments to `method_missing` so that + # the attribute can be added to the factory. + # + # Source: https://github.com/lsegal/yard/blob/efb33b5411f54ae491c10ce5cd227fa49b985fde/lib/yard/globals.rb#L20-L22 + def log(...) + method_missing(:log, ...) + end + # Adds an attribute that will have unique values generated by a sequence with # a specified format. # diff --git a/spec/factory_bot/definition_proxy_spec.rb b/spec/factory_bot/definition_proxy_spec.rb index 80272bcb..1bd5b214 100644 --- a/spec/factory_bot/definition_proxy_spec.rb +++ b/spec/factory_bot/definition_proxy_spec.rb @@ -75,6 +75,22 @@ end end +describe FactoryBot::DefinitionProxy, "#log" do + it "ensures that `log` can be declared on the factory" do + begin + Kernel.define_method(:log) { raise "I SHOULDN'T BE CALLED" } + + definition = FactoryBot::Definition.new(:name) + proxy = FactoryBot::DefinitionProxy.new(definition) + proxy.log + + expect(definition).to have_implicit_declaration(:log).with_factory(definition) + ensure + Kernel.send(:remove_method, :log) + end + end +end + describe FactoryBot::DefinitionProxy, "#sequence" do def build_proxy(factory_name) definition = FactoryBot::Definition.new(factory_name)