Skip to content

Commit

Permalink
Add method to create the time scopes for time-related columns
Browse files Browse the repository at this point in the history
  • Loading branch information
dtaniwaki committed Sep 28, 2014
1 parent 4e2a8bd commit 9fb32a2
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 56 deletions.
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ And run `bundle install`.

### Time

This gem automatically create scopes for time-related columns of your ActiveRecord model such as 'created_at'.
#### Auto

To create scopes for time-related columns of your ActiveRecord model such as 'created_at',

```ruby
class Foo < ActiveRecord::Base
create_time_scopes
end
```

Expand All @@ -39,6 +42,24 @@ Foo.created_within 3.days.ago, 3.days.from_now

Any columns with `_at`, `_on`, `_time` and `_date` postfix are considered as time-related columns.

#### Manual

If the column name is not time-related, you can create the time scope manually.

```ruby
class Foo < ActiveRecord::Base
create_time_scope :started, :created_at
end
```

Then, these scopes will be available.

```ruby
Foo.started_before 3.days.ago
Foo.started_after 3.days.ago
Foo.started_within 3.days.ago, 3.days.from_now
```

### Time Range

If you want scopes for time ranges, you can create it manually.
Expand Down
13 changes: 5 additions & 8 deletions lib/active_record/time_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ def self.included(base)
end

module ClassMethods
def inherited(subclass)
super
if subclass.table_exists?
subclass.column_names.each do |cn|
verb = cn.sub TIME_POSTFIX_REGEXP, ''
next if verb == cn
subclass.create_time_scope verb, cn
end
def create_time_scopes
column_names.each do |cn|
verb = cn.sub TIME_POSTFIX_REGEXP, ''
next if verb == cn
create_time_scope verb, cn
end
end

Expand Down
11 changes: 7 additions & 4 deletions spec/support/tmp_model.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
def create_tmp_model(_model_name, _table_name = 'tmp', _columns = {}, &_block)
if ActiveRecord::Base.connection.table_exists? _table_name
ActiveRecord::Migration.drop_table _table_name
end
def create_tmp_model(_columns = {}, &_block)
time = Time.now.to_f.to_s.gsub('.', '_')
_model_name = "TmpClass#{time}"
_table_name = "tmp_class#{time}s"
# if ActiveRecord::Base.connection.table_exists? _table_name
# ActiveRecord::Migration.drop_table _table_name
# end
begin
Object.send :remove_const, _model_name
rescue NameError
Expand Down
30 changes: 15 additions & 15 deletions spec/time_scope/time_range_spec.rb
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
require 'spec_helper'

RSpec.describe "time_range_spec" do
klass = create_tmp_model "Test2Class", "test2_classes", foo_at: :datetime, bar_at: :datetime do
create_time_range_scope :wow, :foo_at, :bar_at
RSpec.describe ActiveRecord::TimeScope::TimeRangeProxy do
klass = create_tmp_model foo: :datetime, bar: :datetime do
create_time_range_scope :wow, :foo, :bar
end

describe "::wow_before" do
subject { klass.__send__("wow_before", time) }
let(:time) { DateTime.now }
context "foo & bar < time" do
let!(:model) { klass.create! foo_at: time - 2.days, bar_at: time - 1.days }
let!(:model) { klass.create! foo: time - 2.days, bar: time - 1.days }
it { is_expected.to eq [model] }
end
context "time < foo & bar" do
let!(:model) { klass.create! foo_at: time + 1.days, bar_at: time + 2.days }
let!(:model) { klass.create! foo: time + 1.days, bar: time + 2.days }
it { is_expected.to eq [] }
end
context "foo < time < bar" do
let!(:model) { klass.create! foo_at: time - 1.days, bar_at: time + 1.days }
let!(:model) { klass.create! foo: time - 1.days, bar: time + 1.days }
it { is_expected.to eq [] }
end
end
describe "::wow_after" do
subject { klass.__send__("wow_after", time) }
let(:time) { DateTime.now }
context "foo & bar < time" do
let!(:model) { klass.create! foo_at: time - 2.days, bar_at: time - 1.days }
let!(:model) { klass.create! foo: time - 2.days, bar: time - 1.days }
it { is_expected.to eq [] }
end
context "time < foo & bar" do
let!(:model) { klass.create! foo_at: time + 1.days, bar_at: time + 2.days }
let!(:model) { klass.create! foo: time + 1.days, bar: time + 2.days }
it { is_expected.to eq [model] }
end
context "foo < time < bar" do
let!(:model) { klass.create! foo_at: time - 1.days, bar_at: time + 1.days }
let!(:model) { klass.create! foo: time - 1.days, bar: time + 1.days }
it { is_expected.to eq [] }
end
end
describe "::wow_within" do
subject { klass.__send__("wow_within", time - 2.days, time + 2.days) }
let(:time) { DateTime.now }
context "time - 2.days < foo & bar < time + 2.days" do
let!(:model) { klass.create! foo_at: time - 1.days, bar_at: time + 1.days }
let!(:model) { klass.create! foo: time - 1.days, bar: time + 1.days }
it { is_expected.to eq [model] }
end
context "time - 2.days < foo < time + 2.days < bar" do
let!(:model) { klass.create! foo_at: time + 1.days, bar_at: time + 3.days }
let!(:model) { klass.create! foo: time + 1.days, bar: time + 3.days }
it { is_expected.to eq [] }
end
context "foo < time - 2.days < bar < time + 2.days" do
let!(:model) { klass.create! foo_at: time - 3.days, bar_at: time - 1.days }
let!(:model) { klass.create! foo: time - 3.days, bar: time - 1.days }
it { is_expected.to eq [] }
end
context "foo < time - 2.days < time + 2.days < bar" do
let!(:model) { klass.create! foo_at: time - 3.days, bar_at: time + 3.days }
let!(:model) { klass.create! foo: time - 3.days, bar: time + 3.days }
it { is_expected.to eq [] }
end
context "time - 2.days < time + 2.days < foo & bar" do
let!(:model) { klass.create! foo_at: time + 3.days, bar_at: time + 4.days }
let!(:model) { klass.create! foo: time + 3.days, bar: time + 4.days }
it { is_expected.to eq [] }
end
context "foo & bar < time - 2.days < time + 2.days" do
let!(:model) { klass.create! foo_at: time - 4.days, bar_at: time - 3.days }
let!(:model) { klass.create! foo: time - 4.days, bar: time - 3.days }
it { is_expected.to eq [] }
end
end
Expand Down
39 changes: 11 additions & 28 deletions spec/time_scope/time_spec.rb
Original file line number Diff line number Diff line change
@@ -1,65 +1,48 @@
require 'spec_helper'

