support_table_data 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fded73fcb55268fa76b155b9cb192667bbe535e4e11f0cf00f8c3b8536fe3ee
4
- data.tar.gz: 9e06e50abcba73a18918a7fe8fa0168c93a2d0b39c0d1cfa03f1d512368632af
3
+ metadata.gz: '081b2612659ea90591ecf5fd7386acbb9d10dbd90c20301e12fba39d3d81e4b3'
4
+ data.tar.gz: b7d4960153f4799031127c8e2fb6ffaa5da49acc1e59833b64c9f417dd9d77df
5
5
  SHA512:
6
- metadata.gz: c107aa8e78cfbdfe8fdafd1cc42bf2f25b90075f561e9a7933e643ec2773647f4f96cc047d4ed0b90f8b15cd50ffa1e1f282c7f3abc61e25d70c3fb5150a2958
7
- data.tar.gz: 612b88d848c4eb101018bf2c643f8b76825e7bb22b459a6b5998a70238f9eb8627bbe7f6d8533b362b99300dcdce3a905bc3a22ca30c680ca03e4043c8837c7c
6
+ metadata.gz: e38a2f56f37888a737c8493ec0078666cf8a138415326946829c506a57fc81f5bc3e8407232e7bacbd82a5d0066d9513dd14340360e9d4179a3b1d51a7d69517
7
+ data.tar.gz: 569bbabe38749923686c5d9aa757851f6ba3fad64317f18e3fdb209aec9c714ed1f020a6c07a1588464d1ed9c129bb983ae25d5378ae324b0abee8e467e0fa96
data/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 1.5.1
8
+
9
+ ### Added
10
+
11
+ - YARD documentation tasks can now take an optional file path argument to add, verify, or remove documentation for a specific support table model instead of all models. For example, you can run `bundle exec rake support_table_data:yard_docs:add[app/models/color.rb]` to add documentation for the `Color` model.
12
+ - Added comment in generated YARD documentation indicating the command to run to update them so that it's clear to users how to keep the documentation up to date.
13
+ - Aliased `support_table_data:yard_docs` to `support_table_data:yard_docs:add` for convenience since adding the documentation is the most common action.
14
+
7
15
  ## 1.5.0
8
16
 
9
17
  ### Added
data/README.md CHANGED
@@ -187,7 +187,9 @@ completed:
187
187
 
188
188
  #### Documenting Named Instance Helpers
189
189
 
190
- In a Rails application, you can add YARD documentation for the named instance helpers by running the rake task `support_table_data:yard_docs:add`. This will add YARD comments to your model classes for each of the named instance helper methods defined on the model. Adding this documentation will help IDEs provide better code completion and inline documentation for the helper methods and expose the methods to AI agents.
190
+ In a Rails application, you can add YARD documentation for the named instance helpers by running the rake task `support_table_data:yard_docs`. This will add YARD comments to your model classes for each of the named instance helper methods defined on the model. Adding this documentation will help IDEs provide better code completion and inline documentation for the helper methods and expose the methods to AI agents.
191
+
192
+ To update a single model file, pass an optional file path argument, for example: `bundle exec rake "support_table_data:yard_docs[app/models/status.rb]"`.
191
193
 
192
194
  The default behavior is to add the documentation comments at the end of the model class by reopening the class definition. If you prefer to have the documentation comments appear elsewhere in the file, you can add the following markers to your model class and the YARD documentation will be inserted between these markers.
193
195
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.0
1
+ 1.5.1
@@ -9,6 +9,7 @@ module SupportTableData
9
9
  END_YARD_COMMENT = "# End YARD docs for support_table_data"
10
10
  YARD_COMMENT_REGEX = /^(?<indent>[ \t]*)#{BEGIN_YARD_COMMENT}.*^[ \t]*#{END_YARD_COMMENT}$/m
11
11
  CLASS_DEF_REGEX = /^[ \t]*class [a-zA-Z_0-9:]+.*?$/
12
+ UPDATE_COMMAND_COMMENT = "# To update these docs, run `bundle exec rake support_table_data:yard_docs`"
12
13
 
13
14
  # Initialize a new source file representation.
14
15
  #
@@ -53,6 +54,7 @@ module SupportTableData
53
54
 
54
55
  updated_source = source[0, existing_yard_docs.begin(0)]
