active_record-events 4.0.1 → 4.1.0
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 +22 -1
- data/lib/active_record/events/method_factory.rb +25 -9
- data/lib/active_record/events/version.rb +1 -1
- data/lib/generators/active_record/event/event_generator.rb +5 -2
- data/spec/active_record/events_spec.rb +46 -0
- data/spec/dummy/app/models/task.rb +2 -1
- data/spec/dummy/db/migrate/20220609015338_add_expired_at_to_tasks.rb +5 -0
- data/spec/dummy/db/schema.rb +7 -6
- data/spec/generators/active_record/event/event_generator_spec.rb +8 -2
- data/spec/spec_helper.rb +13 -2
- metadata +33 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1eace6bdc4fb78e2ac6c90a8521c976f8b707caeed3e035da39d0218e0724ad7
|
4
|
+
data.tar.gz: 8e9754766994b37d29dd29a9a44963fa9c90b1d4f90418e8e06bf3863f32ea02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1260729b2209565867c7824850be4450b45565da6fc1d7864d247ff6fcc659b89f1969ef2f9530e2bfc7d8de934a90f3eab585c18fb2c0d8ec3809f8242a864f
|
7
|
+
data.tar.gz: b876227c57657edb00198bda46eb42e2b2aebdb39379cd61261c9586805a5e736575515b2ddbbd336ed7e1612b603b0f6c30982b3c8e721da9ef849a93f41a2f
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# ActiveRecord::Events [](https://rubygems.org/gems/active_record-events) [](https://rubygems.org/gems/active_record-events) [](https://github.com/pienkowb/active_record-events/actions/workflows/test.yml?query=branch%3Adevelop) [](https://coveralls.io/github/pienkowb/active_record-events) [](https://codeclimate.com/github/pienkowb/active_record-events)
|
2
2
|
|
3
3
|
An ActiveRecord extension providing convenience methods for timestamp management.
|
4
4
|
|
@@ -119,6 +119,26 @@ has_event :complete, field_name: :completion_time
|
|
119
119
|
|
120
120
|
Note that the `field_name` option takes precedence over the `field_type` option.
|
121
121
|
|
122
|
+
### Comparison strategy
|
123
|
+
|
124
|
+
By default the timestamp's presence will dictate the behavior. However in some cases you may want to check against the current time.
|
125
|
+
|
126
|
+
You can do this with the `strategy` option, which can be either `presence` or `time_comparison`:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
has_event :complete, strategy: :time_comparison
|
130
|
+
```
|
131
|
+
|
132
|
+
**Example:**
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
task.completed_at = 1.hour.ago
|
136
|
+
task.completed? # => true
|
137
|
+
|
138
|
+
task.completed_at = 1.hour.from_now
|
139
|
+
task.completed? # => false
|
140
|
+
```
|
141
|
+
|
122
142
|
### Specifying an object
|
123
143
|
|
124
144
|
There are events which do not relate to a model itself but to one of its attributes – take the `User` model with the `email_confirmed_at` field as an example.
|
@@ -208,6 +228,7 @@ end
|
|
208
228
|
- [Tomasz Skupiński](https://github.com/tskupinski)
|
209
229
|
- [Oskar Janusz](https://github.com/oskaror)
|
210
230
|
- [Mike Rogers](https://github.com/MikeRogers0)
|
231
|
+
- [Spencer Rogers](https://github.com/serogers)
|
211
232
|
|
212
233
|
## See also
|
213
234
|
|
@@ -6,11 +6,12 @@ module ActiveRecord
|
|
6
6
|
def initialize(event_name, options)
|
7
7
|
@options = options
|
8
8
|
@naming = Naming.new(event_name, options)
|
9
|
+
@strategy = options[:strategy].try(:to_sym)
|
9
10
|
end
|
10
11
|
|
11
12
|
def instance_methods
|
12
13
|
Module.new.tap do |module_|
|
13
|
-
define_predicate_method(module_, naming)
|
14
|
+
define_predicate_method(module_, naming, strategy)
|
14
15
|
define_inverse_predicate_method(module_, naming)
|
15
16
|
|
16
17
|
define_action_method(module_, naming)
|
@@ -23,8 +24,8 @@ module ActiveRecord
|
|
23
24
|
define_collective_action_method(module_, naming)
|
24
25
|
|
25
26
|
unless options[:skip_scopes]
|
26
|
-
define_scope_method(module_, naming)
|
27
|
-
define_inverse_scope_method(module_, naming)
|
27
|
+
define_scope_method(module_, naming, strategy)
|
28
|
+
define_inverse_scope_method(module_, naming, strategy)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -33,10 +34,15 @@ module ActiveRecord
|
|
33
34
|
|
34
35
|
attr_reader :options
|
35
36
|
attr_reader :naming
|
37
|
+
attr_reader :strategy
|
36
38
|
|
37
|
-
def define_predicate_method(module_, naming)
|
39
|
+
def define_predicate_method(module_, naming, strategy)
|
38
40
|
module_.send(:define_method, naming.predicate) do
|
39
|
-
|
41
|
+
if strategy == :time_comparison
|
42
|
+
self[naming.field].present? && self[naming.field].past?
|
43
|
+
else
|
44
|
+
self[naming.field].present?
|
45
|
+
end
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
@@ -72,15 +78,25 @@ module ActiveRecord
|
|
72
78
|
end
|
73
79
|
end
|
74
80
|
|
75
|
-
def define_scope_method(module_, naming)
|
81
|
+
def define_scope_method(module_, naming, strategy)
|
76
82
|
module_.send(:define_method, naming.scope) do
|
77
|
-
|
83
|
+
if strategy == :time_comparison
|
84
|
+
where(arel_table[naming.field].lteq(Time.current))
|
85
|
+
else
|
86
|
+
where(arel_table[naming.field].not_eq(nil))
|
87
|
+
end
|
78
88
|
end
|
79
89
|
end
|
80
90
|
|
81
|
-
def define_inverse_scope_method(module_, naming)
|
91
|
+
def define_inverse_scope_method(module_, naming, strategy)
|
82
92
|
module_.send(:define_method, naming.inverse_scope) do
|
83
|
-
|
93
|
+
arel_field = arel_table[naming.field]
|
94
|
+
|
95
|
+
if strategy == :time_comparison
|
96
|
+
where(arel_field.eq(nil).or(arel_field.gt(Time.current)))
|
97
|
+
else
|
98
|
+
where(arel_field.eq(nil))
|
99
|
+
end
|
84
100
|
end
|
85
101
|
end
|
86
102
|
end
|
@@ -6,7 +6,7 @@ require 'active_record/events/macro'
|
|
6
6
|
module ActiveRecord
|
7
7
|
module Generators
|
8
8
|
class EventGenerator < Rails::Generators::Base
|
9
|
-
MACRO_OPTIONS = %w[object field_type skip_scopes].freeze
|
9
|
+
MACRO_OPTIONS = %w[object field_type skip_scopes strategy].freeze
|
10
10
|
|
11
11
|
argument :model_name, type: :string
|
12
12
|
argument :event_name, type: :string
|
@@ -17,6 +17,8 @@ module ActiveRecord
|
|
17
17
|
desc: 'The field type (datetime or date)'
|
18
18
|
class_option :object, type: :string,
|
19
19
|
desc: 'The name of the object'
|
20
|
+
class_option :strategy, type: :string,
|
21
|
+
desc: 'The comparison strategy (presence or time_comparison)'
|
20
22
|
|
21
23
|
source_root File.expand_path('templates', __dir__)
|
22
24
|
|
@@ -38,8 +40,9 @@ module ActiveRecord
|
|
38
40
|
|
39
41
|
macro_options = options.slice(*MACRO_OPTIONS)
|
40
42
|
macro = ActiveRecord::Events::Macro.new(event_name, macro_options)
|
43
|
+
pattern = /^\s*class\s.+\n/
|
41
44
|
|
42
|
-
inject_into_file model_file_path, "\s\s#{macro}\n", after:
|
45
|
+
inject_into_file model_file_path, "\s\s#{macro}\n", after: pattern
|
43
46
|
end
|
44
47
|
|
45
48
|
private
|
@@ -71,4 +71,50 @@ RSpec.describe ActiveRecord::Events do
|
|
71
71
|
|
72
72
|
expect(task.reload).to be_completed
|
73
73
|
end
|
74
|
+
|
75
|
+
describe 'time comparison strategy' do
|
76
|
+
it 'defines a predicate method comparing against current time' do
|
77
|
+
task.update_columns(expired_at: 1.hour.from_now)
|
78
|
+
expect(task.expired?).to eq(false)
|
79
|
+
|
80
|
+
task.update_columns(expired_at: 1.hour.ago)
|
81
|
+
expect(task.expired?).to eq(true)
|
82
|
+
|
83
|
+
task.update_columns(expired_at: nil)
|
84
|
+
expect(task.expired?).to eq(false)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'defines an inverse predicate method comparing against current time' do
|
88
|
+
task.update_columns(expired_at: 1.hour.from_now)
|
89
|
+
expect(task.not_expired?).to eq(true)
|
90
|
+
|
91
|
+
task.update_columns(expired_at: 1.hour.ago)
|
92
|
+
expect(task.not_expired?).to eq(false)
|
93
|
+
|
94
|
+
task.update_columns(expired_at: nil)
|
95
|
+
expect(task.not_expired?).to eq(true)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'defines a scope comparing against current time' do
|
99
|
+
task.update_columns(expired_at: 1.hour.from_now)
|
100
|
+
expect(Task.expired).not_to include(task)
|
101
|
+
|
102
|
+
task.update_columns(expired_at: 1.hour.ago)
|
103
|
+
expect(Task.expired).to include(task)
|
104
|
+
|
105
|
+
task.update_columns(expired_at: nil)
|
106
|
+
expect(Task.expired).not_to include(task)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'defines an inverse scope comparing against current time' do
|
110
|
+
task.update_columns(expired_at: 1.hour.from_now)
|
111
|
+
expect(Task.not_expired).to include(task)
|
112
|
+
|
113
|
+
task.update_columns(expired_at: 1.hour.ago)
|
114
|
+
expect(Task.not_expired).not_to include(task)
|
115
|
+
|
116
|
+
task.update_columns(expired_at: nil)
|
117
|
+
expect(Task.not_expired).to include(task)
|
118
|
+
end
|
119
|
+
end
|
74
120
|
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -2,20 +2,21 @@
|
|
2
2
|
# of editing this file, please use the migrations feature of Active Record to
|
3
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# from scratch.
|
9
|
-
#
|
5
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
6
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
7
|
+
# be faster and is potentially less error prone than running all of your
|
8
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
9
|
+
# migrations use external dependencies or application code.
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(version:
|
13
|
+
ActiveRecord::Schema.define(version: 2022_06_09_015338) do
|
14
14
|
|
15
15
|
create_table "tasks", force: :cascade do |t|
|
16
16
|
t.datetime "completed_at"
|
17
17
|
t.datetime "created_at", null: false
|
18
18
|
t.datetime "updated_at", null: false
|
19
|
+
t.datetime "expired_at"
|
19
20
|
end
|
20
21
|
|
21
22
|
end
|
@@ -2,7 +2,13 @@ require 'spec_helper'
|
|
2
2
|
require 'generators/active_record/event/event_generator'
|
3
3
|
|
4
4
|
RSpec.describe ActiveRecord::Generators::EventGenerator, type: :generator do
|
5
|
-
arguments %w[
|
5
|
+
arguments %w[
|
6
|
+
task complete
|
7
|
+
--field-type=date
|
8
|
+
--skip-scopes
|
9
|
+
--strategy=time_comparison
|
10
|
+
]
|
11
|
+
|
6
12
|
destination File.expand_path('../../../../tmp', __dir__)
|
7
13
|
|
8
14
|
before { prepare_destination }
|
@@ -30,7 +36,7 @@ RSpec.describe ActiveRecord::Generators::EventGenerator, type: :generator do
|
|
30
36
|
|
31
37
|
assert_file 'app/models/task.rb', <<-RUBY.strip_heredoc
|
32
38
|
class Task < ActiveRecord::Base
|
33
|
-
has_event :complete, field_type: :date, skip_scopes: true
|
39
|
+
has_event :complete, field_type: :date, skip_scopes: true, strategy: :time_comparison
|
34
40
|
end
|
35
41
|
RUBY
|
36
42
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
1
|
ENV['RAILS_ENV'] ||= 'test'
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
|
-
require '
|
4
|
+
require 'simplecov'
|
5
5
|
|
6
|
-
|
6
|
+
SimpleCov.start do
|
7
|
+
if ENV['CI']
|
8
|
+
require 'simplecov-lcov'
|
9
|
+
|
10
|
+
SimpleCov::Formatter::LcovFormatter.config do |config|
|
11
|
+
config.report_with_single_file = true
|
12
|
+
config.single_report_path = 'coverage/lcov.info'
|
13
|
+
end
|
14
|
+
|
15
|
+
formatter SimpleCov::Formatter::LcovFormatter
|
16
|
+
end
|
17
|
+
end
|
7
18
|
|
8
19
|
require File.expand_path('dummy/config/environment.rb', __dir__)
|
9
20
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record-events
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bartosz Pieńkowski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.2'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: coveralls
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.8'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0.8'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: factory_girl
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +108,34 @@ dependencies:
|
|
122
108
|
- - "~>"
|
123
109
|
- !ruby/object:Gem::Version
|
124
110
|
version: 0.50.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.16.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.16.1
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov-lcov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.7.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.7.0
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: sqlite3
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -191,6 +205,7 @@ files:
|
|
191
205
|
- spec/dummy/config/database.yml
|
192
206
|
- spec/dummy/config/environment.rb
|
193
207
|
- spec/dummy/db/migrate/20150813132804_create_tasks.rb
|
208
|
+
- spec/dummy/db/migrate/20220609015338_add_expired_at_to_tasks.rb
|
194
209
|
- spec/dummy/db/schema.rb
|
195
210
|
- spec/generators/active_record/event/event_generator_spec.rb
|
196
211
|
- spec/spec_helper.rb
|
@@ -216,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
216
231
|
- !ruby/object:Gem::Version
|
217
232
|
version: '0'
|
218
233
|
requirements: []
|
219
|
-
rubygems_version: 3.
|
234
|
+
rubygems_version: 3.1.6
|
220
235
|
signing_key:
|
221
236
|
specification_version: 4
|
222
237
|
summary: Manage timestamps in ActiveRecord models
|
@@ -228,6 +243,7 @@ test_files:
|
|
228
243
|
- spec/dummy/config/boot.rb
|
229
244
|
- spec/dummy/db/schema.rb
|
230
245
|
- spec/dummy/db/migrate/20150813132804_create_tasks.rb
|
246
|
+
- spec/dummy/db/migrate/20220609015338_add_expired_at_to_tasks.rb
|
231
247
|
- spec/active_record/events/method_factory_spec.rb
|
232
248
|
- spec/active_record/events/naming_spec.rb
|
233
249
|
- spec/active_record/events/macro_spec.rb
|