RSpec.describe "time_range_spec" do
klass = create_tmp_model "TestClass", "test_classes", foo_at: :datetime, bar_on: :date, xxx_time: :datetime, yyy_date: :date, zzz: :date do
create_time_scope :www, :zzz
RSpec.describe ActiveRecord::TimeScope::TimeProxy do
klass = create_tmp_model foo: :datetime, bar_on: :date do
create_time_scope :foo, :foo
create_time_scope :bar, :bar
end

describe "::create_time_scope" do
subject { klass }
it do
is_expected.to respond_to :www_before
is_expected.to respond_to :www_after
is_expected.to respond_to :www_within
end
end
describe "::inherited" do
subject { klass }
it do
%w(foo bar xxx yyy).each do |verb|
is_expected.to respond_to "#{verb}_before"
is_expected.to respond_to "#{verb}_after"
is_expected.to respond_to "#{verb}_within"
end
end
end
describe "::foo_before" do
subject { klass.foo_before(time) }
let(:time) { DateTime.now }
context "foo < time" do
let!(:model) { klass.create! foo_at: time + 1.days }
let!(:model) { klass.create! foo: time + 1.days }
it { is_expected.to eq [] }
end
context "time < foo" do
let!(:model) { klass.create! foo_at: time - 1.days }
let!(:model) { klass.create! foo: time - 1.days }
it { is_expected.to eq [model] }
end
end
describe "::foo_after" do
subject { klass.foo_after(time) }
let(:time) { DateTime.now }
context "foo < time" do
let!(:model) { klass.create! foo_at: time + 1.days }
let!(:model) { klass.create! foo: time + 1.days }
it { is_expected.to eq [model] }
end
context "time < foo" do
let!(:model) { klass.create! foo_at: time - 1.days }
let!(:model) { klass.create! foo: time - 1.days }
it { is_expected.to eq [] }
end
end
describe "::foo_within" do
subject { klass.foo_within(time - 2.days, time + 2.days) }
let(:time) { DateTime.now }
context "foo < -2 days < +2 days" do
let!(:model) { klass.create! foo_at: time - 3.days }
let!(:model) { klass.create! foo: time - 3.days }
it { is_expected.to eq [] }
end
context "-2 days < foo < +2 days" do
let!(:model) { klass.create! foo_at: time }
let!(:model) { klass.create! foo: time }
it { is_expected.to eq [model] }
end
context "-2 days < +2 days < foo" do
let!(:model) { klass.create! foo_at: time + 3.days }
let!(:model) { klass.create! foo: time + 3.days }
it { is_expected.to eq [] }
end
end
Expand Down
56 changes: 56 additions & 0 deletions spec/time_scope_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require 'spec_helper'

RSpec.describe ActiveRecord::TimeScope do
describe "::create_time_scopes" do
subject {
create_tmp_model foo_at: :datetime, bar_on: :date, xxx_time: :datetime, yyy_date: :date, zzz: :date do
create_time_scopes
end
}
it do
%w(foo bar xxx yyy).each do |key|
is_expected.to respond_to "#{key}_before"
is_expected.to respond_to "#{key}_after"
is_expected.to respond_to "#{key}_within"
end
%w(zzz).each do |key|
is_expected.not_to respond_to "#{key}_before"
is_expected.not_to respond_to "#{key}_after"
is_expected.not_to respond_to "#{key}_within"
end
end
end
describe "::create_time_scope" do
subject {
create_tmp_model zzz: :date do
create_time_scope :www, :zzz
end
}
it do
is_expected.to respond_to :www_before
is_expected.to respond_to :www_after
is_expected.to respond_to :www_within
is_expected.not_to respond_to :zzz_before
is_expected.not_to respond_to :zzz_after
is_expected.not_to respond_to :zzz_within
end
end
describe "::create_time_range_scope" do
subject {
create_tmp_model aaa: :date, bbb: :date do
create_time_range_scope :xxx, :aaa, :bbb
end
}
it do
is_expected.to respond_to :xxx_before
is_expected.to respond_to :xxx_after
is_expected.to respond_to :xxx_within
is_expected.not_to respond_to :aaa_before
is_expected.not_to respond_to :aaa_after
is_expected.not_to respond_to :aaa_within
is_expected.not_to respond_to :bbb_before
is_expected.not_to respond_to :bbb_after
is_expected.not_to respond_to :bbb_within
end
end
end

0 comments on commit 9fb32a2

Please sign in to comment.