ta_has_event 1.0.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.
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'active_record/events/macro'
3
+
4
+ RSpec.describe ActiveRecord::Events::Macro do
5
+ let(:event_name) { :confirm }
6
+
7
+ subject { described_class.new(event_name, options) }
8
+
9
+ context 'without options' do
10
+ let(:options) { {} }
11
+
12
+ it "doesn't include any options" do
13
+ expect(subject.to_s).to eq('has_event :confirm')
14
+ end
15
+ end
16
+
17
+ context 'with a string option' do
18
+ let(:options) { { object: 'email' } }
19
+
20
+ it 'prepends the option value with a colon' do
21
+ expect(subject.to_s).to eq('has_event :confirm, object: :email')
22
+ end
23
+ end
24
+
25
+ context 'with a symbol option' do
26
+ let(:options) { { object: :email } }
27
+
28
+ it 'prepends the option value with a colon' do
29
+ expect(subject.to_s).to eq('has_event :confirm, object: :email')
30
+ end
31
+ end
32
+
33
+ context 'with a boolean option' do
34
+ let(:options) { { skip_scopes: true } }
35
+
36
+ it "doesn't prepend the option value with a colon" do
37
+ expect(subject.to_s).to eq('has_event :confirm, skip_scopes: true')
38
+ end
39
+ end
40
+
41
+ context 'with multiple options' do
42
+ let(:options) { { object: :email, field_type: :date } }
43
+
44
+ it 'includes all of the options' do
45
+ macro = 'has_event :confirm, object: :email, field_type: :date'
46
+ expect(subject.to_s).to eq(macro)
47
+ end
48
+ end
49
+ end
@@ -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
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveRecord::Events::Naming do
4
+ let(:event_name) { :complete }
5
+ let(:options) { {} }
6
+
7
+ subject { described_class.new(event_name, options) }
8
+
9
+ it 'generates a field name' do
10
+ expect(subject.field).to eq('completed_at')
11
+ end
12
+
13
+ it 'generates a predicate name' do
14
+ expect(subject.predicate).to eq('completed?')
15
+ end
16
+
17
+ it 'generates an inverse predicate name' do
18
+ expect(subject.inverse_predicate).to eq('not_completed?')
19
+ end
20
+
21
+ it 'generates an action name' do
22
+ expect(subject.action).to eq('complete!')
23
+ end
24
+
25
+ it 'generates a safe action name' do
26
+ expect(subject.safe_action).to eq('complete')
27
+ end
28
+
29
+ it 'generates a collective action name' do
30
+ expect(subject.collective_action).to eq('complete_all')
31
+ end
32
+
33
+ it 'generates a scope name' do
34
+ expect(subject.scope).to eq('completed')
35
+ end
36
+
37
+ it 'generates an inverse scope name' do
38
+ expect(subject.inverse_scope).to eq('not_completed')
39
+ end
40
+
41
+ context 'with an object' do
42
+ let(:options) { { object: :task } }
43
+
44
+ it 'generates a field name' do
45
+ expect(subject.field).to eq('task_completed_at')
46
+ end
47
+
48
+ it 'generates a predicate name' do
49
+ expect(subject.predicate).to eq('task_completed?')
50
+ end
51
+
52
+ it 'generates an inverse predicate name' do
53
+ expect(subject.inverse_predicate).to eq('task_not_completed?')
54
+ end
55
+
56
+ it 'generates an action name' do
57
+ expect(subject.action).to eq('complete_task!')
58
+ end
59
+
60
+ it 'generates a safe action name' do
61
+ expect(subject.safe_action).to eq('complete_task')
62
+ end
63
+
64
+ it 'generates a collective action name' do
65
+ expect(subject.collective_action).to eq('complete_all_tasks')
66
+ end
67
+
68
+ it 'generates a scope name' do
69
+ expect(subject.scope).to eq('task_completed')
70
+ end
71
+
72
+ it 'generates an inverse scope name' do
73
+ expect(subject.inverse_scope).to eq('task_not_completed')
74
+ end
75
+ end
76
+
77
+ context 'with a date field' do
78
+ let(:options) { { field_type: :date } }
79
+
80
+ it 'generates a field name' do
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')
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveRecord::Events do
4
+ around(:each) do |example|
5
+ Timecop.freeze { example.run }
6
+ end
7
+
8
+ let!(:task) { create(:task) }
9
+
10
+ it 'records a timestamp' do
11
+ task.complete
12
+
13
+ expect(task.completed?).to eq(true)
14
+ expect(task.not_completed?).to eq(false)
15
+
16
+ expect(task.completed_at).to eq(Time.current)
17
+ end
18
+
19
+ it 'preserves a timestamp' do
20
+ task = create(:task, completed_at: 3.days.ago)
21
+
22
+ task.complete
23
+
24
+ expect(task.completed_at).to eq(3.days.ago)
25
+ end
26
+
27
+ it 'updates a timestamp' do
28
+ task = create(:task, completed_at: 3.days.ago)
29
+
30
+ task.complete!
31
+
32
+ expect(task.completed_at).to eq(Time.current)
33
+ end
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
+
45
+ it 'records multiple timestamps at once' do
46
+ Task.complete_all
47
+
48
+ expect(task.reload).to be_completed
49
+ end
50
+
51
+ it 'defines a scope' do
52
+ expect(Task.completed).not_to include(task)
53
+ end
54
+
55
+ it 'defines an inverse scope' do
56
+ expect(Task.not_completed).to include(task)
57
+ end
58
+
59
+ it 'allows overriding instance methods' do
60
+ expect(ActiveRecord::Base.logger).to receive(:info)
61
+
62
+ task.complete!
63
+
64
+ expect(task).to be_completed
65
+ end
66
+
67
+ it 'allows overriding class methods' do
68
+ expect(ActiveRecord::Base.logger).to receive(:info)
69
+
70
+ Task.complete_all
71
+
72
+ expect(task.reload).to be_completed
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ class Task < ActiveRecord::Base
2
+ has_event :complete
3
+ has_events :archive, skip_scopes: true
4
+
5
+ def complete!
6
+ super
7
+ logger.info("Task #{id} has been completed")
8
+ end
9
+
10
+ def self.complete_all
11
+ super
12
+ logger.info('All tasks have been completed')
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ ENV['RAILS_ENV'] ||= 'development'
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+
6
+ $LOAD_PATH.unshift(File.expand_path('../../../lib', __dir__))
@@ -0,0 +1,25 @@
1
+ # SQLite version 3.x
2
+ # gem install sqlite3
3
+ #
4
+ # Ensure the SQLite 3 gem is defined in your Gemfile
5
+ # gem 'sqlite3'
6
+ development:
7
+ adapter: sqlite3
8
+ database: db/development.sqlite3
9
+ pool: 5
10
+ timeout: 5000
11
+
12
+ # Warning: The database defined as "test" will be erased and
13
+ # re-generated from your development database when you run "rake".
14
+ # Do not set this db to the same as development or production.
15
+ test:
16
+ adapter: sqlite3
17
+ database: db/test.sqlite3
18
+ pool: 5
19
+ timeout: 5000
20
+
21
+ production:
22
+ adapter: sqlite3
23
+ database: db/production.sqlite3
24
+ pool: 5
25
+ timeout: 5000
@@ -0,0 +1,16 @@
1
+ require File.expand_path('boot', __dir__)
2
+
3
+ require 'active_record'
4
+
5
+ Bundler.require(:default, ENV['RAILS_ENV'])
6
+
7
+ # Load application files
8
+ Dir["#{__dir__}/../app/**/*.rb"].each { |f| require f }
9
+
10
+ # Load the database configuration
11
+ config_file = File.expand_path('database.yml', __dir__)
12
+ config = YAML.load_file(config_file)[ENV['RAILS_ENV']]
13
+
14
+ ActiveRecord::Base.logger = Logger.new(File::NULL)
15
+
16
+ ActiveRecord::Base.establish_connection(config)
@@ -0,0 +1,9 @@
1
+ class CreateTasks < ACTIVE_RECORD_MIGRATION_CLASS
2
+ def change
3
+ create_table :tasks do |t|
4
+ t.datetime :completed_at
5
+
6
+ t.timestamps null: false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
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).
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
12
+
13
+ ActiveRecord::Schema.define(version: 2015_08_13_132804) do
14
+
15
+ create_table "tasks", force: :cascade do |t|
16
+ t.datetime "completed_at"
17
+ t.datetime "created_at", null: false
18
+ t.datetime "updated_at", null: false
19
+ end
20
+
21
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'generators/active_record/event/event_generator'
3
+
4
+ RSpec.describe ActiveRecord::Generators::EventGenerator, type: :generator do
5
+ arguments %w[task complete --field-type=date --skip-scopes]
6
+ destination File.expand_path('../../../../tmp', __dir__)
7
+
8
+ before { prepare_destination }
9
+
10
+ it 'generates a migration file' do
11
+ run_generator
12
+
13
+ assert_migration 'db/migrate/add_completed_on_to_tasks' do |migration|
14
+ assert_instance_method :change, migration do |content|
15
+ assert_match 'add_column :tasks, :completed_on, :date', content
16
+ end
17
+ end
18
+ end
19
+
20
+ context 'when the model file exists' do
21
+ before do
22
+ write_file 'app/models/task.rb', <<-RUBY.strip_heredoc
23
+ class Task < ActiveRecord::Base
24
+ end
25
+ RUBY
26
+ end
27
+
28
+ it 'updates the model file' do
29
+ run_generator
30
+
31
+ assert_file 'app/models/task.rb', <<-RUBY.strip_heredoc
32
+ class Task < ActiveRecord::Base
33
+ has_event :complete, field_type: :date, skip_scopes: true
34
+ end
35
+ RUBY
36
+ end
37
+ end
38
+
39
+ context "when the model file doesn't exist" do
40
+ it "doesn't create the model file" do
41
+ run_generator
42
+ assert_no_file 'app/models/task.rb'
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+
3
+ require 'bundler/setup'
4
+ require 'coveralls'
5
+
6
+ Coveralls.wear!
7
+
8
+ require File.expand_path('dummy/config/environment.rb', __dir__)
9
+
10
+ require 'factory_girl'
11
+ require 'generator_spec'
12
+ require 'timecop'
13
+ require 'zonebie/rspec'
14
+
15
+ Dir["#{__dir__}/support/**/*.rb"].each { |f| require f }
16
+
17
+ RSpec.configure do |config|
18
+ config.include FactoryGirl::Syntax::Methods
19
+ config.include GeneratorHelpers, type: :generator
20
+ end
@@ -0,0 +1,3 @@
1
+ FactoryGirl.define do
2
+ factory :task
3
+ end
@@ -0,0 +1,8 @@
1
+ module GeneratorHelpers
2
+ def write_file(file_name, contents)
3
+ file_path = File.expand_path(file_name, destination_root)
4
+
5
+ FileUtils.mkdir_p(File.dirname(file_path))
6
+ File.write(file_path, contents)
7
+ end
8
+ 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