active_record-events 3.0.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d3c49af800cff40043af18ec6357dd41a8492a75942525701fa607b078a0bb0
4
- data.tar.gz: 01b3d06c56050a764fa67b772e8fdf6f791603be7e220773d7e7547a53450ef6
3
+ metadata.gz: 1eace6bdc4fb78e2ac6c90a8521c976f8b707caeed3e035da39d0218e0724ad7
4
+ data.tar.gz: 8e9754766994b37d29dd29a9a44963fa9c90b1d4f90418e8e06bf3863f32ea02
5
5
  SHA512:
6
- metadata.gz: a3f18c26a27d1eca9ee0517ea19dbf087019200e02fa02b95f0412c4901f4a2aec4239115fc38191d1e6ad7f643067f1567fde10633ace0beb71ddb4623f027b
7
- data.tar.gz: a388c51a55a45a13bccc7aad2288aefbef85c49ba322f6bd7fe0791aa4f378b1be1e41ac85562c732168be41553499560e1f8d79a2e0ea2b4691d25980189087
6
+ metadata.gz: 1260729b2209565867c7824850be4450b45565da6fc1d7864d247ff6fcc659b89f1969ef2f9530e2bfc7d8de934a90f3eab585c18fb2c0d8ec3809f8242a864f
7
+ data.tar.gz: b876227c57657edb00198bda46eb42e2b2aebdb39379cd61261c9586805a5e736575515b2ddbbd336ed7e1612b603b0f6c30982b3c8e721da9ef849a93f41a2f
data/README.md CHANGED
@@ -1,7 +1,15 @@
1
- # ActiveRecord::Events [![Gem version](https://img.shields.io/gem/v/active_record-events.svg)](https://rubygems.org/gems/active_record-events) [![Build status](https://img.shields.io/travis/pienkowb/active_record-events.svg)](https://travis-ci.org/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
 
