familia 2.0.0.pre13 → 2.0.0.pre15
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 +4 -4
- data/CHANGELOG.rst +29 -7
- data/Gemfile.lock +1 -1
- data/README.md +21 -2
- data/docs/guides/Feature-System-Autoloading.md +3 -33
- data/docs/guides/time-utilities.md +4 -4
- data/docs/migrating/v2.0.0-pre11.md +2 -2
- data/docs/migrating/v2.0.0-pre13.md +38 -272
- data/docs/migrating/v2.0.0-pre14.md +37 -0
- data/examples/safe_dump.rb +1 -1
- data/lib/familia/base.rb +1 -1
- data/lib/familia/data_type.rb +1 -1
- data/lib/familia/{autoloader.rb → features/autoloader.rb} +33 -25
- data/lib/familia/features/encrypted_fields.rb +2 -2
- data/lib/familia/features/expiration/extensions.rb +61 -0
- data/lib/familia/features/expiration.rb +5 -62
- data/lib/familia/features/external_identifier.rb +6 -4
- data/lib/familia/features/object_identifier.rb +2 -1
- data/lib/familia/features/quantization.rb +3 -3
- data/lib/familia/features/relationships.rb +5 -6
- data/lib/familia/features/safe_dump.rb +3 -5
- data/lib/familia/features/transient_fields.rb +3 -1
- data/lib/familia/features.rb +20 -11
- data/lib/familia/field_type.rb +1 -1
- data/lib/familia/horreum.rb +1 -1
- data/lib/familia/refinements/{time_utils.rb → time_literals.rb} +35 -4
- data/lib/familia/refinements.rb +1 -1
- data/lib/familia/utils.rb +1 -1
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +0 -1
- data/try/core/autoloader_try.rb +9 -9
- data/try/core/extensions_try.rb +1 -1
- data/try/core/time_utils_try.rb +18 -18
- data/try/features/external_identifier/external_identifier_try.rb +26 -0
- data/try/features/safe_dump/module_based_extensions_try.rb +100 -0
- data/try/features/safe_dump/safe_dump_autoloading_try.rb +0 -4
- data/try/helpers/test_helpers.rb +6 -6
- metadata +6 -5
- data/lib/familia/features/autoloadable.rb +0 -113
- data/try/features/autoloadable/autoloadable_try.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00416beac08786c1fffd75a0c2578669c6a0d18169824ca1a23e9122018a386b
|
4
|
+
data.tar.gz: c38f7bfe985a7d6151abf2ce4b6d7ca32ddb97adf8d069880f7e919662937851
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3d6a60c86460578567fbd6f33e96c8ae0ee2dbfc80f3ffc6f123dc6fb84c6020efd359601122e63543c0128401d235587e9770df8acbbfa1f55cb908a012e07
|
7
|
+
data.tar.gz: 5062f93d7494df05a6d62dade395a0522ca8ab02afd4fdc5a00ee21db08b05ace8c3227d07739ef7cdd727fa72888ea4ec415491eb60028b25166d107d574e8e
|
data/CHANGELOG.rst
CHANGED
@@ -12,6 +12,28 @@ Versioning <https://semver.org/spec/v2.0.0.html>`__.
|
|
12
12
|
|
13
13
|
<!--scriv-insert-here-->
|
14
14
|
|
15
|
+
.. _changelog-2.0.0.pre14:
|
16
|
+
|
17
|
+
2.0.0.pre14 — 2025-09-08
|
18
|
+
========================
|
19
|
+
|
20
|
+
Changed
|
21
|
+
-------
|
22
|
+
|
23
|
+
- **BREAKING CHANGE**: Renamed ``Familia::Refinements::TimeUtils`` to ``Familia::Refinements::TimeLiterals`` to better reflect the module's primary purpose of enabling numeric and string values to be treated as time unit literals (e.g., ``5.minutes``, ``"30m".in_seconds``). Functionality remains the same - only the module name has changed. Users must update their refinement usage from ``using Familia::Refinements::TimeUtils`` to ``using Familia::Refinements::TimeLiterals``.
|
24
|
+
|
25
|
+
Fixed
|
26
|
+
-----
|
27
|
+
|
28
|
+
- Fixed ExternalIdentifier HashKey method calls by replacing incorrect ``.del()`` calls with ``.remove_field()`` in three critical locations: extid setter (cleanup old mapping when changing value), find_by_extid (cleanup orphaned mapping when object not found), and destroy! (cleanup mapping when object is destroyed). Added comprehensive test coverage for all scenarios to prevent regression. PR #100
|
29
|
+
|
30
|
+
AI Assistance
|
31
|
+
-------------
|
32
|
+
|
33
|
+
- Claude Code helped rename TimeUtils to TimeLiterals throughout the codebase, including module name, file path, all usage references, and updating existing documentation.
|
34
|
+
- Gemini 2.5 Flash wrote the inline docs for TimeLiterals based on a discussion re: naming rationale.
|
35
|
+
- Claude Code fixed the ExternalIdentifier HashKey method bug, replacing incorrect ``.del()`` calls with proper ``.remove_field()`` calls, and implemented test coverage for the affected scenarios.
|
36
|
+
|
15
37
|
.. _changelog-2.0.0.pre13:
|
16
38
|
|
17
39
|
2.0.0.pre13 — 2025-09-07
|
@@ -20,13 +42,13 @@ Versioning <https://semver.org/spec/v2.0.0.html>`__.
|
|
20
42
|
Added
|
21
43
|
-----
|
22
44
|
|
23
|
-
- **Feature
|
45
|
+
- **Feature Autoloading System**: Features can now automatically discover and load extension files from your project directories. When you include a feature like ``safe_dump``, Familia searches for configuration files using conventional patterns like ``{model_name}/{feature_name}_*.rb``, enabling clean separation between core model definitions and feature-specific configurations. See ``docs/migrating/v2.0.0-pre13.md`` for migration details.
|
24
46
|
|
25
|
-
- **Consolidated autoloader architecture**: Introduced ``Familia::Autoloader`` as a shared utility for consistent file loading patterns across the framework, supporting both general-purpose and feature-specific autoloading scenarios.
|
47
|
+
- **Consolidated autoloader architecture**: Introduced ``Familia::Features::Autoloader`` as a shared utility for consistent file loading patterns across the framework, supporting both general-purpose and feature-specific autoloading scenarios.
|
26
48
|
|
27
49
|
- Added ``PER_MONTH`` constant (2,629,746 seconds = 30.437 days) derived from Gregorian year for consistent month calculations.
|
28
50
|
- Added ``months``, ``month``, and ``in_months`` conversion methods to Numeric refinement.
|
29
|
-
- Added month unit mappings (``'mo'``, ``'month'``, ``'months'``) to
|
51
|
+
- Added month unit mappings (``'mo'``, ``'month'``, ``'months'``) to TimeLiterals ``UNIT_METHODS`` hash.
|
30
52
|
|
31
53
|
- **Error Handling**: Added ``NotSupportedError`` for invalid serialization mode combinations in encryption subsystem. PR #97
|
32
54
|
|
@@ -34,7 +56,7 @@ Changed
|
|
34
56
|
-------
|
35
57
|
|
36
58
|
- Refactored time and numeric extensions from global monkey patches to proper Ruby refinements for better encapsulation and reduced global namespace pollution
|
37
|
-
- Updated all internal classes to use refinements via ``using Familia::Refinements::
|
59
|
+
- Updated all internal classes to use refinements via ``using Familia::Refinements::TimeLiterals`` statements
|
38
60
|
- Added centralized ``RefinedContext`` module in test helpers to support refinement testing in tryouts files
|
39
61
|
|
40
62
|
- Updated ``PER_YEAR`` constant to use Gregorian year (31,556,952 seconds = 365.2425 days) for calendar consistency.
|
@@ -49,7 +71,7 @@ Fixed
|
|
49
71
|
- Fixed byte conversion logic in ``to_bytes`` method to correctly handle exact 1024-byte boundaries (``size >= 1024`` instead of ``size > 1024``)
|
50
72
|
- Resolved refinement testing issues in tryouts by implementing ``eval``-based code execution within refined contexts
|
51
73
|
|
52
|
-
- Fixed
|
74
|
+
- Fixed TimeLiterals refinement ``months_old`` and ``years_old`` methods returning incorrect values (raw seconds instead of months/years). The underlying ``age_in`` method now properly handles ``:months`` and ``:years`` units. Issue #94.
|
53
75
|
- Fixed calendar consistency issue where ``12.months != 1.year`` by updating ``PER_YEAR`` to use Gregorian year (365.2425 days) and defining ``PER_MONTH`` as ``PER_YEAR / 12``.
|
54
76
|
|
55
77
|
Security
|
@@ -72,7 +94,7 @@ AI Assistance
|
|
72
94
|
|
73
95
|
- Significant AI assistance in architectural design and implementation of the feature-specific autoloading system, including pattern matching logic, Ruby introspection methods, and comprehensive debugging of edge cases and thread safety considerations.
|
74
96
|
|
75
|
-
- Claude Code assisted with implementing the fix for broken ``months_old`` and ``years_old`` methods in the
|
97
|
+
- Claude Code assisted with implementing the fix for broken ``months_old`` and ``years_old`` methods in the TimeLiterals refinement, including analysis, implementation, testing, and documentation.
|
76
98
|
|
77
99
|
- Performance optimization research and OJ gem integration strategy, including compatibility analysis and testing approach for seamless stdlib JSON replacement. PR #97
|
78
100
|
|
@@ -161,7 +183,7 @@ Added
|
|
161
183
|
with ancestry chain traversal for model-specific feature
|
162
184
|
registration. This enables better organization, standardized naming,
|
163
185
|
and automatic loading of project-specific features via the new
|
164
|
-
``Familia::Autoloader`` module.
|
186
|
+
``Familia::Features::Autoloader`` module.
|
165
187
|
- **Improved SafeDump DSL**: Replaced the internal
|
166
188
|
``@safe_dump_fields`` implementation with a cleaner, more robust DSL
|
167
189
|
using ``safe_dump_field`` and ``safe_dump_fields`` methods.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -170,7 +170,26 @@ All relationships support automatic indexing and tracking - objects are automati
|
|
170
170
|
|
171
171
|
## Organizing Complex Models
|
172
172
|
|
173
|
-
For large applications, you can organize model complexity using custom features:
|
173
|
+
For large applications, you can organize model complexity using custom features and the Feature Autoloading System:
|
174
|
+
|
175
|
+
### Feature Autoloading System
|
176
|
+
|
177
|
+
Familia automatically discovers and loads feature-specific configuration files, enabling clean separation between core model definitions and feature configurations:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
# app/models/user.rb - Clean model definition
|
181
|
+
class User < Familia::Horreum
|
182
|
+
field :name, :email, :password
|
183
|
+
feature :safe_dump # Configuration auto-loaded
|
184
|
+
end
|
185
|
+
|
186
|
+
# app/models/user/safe_dump_extensions.rb - Automatically discovered
|
187
|
+
class User
|
188
|
+
safe_dump_fields :name, :email # password excluded for security
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
192
|
+
Extension files follow the pattern: `{model_name}/{feature_name}_*.rb`
|
174
193
|
|
175
194
|
### Self-Registering Features
|
176
195
|
|
@@ -201,7 +220,7 @@ class Customer < Familia::Horreum
|
|
201
220
|
end
|
202
221
|
```
|
203
222
|
|
204
|
-
|
223
|
+
These approaches keep complex models organized while maintaining Familia's clean, declarative style. For detailed migration information, see the [migration guides](docs/migrating/).
|
205
224
|
|
206
225
|
## AI Development Assistance
|
207
226
|
|
@@ -44,7 +44,7 @@ end
|
|
44
44
|
|
45
45
|
The `post_inclusion_autoload` system works in **two phases**:
|
46
46
|
|
47
|
-
###
|
47
|
+
### Feature System Hook
|
48
48
|
|
49
49
|
In `lib/familia/features.rb`, after including the feature module:
|
50
50
|
|
@@ -61,29 +61,6 @@ def feature(feature_name, **options)
|
|
61
61
|
end
|
62
62
|
```
|
63
63
|
|
64
|
-
### Phase 2: Autoloadable Implementation
|
65
|
-
|
66
|
-
The `post_inclusion_autoload` method in `lib/familia/features/autoloadable.rb`:
|
67
|
-
|
68
|
-
1. **Gets the source location** of the user's class file using Ruby's introspection:
|
69
|
-
```ruby
|
70
|
-
location_info = Module.const_source_location(base.name)
|
71
|
-
source_location = location_info&.first # e.g., "/path/to/models/user.rb"
|
72
|
-
```
|
73
|
-
|
74
|
-
2. **Calculates extension file paths** based on conventions:
|
75
|
-
```ruby
|
76
|
-
base_dir = File.dirname(location_path) # "/path/to/models"
|
77
|
-
model_name = base.name.snake_case # "user"
|
78
|
-
|
79
|
-
# Look for files like:
|
80
|
-
patterns = [
|
81
|
-
"/path/to/models/user/safe_dump_*.rb",
|
82
|
-
"/path/to/models/user/features/safe_dump_*.rb",
|
83
|
-
"/path/to/models/features/safe_dump_*.rb"
|
84
|
-
]
|
85
|
-
```
|
86
|
-
|
87
64
|
3. **Loads any matching files** found in those locations
|
88
65
|
|
89
66
|
## Why This Timing Matters
|
@@ -199,17 +176,10 @@ The `post_inclusion_autoload` system provides a clean, automatic, and safe way t
|
|
199
176
|
|
200
177
|
## Implementation Details
|
201
178
|
|
202
|
-
###
|
179
|
+
### Autoloader
|
203
180
|
|
204
|
-
|
181
|
+
Looks for features files in models/features.rb, models/features/, models/model_name/features.rb, models/model_name/features/
|
205
182
|
|
206
|
-
```ruby
|
207
|
-
module Familia::Features::SafeDump
|
208
|
-
include Familia::Features::Autoloadable # ← Enables autoloading
|
209
|
-
|
210
|
-
# Feature implementation...
|
211
|
-
end
|
212
|
-
```
|
213
183
|
|
214
184
|
### Anonymous Class Handling
|
215
185
|
|
@@ -4,10 +4,10 @@ Familia provides a comprehensive time utilities refinement that adds convenient
|
|
4
4
|
|
5
5
|
## Overview
|
6
6
|
|
7
|
-
The `Familia::Refinements::
|
7
|
+
The `Familia::Refinements::TimeLiterals` module extends Ruby's built-in classes with intuitive time manipulation methods:
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
using Familia::Refinements::
|
10
|
+
using Familia::Refinements::TimeLiterals
|
11
11
|
|
12
12
|
2.hours #=> 7200 (seconds)
|
13
13
|
"30m".in_seconds #=> 1800
|
@@ -40,7 +40,7 @@ This prevents subtle bugs where `12.months` and `1.year` would differ by ~5.8 ho
|
|
40
40
|
### Converting Numbers to Time Units
|
41
41
|
|
42
42
|
```ruby
|
43
|
-
using Familia::Refinements::
|
43
|
+
using Familia::Refinements::TimeLiterals
|
44
44
|
|
45
45
|
# Singular and plural forms work identically
|
46
46
|
1.second #=> 1
|
@@ -140,7 +140,7 @@ timestamp.within?(1.hour) #=> false
|
|
140
140
|
### Cache Expiration
|
141
141
|
|
142
142
|
```ruby
|
143
|
-
using Familia::Refinements::
|
143
|
+
using Familia::Refinements::TimeLiterals
|
144
144
|
|
145
145
|
class CacheEntry < Familia::Horreum
|
146
146
|
field :data
|
@@ -124,7 +124,7 @@ end
|
|
124
124
|
|
125
125
|
class Customer < Familia::Horreum
|
126
126
|
module Features
|
127
|
-
include Familia::Autoloader
|
127
|
+
include Familia::Features::Autoloader
|
128
128
|
# Automatically discovers and loads all *.rb files from customer/features/
|
129
129
|
end
|
130
130
|
end
|
@@ -210,7 +210,7 @@ If you have project-specific features, set up auto-loading:
|
|
210
210
|
module YourProject
|
211
211
|
class ModelName < Familia::Horreum
|
212
212
|
module Features
|
213
|
-
include Familia::Autoloader
|
213
|
+
include Familia::Features::Autoloader
|
214
214
|
end
|
215
215
|
end
|
216
216
|
end
|
@@ -1,320 +1,86 @@
|
|
1
1
|
# Migrating Guide: v2.0.0-pre13
|
2
2
|
|
3
|
-
This version introduces
|
3
|
+
This version introduces the Feature Autoloading System for automatic discovery and loading of feature-specific configuration files, enabling cleaner separation between core model definitions and feature configurations.
|
4
4
|
|
5
|
-
## Feature
|
5
|
+
## Feature Autoloading System
|
6
6
|
|
7
|
-
###
|
7
|
+
### What Changed
|
8
8
|
|
9
|
-
|
9
|
+
Features now automatically discover and load extension files from your project directories using conventional file naming patterns. This eliminates the need to configure features in your main model files.
|
10
10
|
|
11
|
-
### Basic
|
11
|
+
### Basic Migration
|
12
12
|
|
13
|
-
#### Before
|
13
|
+
#### Before
|
14
14
|
```ruby
|
15
15
|
# app/models/user.rb
|
16
16
|
class User < Familia::Horreum
|
17
17
|
field :name, :email, :password
|
18
18
|
|
19
19
|
feature :safe_dump
|
20
|
-
|
21
|
-
safe_dump_fields :name, :email # password excluded for security
|
20
|
+
safe_dump_fields :name, :email # Configuration mixed with model
|
22
21
|
end
|
23
22
|
```
|
24
23
|
|
25
|
-
#### After
|
24
|
+
#### After
|
26
25
|
```ruby
|
27
26
|
# app/models/user.rb - Clean model definition
|
28
27
|
class User < Familia::Horreum
|
29
28
|
field :name, :email, :password
|
30
|
-
feature :safe_dump #
|
29
|
+
feature :safe_dump # Configuration auto-loaded
|
31
30
|
end
|
32
31
|
|
33
|
-
# app/models/user/safe_dump_extensions.rb - Automatically
|
32
|
+
# app/models/user/safe_dump_extensions.rb - Automatically discovered
|
34
33
|
class User
|
35
|
-
safe_dump_fields :name, :email
|
34
|
+
safe_dump_fields :name, :email
|
36
35
|
end
|
37
36
|
```
|
38
37
|
|
39
|
-
### File Naming
|
40
|
-
|
41
|
-
The autoloading system follows these patterns for discovering extension files:
|
38
|
+
### File Naming Convention
|
42
39
|
|
43
|
-
|
40
|
+
Extension files follow the pattern: `{model_name}/{feature_name}_*.rb`
|
44
41
|
|
45
|
-
**Example Structures:**
|
46
42
|
```
|
47
43
|
app/models/
|
48
|
-
├── user.rb
|
44
|
+
├── user.rb
|
49
45
|
├── user/
|
50
|
-
│ ├── safe_dump_extensions.rb
|
51
|
-
│
|
52
|
-
│ └── relationships_config.rb # Relationships configuration
|
53
|
-
├── product.rb # Another model
|
54
|
-
└── product/
|
55
|
-
├── safe_dump_fields.rb # Product's SafeDump config
|
56
|
-
└── expiration_settings.rb # Expiration configuration
|
57
|
-
```
|
58
|
-
|
59
|
-
#### Supported Patterns
|
60
|
-
- `safe_dump_extensions.rb`
|
61
|
-
- `safe_dump_*.rb` (any filename starting with the feature name)
|
62
|
-
- `expiration_config.rb`
|
63
|
-
- `relationships_setup.rb`
|
64
|
-
|
65
|
-
### Advanced Configuration Examples
|
66
|
-
|
67
|
-
#### Complex SafeDump Setup
|
68
|
-
```ruby
|
69
|
-
# app/models/customer.rb
|
70
|
-
class Customer < Familia::Horreum
|
71
|
-
field :first_name, :last_name, :email, :phone
|
72
|
-
field :credit_card_number, :ssn, :internal_notes
|
73
|
-
|
74
|
-
feature :safe_dump
|
75
|
-
end
|
76
|
-
|
77
|
-
# app/models/customer/safe_dump_configuration.rb
|
78
|
-
class Customer
|
79
|
-
# Define which fields are safe for API responses
|
80
|
-
safe_dump_fields :first_name, :last_name, :email
|
81
|
-
|
82
|
-
# Custom serialization for specific fields
|
83
|
-
def safe_dump_email
|
84
|
-
email&.downcase
|
85
|
-
end
|
86
|
-
|
87
|
-
# Computed fields for API
|
88
|
-
def safe_dump_full_name
|
89
|
-
"#{first_name} #{last_name}".strip
|
90
|
-
end
|
91
|
-
end
|
92
|
-
```
|
93
|
-
|
94
|
-
#### Multi-Feature Organization
|
95
|
-
```ruby
|
96
|
-
# app/models/session.rb
|
97
|
-
class Session < Familia::Horreum
|
98
|
-
field :user_id, :token, :ip_address, :user_agent
|
99
|
-
|
100
|
-
feature :safe_dump
|
101
|
-
feature :expiration
|
102
|
-
end
|
103
|
-
|
104
|
-
# app/models/session/safe_dump_api.rb
|
105
|
-
class Session
|
106
|
-
safe_dump_fields :user_id, :ip_address
|
107
|
-
# token excluded for security
|
108
|
-
end
|
109
|
-
|
110
|
-
# app/models/session/expiration_policy.rb
|
111
|
-
class Session
|
112
|
-
# Sessions expire after 24 hours
|
113
|
-
def self.default_ttl
|
114
|
-
24 * 60 * 60
|
115
|
-
end
|
116
|
-
|
117
|
-
# Cascade expiration to related data
|
118
|
-
cascade_expiration_to :user_sessions
|
119
|
-
end
|
120
|
-
```
|
121
|
-
|
122
|
-
### Consolidated Autoloader Architecture
|
123
|
-
|
124
|
-
#### Familia::Autoloader
|
125
|
-
|
126
|
-
The new `Familia::Autoloader` class provides a shared utility for consistent file loading patterns across the framework:
|
127
|
-
|
128
|
-
```ruby
|
129
|
-
# Internal usage example (you typically won't call this directly)
|
130
|
-
autoloader = Familia::Autoloader.new(
|
131
|
-
base_class: User,
|
132
|
-
feature_name: :safe_dump,
|
133
|
-
search_patterns: ['user/safe_dump_*.rb']
|
134
|
-
)
|
135
|
-
|
136
|
-
# Discovers and loads matching files
|
137
|
-
autoloader.discover_and_load_extensions
|
138
|
-
```
|
139
|
-
|
140
|
-
#### Autoloading Strategies
|
141
|
-
|
142
|
-
The autoloader supports multiple discovery strategies:
|
143
|
-
|
144
|
-
1. **Directory-based**: Search in conventional directories
|
145
|
-
2. **Pattern-based**: Use glob patterns for flexible matching
|
146
|
-
3. **Explicit paths**: Load specific files when found
|
147
|
-
|
148
|
-
### How Autoloading Works
|
149
|
-
|
150
|
-
#### Discovery Process
|
151
|
-
|
152
|
-
1. **Feature Activation**: When `feature :safe_dump` is called
|
153
|
-
2. **Path Resolution**: Autoloader determines search paths based on model location
|
154
|
-
3. **Pattern Matching**: Searches for files matching `{model_name}/{feature_name}_*.rb`
|
155
|
-
4. **File Loading**: Loads discovered files in alphabetical order
|
156
|
-
5. **Extension Application**: Feature-specific methods become available
|
157
|
-
|
158
|
-
#### Search Locations
|
159
|
-
|
160
|
-
The autoloader searches in these locations (in order):
|
161
|
-
|
162
|
-
```ruby
|
163
|
-
# If your model is in app/models/user.rb, it searches:
|
164
|
-
[
|
165
|
-
'app/models/user/', # Same directory as model
|
166
|
-
'lib/user/', # Lib directory
|
167
|
-
'config/models/user/', # Config directory
|
168
|
-
'./user/' # Current directory
|
169
|
-
]
|
46
|
+
│ ├── safe_dump_extensions.rb # SafeDump configuration
|
47
|
+
│ └── expiration_config.rb # Expiration settings
|
170
48
|
```
|
171
49
|
|
172
50
|
### Migration Steps
|
173
51
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
```bash
|
179
|
-
# Create directories for feature configurations
|
180
|
-
mkdir -p app/models/user
|
181
|
-
mkdir -p app/models/product
|
182
|
-
mkdir -p app/models/order
|
183
|
-
|
184
|
-
# Move configurations
|
185
|
-
# From app/models/user.rb, extract safe_dump configuration to:
|
186
|
-
# app/models/user/safe_dump_extensions.rb
|
187
|
-
```
|
188
|
-
|
189
|
-
#### 2. Update Model Files
|
52
|
+
1. **Create extension directories**: `mkdir -p app/models/user`
|
53
|
+
2. **Extract feature configuration** from main model files to separate extension files
|
54
|
+
3. **Verify autoloading**: Check that feature methods are available after migration
|
190
55
|
|
191
|
-
|
56
|
+
### Debugging
|
192
57
|
|
58
|
+
Enable debug output to troubleshoot autoloading:
|
193
59
|
```ruby
|
194
|
-
#
|
195
|
-
class User < Familia::Horreum
|
196
|
-
field :name, :email, :password, :role
|
197
|
-
|
198
|
-
feature :safe_dump
|
199
|
-
safe_dump_fields :name, :email
|
200
|
-
|
201
|
-
feature :expiration
|
202
|
-
def self.default_ttl
|
203
|
-
86400
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# After: Clean separation
|
208
|
-
class User < Familia::Horreum
|
209
|
-
field :name, :email, :password, :role
|
210
|
-
|
211
|
-
feature :safe_dump # Configuration auto-loaded
|
212
|
-
feature :expiration # Configuration auto-loaded
|
213
|
-
end
|
214
|
-
```
|
215
|
-
|
216
|
-
#### 3. Create Extension Files
|
217
|
-
|
218
|
-
Set up your feature-specific configurations:
|
219
|
-
|
220
|
-
```ruby
|
221
|
-
# app/models/user/safe_dump_extensions.rb
|
222
|
-
class User
|
223
|
-
safe_dump_fields :name, :email
|
224
|
-
# password and role excluded for security
|
225
|
-
end
|
226
|
-
|
227
|
-
# app/models/user/expiration_config.rb
|
228
|
-
class User
|
229
|
-
def self.default_ttl
|
230
|
-
86400 # 24 hours
|
231
|
-
end
|
232
|
-
end
|
60
|
+
ENV['FAMILIA_DEBUG'] = '1' # Shows discovered and loaded files
|
233
61
|
```
|
234
62
|
|
235
|
-
|
63
|
+
Common issues:
|
64
|
+
- Files must follow `{feature_name}_*.rb` naming pattern
|
65
|
+
- Extension files should reopen the same class as your model
|
236
66
|
|
237
|
-
|
238
|
-
- **Separation of Concerns**: Feature logic separated from core model definition
|
239
|
-
- **Maintainability**: Easier to find and modify feature-specific code
|
240
|
-
- **Readability**: Core models are cleaner and more focused
|
67
|
+
## Architecture
|
241
68
|
|
242
|
-
|
243
|
-
- **Reduced Conflicts**: Multiple developers can work on different features without merge conflicts
|
244
|
-
- **Feature Ownership**: Clear boundaries for feature-specific code
|
245
|
-
- **Testing**: Easier to test features in isolation
|
69
|
+
The Feature Autoloading System consists of two key components:
|
246
70
|
|
247
|
-
|
248
|
-
|
249
|
-
-
|
250
|
-
-
|
71
|
+
### Familia::Features::Autoloader
|
72
|
+
A utility module providing shared file loading functionality:
|
73
|
+
- Handles Dir.glob pattern matching and file loading
|
74
|
+
- Provides consistent debug logging across all autoloading scenarios
|
75
|
+
- Used by both feature-specific and general-purpose autoloading
|
251
76
|
|
252
|
-
###
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
# In your application initialization
|
258
|
-
ENV['FAMILIA_DEBUG'] = '1'
|
77
|
+
### Familia::Features::Autoloadable
|
78
|
+
A mixin for feature modules that enables post-inclusion autoloading:
|
79
|
+
- Uses `Module.const_source_location` to find where user classes are defined
|
80
|
+
- Discovers extension files using conventional patterns relative to the user class location
|
81
|
+
- Integrates with the feature system's inclusion lifecycle
|
259
82
|
|
260
|
-
|
261
|
-
Familia::Features::Autoloadable.debug = true
|
262
|
-
```
|
263
|
-
|
264
|
-
#### Debug Output Example
|
265
|
-
```
|
266
|
-
[Familia::Autoloader] Searching for User safe_dump extensions...
|
267
|
-
[Familia::Autoloader] Found: app/models/user/safe_dump_extensions.rb
|
268
|
-
[Familia::Autoloader] Loading: app/models/user/safe_dump_extensions.rb
|
269
|
-
[Familia::Autoloader] SafeDump extension loaded successfully for User
|
270
|
-
```
|
271
|
-
|
272
|
-
#### Troubleshooting
|
273
|
-
|
274
|
-
**Common Issues:**
|
275
|
-
|
276
|
-
1. **File Not Found**: Ensure file naming follows the `{feature_name}_*.rb` pattern
|
277
|
-
2. **Load Order**: Files are loaded alphabetically; prefix with numbers if order matters
|
278
|
-
3. **Class Scope**: Extension files should reopen the same class as your model
|
279
|
-
|
280
|
-
**Validation:**
|
281
|
-
```ruby
|
282
|
-
# Check if autoloading worked
|
283
|
-
User.respond_to?(:safe_dump_field_names) # => true
|
284
|
-
User.safe_dump_field_names # => [:name, :email]
|
285
|
-
```
|
286
|
-
|
287
|
-
### Backward Compatibility
|
288
|
-
|
289
|
-
The autoloading system is fully backward compatible:
|
290
|
-
|
291
|
-
- **Existing Models**: Continue to work without changes
|
292
|
-
- **Manual Configuration**: Still supported alongside autoloading
|
293
|
-
- **Gradual Migration**: You can migrate models one at a time
|
294
|
-
|
295
|
-
### Performance Considerations
|
296
|
-
|
297
|
-
- **Load Time**: Files are loaded once during feature activation
|
298
|
-
- **Memory Usage**: No additional memory overhead after loading
|
299
|
-
- **Caching**: Discovered files are cached to avoid repeated filesystem scans
|
300
|
-
|
301
|
-
### Testing Your Migration
|
302
|
-
|
303
|
-
```ruby
|
304
|
-
# Test that autoloading is working
|
305
|
-
class TestUser < Familia::Horreum
|
306
|
-
field :name, :email
|
307
|
-
feature :safe_dump
|
308
|
-
end
|
309
|
-
|
310
|
-
# Verify extension methods are available
|
311
|
-
puts TestUser.respond_to?(:safe_dump_field_names)
|
312
|
-
puts TestUser.safe_dump_field_names.inspect
|
313
|
-
|
314
|
-
# Test instance methods
|
315
|
-
user = TestUser.new(name: "John", email: "john@example.com")
|
316
|
-
puts user.safe_dump.inspect
|
317
|
-
```
|
83
|
+
When you call `feature :safe_dump`, the SafeDump module (which includes Autoloadable) triggers post-inclusion autoloading that searches for `user/safe_dump_*.rb` files and loads them automatically.
|
318
84
|
|
319
85
|
## New Capabilities
|
320
86
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Migrating Guide: v2.0.0-pre14
|
2
|
+
|
3
|
+
This version renames TimeUtils to TimeLiterals for semantic clarity and fixes an ExternalIdentifier bug.
|
4
|
+
|
5
|
+
## Breaking Change: TimeUtils → TimeLiterals
|
6
|
+
|
7
|
+
**Migration Required:**
|
8
|
+
|
9
|
+
Find and replace in your codebase:
|
10
|
+
```bash
|
11
|
+
# Find files to update
|
12
|
+
grep -r "using Familia::Refinements::TimeUtils" .
|
13
|
+
|
14
|
+
# Replace the import
|
15
|
+
sed -i 's/using Familia::Refinements::TimeUtils/using Familia::Refinements::TimeLiterals/g' *.rb
|
16
|
+
```
|
17
|
+
|
18
|
+
**Before:**
|
19
|
+
```ruby
|
20
|
+
using Familia::Refinements::TimeUtils
|
21
|
+
```
|
22
|
+
|
23
|
+
**After:**
|
24
|
+
```ruby
|
25
|
+
using Familia::Refinements::TimeLiterals
|
26
|
+
```
|
27
|
+
|
28
|
+
All functionality remains identical - only the module name changed.
|
29
|
+
|
30
|
+
## Bug Fix: ExternalIdentifier
|
31
|
+
|
32
|
+
Fixed `NoMethodError` when using ExternalIdentifier by replacing incorrect `.del()` calls with `.remove_field()` in HashKey operations. This affected:
|
33
|
+
- Changing external identifier values
|
34
|
+
- Looking up objects by external ID
|
35
|
+
- Destroying objects with external identifiers
|
36
|
+
|
37
|
+
No migration needed - the fix is automatic.
|
data/examples/safe_dump.rb
CHANGED
@@ -273,7 +273,7 @@ puts "LegacyModel fields after set_safe_dump_fields: #{LegacyModel.safe_dump_fie
|
|
273
273
|
puts
|
274
274
|
puts '=== Cleaning up test data ==='
|
275
275
|
[User, Product, Order, Address, Customer, LegacyModel].each do |klass|
|
276
|
-
klass.
|
276
|
+
klass.dbclient.del(klass.dbclient.keys("#{klass.name.downcase}:*"))
|
277
277
|
rescue StandardError => e
|
278
278
|
puts "Error cleaning #{klass}: #{e.message}"
|
279
279
|
end
|
data/lib/familia/base.rb
CHANGED
data/lib/familia/data_type.rb
CHANGED
@@ -16,7 +16,7 @@ module Familia
|
|
16
16
|
include Familia::Base
|
17
17
|
extend Familia::Features
|
18
18
|
|
19
|
-
using Familia::Refinements::
|
19
|
+
using Familia::Refinements::TimeLiterals
|
20
20
|
|
21
21
|
@registered_types = {}
|
22
22
|
@valid_options = %i[class parent default_expiration default logical_database dbkey dbclient suffix prefix]
|