Skip to content

Bug fixes#24

Open
bdurand wants to merge 3 commits into
mainfrom
detailed-review
Open

Bug fixes#24
bdurand wants to merge 3 commits into
mainfrom
detailed-review

Conversation

@bdurand

@bdurand bdurand commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Fixed

  • sync_table_data! with delete_missing: true now raises an ArgumentError instead of deleting every row in the table when the data files contain no rows (for example, when a data file was accidentally emptied or truncated).
  • Generated predicate methods (e.g. record.active?) now cast the data file value to the attribute type before comparing. Previously the raw file value was compared to the cast database attribute, so predicates silently returned false whenever the types differed (guaranteed for CSV data files, where all values are strings).
  • Single table inheritance subclasses no longer raise NoMethodError from instance_names, instance_keys, protected_instance?, and other class methods. Subclasses now share the support table state defined on their base class.
  • Named instance helper methods are now redefined when a later data file overrides an attribute or key value, so the helpers always return the merged values that are synced to the database. Previously they permanently returned the values from the first file that defined the named instance.
  • named_instance_attribute_helpers can now be called again with an attribute that was already registered without raising an ArgumentError.
  • YAML data files can now use anchors/aliases and date/time values. Previously these raised Psych::AliasesNotEnabled or Psych::DisallowedClass errors.
  • protected_instance? no longer returns stale results when data files are added after the protected keys were first computed.
  • Fixed broken cycle detection in the autosave association check during syncs that could cause infinite recursion on cyclic autosave associations.
  • sync_table_data! now retries once on ActiveRecord::RecordNotUnique errors caused by concurrent syncs inserting the same rows from another process.
  • sync_table_data! now returns an empty array instead of nil when the table does not exist.
  • named_instance now raises a clear ActiveRecord::RecordNotFound error for undefined named instances instead of querying the database for a nil key (which could silently return a row with a NULL key value).
  • Memoized class-level state is now consistently synchronized with the class mutex to avoid races on non-MRI Ruby implementations.
  • Setting config.support_table.auto_sync = false before the gem is loaded is no longer overwritten back to true by the Railtie.
  • The documentation tasks no longer corrupt model source files that contain duplicated generated YARD doc blocks (e.g. from a bad merge); the regex that finds the generated block is no longer greedy.
  • Data file names containing extra dots no longer break the class name detection used by SupportTableData.sync_all! to eager load models.
  • Error messages for invalid named instance definitions now include the model class name instead of repeating the instance name.

Summary by CodeRabbit

  • Bug Fixes

    • Improved support-table synchronization safety, including protection against deleting all records from empty data files.
    • Added retry handling for concurrent sync conflicts.
    • Fixed predicate value casting, inheritance behavior, named helper redefinition, and protected-instance detection.
    • Improved YAML support for anchors, aliases, dates, and times.
    • Preserved auto_sync: false configuration values.
    • Clarified handling of missing tables and undefined named instances.
  • Documentation

    • Updated loading guidance and release notes for synchronization safeguards and concurrency behavior.
  • Version

    • Updated release version to 1.6.2.

@greptile-apps

greptile-apps Bot commented Jul 12, 2026

Copy link
Copy Markdown

Greptile Summary

This is a comprehensive bug-fix release (v1.6.2) addressing 15 distinct issues across the SupportTableData concern, covering correctness, thread safety, STI support, YAML parsing, and documentation tooling.

  • Core sync logic: sync_table_data! gains an empty-data safeguard (raises ArgumentError instead of wiping the table), a single-retry on ActiveRecord::RecordNotUnique, and a corrected return type ([] instead of nil) when the table doesn't exist.
  • STI and thread safety: Private reader methods (support_table_mutex, support_table_data_files, etc.) now fall back to the superclass chain so STI subclasses share their base class's state, and memoized state is consistently guarded by the mutex to avoid races on non-MRI Ruby.
  • Method helpers and predicates: Named-instance helper methods are now redefined when a later data file overrides a value, predicate methods now cast the raw file value to the column type before comparing, and re-registering an already-registered attribute helper no longer raises ArgumentError.