55
56
  updated_source << "#{indent}#{BEGIN_YARD_COMMENT}\n"
57
+ updated_source << "#{indent}#{UPDATE_COMMAND_COMMENT}\n"
56
58
  updated_source << "#{indent}class #{klass.name}\n" if has_class_def
57
59
  updated_source << yard_docs
58
60
  updated_source << "\n#{indent}end" if has_class_def
@@ -62,6 +64,7 @@ module SupportTableData
62
64
  else
63
65
  yard_comments = <<~SOURCE.chomp("\n")
64
66
  #{BEGIN_YARD_COMMENT}
67
+ #{UPDATE_COMMAND_COMMENT}
65
68
  class #{klass.name}
66
69
  #{yard_docs.lines.map { |line| line.blank? ? "\n" : " #{line}" }.join}
67
70
  end
@@ -23,14 +23,16 @@ namespace :support_table_data do
23
23
  end
24
24
  end
25
25
 
26
+ task yard_docs: "yard_docs:add"
27
+
26
28
  namespace :yard_docs do
27
- desc "Adds YARD documentation comments to models to document the named instance methods."
28
- task add: :environment do
29
+ desc "Adds YARD documentation comments to models to document the named instance methods. Optional arg: file_path"
30
+ task :add, [:file_path] => :environment do |_task, args|
29
31
  require_relative "../support_table_data/documentation"
30
32
  require_relative "utils"
31
33
 
32
34
  SupportTableData::Tasks::Utils.eager_load!
33
- SupportTableData::Tasks::Utils.support_table_sources.each do |source_file|
35
+ SupportTableData::Tasks::Utils.support_table_sources(args[:file_path]).each do |source_file|
34
36
  next if source_file.yard_docs_up_to_date?
35
37
 
36
38
  source_file.path.write(source_file.source_with_yard_docs)
@@ -38,13 +40,13 @@ namespace :support_table_data do
38
40
  end
39
41
  end
40
42
 
41
- desc "Removes YARD documentation comments added by support_table_data from models."
42
- task remove: :environment do
43
+ desc "Removes YARD documentation comments added by support_table_data from models. Optional arg: file_path"
44
+ task :remove, [:file_path] => :environment do |_task, args|
43
45
  require_relative "../support_table_data/documentation"
44
46
  require_relative "utils"
45
47
 
46
48
  SupportTableData::Tasks::Utils.eager_load!
47
- SupportTableData::Tasks::Utils.support_table_sources.each do |source_file|
49
+ SupportTableData::Tasks::Utils.support_table_sources(args[:file_path]).each do |source_file|
48
50
  next unless source_file.has_yard_docs?
49
51
 
50
52
  source_file.path.write(source_file.source_without_yard_docs)
@@ -52,15 +54,15 @@ namespace :support_table_data do
52
54
  end
53
55
  end
54
56
 
55
- desc "Verify that all the support table models have up to date YARD documentation for named instance methods."
56
- task verify: :environment do
57
+ desc "Verify that support table models have up to date YARD docs for named instance methods. Optional arg: file_path"
58
+ task :verify, [:file_path] => :environment do |_task, args|
57
59
  require_relative "../support_table_data/documentation"
58
60
  require_relative "utils"
59
61
 
60
62
  SupportTableData::Tasks::Utils.eager_load!
61
63
 
62
64
  all_up_to_date = true
63
- SupportTableData::Tasks::Utils.support_table_sources.each do |source_file|
65
+ SupportTableData::Tasks::Utils.support_table_sources(args[:file_path]).each do |source_file|
64
66
  unless source_file.yard_docs_up_to_date?
65
67
  puts "YARD documentation is not up to date for #{source_file.klass.name}."
66
68
  all_up_to_date = false
@@ -68,9 +70,13 @@ namespace :support_table_data do
68
70
  end
69
71
 
70
72
  if all_up_to_date
71
- puts "All support table models have up to date YARD documentation."
73
+ if args[:file_path]
74
+ puts "YARD documentation is up to date for #{args[:file_path]}."
75
+ else
76
+ puts "All support table models have up to date YARD documentation."
77
+ end
72
78
  else
73
- raise "Run bundle exec rails support_table_data:yard_docs:add to update the documentation."
79
+ raise "Run bundle exec rake support_table_data:yard_docs to update the documentation."
74
80
  end
