familia 2.0.0.pre10 → 2.0.0.pre13
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/.rubocop_todo.yml +2 -3
- data/CHANGELOG.rst +507 -0
- data/CLAUDE.md +5 -55
- data/Gemfile +1 -6
- data/Gemfile.lock +13 -7
- data/changelog.d/README.md +45 -34
- data/changelog.d/scriv.ini +5 -0
- data/docs/archive/FAMILIA_RELATIONSHIPS.md +1 -1
- data/docs/archive/FAMILIA_UPDATE.md +1 -1
- data/docs/archive/README.md +15 -19
- data/docs/guides/Feature-System-Autoloading.md +228 -0
- data/docs/guides/Home.md +1 -1
- data/docs/guides/Implementation-Guide.md +1 -1
- data/docs/guides/relationships-methods.md +1 -1
- data/docs/guides/time-utilities.md +221 -0
- data/docs/migrating/.gitignore +2 -0
- data/docs/migrating/v2.0.0-pre.md +84 -0
- data/docs/migrating/v2.0.0-pre11.md +253 -0
- data/docs/migrating/v2.0.0-pre12.md +306 -0
- data/docs/migrating/v2.0.0-pre13.md +329 -0
- data/docs/migrating/v2.0.0-pre5.md +110 -0
- data/docs/migrating/v2.0.0-pre6.md +154 -0
- data/docs/migrating/v2.0.0-pre7.md +222 -0
- data/docs/overview.md +6 -7
- data/{examples/redis_command_validation_example.rb → docs/reference/auditing_database_commands.rb} +29 -32
- data/examples/autoloader/mega_customer/safe_dump_fields.rb +6 -0
- data/examples/autoloader/mega_customer.rb +17 -0
- data/examples/{bit_encoding_integration.rb → permissions.rb} +30 -27
- data/examples/{relationships_basic.rb → relationships.rb} +2 -3
- data/examples/safe_dump.rb +281 -0
- data/familia.gemspec +5 -4
- data/lib/familia/autoloader.rb +53 -0
- data/lib/familia/base.rb +57 -0
- data/lib/familia/data_type.rb +4 -0
- data/lib/familia/encryption/encrypted_data.rb +4 -4
- data/lib/familia/encryption/manager.rb +6 -4
- data/lib/familia/{encryption_request_cache.rb → encryption/request_cache.rb} +1 -1
- data/lib/familia/encryption.rb +1 -1
- data/lib/familia/errors.rb +5 -0
- data/lib/familia/features/autoloadable.rb +113 -0
- data/lib/familia/features/encrypted_fields/concealed_string.rb +4 -2
- data/lib/familia/features/expiration.rb +4 -0
- data/lib/familia/features/external_identifier.rb +310 -0
- data/lib/familia/features/object_identifier.rb +307 -0
- data/lib/familia/features/quantization.rb +5 -0
- data/lib/familia/features/safe_dump.rb +74 -73
- data/lib/familia/features.rb +109 -17
- data/lib/familia/field_type.rb +2 -0
- data/lib/familia/horreum/core/serialization.rb +3 -3
- data/lib/familia/horreum/subclass/definition.rb +50 -7
- data/lib/familia/horreum.rb +2 -0
- data/lib/familia/json_serializer.rb +70 -0
- data/lib/familia/logging.rb +12 -10
- data/lib/familia/refinements/logger_trace.rb +57 -0
- data/lib/familia/refinements/snake_case.rb +40 -0
- data/lib/familia/refinements/time_utils.rb +248 -0
- data/lib/familia/refinements.rb +3 -49
- data/lib/familia/secure_identifier.rb +51 -75
- data/lib/familia/utils.rb +2 -0
- data/lib/familia/validation/{test_helpers.rb → validation_helpers.rb} +2 -2
- data/lib/familia/validation.rb +1 -1
- data/lib/familia/verifiable_identifier.rb +162 -0
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +15 -2
- data/try/core/autoloader_try.rb +112 -0
- data/try/core/extensions_try.rb +38 -21
- data/try/core/familia_extended_try.rb +4 -3
- data/try/core/secure_identifier_try.rb +47 -18
- data/try/core/time_utils_try.rb +130 -0
- data/try/core/verifiable_identifier_try.rb +171 -0
- data/try/data_types/datatype_base_try.rb +3 -2
- data/try/features/autoloadable/autoloadable_try.rb +61 -0
- data/try/features/encrypted_fields/concealed_string_core_try.rb +8 -3
- data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +59 -17
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +36 -12
- data/try/features/{external_identifiers/external_identifiers_try.rb → external_identifier/external_identifier_try.rb} +25 -28
- data/try/features/feature_improvements_try.rb +127 -0
- data/try/features/{object_identifiers/object_identifiers_integration_try.rb → object_identifier/object_identifier_integration_try.rb} +28 -30
- data/try/features/{object_identifiers/object_identifiers_try.rb → object_identifier/object_identifier_try.rb} +13 -13
- data/try/features/real_feature_integration_try.rb +8 -7
- data/try/features/safe_dump/safe_dump_autoloading_try.rb +111 -0
- data/try/features/safe_dump/safe_dump_try.rb +8 -9
- data/try/helpers/test_helpers.rb +41 -17
- data/try/integration/cross_component_try.rb +3 -1
- metadata +61 -26
- data/CHANGELOG.md +0 -184
- data/changelog.d/fragments/.keep +0 -0
- data/changelog.d/template.md.j2 +0 -29
- data/lib/familia/core_ext.rb +0 -135
- data/lib/familia/features/external_identifiers/external_identifier_field_type.rb +0 -120
- data/lib/familia/features/external_identifiers.rb +0 -111
- data/lib/familia/features/object_identifiers/object_identifier_field_type.rb +0 -91
- data/lib/familia/features/object_identifiers.rb +0 -194
- data/setup.cfg +0 -12
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
familia (2.0.0.
|
5
|
-
benchmark
|
6
|
-
connection_pool
|
7
|
-
csv
|
8
|
-
logger
|
4
|
+
familia (2.0.0.pre13)
|
5
|
+
benchmark (~> 0.4)
|
6
|
+
connection_pool (~> 2.5)
|
7
|
+
csv (~> 3.3)
|
8
|
+
logger (~> 1.7)
|
9
|
+
oj (~> 3.16)
|
9
10
|
redis (>= 4.8.1, < 6.0)
|
10
11
|
stringio (~> 3.1.1)
|
11
12
|
uri-valkey (~> 1.4)
|
@@ -16,6 +17,7 @@ GEM
|
|
16
17
|
ast (2.4.3)
|
17
18
|
base64 (0.3.0)
|
18
19
|
benchmark (0.4.1)
|
20
|
+
bigdecimal (3.2.3)
|
19
21
|
byebug (11.1.3)
|
20
22
|
coderay (1.1.3)
|
21
23
|
concurrent-ruby (1.3.5)
|
@@ -39,6 +41,10 @@ GEM
|
|
39
41
|
logger (1.7.0)
|
40
42
|
method_source (1.1.0)
|
41
43
|
minitest (5.25.5)
|
44
|
+
oj (3.16.11)
|
45
|
+
bigdecimal (>= 3.0)
|
46
|
+
ostruct (>= 0.2)
|
47
|
+
ostruct (0.6.3)
|
42
48
|
parallel (1.27.0)
|
43
49
|
parser (3.3.8.0)
|
44
50
|
ast (~> 2.4.1)
|
@@ -113,7 +119,7 @@ GEM
|
|
113
119
|
ruby-progressbar (1.13.0)
|
114
120
|
stackprof (0.2.27)
|
115
121
|
stringio (3.1.7)
|
116
|
-
tryouts (3.
|
122
|
+
tryouts (3.6.0)
|
117
123
|
concurrent-ruby (~> 1.0)
|
118
124
|
irb
|
119
125
|
minitest (~> 5.0)
|
@@ -148,7 +154,7 @@ DEPENDENCIES
|
|
148
154
|
rubocop-thread_safety
|
149
155
|
ruby-prof
|
150
156
|
stackprof
|
151
|
-
tryouts (~> 3.
|
157
|
+
tryouts (~> 3.6.0)
|
152
158
|
yard (~> 0.9)
|
153
159
|
|
154
160
|
BUNDLED WITH
|
data/changelog.d/README.md
CHANGED
@@ -4,7 +4,7 @@ This directory contains changelog fragments managed by [Scriv](https://scriv.rea
|
|
4
4
|
|
5
5
|
## Our Approach
|
6
6
|
|
7
|
-
Changelogs are for humans and agents, not just machines. We follow the core principles of [Keep a Changelog](https://keepachangelog.com) to ensure our release notes are clear, consistent, and
|
7
|
+
Changelogs are for humans and agents, not just machines. We follow the core principles of [Keep a Changelog](https://keepachangelog.com) and semvar to ensure our release notes are clear, consistent, and useful.
|
8
8
|
|
9
9
|
To achieve this, we use a fragment-based workflow with `scriv`. Instead of a single, large `CHANGELOG.md` file that can cause merge conflicts, each developer includes a small changelog fragment with their pull request. At release time, these fragments are collected and aggregated into the main changelog.
|
10
10
|
|
@@ -12,55 +12,66 @@ This approach provides several benefits:
|
|
12
12
|
- **Reduces Merge Conflicts:** Developers can work in parallel without conflicting over a central changelog file.
|
13
13
|
- **Improves Developer Experience:** Creating a small, focused fragment is a simple and repeatable task during development.
|
14
14
|
- **Ensures Consistency:** Automation helps maintain a consistent structure for all changelog entries.
|
15
|
+
- **AI Transparency:** An opportunity to be specific and detailed about the assistance provided.
|
15
16
|
- **Builds Trust:** A clear and well-maintained changelog communicates respect for our users and collaborators.
|
16
17
|
|
18
|
+
## Relevant paths
|
19
|
+
|
20
|
+
* `changelog.d/` - (e.g. changelog.d/YYYYMMDD_HHmmss_username_branch.rst)
|
21
|
+
* `docs/migrating/` - (e.g. docs/migrating/v2.0.0-pre.md)
|
22
|
+
* `CHANGELOG.rst` - The full changelog for all releases, in reverse chronological order. Careful: LARGE DOCUMENT. Limit reading to the first 50 lines.
|
23
|
+
|
24
|
+
* `changelog.d/scriv.ini` - Scriv tool settings
|
25
|
+
|
17
26
|
## How to Add a Changelog Entry
|
18
27
|
|
19
28
|
1. **Create a New Fragment:**
|
20
|
-
```bash
|
21
|
-
scriv create
|
22
|
-
```
|
23
|
-
This will create a new file in the `changelog.d/fragments/` directory.
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
```bash
|
31
|
+
# This will create a new file in the `changelog.d/` directory.
|
32
|
+
scriv create
|
33
|
+
```
|
27
34
|
|
28
35
|
2. **Edit the Fragment File:**
|
29
|
-
|
36
|
+
Open the newly created file and add your entry under the relevant category. See the guidelines below for writing good CHANGELOG entries.
|
37
|
+
|
38
|
+
3. **Add or Update Migrating Guide:** (optional)
|
39
|
+
Include technical details to help developers update to the new version. Start with a specific introduction, e.g. "This version introduces significant improvements to Familia's feature system, making it easier to organize and use features across complex projects.". Including code snippets and multi-line content that is too detailed for the CHANGELOG.
|
40
|
+
|
41
|
+
Use the content of an existing `docs/migrating/vMajor.Minor.Patch*.md file as a reference.
|
30
42
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
43
|
+
Compare the headers of your draft content with the headers of the previous migration guide to make sure it does not repeat or overlap.
|
44
|
+
|
45
|
+
4. **Commit with Your Code:**
|
46
|
+
```bash
|
47
|
+
git add changelog.d/YYYYMMDD_HHmmss_username_branch.rst [docs/migrating/v2.0.0-pre.md]
|
48
|
+
git commit
|
49
|
+
```
|
36
50
|
|
37
51
|
## Fragment Guidelines
|
38
52
|
|
39
|
-
-
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
44
|
-
-
|
45
|
-
-
|
46
|
-
-
|
53
|
+
- **One Fragment Per Change:** Keep each fragment focused on a single feature, fix, or improvement.
|
54
|
+
- **Documenting AI Assistance:** If a change involved significant AI assistance, place it in its own fragment. This ensures the `### AI Assistance` section clearly corresponds to the single change described in that fragment.
|
55
|
+
- **Write for a Human Audience:** Describe the *impact* of the change, not just the implementation details.
|
56
|
+
- **Good:** "Improved the performance and stability of Redis connections under high load."
|
57
|
+
- **Bad:** "Refactored the `RedisManager`."
|
58
|
+
- **Be Specific:** Avoid generic messages like "fixed a bug." Clearly state what was fixed.
|
59
|
+
- **Include Context:** Reference issue or pull request numbers to provide a link to the discussion and implementation details. `scriv` will automatically create links for them.
|
60
|
+
- **Example:** `- Fixed a bug where users could not reset their passwords. PR #123`
|
47
61
|
|
48
62
|
### Categories
|
49
63
|
|
50
|
-
Use these categories
|
64
|
+
Use these categories:
|
51
65
|
|
52
|
-
-
|
53
|
-
-
|
54
|
-
-
|
55
|
-
-
|
56
|
-
-
|
57
|
-
-
|
58
|
-
-
|
66
|
+
- **Added**: New features or capabilities.
|
67
|
+
- **Changed**: Changes to existing functionality.
|
68
|
+
- **Deprecated**: Soon-to-be removed features.
|
69
|
+
- **Removed**: Now removed features.
|
70
|
+
- **Fixed**: Bug fixes.
|
71
|
+
- **Security**: Security-related improvements.
|
72
|
+
- **Documentation**: Documentation improvements.
|
73
|
+
- **AI Assistance**: Significant AI assistance in the change, including discussion, rubber ducking, formatting, writing documentation, writing tests.
|
59
74
|
|
60
75
|
## Release Process
|
61
76
|
|
62
|
-
At release time,
|
63
|
-
|
64
|
-
```bash
|
65
|
-
scriv collect --version 2.0.0
|
66
|
-
```
|
77
|
+
At release time, scriv will collect all fragments into the main `CHANGELOG.rst` file with th command `scriv collect`. The version is taken automatically from `lib/familia/version.rb`.
|
data/docs/archive/README.md
CHANGED
@@ -10,9 +10,9 @@ This directory contains original documentation files that have been migrated to
|
|
10
10
|
### FAMILIA_UPDATE.md
|
11
11
|
**Original Purpose:** Version summary table and detailed release notes for v2.0.0-pre series
|
12
12
|
|
13
|
-
**
|
13
|
+
**Migrating Destinations:**
|
14
14
|
- **Changelog entries** → Extracted to Scriv fragments, aggregated into `CHANGELOG.md`
|
15
|
-
- **
|
15
|
+
- **Migrating guides** → Reorganized into `docs/migrating/v2.0.0-pre*.md`
|
16
16
|
- **Feature descriptions** → Cross-referenced with existing feature guides in `docs/guides/`
|
17
17
|
|
18
18
|
### FAMILIA_RELATIONSHIPS.md
|
@@ -33,26 +33,22 @@ This directory contains original documentation files that have been migrated to
|
|
33
33
|
|
34
34
|
```
|
35
35
|
docs/
|
36
|
-
├──
|
37
|
-
│ ├── v2.0.0-pre.md
|
38
|
-
│ ├── v2.0.0-pre5.md
|
39
|
-
│ ├── v2.0.0-pre6.md
|
40
|
-
│ └── v2.0.0-pre7.md
|
41
|
-
|
42
|
-
|
36
|
+
├── migrating/ # Version-specific migrating guides
|
37
|
+
│ ├── v2.0.0-pre.md
|
38
|
+
│ ├── v2.0.0-pre5.md # Security features
|
39
|
+
│ ├── v2.0.0-pre6.md # Architecture improvements
|
40
|
+
│ └── v2.0.0-pre7.md # Relationships system
|
41
|
+
│
|
42
|
+
├── guides/ # Feature-specific guides (moved from wiki/)
|
43
|
+
│ ├── relationships.md # From FAMILIA_RELATIONSHIPS.md
|
43
44
|
│ └── [other guides...]
|
44
|
-
|
45
|
-
|
46
|
-
└──
|
45
|
+
│
|
46
|
+
├── reference/ # Technical reference
|
47
|
+
│ └── api-technical.md
|
48
|
+
│
|
49
|
+
└── archive/ # This directory
|
47
50
|
```
|
48
51
|
|
49
|
-
## Why These Files Were Archived
|
50
|
-
|
51
|
-
1. **Sustainability** - The original files accumulated overlapping content without clear organization
|
52
|
-
2. **Maintainability** - Scriv fragment system prevents documentation bloat
|
53
|
-
3. **Clarity** - Separation of changelog, guides, and reference improves findability
|
54
|
-
4. **Workflow** - Fragment-based workflow scales better with development
|
55
|
-
|
56
52
|
## Finding Migrated Content
|
57
53
|
|
58
54
|
- **Version changes** → Check `CHANGELOG.md` (generated from fragments)
|
@@ -0,0 +1,228 @@
|
|
1
|
+
# Feature System Autoloading
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
Familia's feature system includes an autoloading mechanism that automatically discovers and loads feature-specific extension files when features are included in your classes. This allows you to keep your main model files clean while organizing feature-specific configurations in separate files.
|
6
|
+
|
7
|
+
## The Problem It Solves
|
8
|
+
|
9
|
+
When you include a feature like `safe_dump` in a Familia class:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class User < Familia::Horreum
|
13
|
+
feature :safe_dump # This line should trigger autoloading
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
You want to be able to define the safe dump configuration in a separate file:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# user/safe_dump_extensions.rb
|
21
|
+
class User
|
22
|
+
safe_dump_fields :name, :email # Don't dump :password
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
But there's a **timing problem**: when should this extension file be loaded?
|
27
|
+
|
28
|
+
## Why Standard `included` Hook Doesn't Work
|
29
|
+
|
30
|
+
The original approach tried to use the standard `included` hook:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
module SafeDump
|
34
|
+
def self.included(base)
|
35
|
+
# Try to autoload here - BUT THIS IS TOO EARLY!
|
36
|
+
autoload_files_for(base)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
**Problem**: This happens **during** the feature inclusion process, before the feature is fully set up. The class isn't in a stable state yet.
|
42
|
+
|
43
|
+
## The Solution: Post-Inclusion Hook
|
44
|
+
|
45
|
+
The `post_inclusion_autoload` system works in **two phases**:
|
46
|
+
|
47
|
+
### Phase 1: Feature System Hook
|
48
|
+
|
49
|
+
In `lib/familia/features.rb`, after including the feature module:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
def feature(feature_name, **options)
|
53
|
+
# ... setup code ...
|
54
|
+
|
55
|
+
include feature_class # Include the feature module
|
56
|
+
|
57
|
+
# NOW call the post-inclusion hook
|
58
|
+
if feature_class.respond_to?(:post_inclusion_autoload)
|
59
|
+
feature_class.post_inclusion_autoload(self, feature_name, options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
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
|
+
3. **Loads any matching files** found in those locations
|
88
|
+
|
89
|
+
## Why This Timing Matters
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
class User < Familia::Horreum
|
93
|
+
feature :safe_dump # ← Timing is critical here
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
**What happens in order:**
|
98
|
+
|
99
|
+
1. `feature :safe_dump` is called
|
100
|
+
2. Feature system includes `Familia::Features::SafeDump` module
|
101
|
+
3. **Feature is now fully included and stable**
|
102
|
+
4. `post_inclusion_autoload` is called
|
103
|
+
5. Extension files are discovered and loaded
|
104
|
+
6. `safe_dump_fields :name, :email` executes in the extension file
|
105
|
+
|
106
|
+
## File Naming Conventions
|
107
|
+
|
108
|
+
The autoloading system looks for files matching these patterns (in order of precedence):
|
109
|
+
|
110
|
+
1. `{model_directory}/{model_name}/{feature_name}_*.rb`
|
111
|
+
2. `{model_directory}/{model_name}/features/{feature_name}_*.rb`
|
112
|
+
3. `{model_directory}/features/{feature_name}_*.rb`
|
113
|
+
|
114
|
+
### Examples
|
115
|
+
|
116
|
+
For a `User` class defined in `app/models/user.rb` with `feature :safe_dump`:
|
117
|
+
|
118
|
+
```
|
119
|
+
app/models/user/safe_dump_extensions.rb # ← Most specific
|
120
|
+
app/models/user/safe_dump_config.rb # ← Also matches pattern
|
121
|
+
app/models/user/features/safe_dump_*.rb # ← Feature subdirectory
|
122
|
+
app/models/features/safe_dump_*.rb # ← Shared feature configs
|
123
|
+
```
|
124
|
+
|
125
|
+
## Complete Example
|
126
|
+
|
127
|
+
### Main Model File
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
# app/models/user.rb
|
131
|
+
class User < Familia::Horreum
|
132
|
+
field :name
|
133
|
+
field :email
|
134
|
+
field :password
|
135
|
+
field :created_at
|
136
|
+
|
137
|
+
feature :safe_dump # ← Triggers autoloading
|
138
|
+
feature :expiration
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
### Safe Dump Extensions
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
# app/models/user/safe_dump_extensions.rb
|
146
|
+
class User
|
147
|
+
# Configure which fields are safe to dump in API responses
|
148
|
+
safe_dump_fields :name, :email, :created_at
|
149
|
+
# Note: :password is intentionally excluded for security
|
150
|
+
|
151
|
+
def safe_dump_display_name
|
152
|
+
"#{name} (#{email})"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
### Expiration Extensions
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
# app/models/user/expiration_config.rb
|
161
|
+
class User
|
162
|
+
# Set default TTL for user objects
|
163
|
+
expires_in 30.days
|
164
|
+
|
165
|
+
# Custom expiration logic
|
166
|
+
def should_expire?
|
167
|
+
!active? && last_login_at < 90.days.ago
|
168
|
+
end
|
169
|
+
end
|
170
|
+
```
|
171
|
+
|
172
|
+
### Result
|
173
|
+
|
174
|
+
After loading, the `User` class has:
|
175
|
+
- `User.safe_dump_field_names` returns `[:name, :email, :created_at]`
|
176
|
+
- `User.ttl` returns the configured expiration
|
177
|
+
- All extension methods are available on instances
|
178
|
+
|
179
|
+
## Key Benefits
|
180
|
+
|
181
|
+
1. **Separation of Concerns**: Main model file focuses on core definition, extension files handle feature-specific configuration
|
182
|
+
|
183
|
+
2. **Convention Over Configuration**: No manual requires, just follow naming conventions
|
184
|
+
|
185
|
+
3. **Safe Timing**: Extension files load after the feature is fully set up
|
186
|
+
|
187
|
+
4. **Thread Safe**: No shared state between classes
|
188
|
+
|
189
|
+
5. **Discoverable**: Clear file organization makes extensions easy to find
|
190
|
+
|
191
|
+
## Why It's Better Than Alternatives
|
192
|
+
|
193
|
+
- **Manual requires**: Error-prone, verbose, easy to forget
|
194
|
+
- **Configuration blocks**: Clutters the main model file
|
195
|
+
- **Included hook**: Wrong timing, class not stable yet
|
196
|
+
- **Class_eval strings**: Complex, hard to debug and maintain
|
197
|
+
|
198
|
+
The `post_inclusion_autoload` system provides a clean, automatic, and safe way to extend feature behavior without polluting the main class definitions.
|
199
|
+
|
200
|
+
## Implementation Details
|
201
|
+
|
202
|
+
### Autoloadable Module
|
203
|
+
|
204
|
+
Features that support autoloading include the `Familia::Features::Autoloadable` module:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
module Familia::Features::SafeDump
|
208
|
+
include Familia::Features::Autoloadable # ← Enables autoloading
|
209
|
+
|
210
|
+
# Feature implementation...
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
### Anonymous Class Handling
|
215
|
+
|
216
|
+
The system gracefully handles edge cases:
|
217
|
+
|
218
|
+
- **Anonymous classes**: Classes without names (e.g., `Class.new`) are skipped
|
219
|
+
- **Eval contexts**: Classes defined in `eval` or irb are skipped
|
220
|
+
- **Missing files**: No errors if extension files don't exist
|
221
|
+
|
222
|
+
### Error Handling
|
223
|
+
|
224
|
+
- Missing extension files are silently ignored
|
225
|
+
- Syntax errors in extension files propagate normally
|
226
|
+
- `NameError` during constant resolution is caught and logged
|
227
|
+
|
228
|
+
This robust error handling ensures the autoloading system never breaks your application, even with unusual class definitions or missing files.
|
data/docs/guides/Home.md
CHANGED
@@ -23,7 +23,7 @@ Welcome to the comprehensive documentation for Familia v2.0. This wiki covers al
|
|
23
23
|
|
24
24
|
### 🚀 Operations (As Needed)
|
25
25
|
|
26
|
-
9. **[
|
26
|
+
9. **[Migrating Guide](Migrating-Guide.md)** - Upgrading existing fields _(coming soon)_
|
27
27
|
10. **[Key Management](Key-Management.md)** - Rotation and best practices _(coming soon)_
|
28
28
|
|
29
29
|
## 🚀 Quick Start Examples
|
@@ -273,4 +273,4 @@ end
|
|
273
273
|
|
274
274
|
- [Security Model](Security-Model) - Understand the cryptographic design
|
275
275
|
- [Key Management](Key-Management) - Rotation and best practices
|
276
|
-
- [
|
276
|
+
- [Migrating Guide](Migrating-Guide) - Upgrade existing fields
|