active_record-events 3.0.0 → 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: 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