75
81
  end
76
82
  end
data/lib/tasks/utils.rb CHANGED
@@ -18,14 +18,17 @@ module SupportTableData
18
18
  end
19
19
  end
20
20
 
21
- # Return a hash mapping all models that include SupportTableData to their source file paths.
21
+ # Return all source files for models that include SupportTableData.
22
22
  #
23
+ # @param file_path [String, Pathname, nil] Optional file path to filter by.
23
24
  # @return [Array<SupportTableData::Documentation::SourceFile>]
24
- def support_table_sources
25
+ def support_table_sources(file_path = nil)
26
+ require_relative file_path if file_path
27
+
25
28
  sources = []
26
29
 
27
30
  ActiveRecord::Base.descendants.each do |klass|
28
- next unless klass.included_modules.include?(SupportTableData)
31
+ next unless klass.include?(SupportTableData)
29
32
 
30
33
  begin
31
34
  next if klass.instance_names.empty?
@@ -34,13 +37,18 @@ module SupportTableData
34
37
  next
35
38
  end
36
39
 
37
- file_path = SupportTableData::Tasks::Utils.model_file_path(klass)
38
- next unless file_path&.file? && file_path.readable?
40
+ model_file_path = SupportTableData::Tasks::Utils.model_file_path(klass)
41
+ next unless model_file_path&.file? && model_file_path.readable?
39
42
 
40
- sources << Documentation::SourceFile.new(klass, file_path)
43
+ sources << Documentation::SourceFile.new(klass, model_file_path)
41
44
  end
42
45
 
43
- sources
46
+ return sources if file_path.nil?
47
+
48
+ resolved_path = Pathname.new(file_path.to_s).expand_path
49
+ sources.select { |source| source.path.expand_path == resolved_path }
50
+ rescue ArgumentError
51
+ []
44
52
  end
45
53
 
