ta_has_event 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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