microscope 0.3 → 0.4
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.
- data/README.md +11 -0
- data/lib/microscope/instance_method/date_instance_method.rb +16 -0
- data/lib/microscope/instance_method/datetime_instance_method.rb +16 -0
- data/lib/microscope/instance_method.rb +14 -0
- data/lib/microscope/scope/boolean_scope.rb +12 -0
- data/lib/microscope/scope/date_scope.rb +13 -0
- data/lib/microscope/scope/datetime_scope.rb +55 -0
- data/lib/microscope/scope.rb +14 -0
- data/lib/microscope/version.rb +1 -1
- data/lib/microscope.rb +19 -5
- data/spec/microscope/scope/boolean_scope_spec.rb +31 -0
- data/spec/microscope/scope/date_scope_spec.rb +95 -0
- data/spec/microscope/scope/datetime_scope_spec.rb +93 -0
- data/spec/microscope/scope_spec.rb +56 -0
- data/spec/spec_helper.rb +0 -3
- metadata +19 -8
- data/lib/microscope/mixin.rb +0 -62
- data/lib/microscope/railtie.rb +0 -10
- data/spec/microscope/mixin_spec.rb +0 -250
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Microscope
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/microscope)
|
4
|
+
[](https://codeclimate.com/github/mirego/microscope)
|
4
5
|
[](https://travis-ci.org/mirego/microscope)
|
5
6
|
|
6
7
|
Microscope adds useful scopes targeting ActiveRecord boolean, date and datetime fields.
|
@@ -61,6 +62,16 @@ Event.not_started
|
|
61
62
|
# SELECT * FROM `events` where `events`.`started_at` IS NULL OR `events`.`started_at` > '2013-07-05 15:43:42'
|
62
63
|
```
|
63
64
|
|
65
|
+
Microscope also adds two instance methods to the model per scope.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
event = Event.started.first
|
69
|
+
# SELECT * FROM `events` where `events`.`started_at` IS NOT NULL AND `events`.`started_at` <= '2013-07-05 15:43:42' LIMIT 1
|
70
|
+
|
71
|
+
event.started? # => true
|
72
|
+
event.not_started? # => false
|
73
|
+
```
|
74
|
+
|
64
75
|
### Options
|
65
76
|
|
66
77
|
You can use a few options when calling `acts_as_microscope`:
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Microscope
|
2
|
+
class InstanceMethod
|
3
|
+
class DateInstanceMethod < InstanceMethod
|
4
|
+
def apply
|
5
|
+
cropped_field = field.name.gsub(/_on$/, '')
|
6
|
+
|
7
|
+
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
8
|
+
define_method "#{cropped_field}?" do
|
9
|
+
value = send("#{field.name}")
|
10
|
+
!value.nil? && value <= Date.today
|
11
|
+
end
|
12
|
+
RUBY
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Microscope
|
2
|
+
class InstanceMethod
|
3
|
+
class DatetimeInstanceMethod < InstanceMethod
|
4
|
+
def apply
|
5
|
+
cropped_field = field.name.gsub(/_at$/, '')
|
6
|
+
|
7
|
+
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
8
|
+
define_method "#{cropped_field}?" do
|
9
|
+
value = send("#{field.name}")
|
10
|
+
!value.nil? && value <= Time.now
|
11
|
+
end
|
12
|
+
RUBY
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Microscope
|
2
|
+
class InstanceMethod < Struct.new(:model, :field)
|
3
|
+
# Inject ActiveRecord scopes into a model
|
4
|
+
def self.inject_instance_methods(model, fields, options = {})
|
5
|
+
fields.each do |field|
|
6
|
+
scope = "#{field.type.to_s.camelize}InstanceMethod"
|
7
|
+
|
8
|
+
if Microscope::InstanceMethod.const_defined?(scope)
|
9
|
+
"Microscope::InstanceMethod::#{scope}".constantize.new(model, field).apply
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Microscope
|
2
|
+
class Scope
|
3
|
+
class BooleanScope < Scope
|
4
|
+
def apply
|
5
|
+
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
6
|
+
scope "#{field.name}", lambda { where("#{field.name}" => true) }
|
7
|
+
scope "not_#{field.name}", lambda { where("#{field.name}" => false) }
|
8
|
+
RUBY
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Microscope
|
2
|
+
class Scope
|
3
|
+
class DatetimeScope < Scope
|
4
|
+
def initialize(*args)
|
5
|
+
super
|
6
|
+
|
7
|
+
@now = 'Time.now'
|
8
|
+
@now_suffix = '_now'
|
9
|
+
@cropped_field_regex = /_at$/
|
10
|
+
end
|
11
|
+
|
12
|
+
def apply
|
13
|
+
@cropped_field = field.name.gsub(@cropped_field_regex, '')
|
14
|
+
|
15
|
+
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
16
|
+
#{before_scopes}
|
17
|
+
#{after_scopes}
|
18
|
+
#{between_scopes}
|
19
|
+
#{boolean_scopes}
|
20
|
+
RUBY
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def before_scopes
|
26
|
+
<<-RUBY
|
27
|
+
scope "#{@cropped_field}_before", lambda { |time| where("#{field.name} < ?", time) }
|
28
|
+
scope "#{@cropped_field}_before_or_at", lambda { |time| where("#{field.name} <= ?", time) }
|
29
|
+
scope "#{@cropped_field}_before#{@now_suffix}", lambda { where("#{field.name} < ?", #{@now}) }
|
30
|
+
RUBY
|
31
|
+
end
|
32
|
+
|
33
|
+
def after_scopes
|
34
|
+
<<-RUBY
|
35
|
+
scope "#{@cropped_field}_after", lambda { |time| where("#{field.name} > ?", time) }
|
36
|
+
scope "#{@cropped_field}_after_or_at", lambda { |time| where("#{field.name} >= ?", time) }
|
37
|
+
scope "#{@cropped_field}_after#{@now_suffix}", lambda { where("#{field.name} > ?", #{@now}) }
|
38
|
+
RUBY
|
39
|
+
end
|
40
|
+
|
41
|
+
def between_scopes
|
42
|
+
<<-RUBY
|
43
|
+
scope "#{@cropped_field}_between", lambda { |range| where("#{field.name}" => range) }
|
44
|
+
RUBY
|
45
|
+
end
|
46
|
+
|
47
|
+
def boolean_scopes
|
48
|
+
<<-RUBY
|
49
|
+
scope "#{@cropped_field}", lambda { where("#{field.name} IS NOT NULL AND #{field.name} <= ?", #{@now}) }
|
50
|
+
scope "not_#{@cropped_field}", lambda { where("#{field.name} IS NULL OR #{field.name} > ?", #{@now}) }
|
51
|
+
RUBY
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Microscope
|
2
|
+
class Scope < Struct.new(:model, :field)
|
3
|
+
# Inject ActiveRecord scopes into a model
|
4
|
+
def self.inject_scopes(model, fields, options = {})
|
5
|
+
fields.each do |field|
|
6
|
+
scope = "#{field.type.to_s.camelize}Scope"
|
7
|
+
|
8
|
+
if Microscope::Scope.const_defined?(scope)
|
9
|
+
"Microscope::Scope::#{scope}".constantize.new(model, field).apply
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/microscope/version.rb
CHANGED
data/lib/microscope.rb
CHANGED
@@ -3,17 +3,31 @@ require "microscope/version"
|
|
3
3
|
require 'active_record'
|
4
4
|
require 'active_support'
|
5
5
|
|
6
|
-
require "microscope/
|
6
|
+
require "microscope/scope"
|
7
|
+
require "microscope/scope/boolean_scope"
|
8
|
+
require "microscope/scope/datetime_scope"
|
9
|
+
require "microscope/scope/date_scope"
|
10
|
+
|
11
|
+
require "microscope/instance_method"
|
12
|
+
require "microscope/instance_method/datetime_instance_method"
|
13
|
+
require "microscope/instance_method/date_instance_method"
|
7
14
|
|
8
15
|
module Microscope
|
9
16
|
def self.inject_into_active_record
|
10
|
-
|
17
|
+
Proc.new do
|
11
18
|
def self.acts_as_microscope(options = {})
|
12
|
-
|
13
|
-
include
|
19
|
+
except = options[:except] || []
|
20
|
+
model_columns = columns.dup.reject { |c| except.include?(c.name.to_sym) }
|
21
|
+
|
22
|
+
if only = options[:only]
|
23
|
+
model_columns = model_columns.select { |c| only.include?(c.name.to_sym) }
|
24
|
+
end
|
25
|
+
|
26
|
+
Microscope::Scope.inject_scopes(self, model_columns, options)
|
27
|
+
Microscope::InstanceMethod.inject_instance_methods(self, model_columns, options)
|
14
28
|
end
|
15
29
|
end
|
16
30
|
end
|
17
31
|
end
|
18
32
|
|
19
|
-
|
33
|
+
ActiveRecord::Base.class_eval(&Microscope.inject_into_active_record)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Microscope::Scope::BooleanScope do
|
4
|
+
subject { User }
|
5
|
+
|
6
|
+
before do
|
7
|
+
run_migration do
|
8
|
+
create_table(:users, force: true) do |t|
|
9
|
+
t.boolean :active, default: false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
microscope 'User'
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'positive scope' do
|
17
|
+
before { @user1 = User.create(active: true) }
|
18
|
+
|
19
|
+
its(:active) { should have(1).items }
|
20
|
+
its(:active) { should include(@user1) }
|
21
|
+
its(:not_active) { should be_empty }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'negative scope' do
|
25
|
+
before { @user1 = User.create(active: false) }
|
26
|
+
|
27
|
+
its(:not_active) { should have(1).items }
|
28
|
+
its(:not_active) { should include(@user1) }
|
29
|
+
its(:active) { should be_empty }
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Microscope::Scope::DateScope do
|
4
|
+
subject { Event }
|
5
|
+
|
6
|
+
before do
|
7
|
+
run_migration do
|
8
|
+
create_table(:events, force: true) do |t|
|
9
|
+
t.date :started_on, default: nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
microscope 'Event'
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'before scope' do
|
17
|
+
before do
|
18
|
+
@event = Event.create(started_on: 2.months.ago)
|
19
|
+
Event.create(started_on: 1.month.from_now)
|
20
|
+
end
|
21
|
+
|
22
|
+
it { expect(Event.started_before(1.month.ago).to_a).to eql [@event] }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'before_today scope' do
|
26
|
+
before do
|
27
|
+
@event = Event.create(started_on: 2.months.ago)
|
28
|
+
Event.create(started_on: 1.month.from_now)
|
29
|
+
end
|
30
|
+
|
31
|
+
it { expect(Event.started_before_today.to_a).to eql [@event] }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'after scope' do
|
35
|
+
before do
|
36
|
+
@event = Event.create(started_on: 2.months.from_now)
|
37
|
+
Event.create(started_on: 1.month.ago)
|
38
|
+
end
|
39
|
+
|
40
|
+
it { expect(Event.started_after(1.month.from_now).to_a).to eql [@event] }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'after_today scope' do
|
44
|
+
before do
|
45
|
+
@event = Event.create(started_on: 2.months.from_now)
|
46
|
+
Event.create(started_on: 1.month.ago)
|
47
|
+
end
|
48
|
+
|
49
|
+
it { expect(Event.started_after_today.to_a).to eql [@event] }
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'between scope' do
|
53
|
+
before do
|
54
|
+
Event.create(started_on: 1.month.ago)
|
55
|
+
@event = Event.create(started_on: 3.months.ago)
|
56
|
+
Event.create(started_on: 5.month.ago)
|
57
|
+
end
|
58
|
+
|
59
|
+
it { expect(Event.started_between(4.months.ago..2.months.ago).to_a).to eql [@event] }
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'super-boolean positive scope' do
|
63
|
+
before do
|
64
|
+
@event1 = Event.create(started_on: 1.month.ago)
|
65
|
+
@event2 = Event.create(started_on: 3.months.ago)
|
66
|
+
Event.create(started_on: 2.months.from_now)
|
67
|
+
Event.create(started_on: nil)
|
68
|
+
end
|
69
|
+
|
70
|
+
it { expect(Event.started.to_a).to eql [@event1, @event2] }
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'super-boolean negative scope' do
|
74
|
+
before do
|
75
|
+
Event.create(started_on: 1.month.ago)
|
76
|
+
Event.create(started_on: 3.months.ago)
|
77
|
+
@event1 = Event.create(started_on: 2.months.from_now)
|
78
|
+
@event2 = Event.create(started_on: nil)
|
79
|
+
end
|
80
|
+
|
81
|
+
it { expect(Event.not_started.to_a).to eql [@event1, @event2] }
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'boolean instance method' do
|
85
|
+
context 'for positive record' do
|
86
|
+
subject { Event.create(started_on: 3.months.ago) }
|
87
|
+
it { should be_started }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'for negative record' do
|
91
|
+
subject { Event.create(started_on: 2.months.from_now) }
|
92
|
+
it { should_not be_started }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
describe Microscope::Scope::DatetimeScope do
|
2
|
+
subject { Event }
|
3
|
+
|
4
|
+
before do
|
5
|
+
run_migration do
|
6
|
+
create_table(:events, force: true) do |t|
|
7
|
+
t.datetime :started_at, default: nil
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
microscope 'Event'
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'before scope' do
|
15
|
+
before do
|
16
|
+
@event = Event.create(started_at: 2.months.ago)
|
17
|
+
Event.create(started_at: 1.month.from_now)
|
18
|
+
end
|
19
|
+
|
20
|
+
it { expect(Event.started_before(1.month.ago).to_a).to eql [@event] }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'before_now scope' do
|
24
|
+
before do
|
25
|
+
@event = Event.create(started_at: 2.months.ago)
|
26
|
+
Event.create(started_at: 1.month.from_now)
|
27
|
+
end
|
28
|
+
|
29
|
+
it { expect(Event.started_before_now.to_a).to eql [@event] }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'after scope' do
|
33
|
+
before do
|
34
|
+
@event = Event.create(started_at: 2.months.from_now)
|
35
|
+
Event.create(started_at: 1.month.ago)
|
36
|
+
end
|
37
|
+
|
38
|
+
it { expect(Event.started_after(1.month.from_now).to_a).to eql [@event] }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'after_now scope' do
|
42
|
+
before do
|
43
|
+
@event = Event.create(started_at: 2.months.from_now)
|
44
|
+
Event.create(started_at: 1.month.ago)
|
45
|
+
end
|
46
|
+
|
47
|
+
it { expect(Event.started_after_now.to_a).to eql [@event] }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'between scope' do
|
51
|
+
before do
|
52
|
+
Event.create(started_at: 1.month.ago)
|
53
|
+
@event = Event.create(started_at: 3.months.ago)
|
54
|
+
Event.create(started_at: 5.month.ago)
|
55
|
+
end
|
56
|
+
|
57
|
+
it { expect(Event.started_between(4.months.ago..2.months.ago).to_a).to eql [@event] }
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'super-boolean positive scope', focus: true do
|
61
|
+
before do
|
62
|
+
@event1 = Event.create(started_at: 1.month.ago)
|
63
|
+
@event2 = Event.create(started_at: 3.months.ago)
|
64
|
+
Event.create(started_at: 2.months.from_now)
|
65
|
+
Event.create(started_at: nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
it { expect(Event.started.to_a).to eql [@event1, @event2] }
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'super-boolean negative scope' do
|
72
|
+
before do
|
73
|
+
Event.create(started_at: 1.month.ago)
|
74
|
+
Event.create(started_at: 3.months.ago)
|
75
|
+
@event1 = Event.create(started_at: 2.months.from_now)
|
76
|
+
@event2 = Event.create(started_at: nil)
|
77
|
+
end
|
78
|
+
|
79
|
+
it { expect(Event.not_started.to_a).to eql [@event1, @event2] }
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'boolean instance method' do
|
83
|
+
context 'for positive record' do
|
84
|
+
subject { Event.create(started_at: 3.months.ago) }
|
85
|
+
it { should be_started }
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'for negative record' do
|
89
|
+
subject { Event.create(started_at: 2.months.from_now) }
|
90
|
+
it { should_not be_started }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Microscope::Scope do
|
4
|
+
describe :inject_scopes do
|
5
|
+
subject { User }
|
6
|
+
|
7
|
+
before do
|
8
|
+
run_migration do
|
9
|
+
create_table(:users, force: true) do |t|
|
10
|
+
t.boolean :active, default: false
|
11
|
+
t.boolean :admin, default: false
|
12
|
+
t.boolean :moderator, default: false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe :except do
|
18
|
+
before do
|
19
|
+
microscope 'User', except: [:admin]
|
20
|
+
end
|
21
|
+
|
22
|
+
it { should respond_to :active }
|
23
|
+
it { should respond_to :not_active }
|
24
|
+
it { should respond_to :moderator }
|
25
|
+
it { should respond_to :not_moderator }
|
26
|
+
it { should_not respond_to :admin }
|
27
|
+
it { should_not respond_to :not_admin }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe :only do
|
31
|
+
before do
|
32
|
+
microscope 'User', only: [:admin]
|
33
|
+
end
|
34
|
+
|
35
|
+
it { should_not respond_to :active }
|
36
|
+
it { should_not respond_to :not_active }
|
37
|
+
it { should_not respond_to :moderator }
|
38
|
+
it { should_not respond_to :not_moderator }
|
39
|
+
it { should respond_to :admin }
|
40
|
+
it { should respond_to :not_admin }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'except and only' do
|
44
|
+
before do
|
45
|
+
microscope 'User', only: [:admin], except: [:active]
|
46
|
+
end
|
47
|
+
|
48
|
+
it { should_not respond_to :active }
|
49
|
+
it { should_not respond_to :not_active }
|
50
|
+
it { should_not respond_to :moderator }
|
51
|
+
it { should_not respond_to :not_moderator }
|
52
|
+
it { should respond_to :admin }
|
53
|
+
it { should respond_to :not_admin }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,9 +8,6 @@ require 'microscope'
|
|
8
8
|
# Require our macros and extensions
|
9
9
|
Dir[File.expand_path('../../spec/support/macros/*.rb', __FILE__)].map(&method(:require))
|
10
10
|
|
11
|
-
# Inject our methods into ActiveRecord (like our railtie does)
|
12
|
-
ActiveRecord::Base.class_eval(&Microscope.inject_into_active_record)
|
13
|
-
|
14
11
|
RSpec.configure do |config|
|
15
12
|
# Include our macros
|
16
13
|
config.include DatabaseMacros
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: microscope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.4'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-08-
|
13
|
+
date: 2013-08-13 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -127,11 +127,19 @@ files:
|
|
127
127
|
- gemfiles/Gemfile.activerecord-3.2.x
|
128
128
|
- gemfiles/Gemfile.activerecord-4.0
|
129
129
|
- lib/microscope.rb
|
130
|
-
- lib/microscope/
|
131
|
-
- lib/microscope/
|
130
|
+
- lib/microscope/instance_method.rb
|
131
|
+
- lib/microscope/instance_method/date_instance_method.rb
|
132
|
+
- lib/microscope/instance_method/datetime_instance_method.rb
|
133
|
+
- lib/microscope/scope.rb
|
134
|
+
- lib/microscope/scope/boolean_scope.rb
|
135
|
+
- lib/microscope/scope/date_scope.rb
|
136
|
+
- lib/microscope/scope/datetime_scope.rb
|
132
137
|
- lib/microscope/version.rb
|
133
138
|
- microscope.gemspec
|
134
|
-
- spec/microscope/
|
139
|
+
- spec/microscope/scope/boolean_scope_spec.rb
|
140
|
+
- spec/microscope/scope/date_scope_spec.rb
|
141
|
+
- spec/microscope/scope/datetime_scope_spec.rb
|
142
|
+
- spec/microscope/scope_spec.rb
|
135
143
|
- spec/spec_helper.rb
|
136
144
|
- spec/support/macros/database_macros.rb
|
137
145
|
- spec/support/macros/model_macros.rb
|
@@ -150,7 +158,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
150
158
|
version: '0'
|
151
159
|
segments:
|
152
160
|
- 0
|
153
|
-
hash:
|
161
|
+
hash: 2193329954126245792
|
154
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
163
|
none: false
|
156
164
|
requirements:
|
@@ -159,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
167
|
version: '0'
|
160
168
|
segments:
|
161
169
|
- 0
|
162
|
-
hash:
|
170
|
+
hash: 2193329954126245792
|
163
171
|
requirements: []
|
164
172
|
rubyforge_project:
|
165
173
|
rubygems_version: 1.8.23
|
@@ -168,7 +176,10 @@ specification_version: 3
|
|
168
176
|
summary: Microscope adds useful scopes targeting ActiveRecord boolean and datetime
|
169
177
|
fields.
|
170
178
|
test_files:
|
171
|
-
- spec/microscope/
|
179
|
+
- spec/microscope/scope/boolean_scope_spec.rb
|
180
|
+
- spec/microscope/scope/date_scope_spec.rb
|
181
|
+
- spec/microscope/scope/datetime_scope_spec.rb
|
182
|
+
- spec/microscope/scope_spec.rb
|
172
183
|
- spec/spec_helper.rb
|
173
184
|
- spec/support/macros/database_macros.rb
|
174
185
|
- spec/support/macros/model_macros.rb
|
data/lib/microscope/mixin.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
module Microscope
|
2
|
-
module Mixin
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
included do
|
6
|
-
define_microscrope_scopes
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
def define_microscrope_scopes
|
11
|
-
except = @microscope_options[:except] || []
|
12
|
-
model_columns = self.columns.dup.reject { |c| except.include?(c.name.to_sym) }
|
13
|
-
|
14
|
-
if only = @microscope_options[:only]
|
15
|
-
model_columns = model_columns.select { |c| only.include?(c.name.to_sym) }
|
16
|
-
end
|
17
|
-
|
18
|
-
boolean_fields = model_columns.select { |c| c.type == :boolean }.map(&:name)
|
19
|
-
boolean_fields.each do |field|
|
20
|
-
scope field, lambda { where(field => true) }
|
21
|
-
scope "not_#{field}", lambda { where(field => false) }
|
22
|
-
end
|
23
|
-
|
24
|
-
datetime_fields = model_columns.select { |c| c.type == :datetime }.map(&:name)
|
25
|
-
datetime_fields.each do |field|
|
26
|
-
cropped_field = field.gsub(/_at$/, '')
|
27
|
-
|
28
|
-
scope "#{cropped_field}_before", lambda { |time| where("#{field} < ?", time) }
|
29
|
-
scope "#{cropped_field}_before_or_at", lambda { |time| where("#{field} <= ?", time) }
|
30
|
-
scope "#{cropped_field}_before_now", lambda { where("#{field} < ?", Time.now) }
|
31
|
-
|
32
|
-
scope "#{cropped_field}_after", lambda { |time| where("#{field} > ?", time) }
|
33
|
-
scope "#{cropped_field}_after_or_at", lambda { |time| where("#{field} >= ?", time) }
|
34
|
-
scope "#{cropped_field}_after_now", lambda { where("#{field} > ?", Time.now) }
|
35
|
-
|
36
|
-
scope "#{cropped_field}_between", lambda { |range| where(field => range) }
|
37
|
-
|
38
|
-
scope "#{cropped_field}", lambda { where("#{field} IS NOT NULL AND #{field} <= ?", Time.now) }
|
39
|
-
scope "not_#{cropped_field}", lambda { where("#{field} IS NULL OR #{field} > ?", Time.now) }
|
40
|
-
end
|
41
|
-
|
42
|
-
date_fields = model_columns.select { |c| c.type == :date }.map(&:name)
|
43
|
-
date_fields.each do |field|
|
44
|
-
cropped_field = field.gsub(/_on$/, '')
|
45
|
-
|
46
|
-
scope "#{cropped_field}_before", lambda { |time| where("#{field} < ?", time) }
|
47
|
-
scope "#{cropped_field}_before_or_on", lambda { |time| where("#{field} <= ?", time) }
|
48
|
-
scope "#{cropped_field}_before_today", lambda { where("#{field} < ?", Date.today) }
|
49
|
-
|
50
|
-
scope "#{cropped_field}_after", lambda { |time| where("#{field} > ?", time) }
|
51
|
-
scope "#{cropped_field}_after_or_at", lambda { |time| where("#{field} >= ?", time) }
|
52
|
-
scope "#{cropped_field}_after_today", lambda { where("#{field} > ?", Date.today) }
|
53
|
-
|
54
|
-
scope "#{cropped_field}_between", lambda { |range| where(field => range) }
|
55
|
-
|
56
|
-
scope "#{cropped_field}", lambda { where("#{field} IS NOT NULL AND #{field} <= ?", Date.today) }
|
57
|
-
scope "not_#{cropped_field}", lambda { where("#{field} IS NULL OR #{field} > ?", Date.today) }
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
data/lib/microscope/railtie.rb
DELETED
@@ -1,250 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Microscope::Mixin do
|
4
|
-
describe :acts_as_microscope do
|
5
|
-
subject { User }
|
6
|
-
|
7
|
-
before do
|
8
|
-
run_migration do
|
9
|
-
create_table(:users, force: true) do |t|
|
10
|
-
t.boolean :active, default: false
|
11
|
-
t.boolean :admin, default: false
|
12
|
-
t.boolean :moderator, default: false
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe :except do
|
18
|
-
before do
|
19
|
-
microscope 'User', except: [:admin]
|
20
|
-
end
|
21
|
-
|
22
|
-
it { should respond_to :active }
|
23
|
-
it { should respond_to :not_active }
|
24
|
-
it { should respond_to :moderator }
|
25
|
-
it { should respond_to :not_moderator }
|
26
|
-
it { should_not respond_to :admin }
|
27
|
-
it { should_not respond_to :not_admin }
|
28
|
-
end
|
29
|
-
|
30
|
-
describe :only do
|
31
|
-
before do
|
32
|
-
microscope 'User', only: [:admin]
|
33
|
-
end
|
34
|
-
|
35
|
-
it { should_not respond_to :active }
|
36
|
-
it { should_not respond_to :not_active }
|
37
|
-
it { should_not respond_to :moderator }
|
38
|
-
it { should_not respond_to :not_moderator }
|
39
|
-
it { should respond_to :admin }
|
40
|
-
it { should respond_to :not_admin }
|
41
|
-
end
|
42
|
-
|
43
|
-
describe 'except and only' do
|
44
|
-
before do
|
45
|
-
microscope 'User', only: [:admin], except: [:active]
|
46
|
-
end
|
47
|
-
|
48
|
-
it { should_not respond_to :active }
|
49
|
-
it { should_not respond_to :not_active }
|
50
|
-
it { should_not respond_to :moderator }
|
51
|
-
it { should_not respond_to :not_moderator }
|
52
|
-
it { should respond_to :admin }
|
53
|
-
it { should respond_to :not_admin }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe 'Boolean scopes' do
|
58
|
-
subject { User }
|
59
|
-
|
60
|
-
before do
|
61
|
-
run_migration do
|
62
|
-
create_table(:users, force: true) do |t|
|
63
|
-
t.boolean :active, default: false
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
microscope 'User'
|
68
|
-
end
|
69
|
-
|
70
|
-
describe 'positive scope' do
|
71
|
-
before { @user1 = User.create(active: true) }
|
72
|
-
|
73
|
-
its(:active) { should have(1).items }
|
74
|
-
its(:active) { should include(@user1) }
|
75
|
-
its(:not_active) { should be_empty }
|
76
|
-
end
|
77
|
-
|
78
|
-
describe 'negative scope' do
|
79
|
-
before { @user1 = User.create(active: false) }
|
80
|
-
|
81
|
-
its(:not_active) { should have(1).items }
|
82
|
-
its(:not_active) { should include(@user1) }
|
83
|
-
its(:active) { should be_empty }
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
describe 'DateTime scopes' do
|
88
|
-
subject { Event }
|
89
|
-
|
90
|
-
before do
|
91
|
-
run_migration do
|
92
|
-
create_table(:events, force: true) do |t|
|
93
|
-
t.datetime :started_at, default: nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
microscope 'Event'
|
98
|
-
end
|
99
|
-
|
100
|
-
describe 'before scope' do
|
101
|
-
before do
|
102
|
-
@event = Event.create(started_at: 2.months.ago)
|
103
|
-
Event.create(started_at: 1.month.from_now)
|
104
|
-
end
|
105
|
-
|
106
|
-
it { expect(Event.started_before(1.month.ago).to_a).to eql [@event] }
|
107
|
-
end
|
108
|
-
|
109
|
-
describe 'before_now scope' do
|
110
|
-
before do
|
111
|
-
@event = Event.create(started_at: 2.months.ago)
|
112
|
-
Event.create(started_at: 1.month.from_now)
|
113
|
-
end
|
114
|
-
|
115
|
-
it { expect(Event.started_before_now.to_a).to eql [@event] }
|
116
|
-
end
|
117
|
-
|
118
|
-
describe 'after scope' do
|
119
|
-
before do
|
120
|
-
@event = Event.create(started_at: 2.months.from_now)
|
121
|
-
Event.create(started_at: 1.month.ago)
|
122
|
-
end
|
123
|
-
|
124
|
-
it { expect(Event.started_after(1.month.from_now).to_a).to eql [@event] }
|
125
|
-
end
|
126
|
-
|
127
|
-
describe 'after_now scope' do
|
128
|
-
before do
|
129
|
-
@event = Event.create(started_at: 2.months.from_now)
|
130
|
-
Event.create(started_at: 1.month.ago)
|
131
|
-
end
|
132
|
-
|
133
|
-
it { expect(Event.started_after_now.to_a).to eql [@event] }
|
134
|
-
end
|
135
|
-
|
136
|
-
describe 'between scope' do
|
137
|
-
before do
|
138
|
-
Event.create(started_at: 1.month.ago)
|
139
|
-
@event = Event.create(started_at: 3.months.ago)
|
140
|
-
Event.create(started_at: 5.month.ago)
|
141
|
-
end
|
142
|
-
|
143
|
-
it { expect(Event.started_between(4.months.ago..2.months.ago).to_a).to eql [@event] }
|
144
|
-
end
|
145
|
-
|
146
|
-
describe 'super-boolean positive scope', focus: true do
|
147
|
-
before do
|
148
|
-
@event1 = Event.create(started_at: 1.month.ago)
|
149
|
-
@event2 = Event.create(started_at: 3.months.ago)
|
150
|
-
Event.create(started_at: 2.months.from_now)
|
151
|
-
Event.create(started_at: nil)
|
152
|
-
end
|
153
|
-
|
154
|
-
it { expect(Event.started.to_a).to eql [@event1, @event2] }
|
155
|
-
end
|
156
|
-
|
157
|
-
describe 'super-boolean negative scope' do
|
158
|
-
before do
|
159
|
-
Event.create(started_at: 1.month.ago)
|
160
|
-
Event.create(started_at: 3.months.ago)
|
161
|
-
@event1 = Event.create(started_at: 2.months.from_now)
|
162
|
-
@event2 = Event.create(started_at: nil)
|
163
|
-
end
|
164
|
-
|
165
|
-
it { expect(Event.not_started.to_a).to eql [@event1, @event2] }
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
describe 'Date scopes' do
|
170
|
-
subject { Event }
|
171
|
-
|
172
|
-
before do
|
173
|
-
run_migration do
|
174
|
-
create_table(:events, force: true) do |t|
|
175
|
-
t.date :started_on, default: nil
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
microscope 'Event'
|
180
|
-
end
|
181
|
-
|
182
|
-
describe 'before scope' do
|
183
|
-
before do
|
184
|
-
@event = Event.create(started_on: 2.months.ago)
|
185
|
-
Event.create(started_on: 1.month.from_now)
|
186
|
-
end
|
187
|
-
|
188
|
-
it { expect(Event.started_before(1.month.ago).to_a).to eql [@event] }
|
189
|
-
end
|
190
|
-
|
191
|
-
describe 'before_today scope' do
|
192
|
-
before do
|
193
|
-
@event = Event.create(started_on: 2.months.ago)
|
194
|
-
Event.create(started_on: 1.month.from_now)
|
195
|
-
end
|
196
|
-
|
197
|
-
it { expect(Event.started_before_today.to_a).to eql [@event] }
|
198
|
-
end
|
199
|
-
|
200
|
-
describe 'after scope' do
|
201
|
-
before do
|
202
|
-
@event = Event.create(started_on: 2.months.from_now)
|
203
|
-
Event.create(started_on: 1.month.ago)
|
204
|
-
end
|
205
|
-
|
206
|
-
it { expect(Event.started_after(1.month.from_now).to_a).to eql [@event] }
|
207
|
-
end
|
208
|
-
|
209
|
-
describe 'after_today scope' do
|
210
|
-
before do
|
211
|
-
@event = Event.create(started_on: 2.months.from_now)
|
212
|
-
Event.create(started_on: 1.month.ago)
|
213
|
-
end
|
214
|
-
|
215
|
-
it { expect(Event.started_after_today.to_a).to eql [@event] }
|
216
|
-
end
|
217
|
-
|
218
|
-
describe 'between scope' do
|
219
|
-
before do
|
220
|
-
Event.create(started_on: 1.month.ago)
|
221
|
-
@event = Event.create(started_on: 3.months.ago)
|
222
|
-
Event.create(started_on: 5.month.ago)
|
223
|
-
end
|
224
|
-
|
225
|
-
it { expect(Event.started_between(4.months.ago..2.months.ago).to_a).to eql [@event] }
|
226
|
-
end
|
227
|
-
|
228
|
-
describe 'super-boolean positive scope' do
|
229
|
-
before do
|
230
|
-
@event1 = Event.create(started_on: 1.month.ago)
|
231
|
-
@event2 = Event.create(started_on: 3.months.ago)
|
232
|
-
Event.create(started_on: 2.months.from_now)
|
233
|
-
Event.create(started_on: nil)
|
234
|
-
end
|
235
|
-
|
236
|
-
it { expect(Event.started.to_a).to eql [@event1, @event2] }
|
237
|
-
end
|
238
|
-
|
239
|
-
describe 'super-boolean negative scope' do
|
240
|
-
before do
|
241
|
-
Event.create(started_on: 1.month.ago)
|
242
|
-
Event.create(started_on: 3.months.ago)
|
243
|
-
@event1 = Event.create(started_on: 2.months.from_now)
|
244
|
-
@event2 = Event.create(started_on: nil)
|
245
|
-
end
|
246
|
-
|
247
|
-
it { expect(Event.not_started.to_a).to eql [@event1, @event2] }
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|