46
54
  def model_file_path(klass)
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
20
  ignore_files = %w[
21
21
  .
22
+ AGENTS.md
22
23
  Appraisals
23
24
  Gemfile
24
25
  Gemfile.lock
@@ -9,3 +9,112 @@ class Status < ApplicationRecord
9
9
 
10
10
  validates :code, presence: true, uniqueness: true
11
11
  end
12
+
13
+ # Begin YARD docs for support_table_data
14
+ # To update these docs, run `bundle exec rake support_table_data:yard_docs`
15
+ class Status
16
+ # @!group Named Instances
17
+
18
+ # Find the named instance +active+ from the database.
19
+ #
20
+ # @!method self.active
21
+ # @return [Status]
22
+ # @raise [ActiveRecord::RecordNotFound] if the record does not exist
23
+ # @!visibility public
24
+
25
+ # Check if this record is the named instance +active+.
26
+ #
27
+ # @!method active?
28
+ # @return [Boolean]
29
+ # @!visibility public
30
+
31
+ # Get the name attribute from the data file
32
+ # for the named instance +active+.
33
+ #
34
+ # @!method self.active_name
35
+ # @return [Object]
36
+ # @!visibility public
37
+
38
+ # Find the named instance +canceled+ from the database.
39
+ #
40
+ # @!method self.canceled
41
+ # @return [Status]
42
+ # @raise [ActiveRecord::RecordNotFound] if the record does not exist
43
+ # @!visibility public
44
+
45
+ # Check if this record is the named instance +canceled+.
46
+ #
47
+ # @!method canceled?
48
+ # @return [Boolean]
49
+ # @!visibility public
50
+
51
+ # Get the name attribute from the data file
52
+ # for the named instance +canceled+.
53
+ #
54
+ # @!method self.canceled_name
55
+ # @return [Object]
56
+ # @!visibility public
57
+
58
+ # Find the named instance +completed+ from the database.
59
+ #
60
+ # @!method self.completed
61
+ # @return [Status]
62
+ # @raise [ActiveRecord::RecordNotFound] if the record does not exist
63
+ # @!visibility public
64
+
65
+ # Check if this record is the named instance +completed+.
66
+ #
67
+ # @!method completed?
68
+ # @return [Boolean]
69
+ # @!visibility public
70
+
71
+ # Get the name attribute from the data file
72
+ # for the named instance +completed+.
73
+ #
74
+ # @!method self.completed_name
75
+ # @return [Object]
76
+ # @!visibility public
77
+
78
+ # Find the named instance +failed+ from the database.
79
+ #
80
+ # @!method self.failed
81
+ # @return [Status]
82
+ # @raise [ActiveRecord::RecordNotFound] if the record does not exist
83
+ # @!visibility public
84
+
85
+ # Check if this record is the named instance +failed+.
86
+ #
87
+ # @!method failed?
88
+ # @return [Boolean]
89
+ # @!visibility public
90
+
91
+ # Get the name attribute from the data file
92
+ # for the named instance +failed+.
93
+ #
94
+ # @!method self.failed_name
95
+ # @return [Object]
96
+ # @!visibility public
97
+
98
+ # Find the named instance +pending+ from the database.
99
+ #
100
+ # @!method self.pending
101
+ # @return [Status]
102
+ # @raise [ActiveRecord::RecordNotFound] if the record does not exist
103
+ # @!visibility public
104
+
105
+ # Check if this record is the named instance +pending+.
106
+ #
107
+ # @!method pending?
108
+ # @return [Boolean]
109
+ # @!visibility public
110
+
111
+ # Get the name attribute from the data file
112
+ # for the named instance +pending+.
113
+ #
114
+ # @!method self.pending_name
115
+ # @return [Object]
116
+ # @!visibility public
117
+
118
+ # @!endgroup
119
+ end
120
+ # End YARD docs for support_table_data
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: support_table_data
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
@@ -43,7 +43,6 @@ executables: []
43
43
  extensions: []
44
44
  extra_rdoc_files: []
45
45
  files:
46
- - AGENTS.md
47
46
  - ARCHITECTURE.md
48
47
  - CHANGELOG.md
49
48
  - MIT-LICENSE.txt
data/AGENTS.md DELETED
@@ -1,140 +0,0 @@
1
- # Copilot Instructions for support_table_data
2
-
3
- ## Project Overview
4
-
5
- A Ruby gem providing an ActiveRecord mixin for managing support/lookup tables with canonical data defined in YAML/JSON/CSV files. The gem dynamically generates helper methods to reference specific records naturally in code (e.g., `Status.pending` instead of `Status.find_by(name: 'Pending')`).
6
-
7
- **Core concept**: Support tables blur the line between data and code—they contain small canonical datasets that must exist for the application to work.
8
-
9
- ## Architecture
10
-
11
- ### Key Components
12
-
13
- - **`SupportTableData` module** ([lib/support_table_data.rb](lib/support_table_data.rb)): Main concern mixed into ActiveRecord models
14
- - **Named instance system**: Dynamically generates class methods (`.pending`), predicate methods (`.pending?`), and attribute helpers (`.pending_id`) from hash-based data files
15
- - **Data sync engine**: Compares canonical data files with database records, creating/updating as needed in atomic transactions
16
- - **File parsers**: Supports YAML, JSON, and CSV formats with unified interface
17
-
18
- ### Data Flow
19
-
20
- 1. Data files (YAML/JSON/CSV) define canonical records with unique key attributes
21
- 2. `add_support_table_data` registers file paths and triggers method generation for hash-based files
22
- 3. `sync_table_data!` parses files, loads matching DB records, and updates/creates within transactions
23
- 4. Named instance methods are dynamically defined via `class_eval` with memoization
24
-
25
- ## Development Workflows
26
-
27
- ### Running Tests
28
-
29
- ```bash
30
- bundle exec rspec # Run all specs
31
- bundle exec rspec spec/support_table_data_spec.rb # Single file
32
- bundle exec rake appraisals # Test against all ActiveRecord versions
33
- ```
34
-
35
- Uses RSpec with in-memory SQLite database. Test models defined in [spec/models.rb](spec/models.rb), data files in `spec/data/`.
36
-
37
- ### Testing Against Multiple ActiveRecord Versions
38
-
39
- The gem supports ActiveRecord 6.0-8.0. Uses Appraisal for multi-version testing:
40
-
41
- ```bash
42
- bundle exec appraisal install # Install all gemfiles
43
- bundle exec appraisal rspec # Run specs against all versions
44
- ```
45
-
46
- See `Appraisals` file and `gemfiles/` directory.
47
-
48
- ### Code Style
49
-
50
- Uses Standard Ruby formatter:
51
-
52
- ```bash
53
- bundle exec rake standard:fix # Auto-fix style issues
54
- ```
55
-
56
- ## Critical Patterns
57
-
58
- ### Named Instance Method Generation
59
-
60
- **Hash-based data files** trigger dynamic method generation. Example from [spec/data/colors/named_colors.yml](spec/data/colors/named_colors.yml):
61
-
62
- ```yaml
63
- red:
64
- id: 1
65
- name: Red
66
- value: 16711680
67
- ```
68
-
69
- Generates:
70
- - `Color.red` → finds record by id
71
- - `color_instance.red?` → tests if `color_instance.id == 1`
72
- - `Color.red_id` → returns `1` (if `named_instance_attribute_helpers :id` defined)
73
-
74
- **Implementation**: See `define_support_table_named_instance_methods` in [lib/support_table_data.rb](lib/support_table_data.rb#L230-L265). Methods are generated using `class_eval` with string interpolation.
75
-
76
- ### Custom Setters for Associations
77
-
78
- Support tables often reference other support tables via named instances. Pattern from [spec/models.rb](spec/models.rb#L72-L74):
79
-
80
- ```ruby
81
- def group_name=(value)
82
- self.group = Group.named_instance(value)
83
- end
84
- ```
85
-
86
- Allows data files to reference related records by instance name instead of foreign keys.
87
-
88
- ### Key Attribute Configuration
89
-
90
- By default, uses model's `id` column. Override for non-id keys:
91
-
92
- ```ruby
93
- self.support_table_key_attribute = :name # Use 'name' instead of 'id'
94
- ```
95
-
96
- Key attributes cannot be updated—changing them creates new records.
97
-
98
- ### Dependency Resolution
99
-
100
- `sync_all!` automatically resolves dependencies via `belongs_to` associations and loads tables in correct order. For complex cases (join tables, indirect dependencies), explicitly declare:
101
-
102
- ```ruby
103
- support_table_dependency "OtherModel"
104
- ```
105
-
106
- See [lib/support_table_data.rb](lib/support_table_data.rb#L219-L222) and dependency resolution logic.
107
-
108
- ## Testing Conventions
109
-
110
- - **Test data isolation**: Each test deletes all records in `before` block ([spec/spec_helper.rb](spec/spec_helper.rb))
111
- - **Sync before assertions**: Tests call `sync_table_data!` or `sync_all!` before verifying records exist
112
- - **Multi-file merging**: Tests verify that multiple data files for same model merge correctly (see `Color` model with 5 data files)
113
- - **STI handling**: See `Polygon`/`Triangle`/`Rectangle` tests for Single Table Inheritance patterns
114
-
115
- ## Common Pitfalls
116
-
117
- 1. **Method name conflicts**: Named instance methods raise `ArgumentError` if method already exists. Instance names must match `/\A[a-z][a-z0-9_]+\z/`
118
- 2. **Array vs hash data**: Only hash-keyed data generates named instance methods. Use arrays or underscore-prefixed keys (`_others`) for records without helpers
119
- 3. **Protected instances**: Records in data files cannot be deleted via `destroy` (though this gem doesn't enforce it—see companion caching gem)
120
- 4. **Transaction safety**: All sync operations wrapped in transactions; changes rollback on failure
121
-
122
- ## Rails Integration
123
-
124
- In Rails apps, the gem automatically:
125
- - Sets `SupportTableData.data_directory` to `Rails.root/db/support_tables`
126
- - Provides `rake support_table_data:sync` task ([lib/tasks/support_table_data.rake](lib/tasks/support_table_data.rake))
127
- - Handles eager loading in both classic and Zeitwerk autoloaders
128
-
129
- ## File References
130
-
131
- - Main module: [lib/support_table_data.rb](lib/support_table_data.rb)
132
- - Test models: [spec/models.rb](spec/models.rb) - comprehensive examples of patterns
133
- - Sync task: [lib/tasks/support_table_data.rake](lib/tasks/support_table_data.rake)
134
- - Architecture docs: [ARCHITECTURE.md](ARCHITECTURE.md) - detailed diagrams and design decisions
135
-
136
- ## Version Compatibility
137
-
138
- - Ruby ≥ 2.5
139
- - ActiveRecord ≥ 6.0
140
- - Ruby 3.4+: Requires `csv` gem in Gemfile (removed from stdlib)