5
+ ## Screencast
6
+
7
+ <a href="https://www.youtube.com/watch?v=TIR7YDF3O-4">
8
+ <img src="https://img.youtube.com/vi/TIR7YDF3O-4/maxresdefault.jpg" title="ActiveRecord::Events - Awesome Ruby Gems" width="50%">
9
+ </a>
10
+
11
+ [Watch screencast](https://www.youtube.com/watch?v=TIR7YDF3O-4) (courtesy of [Mike Rogers](https://github.com/MikeRogers0))
12
+
5
13
  ## Installation
6
14
 
7
15
  Add the following line to your application's Gemfile:
@@ -93,12 +101,42 @@ In such a case, many lines of code can be replaced with an expressive one-liner.
93
101
  has_events :complete, :archive
94
102
  ```
95
103
 
96
- ### Setting a field type
104
+ ### Date fields
105
+
106
+ In case of date fields, which by convention have names ending with `_on` instead of `_at` (e.g. `completed_on`), the `field_type` option needs to be passed to the macro:
107
+
108
+ ```ruby
109
+ has_event :complete, field_type: :date
110
+ ```
111
+
112
+ ### Custom field name
113
+
114
+ If there's a field with a name that doesn't follow the naming convention (i.e. does not end with `_at` or `_on`), you can pass it as the `field_name` option.
115
+
116
+ ```ruby
117
+ has_event :complete, field_name: :completion_time
118
+ ```
119
+
120
+ Note that the `field_name` option takes precedence over the `field_type` option.
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.
97
125
 
98
- In case of date fields, which by convention have names ending with `_on` instead of `_at` (e.g. `delivered_on`), the `field_type` option needs to be passed to the macro:
126
+ You can do this with the `strategy` option, which can be either `presence` or `time_comparison`:
99
127
 
100
128
  ```ruby
101
- has_event :deliver, field_type: :date
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
102
140
  ```
103
141
 
104
142
  ### Specifying an object
@@ -189,6 +227,8 @@ end
189
227
  - [Bartosz Pieńkowski](https://github.com/pienkowb)
190
228
  - [Tomasz Skupiński](https://github.com/tskupinski)
191
229
  - [Oskar Janusz](https://github.com/oskaror)
230
+ - [Mike Rogers](https://github.com/MikeRogers0)
231
+ - [Spencer Rogers](https://github.com/serogers)
192
232
 
193
233
  ## See also
194
234
 
data/Rakefile CHANGED
@@ -22,9 +22,23 @@ RDoc::Task.new(:rdoc) do |rdoc|
22
22
  rdoc.rdoc_files.include('lib/**/*.rb')
23
23
  end
24
24
 
25
- require 'standalone_migrations'
25
+ require 'active_record'
26
+ require 'yaml'
26
27
 
27
- StandaloneMigrations::Tasks.load_tasks
28
+ include ActiveRecord::Tasks
29
+
30
+ dummy_root = File.expand_path('spec/dummy', __dir__)
31
+ database_config = YAML.load_file("#{dummy_root}/config/database.yml")
32
+
33
+ DatabaseTasks.root = dummy_root
34
+ DatabaseTasks.env = ENV['RAILS_ENV'] || 'development'
35
+ DatabaseTasks.db_dir = "#{dummy_root}/db"
36
+ DatabaseTasks.database_configuration = database_config
37
+ DatabaseTasks.migrations_paths = "#{dummy_root}/db/migrate"
38
+
39
+ task :environment do
40
+ require "#{dummy_root}/config/environment.rb"
41
+ end
28
42
 
29
43
  ACTIVE_RECORD_MIGRATION_CLASS =
30
44
  if ActiveRecord::VERSION::MAJOR >= 5
@@ -33,6 +47,8 @@ ACTIVE_RECORD_MIGRATION_CLASS =
33
47
  ActiveRecord::Migration
34
48
  end
35
49
 
50
+ load 'active_record/railties/databases.rake'
51
+
36
52
  Bundler::GemHelper.install_tasks
37
53
 
38
54
  require 'rspec/core'
@@ -0,0 +1,19 @@
1
+ require 'active_record/events/method_factory'
2
+
3
+ module ActiveRecord
4
+ module Events
5
+ module Extension
6
+ def has_events(*names)
7
+ options = names.extract_options!
8
+ names.each { |n| has_event(n, options) }
9
+ end
10
+
11
+ def has_event(name, options = {})
12
+ method_factory = MethodFactory.new(name, options)
13
+
14
+ include method_factory.instance_methods
15
+ extend method_factory.class_methods
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,104 @@
1
+ require 'active_record/events/naming'
2
+
3
+ module ActiveRecord
4
+ module Events
5
+ class MethodFactory
6
+ def initialize(event_name, options)
7
+ @options = options
8
+ @naming = Naming.new(event_name, options)
9
+ @strategy = options[:strategy].try(:to_sym)
10
+ end
11
+
12
+ def instance_methods
13
+ Module.new.tap do |module_|
14
+ define_predicate_method(module_, naming, strategy)
15
+ define_inverse_predicate_method(module_, naming)
16
+
17
+ define_action_method(module_, naming)
18
+ define_safe_action_method(module_, naming)
19
+ end
20
+ end
21
+
22
+ def class_methods
23
+ Module.new.tap do |module_|
24
+ define_collective_action_method(module_, naming)
25
+
26
+ unless options[:skip_scopes]
27
+ define_scope_method(module_, naming, strategy)
28
+ define_inverse_scope_method(module_, naming, strategy)
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :options
36
+ attr_reader :naming
37
+ attr_reader :strategy
38
+
39
+ def define_predicate_method(module_, naming, strategy)
40
+ module_.send(:define_method, naming.predicate) do
41
+ if strategy == :time_comparison
42
+ self[naming.field].present? && self[naming.field].past?
43
+ else
44
+ self[naming.field].present?
45
+ end
46
+ end
47
+ end
48
+
49
+ def define_inverse_predicate_method(module_, naming)
50
+ module_.send(:define_method, naming.inverse_predicate) do
51
+ !__send__(naming.predicate)
52
+ end
53
+ end
54
+
55
+ def define_action_method(module_, naming)
56
+ module_.send(:define_method, naming.action) do
57
+ if persisted?
58
+ touch(naming.field)
59
+ else
60
+ self[naming.field] = current_time_from_proper_timezone
61
+ end
62
+ end
63
+ end
64
+
65
+ def define_safe_action_method(module_, naming)
66
+ module_.send(:define_method, naming.safe_action) do
67
+ __send__(naming.action) if __send__(naming.inverse_predicate)
68
+ end
69
+ end
70
+
71
+ def define_collective_action_method(module_, naming)
72
+ module_.send(:define_method, naming.collective_action) do
73
+ if respond_to?(:touch_all)
74
+ touch_all(naming.field)
75
+ else
76
+ update_all(naming.field => Time.current)
77
+ end
78
+ end
79
+ end
80
+
81
+ def define_scope_method(module_, naming, strategy)
82
+ module_.send(:define_method, naming.scope) do
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
88
+ end
89
+ end
90
+
91
+ def define_inverse_scope_method(module_, naming, strategy)
92
+ module_.send(:define_method, naming.inverse_scope) do
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
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -1,4 +1,4 @@
1
- require 'active_record/events/verbs'
1
+ require 'verbs'
2
2
 
3
3
  module ActiveRecord
4
4
  module Events
@@ -6,11 +6,15 @@ module ActiveRecord
6
6
  def initialize(infinitive, options = {})
7
7
  @infinitive = infinitive
8
8
  @object = options[:object].presence
9
+ @field_name = options[:field_name].to_s
9
10
  @field_type = options[:field_type].try(:to_sym)
10
11
  end
11
12
 
12
13
  def field
14
+ return field_name if field_name.present?
15
+
13
16
  suffix = field_type == :date ? 'on' : 'at'
17
+
14
18
  concatenate(object, past_participle, suffix)
15
19
  end
16
20
 
@@ -46,6 +50,7 @@ module ActiveRecord
46
50
 
47
51
  attr_reader :infinitive
48
52
  attr_reader :object
53
+ attr_reader :field_name
49
54
  attr_reader :field_type
50
55
 
51
56
  def concatenate(*parts)
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Events
3
- VERSION = '3.0.0'.freeze
3
+ VERSION = '4.1.0'.freeze
4
4
  end
5
5
  end
@@ -1,57 +1,13 @@
1
1
  require 'active_support'
2
- require 'active_record/events/naming'
3
-
4
- module ActiveRecord
5
- module Events
6
- def has_events(*names)
7
- options = names.extract_options!
8
- names.each { |n| has_event(n, options) }
9
- end
10
-
11
- def has_event(name, options = {})
12
- naming = Naming.new(name, options)
13
-
14
- include(Module.new do
15
- define_method(naming.predicate) do
16
- self[naming.field].present?
17
- end
18
-
19
- define_method(naming.inverse_predicate) do
20
- !__send__(naming.predicate)
21
- end
22
2
 
23
- define_method(naming.action) do
24
- touch(naming.field)
25
- end
3
+ require 'active_record/events/version'
26
4
 
27
- define_method(naming.safe_action) do
28
- __send__(naming.action) if __send__(naming.inverse_predicate)
29
- end
30
- end)
31
-
32
- extend(Module.new do
33
- define_method(naming.collective_action) do
34
- if respond_to?(:touch_all)
35
- touch_all(naming.field)
36
- else
37
- update_all(naming.field => Time.current)
38
- end
39
- end
40
-
41
- unless options[:skip_scopes]
42
- define_method(naming.scope) do
43
- where(arel_table[naming.field].not_eq(nil))
44
- end
5
+ require 'active_record/events/naming'
6
+ require 'active_record/events/method_factory'
7
+ require 'active_record/events/extension'
45
8
 
46
- define_method(naming.inverse_scope) do
47
- where(arel_table[naming.field].eq(nil))
48
- end
49
- end
50
- end)
51
- end
52
- end
53
- end
9
+ require 'active_record/events/macro'
54
10
 
55
11
  ActiveSupport.on_load(:active_record) do
56
- extend ActiveRecord::Events
12
+ extend ActiveRecord::Events::Extension
57
13
  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
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveRecord::Events::MethodFactory do
4
+ let(:event_name) { :complete }
5
+ let(:options) { {} }
6
+
7
+ subject { described_class.new(event_name, options) }
8
+
9
+ it 'generates instance methods' do
10
+ result = subject.instance_methods
11
+
12
+ expect(result).to have_method(:completed?)
13
+ expect(result).to have_method(:not_completed?)
14
+ expect(result).to have_method(:complete!)
15
+ expect(result).to have_method(:complete)
16
+ end
17
+
18
+ it 'generates class methods' do
19
+ result = subject.class_methods
20
+
21
+ expect(result).to have_method(:complete_all)
22
+ expect(result).to have_method(:completed)
23
+ expect(result).to have_method(:not_completed)
24
+ end
25
+
26
+ context 'with the object option' do
27
+ let(:options) { { object: :task } }
28
+
29
+ it 'generates instance methods' do
30
+ result = subject.instance_methods
31
+
32
+ expect(result).to have_method(:task_completed?)
33
+ expect(result).to have_method(:task_not_completed?)
34
+ expect(result).to have_method(:complete_task!)
35
+ expect(result).to have_method(:complete_task)
36
+ end
37
+
38
+ it 'generates class methods' do
39
+ result = subject.class_methods
40
+
41
+ expect(result).to have_method(:complete_all_tasks)
42
+ expect(result).to have_method(:task_completed)
43
+ expect(result).to have_method(:task_not_completed)
44
+ end
45
+ end
46
+
47
+ context 'with the skip scopes option' do
48
+ let(:options) { { skip_scopes: true } }
49
+
50
+ it 'generates class methods without scopes' do
51
+ result = subject.class_methods
52
+
53
+ expect(result).to have_method(:complete_all)
54
+
55
+ expect(result).not_to have_method(:completed)
56
+ expect(result).not_to have_method(:not_completed)
57
+ end
58
+ end
59
+ end
@@ -1,7 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe ActiveRecord::Events::Naming do
4
- subject { described_class.new(:complete) }
4
+ let(:event_name) { :complete }
5
+ let(:options) { {} }
6
+
7
+ subject { described_class.new(event_name, options) }
5
8
 
6
9
  it 'generates a field name' do
7
10
  expect(subject.field).to eq('completed_at')
@@ -36,46 +39,54 @@ RSpec.describe ActiveRecord::Events::Naming do
36
39
  end
37
40
 
38
41
  context 'with an object' do
39
- subject { described_class.new(:confirm, object: :email) }
42
+ let(:options) { { object: :task } }
40
43
 
41
44
  it 'generates a field name' do
42
- expect(subject.field).to eq('email_confirmed_at')
45
+ expect(subject.field).to eq('task_completed_at')
43
46
  end
44
47
 
45
48
  it 'generates a predicate name' do
46
- expect(subject.predicate).to eq('email_confirmed?')
49
+ expect(subject.predicate).to eq('task_completed?')
47
50
  end
48
51
 
49
52
  it 'generates an inverse predicate name' do
50
- expect(subject.inverse_predicate).to eq('email_not_confirmed?')
53
+ expect(subject.inverse_predicate).to eq('task_not_completed?')
51
54
  end
52
55
 
53
56
  it 'generates an action name' do
54
- expect(subject.action).to eq('confirm_email!')
57
+ expect(subject.action).to eq('complete_task!')
55
58
  end
56
59
 
57
60
  it 'generates a safe action name' do
58
- expect(subject.safe_action).to eq('confirm_email')
61
+ expect(subject.safe_action).to eq('complete_task')
59
62
  end
60
63
 
61
64
  it 'generates a collective action name' do
62
- expect(subject.collective_action).to eq('confirm_all_emails')
65
+ expect(subject.collective_action).to eq('complete_all_tasks')
63
66
  end
64
67
 
65
68
  it 'generates a scope name' do
66
- expect(subject.scope).to eq('email_confirmed')
69
+ expect(subject.scope).to eq('task_completed')
67
70
  end
68
71
 
69
72
  it 'generates an inverse scope name' do
70
- expect(subject.inverse_scope).to eq('email_not_confirmed')
73
+ expect(subject.inverse_scope).to eq('task_not_completed')
71
74
  end
72
75
  end
73
76
 
74
77
  context 'with a date field' do
75
- subject { described_class.new(:deliver, field_type: :date) }
78
+ let(:options) { { field_type: :date } }
76
79
 
77
80
  it 'generates a field name' do
78
- expect(subject.field).to eq('delivered_on')
81
+ expect(subject.field).to eq('completed_on')
82
+ end
83
+ end
84
+
85
+ context 'with a custom field name' do
86
+ let(:options) { { field_name: :completion_time } }
87
+
88
+ it 'returns the field name' do
89
+ expect(subject.field).to eq('completion_time')
79
90
  end
80
91
  end
81
92
  end
@@ -1,7 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe ActiveRecord::Events do
4
- around { |e| Timecop.freeze { e.run } }
4
+ around(:each) do |example|
5
+ Timecop.freeze { example.run }
6
+ end
5
7
 
6
8
  let!(:task) { create(:task) }
7
9
 
@@ -30,8 +32,19 @@ RSpec.describe ActiveRecord::Events do
30
32
  expect(task.completed_at).to eq(Time.current)
31
33
  end
32
34
 
35
+ context 'with a non-persisted object' do
36
+ it 'updates the timestamp' do
37
+ task = build(:task, completed_at: 3.days.ago)
38
+
39
+ task.complete!
40
+
41
+ expect(task.completed_at).to eq(Time.current)
42
+ end
43
+ end
44
+
33
45
  it 'records multiple timestamps at once' do
34
46
  Task.complete_all
47
+
35
48
  expect(task.reload).to be_completed
36
49
  end
37
50
 
@@ -43,16 +56,6 @@ RSpec.describe ActiveRecord::Events do
43
56
  expect(Task.not_completed).to include(task)
44
57
  end
45
58
 
46
- context 'with the skip scopes flag' do
47
- it "doesn't define a scope" do
48
- expect(Task).not_to respond_to(:archived)
49
- end
50
-
51
- it "doesn't define an inverse scope" do
52
- expect(Task).not_to respond_to(:not_archived)
53
- end
54
- end
55
-
56
59
  it 'allows overriding instance methods' do
57
60
  expect(ActiveRecord::Base.logger).to receive(:info)
58
61
 
@@ -68,4 +71,50 @@ RSpec.describe ActiveRecord::Events do
68
71
 
69
72
  expect(task.reload).to be_completed
70
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
71
120
  end
@@ -1,6 +1,7 @@
1
1
  class Task < ActiveRecord::Base
2
2
  has_event :complete
3
3
  has_event :archive, skip_scopes: true
4
+ has_events :expire, strategy: :time_comparison
4
5
 
5
6
  def complete!
6
7
  super
@@ -1,3 +1,4 @@
1
+ ENV['RAILS_ENV'] ||= 'development'
1
2
  ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
2
3
 
3
4
  require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
@@ -5,7 +5,7 @@
5
5
  # gem 'sqlite3'
6
6
  development:
7
7
  adapter: sqlite3
8
- database: spec/dummy/db/development.sqlite3
8
+ database: db/development.sqlite3
9
9
  pool: 5
10
10
  timeout: 5000
11
11
 
@@ -14,12 +14,12 @@ development:
14
14
  # Do not set this db to the same as development or production.
15
15
  test:
16
16
  adapter: sqlite3
17
- database: spec/dummy/db/test.sqlite3
17
+ database: db/test.sqlite3
18
18
  pool: 5
19
19
  timeout: 5000
20
20
 
21
21
  production:
22
22
  adapter: sqlite3
23
- database: spec/dummy/db/production.sqlite3
23
+ database: db/production.sqlite3
24
24
  pool: 5
25
25
  timeout: 5000
@@ -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,5 +1,21 @@
1
1
  ENV['RAILS_ENV'] ||= 'test'
2
2
 
3
+ require 'bundler/setup'
4
+ require 'simplecov'
5
+
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
18
+
3
19
  require File.expand_path('dummy/config/environment.rb', __dir__)
4
20
 
5
21
  require 'factory_girl'
@@ -10,9 +26,6 @@ require 'zonebie/rspec'
10
26
  Dir["#{__dir__}/support/**/*.rb"].each { |f| require f }
11
27
 
12
28
  RSpec.configure do |config|
13
- config.color = true
14
- config.order = :random
15
-
16
29
  config.include FactoryGirl::Syntax::Methods
17
30
  config.include GeneratorHelpers, type: :generator
18
31
  end
@@ -0,0 +1,5 @@
1
+ RSpec::Matchers.define :have_method do |expected|
2
+ match do |actual|
3
+ actual.public_instance_methods.include?(expected)
4
+ end
5
+ end
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: 3.0.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: 2020-04-28 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
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
19
+ version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.0'
26
+ version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: verbs
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.1'
33
+ version: '2.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.1'
40
+ version: '2.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: appraisal
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -109,33 +109,47 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: 0.50.0
111
111
  - !ruby/object:Gem::Dependency
112
- name: sqlite3
112
+ name: simplecov
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.3.13
117
+ version: 0.16.1
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.3.13
124
+ version: 0.16.1
125
125
  - !ruby/object:Gem::Dependency
126
- name: standalone_migrations
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
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - "~>"
130
144
  - !ruby/object:Gem::Version
131
- version: '5.2'
145
+ version: '1.3'
132
146
  type: :development
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
- version: '5.2'
152
+ version: '1.3'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: timecop
141
155
  requirement: !ruby/object:Gem::Requirement
@@ -175,27 +189,29 @@ files:
175
189
  - README.md
176
190
  - Rakefile
177
191
  - lib/active_record/events.rb
192
+ - lib/active_record/events/extension.rb
178
193
  - lib/active_record/events/macro.rb
194
+ - lib/active_record/events/method_factory.rb
179
195
  - lib/active_record/events/naming.rb
180
- - lib/active_record/events/verbs.rb
181
196
  - lib/active_record/events/version.rb
182
197
  - lib/generators/active_record/event/USAGE
183
198
  - lib/generators/active_record/event/event_generator.rb
184
199
  - spec/active_record/events/macro_spec.rb
200
+ - spec/active_record/events/method_factory_spec.rb
185
201
  - spec/active_record/events/naming_spec.rb
186
202
  - spec/active_record/events_spec.rb
187
203
  - spec/dummy/app/models/task.rb
188
204
  - spec/dummy/config/boot.rb
189
205
  - spec/dummy/config/database.yml
190
206
  - spec/dummy/config/environment.rb
191
- - spec/dummy/db/development.sqlite3
192
207
  - spec/dummy/db/migrate/20150813132804_create_tasks.rb
208
+ - spec/dummy/db/migrate/20220609015338_add_expired_at_to_tasks.rb
193
209
  - spec/dummy/db/schema.rb
194
- - spec/dummy/db/test.sqlite3
195
210
  - spec/generators/active_record/event/event_generator_spec.rb
196
211
  - spec/spec_helper.rb
197
- - spec/support/factories.rb
198
- - spec/support/generator_helpers.rb
212
+ - spec/support/factories/task_factory.rb
213
+ - spec/support/helpers/generator_helpers.rb
214
+ - spec/support/matchers/have_method.rb
199
215
  homepage: https://github.com/pienkowb/active_record-events
200
216
  licenses:
201
217
  - MIT
@@ -215,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
231
  - !ruby/object:Gem::Version
216
232
  version: '0'
217
233
  requirements: []
218
- rubygems_version: 3.0.3
234
+ rubygems_version: 3.1.6
219
235
  signing_key:
220
236
  specification_version: 4
221
237
  summary: Manage timestamps in ActiveRecord models
@@ -226,12 +242,13 @@ test_files:
226
242
  - spec/dummy/config/database.yml
227
243
  - spec/dummy/config/boot.rb
228
244
  - spec/dummy/db/schema.rb
229
- - spec/dummy/db/test.sqlite3
230
245
  - spec/dummy/db/migrate/20150813132804_create_tasks.rb
231
- - spec/dummy/db/development.sqlite3
246
+ - spec/dummy/db/migrate/20220609015338_add_expired_at_to_tasks.rb
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
234
250
  - spec/active_record/events_spec.rb
235
- - spec/support/generator_helpers.rb
236
- - spec/support/factories.rb
251
+ - spec/support/factories/task_factory.rb
252
+ - spec/support/matchers/have_method.rb
253
+ - spec/support/helpers/generator_helpers.rb
237
254
  - spec/generators/active_record/event/event_generator_spec.rb
@@ -1,5 +0,0 @@
1
- require 'verbs'
2
-
3
- Verbs::Conjugator.conjugations do |conjugate|
4
- conjugate.single_terminal_consonant :deliver
5
- end
Binary file
Binary file