Confidence Score: 4/5

This PR is safe to merge; all changes are targeted bug fixes with matching test coverage, and no regressions were identified in the core sync, STI sharing, or thread-safety paths.

The changes are well-scoped and well-tested, covering 15 distinct fixes without introducing new architectural complexity. The most impactful change — the autosave cycle-detection fix that replaced seen << self (the class) with seen << record (the instance) — correctly resolves what was effectively broken cycle tracking. The remaining observations are stylistic choices and one low-probability divergence scenario for STI subclasses calling named_instance_attribute_helpers, neither of which affects the happy path.

lib/support_table_data.rb warrants a second look around the attribute-helper tracking logic for STI subclasses and the Psych::VERSION.to_f version comparison, though neither represents a blocking concern for the supported use cases.

Important Files Changed

Filename Overview
lib/support_table_data.rb Core concern file with the most changes: STI fallback readers, mutex-guarded memoization, autosave cycle-detection fix, predicate type-casting, retry logic, empty-data safeguard, and named_instance guard — all logically sound.
lib/support_table_data/railtie.rb Corrects the auto_sync initialization from `
lib/support_table_data/documentation/source_file.rb YARD regex changed from greedy .* to non-greedy .*? to prevent swallowing user code between duplicated generated blocks.
lib/support_table_data/tasks/utils.rb STI subclass skip logic now uses instance_variable_defined?(:@support_table_data_files) instead of rescuing NoMethodError — cleaner and correct.
spec/support_table_data_spec.rb Adds comprehensive tests for all fixed behaviors: empty-data safeguard, retry, predicate casting, YAML aliases/dates, attribute helper redefinition, STI sharing, and stale-cache invalidation.
spec/models/size.rb New test model supporting YAML alias/date tests and attribute helper override tests.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A([sync_table_data!]) --> B{table_exists?}
    B -- No --> C[return empty array]
    B -- Yes --> D[Build canonical_data from data files]
    D --> E{delete_missing AND canonical_data empty AND rows exist?}
    E -- Yes --> F[raise ArgumentError - guard against table wipe]
    E -- No --> G[Query existing records where key IN canonical_data.keys]
    G --> H[Begin transaction]
    H --> I[Update existing records from canonical_data]
    I --> J[Create new records for remaining canonical_data entries]
    J --> K{delete_missing?}
    K -- Yes --> L[destroy_all records not in synced_ids]
    K -- No --> M[return changes array]
    L --> M
    H -- RecordInvalid --> N[raise ValidationError]
    H -- RecordNotUnique --> O{retried?}
    O -- Yes --> P[re-raise error]
    O -- No --> Q[retried = true]
    Q --> D
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A([sync_table_data!]) --> B{table_exists?}
    B -- No --> C[return empty array]
    B -- Yes --> D[Build canonical_data from data files]
    D --> E{delete_missing AND canonical_data empty AND rows exist?}
    E -- Yes --> F[raise ArgumentError - guard against table wipe]
    E -- No --> G[Query existing records where key IN canonical_data.keys]
    G --> H[Begin transaction]
    H --> I[Update existing records from canonical_data]
    I --> J[Create new records for remaining canonical_data entries]
    J --> K{delete_missing?}
    K -- Yes --> L[destroy_all records not in synced_ids]
    K -- No --> M[return changes array]
    L --> M
    H -- RecordInvalid --> N[raise ValidationError]
    H -- RecordNotUnique --> O{retried?}
    O -- Yes --> P[re-raise error]
    O -- No --> Q[retried = true]
    Q --> D
Loading

Reviews (1): Last reviewed commit: "Bug fixes" | Re-trigger Greptile

Comment thread lib/support_table_data.rb
Comment on lines 434 to 438
class_eval <<~RUBY, __FILE__, __LINE__ + 1
def #{method_name}
#{attribute_name} == #{attribute_value.inspect}
#{attribute_name} == self.class.type_for_attribute(#{attribute_name.inspect}).cast(#{attribute_value.inspect})
end
RUBY

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The predicate method body calls type_for_attribute(...).cast(...) on every single invocation to cast a value that is a compile-time constant (the raw value from the data file). While not incorrect, this repeatedly looks up and invokes the type caster for the same literal input. The cast result could instead be pre-computed at method-definition time and inlined as a constant in the generated Ruby, avoiding the runtime overhead on every predicate call. This matters most for predicate-heavy hot paths.

Suggested change
class_eval <<~RUBY, __FILE__, __LINE__ + 1
def #{method_name}
#{attribute_name} == #{attribute_value.inspect}
#{attribute_name} == self.class.type_for_attribute(#{attribute_name.inspect}).cast(#{attribute_value.inspect})
end
RUBY
cast_value = type_for_attribute(attribute_name).cast(attribute_value)
class_eval <<~RUBY, __FILE__, __LINE__ + 1
def #{method_name}
#{attribute_name} == #{cast_value.inspect}
end
RUBY

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread lib/support_table_data.rb
Comment on lines +459 to +464
data = if Psych::VERSION.to_f >= 3.1
YAML.safe_load(file_data, permitted_classes: [Date, Time], aliases: true)
else
# Positional arguments for Psych < 3.1 (Ruby 2.5).
YAML.safe_load(file_data, [Date, Time], [], true)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Fragile version comparison via to_f

Psych::VERSION.to_f truncates everything after the first decimal point, so "3.1.0" and "3.10.0" both produce 3.1. In practice Psych hasn't released a 3.10.x, but the comparison is inherently imprecise. Consider using Gem::Version for a semantically correct comparison: Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1").

Comment thread lib/support_table_data.rb
Comment on lines +388 to 396
support_table_attribute_helpers_map.each do |attribute_name, defined_methods|
attribute_method_name = "#{method_name}_#{attribute_name}"
next if defined_methods.include?(attribute_method_name)

define_support_table_instance_attribute_helper(attribute_method_name, attributes[attribute_name])
defined_methods << attribute_method_name
if defined_methods.include?(attribute_method_name)
define_support_table_instance_attribute_helper(attribute_method_name, attributes[attribute_name], redefine: true)
else
define_support_table_instance_attribute_helper(attribute_method_name, attributes[attribute_name])
defined_methods << attribute_method_name
end
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Attribute-helper tracking array mutated inside mutex but shared with STI superclass

support_table_attribute_helpers_map returns the parent's @support_table_attribute_helpers hash for STI subclasses. The defined_methods << attribute_method_name mutation therefore writes directly into the parent class's tracking array while holding the parent's mutex — correct for the common case. However, if define_support_table_named_instance_methods is ever invoked on an STI subclass (e.g. via a subclass calling named_instance_attribute_helpers), the write to @support_table_attribute_helpers on line 195 creates a new, independent copy on the subclass, while defined_methods from the previous support_table_attribute_helpers_map call still points into the parent's array. After that point the subclass's map and the parent's map diverge. This is unlikely in practice since STI subclasses should not register their own attribute helpers, but a clarifying comment would help.

@bdurand

bdurand commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

@CodeRabbit full review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Support-table synchronization now handles empty or missing data safely, retries concurrent uniqueness conflicts, and wraps validation failures. STI subclasses share cached state, named-instance helpers can be redefined, YAML supports aliases and date/time values, dependency discovery is updated, and related tests and release documentation are added.

Changes

Support table data behavior

Layer / File(s) Summary
Inherited state and named-instance helpers
lib/support_table_data.rb, spec/support_table_data_spec.rb
STI state caches, helper registration, protected-key tracking, helper redefinition, and predicate type casting are synchronized and covered by tests.
Synchronization safety and retry flow
lib/support_table_data.rb, README.md, spec/support_table_data_spec.rb
sync_table_data! handles missing tables, empty sources, validation failures, and one-time RecordNotUnique retries.
YAML loading and dependency discovery
lib/support_table_data.rb, lib/support_table_data/tasks/utils.rb, spec/data/*, spec/models*, spec/support_table_data_spec.rb
YAML aliases and date/time values are supported, dependency discovery uses updated state readers, and Size fixtures exercise overrides and class discovery.
Runtime defaults and documentation tooling
lib/support_table_data/railtie.rb, lib/support_table_data/documentation/source_file.rb, spec/support_table_data/documentation/source_file_spec.rb, CHANGELOG.md, VERSION
Explicit false auto-sync settings are preserved, YARD block matching is non-greedy, and release metadata documents version 1.6.2.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant SupportTableData
  participant DataFiles
  participant ActiveRecordTable
  Caller->>SupportTableData: sync_table_data!
  SupportTableData->>DataFiles: read canonical rows
  SupportTableData->>ActiveRecordTable: find or insert records
  ActiveRecordTable-->>SupportTableData: RecordNotUnique on concurrent insert
  SupportTableData->>ActiveRecordTable: retry synchronization once
  ActiveRecordTable-->>Caller: synchronized records or error
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is generic and does not indicate the main area of change or the specific fixes in this PR. Use a concise title that names the primary change, such as support table synchronization and helper fixes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch detailed-review

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/support_table_data.rb (1)

209-230: 🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Critical: support_table_data/sync_table_data! silently creates a phantom row and skips the intended override when a later data file overrides a named row's attribute without repeating the key attribute.

support_table_data merges rows solely by attributes[support_table_key_attribute] (defaulting to "id"). But define_support_table_named_instances (used for named-instance/attribute helpers) merges by the YAML top-level name key instead. These two merge strategies diverge whenever an override file specifies only a subset of attributes for a named row without repeating the key attribute — exactly the pattern introduced by this PR's own fixtures:

# spec/data/sizes_override.yml
large:
  label: Large

Since this entry has no id, support_table_data computes key_value = attributes["id"].to_s"", which doesn't match the "3" key already populated from sizes.yml. The result: Size.sync_table_data! will (1) leave the real "large" row's label as "Big" (the override is never applied to the DB row) and (2) silently insert a phantom row with label: "Large" and every other attribute nil.

Meanwhile Size.large_label (built from the name-keyed merge) correctly returns "Large", masking the discrepancy — the "redefines attribute helpers…" test passes even though the actual synced record is wrong. None of the current specs assert Size.count/the DB value of label on the "large" record after sync_table_data!, so this goes unnoticed.

Suggested direction: have support_table_data reuse the name-keyed merge (like define_support_table_named_instances) for Hash-structured files — merge attributes by the YAML top-level name first, then compute the final key attribute from the merged result — before falling back to key-attribute merging for flat array-style (JSON/CSV) records. Also worth adding a regression test asserting Size.sync_table_data! produces exactly 3 rows and that the "large" row's label is "Large".

🐛 Suggested direction (not a drop-in fix — needs verification against JSON/CSV interplay)
 def support_table_data
-  data = {}
-  support_table_data_files.each do |data_file_path|
-    file_data = support_table_parse_data_file(data_file_path)
-    file_data = file_data.values if file_data.is_a?(Hash)
-    file_data = Array(file_data).flatten
-    file_data.each do |attributes|
-      key_value = attributes[support_table_key_attribute].to_s
-      existing = data[key_value]
-      if existing
-        existing.merge!(attributes)
-      else
-        data[key_value] = attributes
-      end
-    end
-  end
-
-  data.values
+  merged_by_name = {}
+  data = {}
+
+  support_table_data_files.each do |data_file_path|
+    file_data = support_table_parse_data_file(data_file_path)
+    if file_data.is_a?(Hash)
+      file_data.each do |name, attributes|
+        next unless attributes.is_a?(Hash)
+        existing = merged_by_name[name.to_s]
+        merged_by_name[name.to_s] = existing ? existing.merge(attributes) : attributes
+      end
+    else
+      Array(file_data).flatten.each do |attributes|
+        key_value = attributes[support_table_key_attribute].to_s
+        existing = data[key_value]
+        data[key_value] = existing ? existing.merge(attributes) : attributes
+      end
+    end
+  end
+
+  merged_by_name.each_value do |attributes|
+    key_value = attributes[support_table_key_attribute].to_s
+    existing = data[key_value]
+    data[key_value] = existing ? existing.merge(attributes) : attributes
+  end
+
+  data.values
 end
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/support_table_data.rb` around lines 209 - 230, Update support_table_data
to merge Hash-structured file records by their top-level YAML name, reusing the
same name-keyed behavior as define_support_table_named_instances, so partial
overrides inherit the existing key attribute before final records are keyed.
Preserve key-attribute merging for flat array-style JSON/CSV records, and add
regression coverage verifying Size.sync_table_data! leaves exactly three rows
and updates the large row’s label to “Large”.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/support_table_data.rb`:
- Around line 483-507: Rename the class-level mutex instance variable used by
support_table_mutex from `@mutex` to the concern-specific `@support_table_mutex`,
and update all initialization and access points consistently. Preserve the
existing superclass fallback behavior for STI subclasses.
- Around line 458-464: Update the Psych version check in the YAML loading branch
to compare Gem::Version instances rather than using Psych::VERSION.to_f, using
the documented 3.1.0.pre1 threshold and preserving the existing safe_load
branches and arguments.

In `@lib/support_table_data/documentation/source_file.rb`:
- Line 10: Update the generated-documentation handling around YARD_COMMENT_REGEX
and its source.sub/source.match callers to process every existing YARD block,
not only the first. Remove all matching generated blocks while preserving
intervening user code, then emit exactly one regenerated block.

---

Outside diff comments:
In `@lib/support_table_data.rb`:
- Around line 209-230: Update support_table_data to merge Hash-structured file
records by their top-level YAML name, reusing the same name-keyed behavior as
define_support_table_named_instances, so partial overrides inherit the existing
key attribute before final records are keyed. Preserve key-attribute merging for
flat array-style JSON/CSV records, and add regression coverage verifying
Size.sync_table_data! leaves exactly three rows and updates the large row’s
label to “Large”.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dd33f181-6177-4306-8a10-a6690bc998b4

📥 Commits

Reviewing files that changed from the base of the PR and between b0997b0 and 0d7667a.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • README.md
  • VERSION
  • lib/support_table_data.rb
  • lib/support_table_data/documentation/source_file.rb
  • lib/support_table_data/railtie.rb
  • lib/support_table_data/tasks/utils.rb
  • spec/data/sizes.yml
  • spec/data/sizes_override.yml
  • spec/models.rb
  • spec/models/size.rb
  • spec/support_table_data/documentation/source_file_spec.rb
  • spec/support_table_data_spec.rb

Comment thread lib/support_table_data.rb
Comment on lines +458 to +464
require "date" unless defined?(Date)
data = if Psych::VERSION.to_f >= 3.1
YAML.safe_load(file_data, permitted_classes: [Date, Time], aliases: true)
else
# Positional arguments for Psych < 3.1 (Ruby 2.5).
YAML.safe_load(file_data, [Date, Time], [], true)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider Gem::Version instead of .to_f for the Psych version check.

Psych::VERSION.to_f >= 3.1 works for the realistic Psych 3.x/4.x/5.x version history, but .to_f is a known-fragile pattern for version comparisons in general (e.g. "3.10".to_f == 3.1, which would compare incorrectly against a real "3.2"). The documented, more robust idiom for this exact check is Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0.pre1").

♻️ Suggested refactor
-        data = if Psych::VERSION.to_f >= 3.1
+        data = if Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0.pre1")
           YAML.safe_load(file_data, permitted_classes: [Date, Time], aliases: true)
         else
           # Positional arguments for Psych < 3.1 (Ruby 2.5).
           YAML.safe_load(file_data, [Date, Time], [], true)
         end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
require "date" unless defined?(Date)
data = if Psych::VERSION.to_f >= 3.1
YAML.safe_load(file_data, permitted_classes: [Date, Time], aliases: true)
else
# Positional arguments for Psych < 3.1 (Ruby 2.5).
YAML.safe_load(file_data, [Date, Time], [], true)
end
require "date" unless defined?(Date)
data = if Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0.pre1")
YAML.safe_load(file_data, permitted_classes: [Date, Time], aliases: true)
else
# Positional arguments for Psych < 3.1 (Ruby 2.5).
YAML.safe_load(file_data, [Date, Time], [], true)
end
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/support_table_data.rb` around lines 458 - 464, Update the Psych version
check in the YAML loading branch to compare Gem::Version instances rather than
using Psych::VERSION.to_f, using the documented 3.1.0.pre1 threshold and
preserving the existing safe_load branches and arguments.

