model_timeline 0.1.1 → 0.1.2
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/README.md +51 -8
- data/lib/model_timeline/rspec/matchers.rb +127 -59
- data/lib/model_timeline/rspec.rb +1 -1
- data/lib/model_timeline/timelineable.rb +37 -14
- data/lib/model_timeline/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d1c5aacdbe6970e7724f4f40d81c2e67b0f7739b7efe4784adb773a88d142a4
|
|
4
|
+
data.tar.gz: 38fc7b5502adf1a18809f8fd7aa54d3f5906888a9e37ed3f6b8fa9ef232e893c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5710fbe04cd8871236b90891e2298098b4d986b9d63e4f0c5943af5592b0e4ee47bf248490f2f508992a3a39ea50f20839f11d5b043196cbb8e6a527925d6d1c
|
|
7
|
+
data.tar.gz: 584e6aeb8875bffd927d86532e0b05cb2989027df80b6b5cf0ed15d587bfdce1f65f9f5cb6a92b8a88dc7e416ac56c653604d6f9635a6dc91a53ab4f97046192
|
data/README.md
CHANGED
|
@@ -385,11 +385,6 @@ Configure RSpec to work with ModelTimeline:
|
|
|
385
385
|
require 'model_timeline/rspec'
|
|
386
386
|
|
|
387
387
|
RSpec.configure do |config|
|
|
388
|
-
# This disables ModelTimeline by default in tests for better performance
|
|
389
|
-
config.before(:suite) do
|
|
390
|
-
ModelTimeline.disable!
|
|
391
|
-
end
|
|
392
|
-
|
|
393
388
|
# Include the RSpec helpers and matchers
|
|
394
389
|
config.include ModelTimeline::RSpec
|
|
395
390
|
end
|
|
@@ -440,17 +435,65 @@ expect(user).to have_timeline_entries
|
|
|
440
435
|
expect(user).to have_timeline_entries(3)
|
|
441
436
|
|
|
442
437
|
# Check for entries with a specific action
|
|
443
|
-
expect(user).to
|
|
438
|
+
expect(user).to have_timeline_entry_action(:update)
|
|
444
439
|
|
|
445
440
|
# Check if a specific attribute was changed
|
|
446
|
-
expect(user).to
|
|
441
|
+
expect(user).to have_timeline_entry_change(:email)
|
|
447
442
|
|
|
448
443
|
# Check if an attribute was changed to a specific value
|
|
449
|
-
expect(user).to
|
|
444
|
+
expect(user).to have_timeline_entry(:status, 'active')
|
|
445
|
+
|
|
446
|
+
# Check if an entry was created with expected metadata
|
|
447
|
+
expect(user).to have_timeline_entry_metadata(foo: 'bar', baz: 'biz')
|
|
450
448
|
```
|
|
451
449
|
|
|
452
450
|
These matchers make it easy to test that your application is correctly tracking model changes.
|
|
453
451
|
|
|
452
|
+
##### Matchers for custom models/tables
|
|
453
|
+
|
|
454
|
+
You can add a configuration in your support file to create matchers for your association.
|
|
455
|
+
Given a model like this:
|
|
456
|
+
|
|
457
|
+
```ruby
|
|
458
|
+
class User < ApplicationRecord
|
|
459
|
+
has_timeline :security_events, class_name: 'SecurityTimelineEntry'
|
|
460
|
+
end
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
You should set a configuration in your RSpec support file with:
|
|
464
|
+
```ruby
|
|
465
|
+
# spec/support/model_timeline.rb
|
|
466
|
+
require 'model_timeline/rspec'
|
|
467
|
+
|
|
468
|
+
RSpec.configure do |config|
|
|
469
|
+
# Include the RSpec helpers and matchers
|
|
470
|
+
config.include ModelTimeline::RSpec
|
|
471
|
+
config.include ModelTimeline::RSpec::Matchers.define_timeline_matchers_for(:security_events)
|
|
472
|
+
end
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Then you have those new matchers:
|
|
476
|
+
|
|
477
|
+
```ruby
|
|
478
|
+
# Check for any timeline entries
|
|
479
|
+
expect(user).to have_security_events
|
|
480
|
+
|
|
481
|
+
# Check for a specific number of entries
|
|
482
|
+
expect(user).to have_security_events(3)
|
|
483
|
+
|
|
484
|
+
# Check for entries with a specific action
|
|
485
|
+
expect(user).to have_security_event_action(:update)
|
|
486
|
+
|
|
487
|
+
# Check if a specific attribute was changed
|
|
488
|
+
expect(user).to have_security_event_change(:email)
|
|
489
|
+
|
|
490
|
+
# Check if an attribute was changed to a specific value
|
|
491
|
+
expect(user).to have_security_event(:status, 'active')
|
|
492
|
+
|
|
493
|
+
# Check if an entry was created with expected metadata
|
|
494
|
+
expect(user).to have_security_event_metadata(foo: 'bar', baz: 'biz')
|
|
495
|
+
```
|
|
496
|
+
|
|
454
497
|
|
|
455
498
|
## License
|
|
456
499
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module ModelTimeline
|
|
4
4
|
module RSpec
|
|
5
|
-
# rubocop:disable Naming/PredicateName
|
|
6
5
|
# Custom RSpec matchers for testing model timeline entries
|
|
7
6
|
#
|
|
8
7
|
# These matchers help you test the timeline entries created by the ModelTimeline gem.
|
|
@@ -16,58 +15,78 @@ module ModelTimeline
|
|
|
16
15
|
# expect(user).to have_timeline_entries(3)
|
|
17
16
|
#
|
|
18
17
|
# # Check for specific action
|
|
19
|
-
# expect(user).to
|
|
18
|
+
# expect(user).to have_timeline_entry_action(:update)
|
|
20
19
|
#
|
|
21
20
|
# # Check for changes to a specific attribute
|
|
22
|
-
# expect(user).to
|
|
21
|
+
# expect(user).to have_timeline_entry_change(:email)
|
|
23
22
|
#
|
|
24
23
|
# # Check for specific value change
|
|
25
|
-
# expect(user).to
|
|
24
|
+
# expect(user).to have_timeline_entry(:status, "active")
|
|
26
25
|
module Matchers
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# @param count [Integer, nil] The expected number of timeline entries (optional)
|
|
30
|
-
# @return [HaveTimelineEntriesMatcher] A matcher that checks for timeline entries
|
|
31
|
-
# @example Without count parameter
|
|
32
|
-
# expect(user).to have_timeline_entries
|
|
33
|
-
# @example With count parameter
|
|
34
|
-
# expect(user).to have_timeline_entries(3)
|
|
35
|
-
def have_timeline_entries(count = nil)
|
|
36
|
-
HaveTimelineEntriesMatcher.new(count)
|
|
26
|
+
def self.included(base)
|
|
27
|
+
base.include define_timeline_matchers_for(:timeline_entries)
|
|
37
28
|
end
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# @param action [String, Symbol] The action name to look for
|
|
42
|
-
# @return [HaveTimelinedAction] A matcher that checks for a specific action
|
|
43
|
-
# @example
|
|
44
|
-
# expect(user).to have_timelined_action(:create)
|
|
45
|
-
# expect(user).to have_timelined_action("update")
|
|
46
|
-
def have_timelined_action(action)
|
|
47
|
-
HaveTimelinedAction.new(action)
|
|
48
|
-
end
|
|
30
|
+
def self.define_timeline_matchers_for(association_name)
|
|
31
|
+
association_name_singularized = association_name.to_s.singularize
|
|
49
32
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
33
|
+
Module.new do
|
|
34
|
+
# Check if a model has timeline entries
|
|
35
|
+
#
|
|
36
|
+
# @param count [Integer, nil] The expected number of timeline entries (optional)
|
|
37
|
+
# @return [HaveTimelineEntriesMatcher] A matcher that checks for timeline entries
|
|
38
|
+
# @example Without count parameter
|
|
39
|
+
# expect(user).to have_timeline_entries
|
|
40
|
+
# @example With count parameter
|
|
41
|
+
# expect(user).to have_timeline_entries(3)
|
|
42
|
+
define_method(:"have_#{association_name}") do |count = nil|
|
|
43
|
+
HaveTimelineEntriesMatcher.new(count, association_name)
|
|
44
|
+
end
|
|
60
45
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
46
|
+
# Check if a specific action was recorded in the timeline
|
|
47
|
+
#
|
|
48
|
+
# @param action [String, Symbol] The action name to look for
|
|
49
|
+
# @return [HaveTimelineAction] A matcher that checks for a specific action
|
|
50
|
+
# @example
|
|
51
|
+
# expect(user).to have_timeline_entry_action(:create)
|
|
52
|
+
# expect(user).to have_timeline_entry_action("update")
|
|
53
|
+
define_method(:"have_#{association_name_singularized}_action") do |action|
|
|
54
|
+
HaveTimelineAction.new(action, association_name)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Check if a specific attribute change was recorded in the timeline
|
|
58
|
+
#
|
|
59
|
+
# @param attribute [String, Symbol] The attribute name to check for changes
|
|
60
|
+
# @return [HaveTimelineChange] A matcher that checks if an attribute was changed
|
|
61
|
+
# @example
|
|
62
|
+
# expect(user).to have_timeline_entry_change(:email)
|
|
63
|
+
# expect(user).to have_timeline_entry_change("status")
|
|
64
|
+
define_method(:"have_#{association_name_singularized}_change") do |attribute|
|
|
65
|
+
HaveTimelineChange.new(attribute, association_name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Check if an attribute was changed to a specific value in the timeline
|
|
69
|
+
#
|
|
70
|
+
# @param attribute [String, Symbol] The attribute name to check
|
|
71
|
+
# @param value [Object] The value to check for
|
|
72
|
+
# @return [HaveTimelineEntry] A matcher that checks for specific attribute values
|
|
73
|
+
# @example
|
|
74
|
+
# expect(user).to have_timeline_entry(:status, "active")
|
|
75
|
+
# expect(user).to have_timeline_entry(:role, :admin)
|
|
76
|
+
define_method(:"have_#{association_name_singularized}") do |attribute, value|
|
|
77
|
+
HaveTimelineEntry.new(attribute, value, association_name)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Check if a model has timeline entries with specific metadata
|
|
81
|
+
#
|
|
82
|
+
# @param expected_metadata [Hash] The metadata key-value pairs to check for
|
|
83
|
+
# @return [HaveTimelineEntryMetadata] A matcher that checks for specific metadata
|
|
84
|
+
# @example
|
|
85
|
+
# expect(user).to have_timeline_entry_metadata(foo: 'bar', baz: 'biz')
|
|
86
|
+
define_method(:"have_#{association_name_singularized}_metadata") do |expected_metadata|
|
|
87
|
+
HaveTimelineEntryMetadata.new(expected_metadata, association_name)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
71
90
|
end
|
|
72
91
|
|
|
73
92
|
# RSpec matcher to check if a model has timeline entries
|
|
@@ -77,8 +96,9 @@ module ModelTimeline
|
|
|
77
96
|
# Initialize the matcher
|
|
78
97
|
#
|
|
79
98
|
# @param expected_count [Integer, nil] The expected number of timeline entries
|
|
80
|
-
def initialize(expected_count)
|
|
99
|
+
def initialize(expected_count, association_name)
|
|
81
100
|
@expected_count = expected_count
|
|
101
|
+
@association_name = association_name
|
|
82
102
|
end
|
|
83
103
|
|
|
84
104
|
# Check if the subject matches the expectations
|
|
@@ -88,9 +108,9 @@ module ModelTimeline
|
|
|
88
108
|
def matches?(subject)
|
|
89
109
|
@subject = subject
|
|
90
110
|
if @expected_count.nil?
|
|
91
|
-
subject.
|
|
111
|
+
subject.public_send(@association_name).any?
|
|
92
112
|
else
|
|
93
|
-
subject.
|
|
113
|
+
subject.public_send(@association_name).count == @expected_count
|
|
94
114
|
end
|
|
95
115
|
end
|
|
96
116
|
|
|
@@ -102,7 +122,7 @@ module ModelTimeline
|
|
|
102
122
|
"expected #{@subject} to have timeline entries, but found none"
|
|
103
123
|
else
|
|
104
124
|
"expected #{@subject} to have #{@expected_count} timeline entries, " \
|
|
105
|
-
"but found #{@subject.
|
|
125
|
+
"but found #{@subject.public_send(@association_name).count}"
|
|
106
126
|
end
|
|
107
127
|
end
|
|
108
128
|
|
|
@@ -111,7 +131,7 @@ module ModelTimeline
|
|
|
111
131
|
# @return [String] A descriptive failure message for negated expectations
|
|
112
132
|
def failure_message_when_negated
|
|
113
133
|
if @expected_count.nil?
|
|
114
|
-
"expected #{@subject} not to have any timeline entries, but found #{@subject.
|
|
134
|
+
"expected #{@subject} not to have any timeline entries, but found #{@subject.public_send(@association_name).count}"
|
|
115
135
|
else
|
|
116
136
|
"expected #{@subject} not to have #{@expected_count} timeline entries, but found exactly that many"
|
|
117
137
|
end
|
|
@@ -121,12 +141,13 @@ module ModelTimeline
|
|
|
121
141
|
# RSpec matcher to check if a model has timeline entries with a specific action
|
|
122
142
|
#
|
|
123
143
|
# @api private
|
|
124
|
-
class
|
|
144
|
+
class HaveTimelineAction
|
|
125
145
|
# Initialize the matcher
|
|
126
146
|
#
|
|
127
147
|
# @param action [String, Symbol] The action to look for
|
|
128
|
-
def initialize(action)
|
|
148
|
+
def initialize(action, association_name)
|
|
129
149
|
@action = action.to_s
|
|
150
|
+
@association_name = association_name
|
|
130
151
|
end
|
|
131
152
|
|
|
132
153
|
# Check if the subject matches the expectations
|
|
@@ -135,7 +156,7 @@ module ModelTimeline
|
|
|
135
156
|
# @return [Boolean] True if the model has timeline entries with the specified action
|
|
136
157
|
def matches?(subject)
|
|
137
158
|
@subject = subject
|
|
138
|
-
subject.
|
|
159
|
+
@subject.public_send(@association_name).where(action: @action).exists?
|
|
139
160
|
end
|
|
140
161
|
|
|
141
162
|
# Message displayed when the expectation fails
|
|
@@ -156,12 +177,13 @@ module ModelTimeline
|
|
|
156
177
|
# RSpec matcher to check if a model has timeline entries with changes to a specific attribute
|
|
157
178
|
#
|
|
158
179
|
# @api private
|
|
159
|
-
class
|
|
180
|
+
class HaveTimelineChange
|
|
160
181
|
# Initialize the matcher
|
|
161
182
|
#
|
|
162
183
|
# @param attribute [String, Symbol] The attribute to check for changes
|
|
163
|
-
def initialize(attribute)
|
|
184
|
+
def initialize(attribute, association_name)
|
|
164
185
|
@attribute = attribute.to_s
|
|
186
|
+
@association_name = association_name
|
|
165
187
|
end
|
|
166
188
|
|
|
167
189
|
# Check if the subject matches the expectations
|
|
@@ -170,7 +192,7 @@ module ModelTimeline
|
|
|
170
192
|
# @return [Boolean] True if the model has timeline entries with changes to the specified attribute
|
|
171
193
|
def matches?(subject)
|
|
172
194
|
@subject = subject
|
|
173
|
-
subject.
|
|
195
|
+
@subject.public_send(@association_name).with_changed_attribute(@attribute).exists?
|
|
174
196
|
end
|
|
175
197
|
|
|
176
198
|
# Message displayed when the expectation fails
|
|
@@ -191,14 +213,15 @@ module ModelTimeline
|
|
|
191
213
|
# RSpec matcher to check if a model has timeline entries where an attribute changed to a specific value
|
|
192
214
|
#
|
|
193
215
|
# @api private
|
|
194
|
-
class
|
|
216
|
+
class HaveTimelineEntry
|
|
195
217
|
# Initialize the matcher
|
|
196
218
|
#
|
|
197
219
|
# @param attribute [String, Symbol] The attribute to check
|
|
198
220
|
# @param value [Object] The value the attribute should have changed to
|
|
199
|
-
def initialize(attribute, value)
|
|
221
|
+
def initialize(attribute, value, association_name)
|
|
200
222
|
@attribute = attribute.to_s
|
|
201
223
|
@value = value
|
|
224
|
+
@association_name = association_name
|
|
202
225
|
end
|
|
203
226
|
|
|
204
227
|
# Check if the subject matches the expectations
|
|
@@ -207,7 +230,7 @@ module ModelTimeline
|
|
|
207
230
|
# @return [Boolean] True if the model has timeline entries where the attribute changed to the specified value
|
|
208
231
|
def matches?(subject)
|
|
209
232
|
@subject = subject
|
|
210
|
-
subject.
|
|
233
|
+
@subject.public_send(@association_name).with_changed_value(@attribute, @value).exists?
|
|
211
234
|
end
|
|
212
235
|
|
|
213
236
|
# Message displayed when the expectation fails
|
|
@@ -224,7 +247,52 @@ module ModelTimeline
|
|
|
224
247
|
"expected #{@subject} not to have tracked '#{@attribute}' changing to '#{@value}', but such a change was found"
|
|
225
248
|
end
|
|
226
249
|
end
|
|
250
|
+
|
|
251
|
+
# RSpec matcher to check if a model has timeline entries with specific metadata
|
|
252
|
+
#
|
|
253
|
+
# @api private
|
|
254
|
+
class HaveTimelineEntryMetadata
|
|
255
|
+
# Initialize the matcher
|
|
256
|
+
#
|
|
257
|
+
# @param expected_metadata [Hash] The metadata key-value pairs to check for
|
|
258
|
+
# @param association_name [Symbol] The name of the timeline association
|
|
259
|
+
def initialize(expected_metadata, association_name)
|
|
260
|
+
@expected_metadata = expected_metadata
|
|
261
|
+
@association_name = association_name
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Check if the subject matches the expectations
|
|
265
|
+
#
|
|
266
|
+
# @param subject [Object] The model to check for timeline entries
|
|
267
|
+
# @return [Boolean] True if the model has timeline entries with the specified metadata
|
|
268
|
+
def matches?(subject)
|
|
269
|
+
@subject = subject
|
|
270
|
+
|
|
271
|
+
# Build a query that checks for each key-value pair in the metadata
|
|
272
|
+
entries = subject.public_send(@association_name)
|
|
273
|
+
|
|
274
|
+
# Construct queries for each metadata key-value pair
|
|
275
|
+
@expected_metadata.all? do |key, value|
|
|
276
|
+
# Use a JSON containment query to check if the metadata contains the key-value pair
|
|
277
|
+
# This syntax works with PostgreSQL's JSONB containment operator @>
|
|
278
|
+
entries.where('metadata @> ?', { key.to_s => value }.to_json).exists?
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Message displayed when the expectation fails
|
|
283
|
+
#
|
|
284
|
+
# @return [String] A descriptive failure message
|
|
285
|
+
def failure_message
|
|
286
|
+
"expected #{@subject} to have timeline entries with metadata #{@expected_metadata.inspect}, but none was found"
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Message displayed when the negated expectation fails
|
|
290
|
+
#
|
|
291
|
+
# @return [String] A descriptive failure message for negated expectations
|
|
292
|
+
def failure_message_when_negated
|
|
293
|
+
"expected #{@subject} not to have timeline entries with metadata #{@expected_metadata.inspect}, but such entries were found"
|
|
294
|
+
end
|
|
295
|
+
end
|
|
227
296
|
end
|
|
228
|
-
# rubocop:enable Naming/PredicateName
|
|
229
297
|
end
|
|
230
298
|
end
|
data/lib/model_timeline/rspec.rb
CHANGED
|
@@ -20,7 +20,7 @@ module ModelTimeline
|
|
|
20
20
|
# describe User, :with_timeline do
|
|
21
21
|
# it "records timeline entries when updated" do
|
|
22
22
|
# user.update(name: "New Name")
|
|
23
|
-
# expect(user).to
|
|
23
|
+
# expect(user).to have_timeline_entry_change(:name)
|
|
24
24
|
# end
|
|
25
25
|
# end
|
|
26
26
|
module RSpec
|
|
@@ -185,8 +185,7 @@ module ModelTimeline
|
|
|
185
185
|
|
|
186
186
|
# Collects metadata for the timeline entry
|
|
187
187
|
#
|
|
188
|
-
# @param meta_config [Hash] The metadata configuration
|
|
189
|
-
# @param config_key [String] The configuration key for this model
|
|
188
|
+
# @param meta_config [Hash, Proc] The metadata configuration
|
|
190
189
|
# @return [Hash] Collected metadata
|
|
191
190
|
def collect_metadata(meta_config)
|
|
192
191
|
metadata = {}
|
|
@@ -194,22 +193,46 @@ module ModelTimeline
|
|
|
194
193
|
# First, add any thread-level metadata
|
|
195
194
|
metadata.merge!(ModelTimeline.metadata)
|
|
196
195
|
|
|
197
|
-
# Then, add any model-specific metadata
|
|
198
|
-
meta_config
|
|
199
|
-
resolved_value = case value
|
|
200
|
-
when Proc
|
|
201
|
-
instance_exec(self, &value)
|
|
202
|
-
when Symbol
|
|
203
|
-
respond_to?(value) ? send(value) : value
|
|
204
|
-
else
|
|
205
|
-
value
|
|
206
|
-
end
|
|
207
|
-
metadata[key] = resolved_value
|
|
208
|
-
end
|
|
196
|
+
# Then, add any model-specific metadata from config
|
|
197
|
+
metadata.merge!(resolve_metadata_value(meta_config))
|
|
209
198
|
|
|
210
199
|
metadata
|
|
211
200
|
end
|
|
212
201
|
|
|
202
|
+
# Recursively resolves metadata values
|
|
203
|
+
#
|
|
204
|
+
# @param value [Hash, Proc, Symbol, Object] The value to resolve
|
|
205
|
+
# @return [Hash, Object] The resolved value
|
|
206
|
+
def resolve_metadata_value(value)
|
|
207
|
+
case value
|
|
208
|
+
when Proc
|
|
209
|
+
# If it's a Proc, execute it and process the result recursively
|
|
210
|
+
proc_result = instance_exec(self, &value)
|
|
211
|
+
proc_result.is_a?(Hash) ? process_metadata_hash(proc_result) : proc_result
|
|
212
|
+
when Hash
|
|
213
|
+
# If it's a Hash, process each key-value pair
|
|
214
|
+
process_metadata_hash(value)
|
|
215
|
+
when Symbol
|
|
216
|
+
# If it's a Symbol, try to call the method
|
|
217
|
+
respond_to?(value) ? send(value) : value
|
|
218
|
+
else
|
|
219
|
+
# Any other value, return as-is
|
|
220
|
+
value
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Processes a metadata hash by resolving each value
|
|
225
|
+
#
|
|
226
|
+
# @param hash [Hash] The hash to process
|
|
227
|
+
# @return [Hash] The processed hash
|
|
228
|
+
def process_metadata_hash(hash)
|
|
229
|
+
result = {}
|
|
230
|
+
hash.each do |key, val|
|
|
231
|
+
result[key] = resolve_metadata_value(val)
|
|
232
|
+
end
|
|
233
|
+
result
|
|
234
|
+
end
|
|
235
|
+
|
|
213
236
|
def column_metadata(config)
|
|
214
237
|
metadata = collect_metadata(config[:meta])
|
|
215
238
|
column_names = config[:klass].column_names.map(&:to_sym)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: model_timeline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexandre Stapenhorst
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-06-
|
|
11
|
+
date: 2025-06-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pg
|