diff --git a/CHANGELOG.md b/CHANGELOG.md index c59afb2..abeff51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.6.1 + +### Fixed + +- Fixed issue with YARD and RBS documentation tasks possibly raising an error if a named value method is deprecated and wrapped to return an error. Types are now inferred directly from the data rather than calling a method. + ## 1.6.0 ### Added diff --git a/VERSION b/VERSION index dc1e644..9c6d629 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.0 +1.6.1 diff --git a/lib/support_table_data/documentation/rbs_doc.rb b/lib/support_table_data/documentation/rbs_doc.rb index 70db651..5c40d96 100644 --- a/lib/support_table_data/documentation/rbs_doc.rb +++ b/lib/support_table_data/documentation/rbs_doc.rb @@ -42,7 +42,7 @@ def instance_signatures(name) lines << "def self.#{name}: () -> #{klass.name}" lines << "def #{name}?: () -> bool" klass.support_table_attribute_helpers.each do |attribute_name| - return_type = TypeInference.rbs_type(TypeInference.value_type(klass, "#{name}_#{attribute_name}")) + return_type = TypeInference.rbs_type(TypeInference.value_type(klass, name, attribute_name)) lines << "def self.#{name}_#{attribute_name}: () -> #{return_type}" end lines diff --git a/lib/support_table_data/documentation/type_inference.rb b/lib/support_table_data/documentation/type_inference.rb index e30bc9e..3d397bc 100644 --- a/lib/support_table_data/documentation/type_inference.rb +++ b/lib/support_table_data/documentation/type_inference.rb @@ -3,26 +3,28 @@ module SupportTableData module Documentation # Infers documentation types for the dynamically-defined attribute helpers - # by calling the generated method and inspecting the class of the value - # it returns. The values returned by these helpers are frozen literals from - # the parsed data file, so this does not require a database connection. - # - # This module must not be used on finder helpers (e.g. `Color.red`), which - # call `find_by!` and would hit the database. + # by reading the canonical value out of the parsed data file and + # inspecting its class. This avoids invoking the generated method, which + # may have been wrapped (e.g. deprecated) to raise. module TypeInference module_function - # Determine the documentation type for an attribute helper by calling - # the method and looking at the class of the returned value. Returns - # nil when the method is not defined. + # Determine the documentation type for a named-instance attribute + # helper by looking up the attribute value in the model's named + # instance data and returning its class. Returns nil when the + # attribute is not defined for the named instance. # # @param klass [Class] The model class - # @param method_name [String, Symbol] The class method name to call + # @param name [String, Symbol] The named instance name + # @param attribute_name [String, Symbol] The attribute name # @return [Class, nil] - def value_type(klass, method_name) - return nil unless klass.respond_to?(method_name) + def value_type(klass, name, attribute_name) + return nil unless klass.respond_to?(:named_instance_data) - klass.public_send(method_name).class + data = klass.named_instance_data(name) + return nil unless data.is_a?(Hash) && data.key?(attribute_name.to_s) + + data[attribute_name.to_s].class end # Map a Ruby value class to a YARD type string. diff --git a/lib/support_table_data/documentation/yard_doc.rb b/lib/support_table_data/documentation/yard_doc.rb index cce9edd..0908bbd 100644 --- a/lib/support_table_data/documentation/yard_doc.rb +++ b/lib/support_table_data/documentation/yard_doc.rb @@ -175,7 +175,7 @@ def compact_instance_block(name) end def attribute_yard_return_type(name, attribute_name) - TypeInference.yard_type(TypeInference.value_type(klass, "#{name}_#{attribute_name}")) + TypeInference.yard_type(TypeInference.value_type(klass, name, attribute_name)) end end end diff --git a/spec/support_table_data/documentation/type_inference_spec.rb b/spec/support_table_data/documentation/type_inference_spec.rb index 4821494..4cd473b 100644 --- a/spec/support_table_data/documentation/type_inference_spec.rb +++ b/spec/support_table_data/documentation/type_inference_spec.rb @@ -4,22 +4,26 @@ RSpec.describe SupportTableData::Documentation::TypeInference do describe ".value_type" do - it "returns the class of the value returned by the helper method" do + it "returns the class of the value from the named instance data" do # Group has named_instance_attribute_helpers :group_id, :name - expect(described_class.value_type(Group, "primary_name")).to eq(String) - expect(described_class.value_type(Group, "primary_group_id")).to eq(Integer) + expect(described_class.value_type(Group, "primary", "name")).to eq(String) + expect(described_class.value_type(Group, "primary", "group_id")).to eq(Integer) end - it "returns nil when the method is not defined" do - expect(described_class.value_type(Group, "not_a_real_method")).to be_nil + it "returns nil when the attribute is not present in the named instance data" do + expect(described_class.value_type(Group, "primary", "not_a_real_attribute")).to be_nil end - it "does not call the database for finder methods" do - # Sanity check: this confirms we are calling literal-returning helpers, - # not finder methods. Calling Group.primary would hit the DB; we should - # never invoke value_type on it. + it "returns nil when the named instance does not exist" do + expect(described_class.value_type(Group, "not_a_real_instance", "name")).to be_nil + end + + it "does not invoke the generated helper methods" do + # The generated method may be wrapped (e.g. deprecated) to raise, so we + # must read the value from the data file rather than calling the method. expect(Group).not_to receive(:primary) - described_class.value_type(Group, "primary_name") + expect(Group).not_to receive(:primary_name) + described_class.value_type(Group, "primary", "name") end end