Comment thread lib/support_table_data.rb
Comment on lines +483 to +507

# The class level state used by the concern is stored in instance variables on the
# class where the concern was included. These readers fall back to the superclass
# so that single table inheritance subclasses share the state defined on their
# base class rather than crashing on uninitialized instance variables.

def support_table_mutex
@mutex || (superclass.include?(SupportTableData) ? superclass.send(:support_table_mutex) : nil)
end

def support_table_data_files
@support_table_data_files || (superclass.include?(SupportTableData) ? superclass.send(:support_table_data_files) : [])
end

def support_table_instance_names_map
@support_table_instance_names || (superclass.include?(SupportTableData) ? superclass.send(:support_table_instance_names_map) : {})
end

def support_table_attribute_helpers_map
@support_table_attribute_helpers || (superclass.include?(SupportTableData) ? superclass.send(:support_table_attribute_helpers_map) : {})
end

def support_table_dependency_names
@support_table_dependencies || (superclass.include?(SupportTableData) ? superclass.send(:support_table_dependency_names) : [])
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Solid cascading-state design; minor naming nit on @mutex.

The superclass-fallback pattern correctly lets STI subclasses share the base class's mutex/caches without re-running included do. One small nit: @mutex is a fairly generic ivar name for a class-level instance variable mixed into arbitrary ActiveRecord::Base subclasses; a more specific name like @support_table_mutex would reduce any (admittedly remote) risk of colliding with another concern/mixin using the same generic name on the same class.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/support_table_data.rb` around lines 483 - 507, Rename the class-level
mutex instance variable used by support_table_mutex from `@mutex` to the
concern-specific `@support_table_mutex`, and update all initialization and access
points consistently. Preserve the existing superclass fallback behavior for STI
subclasses.

BEGIN_YARD_COMMENT = "# Begin YARD docs for support_table_data"
END_YARD_COMMENT = "# End YARD docs for support_table_data"
YARD_COMMENT_REGEX = /^(?<indent>[ \t]*)#{BEGIN_YARD_COMMENT}.*^[ \t]*#{END_YARD_COMMENT}$/m
YARD_COMMENT_REGEX = /^(?<indent>[ \t]*)#{BEGIN_YARD_COMMENT}.*?^[ \t]*#{END_YARD_COMMENT}$/m

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Handle all duplicated generated-doc blocks.

The non-greedy regex preserves user code, but source.sub(...) and source.match(...) still process only the first block. A file with duplicated YARD sections therefore retains stale generated documentation after cleanup or regeneration. Remove all existing generated blocks while preserving user code, then emit exactly one block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/support_table_data/documentation/source_file.rb` at line 10, Update the
generated-documentation handling around YARD_COMMENT_REGEX and its
source.sub/source.match callers to process every existing YARD block, not only
the first. Remove all matching generated blocks while preserving intervening
user code, then emit exactly one regenerated block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant