active_record-events 4.0.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18d2fc6a8788d3190b5da3dd8dc45fbf307bb55344a6072ba24db67ff9b0e6cb
4
- data.tar.gz: 17767f7e00810c9717cc5fa4bd92d49303b22427eb5da06a3f27ea39f8a4fbf8
3
+ metadata.gz: 1eace6bdc4fb78e2ac6c90a8521c976f8b707caeed3e035da39d0218e0724ad7
4
+ data.tar.gz: 8e9754766994b37d29dd29a9a44963fa9c90b1d4f90418e8e06bf3863f32ea02
5
5
  SHA512:
6
- metadata.gz: d39a25b8c5695aa8c81b9780744f0639ab2b0bac74296486721ec1c28cad0c67f801441b78c3faa48162d60938297a33638dada9e597a84a7c8c888c94cc86b2
7
- data.tar.gz: afb5395aba7821776ff9aa3790d0f04f625daa1a4de6495e9069cf210a4ea3023b7449bb6cce58e9eb158887a541da6f927b9ba03e61df0974b6cd473a6beacf
6
+ metadata.gz: 1260729b2209565867c7824850be4450b45565da6fc1d7864d247ff6fcc659b89f1969ef2f9530e2bfc7d8de934a90f3eab585c18fb2c0d8ec3809f8242a864f
7
+ data.tar.gz: b876227c57657edb00198bda46eb42e2b2aebdb39379cd61261c9586805a5e736575515b2ddbbd336ed7e1612b603b0f6c30982b3c8e721da9ef849a93f41a2f
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ActiveRecord::Events [![Gem version](https://img.shields.io/gem/v/active_record-events)](https://rubygems.org/gems/active_record-events) [![Build status](https://img.shields.io/travis/pienkowb/active_record-events/develop)](https://travis-ci.org/pienkowb/active_record-events) [![Coverage status](https://img.shields.io/coveralls/github/pienkowb/active_record-events/develop)](https://coveralls.io/github/pienkowb/active_record-events) [![Maintainability status](https://img.shields.io/codeclimate/maintainability/pienkowb/active_record-events)](https://codeclimate.com/github/pienkowb/active_record-events)
1
+ # ActiveRecord::Events [![Gem version](https://img.shields.io/gem/v/active_record-events)](https://rubygems.org/gems/active_record-events) [![Build status](https://img.shields.io/github/workflow/status/pienkowb/active_record-events/Test/develop)](https://github.com/pienkowb/active_record-events/actions/workflows/test.yml?query=branch%3Adevelop) [![Coverage status](https://img.shields.io/coveralls/github/pienkowb/active_record-events/develop)](https://coveralls.io/github/pienkowb/active_record-events) [![Maintainability status](https://img.shields.io/codeclimate/maintainability/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
- self[naming.field].present?
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
- where(arel_table[naming.field].not_eq(nil))
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
- where(arel_table[naming.field].eq(nil))
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
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Events
3
- VERSION = '4.0.1'.freeze
3
+ VERSION = '4.1.0'.freeze
4
4
  end
5
5
  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: /class.+\n/
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
@@ -1,6 +1,7 @@
1
1
  class Task < ActiveRecord::Base
2
2
  has_event :complete
3
- has_events :archive, skip_scopes: true
3
+ has_event :archive, skip_scopes: true
4
+ has_events :expire, strategy: :time_comparison
4
5
 
5
6
  def complete!
6
7
  super
@@ -0,0 +1,5 @@
1
+ class AddExpiredAtToTasks < ACTIVE_RECORD_MIGRATION_CLASS
2
+ def change
3
+ add_column :tasks, :expired_at, :datetime
4
+ end
5
+ end
@@ -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
- # Note that this schema.rb definition is the authoritative source for your
6
- # database schema. If you need to create the application database on another
7
- # system, you should be using db:schema:load, not running all the migrations
8
- # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
- # you'll amass, the slower it'll run and the greater likelihood for issues).
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: 2015_08_13_132804) do
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[task complete --field-type=date --skip-scopes]
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 'coveralls'
4
+ require 'simplecov'
5
5
 
6
- Coveralls.wear!
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.1
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: 2021-03-15 00:00:00.000000000 Z
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.0.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