acts_as_span 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,10 @@
1
- require 'active_support'
2
-
3
1
  module ActsAsSpan
4
2
  class SpanInstance
5
3
  module Status
6
4
  extend ActiveSupport::Concern
7
-
8
- module InstanceMethods
9
- def span_status(query_date = Date.today)
5
+
6
+ included do
7
+ def span_status(query_date = Date.current)
10
8
  if future?(query_date)
11
9
  :future
12
10
  elsif expired?(query_date)
@@ -20,39 +18,26 @@ module ActsAsSpan
20
18
 
21
19
  alias_method :span_status_on, :span_status
22
20
 
23
- def span_status_to_s(query_date = Date.today)
24
- case span_status(query_date)
25
- when :future
26
- "Future"
27
- when :expired
28
- "Expired"
29
- when :current
30
- "Current"
31
- when :unknown
32
- "Unknown"
33
- end
34
- end
35
-
36
- alias_method :span_status_to_s_on, :span_status_to_s
37
-
38
- def current?(query_date = Date.today)
21
+ def current?(query_date = Date.current)
39
22
  !future?(query_date) && !expired?(query_date)
40
23
  end
41
-
24
+
42
25
  alias_method :current_on?, :current?
43
26
 
44
- def future?(query_date = Date.today)
27
+ def future?(query_date = Date.current)
45
28
  start_date && start_date > query_date
46
29
  end
47
-
30
+
48
31
  alias_method :future_on?, :future?
49
32
 
50
- def expired?(query_date = Date.today)
33
+ def expired?(query_date = Date.current)
51
34
  end_date && end_date < query_date
52
35
  end
53
-
36
+
54
37
  alias_method :expired_on?, :expired?
38
+ alias_method :past_on?, :expired?
39
+ alias_method :past?, :expired?
55
40
  end
56
41
  end
57
42
  end
58
- end
43
+ end
@@ -1,67 +1,19 @@
1
- require 'active_support'
2
-
3
1
  module ActsAsSpan
4
2
  class SpanInstance
5
3
  module Validations
6
4
  extend ActiveSupport::Concern
7
-
8
- module InstanceMethods
5
+
6
+ included do
9
7
  def validate
10
- validate_start_date
11
- validate_end_date
12
8
  validate_start_date_less_than_or_equal_to_end_date
13
- validate_overlap
14
- end
15
-
16
- def validate_start_date
17
- if start_date_field_required && start_date.blank?
18
- span_model.errors.add(start_date_field, :blank)
19
- end
20
9
  end
21
-
22
- def validate_end_date
23
- if end_date_field_required && end_date.blank?
24
- span_model.errors.add(end_date_field, :blank)
25
- end
26
- end
27
-
10
+
28
11
  def validate_start_date_less_than_or_equal_to_end_date
29
12
  if start_date && end_date && end_date < start_date
30
- span_model.errors.add(end_date_field, "Must be on or after #{start_date_field}")
31
- end
32
- end
33
-
34
- def validate_overlap
35
- if span_overlap_count && span_model.errors[start_date_field].empty? && span_model.errors[end_date_field].empty? # && ( respond_to?('archived?') ? !archived? : true )
36
- conditions = {}
37
-
38
- if span_overlap_scope.is_a?(Array)
39
- span_overlap_scope.each do |symbol|
40
- conditions[symbol] = span_model.send(symbol)
41
- end
42
- elsif span_overlap_scope.is_a?(Symbol)
43
- conditions[span_overlap_scope] = span_model.send(span_overlap_scope)
44
- end
45
-
46
- records = span_klass.span_for(name).overlap(self).where(conditions)
47
-
48
- if span_klass.respond_to?('not_archived')
49
- records.not_archived
50
- end
51
-
52
- #TODO - This will have to be an after_save callback...
53
- #if span_overlap_auto_close
54
- # records.each do |record|
55
- # record.close!(start_date)
56
- # end
57
- #end
58
-
59
- if records.count > span_overlap_count
60
- span_model.errors.add(:base, "date range overlaps with #{records.count} other record(s)")
61
- end
13
+ span_model.errors.add(end_field, "Must be on or after #{start_field}")
62
14
  end
63
15
  end
64
16
  end
65
17
  end
66
18
  end
67
- end
19
+ end
@@ -1,31 +1,23 @@
1
- require 'forwardable'
1
+ require 'acts_as_span/span_klass/status'
2
2
 
3
- require ACTS_AS_SPAN_PATH + 'span_klass/status'
4
- require ACTS_AS_SPAN_PATH + 'span_klass/overlap'
3
+ require 'active_support/core_ext/module/delegation'
5
4
 
6
5
  module ActsAsSpan
7
6
  class SpanKlass
8
- extend Forwardable
9
-
10
7
  include ActsAsSpan::SpanKlass::Status
11
- include ActsAsSpan::SpanKlass::Overlap
12
-
13
- def_delegators :@acts_as_span_definition, :start_date_field,
14
- :end_date_field,
15
- :start_date_field_required,
16
- :end_date_field_required,
17
- :exclude_end,
18
- :span_overlap_scope,
19
- :span_overlap_count
20
-
21
- def_delegators :klass, :table_name
22
-
8
+
9
+ delegate :start_field,
10
+ :end_field,
11
+ :exclude_end, to: :@acts_as_span_definition
12
+
13
+ delegate :table_name, :arel_table, to: :klass, allow_nil: true
14
+
23
15
  attr_reader :name, :klass, :acts_as_span_definition
24
-
16
+
25
17
  def initialize(name, klass, acts_as_span_definition)
26
18
  @name = name
27
19
  @klass = klass
28
20
  @acts_as_span_definition = acts_as_span_definition
29
21
  end
30
22
  end
31
- end
23
+ end
@@ -4,26 +4,47 @@ module ActsAsSpan
4
4
  class SpanKlass
5
5
  module Status
6
6
  extend ActiveSupport::Concern
7
-
8
- module InstanceMethods
9
- def current(query_date = Date.today)
10
- klass.where(["(#{table_name}.#{start_date_field} <= :query_date OR #{table_name}.#{start_date_field} IS NULL) AND (#{table_name}.#{end_date_field} >= :query_date OR #{table_name}.#{end_date_field} IS NULL)", { :query_date => query_date } ] )
7
+
8
+ included do
9
+ def current(query_date = Date.current)
10
+ klass.where(
11
+ (arel_table[start_field].lteq(query_date).or(arel_table[start_field].eq(nil))).
12
+ and(
13
+ arel_table[end_field].eq(nil).or(arel_table[end_field].gteq(query_date))
14
+ )
15
+ )
11
16
  end
12
-
17
+
13
18
  alias_method :current_on, :current
14
19
 
15
- def future(query_date = Date.today)
16
- klass.where(["#{table_name}.#{start_date_field} > :query_date", { :query_date => query_date } ] )
20
+ def future(query_date = Date.current)
21
+ klass.where(arel_table[start_field].gt(query_date))
17
22
  end
18
-
23
+
19
24
  alias_method :future_on, :future
20
25
 
21
- def expired(query_date = Date.today)
22
- klass.where(["#{table_name}.#{end_date_field} < :query_date", { :query_date => query_date } ] )
26
+ def expired(query_date = Date.current)
27
+ klass.where(arel_table[end_field].lt(query_date))
23
28
  end
24
-
29
+
25
30
  alias_method :expired_on, :expired
31
+ alias_method :past_on, :expired
32
+ alias_method :past, :expired
33
+
34
+
35
+ def current_or_future_on(query_date = Date.current)
36
+ klass.where(
37
+ arel_table[start_field].lteq(query_date).
38
+ and(
39
+ arel_table[end_field].eq(nil).
40
+ or(arel_table[end_field].gteq(query_date))
41
+ ).
42
+ or(arel_table[start_field].gt(query_date))
43
+ )
44
+ end
45
+
46
+ alias_method :current_or_future, :current_or_future_on
26
47
  end
27
48
  end
28
49
  end
29
- end
50
+ end
@@ -2,11 +2,11 @@ module ActsAsSpan
2
2
  module VERSION
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 5
5
+ TINY = 6
6
6
  PRE = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
-
9
+
10
10
  SUMMARY = "acts_as_span #{STRING}"
11
11
  end
12
12
  end
@@ -0,0 +1,42 @@
1
+ module ActsAsSpan
2
+ class WithinParentDateSpanValidator < ActiveModel::Validator
3
+ def validate(record)
4
+ parents = options[:parent] || options[:parents]
5
+
6
+ Array(parents).each do |parent|
7
+ record.errors.add(:base, :not_within_parent_date_span, parent: record.class.human_attribute_name(parent)) if outside_of_parent_date_span?(record, parent)
8
+ end
9
+ end
10
+
11
+ def outside_of_parent_date_span?(record, parent_sym)
12
+ parent = record.send(parent_sym)
13
+
14
+ return false if parent.nil?
15
+
16
+ child_record_without_start_date(record, parent) ||
17
+ child_record_without_end_date(record, parent) ||
18
+ child_record_started_before_parent_record(record, parent) ||
19
+ child_record_ended_after_parent_record(record, parent)
20
+ end
21
+
22
+ private
23
+
24
+ def child_record_started_before_parent_record(record, parent)
25
+ record.start_date.present? && parent.start_date.present? &&
26
+ record.start_date < parent.start_date
27
+ end
28
+
29
+ def child_record_ended_after_parent_record(record, parent)
30
+ record.end_date.present? && parent.end_date.present? &&
31
+ record.end_date > parent.end_date
32
+ end
33
+
34
+ def child_record_without_start_date(record, parent)
35
+ record.start_date.nil? && parent.start_date.present?
36
+ end
37
+
38
+ def child_record_without_end_date(record, parent)
39
+ record.end_date.nil? && parent.end_date.present?
40
+ end
41
+ end
42
+ end
@@ -1,64 +1,46 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "acts_as_span" do
4
- before(:each) do
5
- build_model :span_model do
6
- acts_as_span
7
- end
8
- end
9
-
3
+ RSpec.describe "acts_as_span" do
10
4
  context "ClassMethods" do
11
- it "should return true for acts_as_span?" do
12
- SpanModel.acts_as_span?.should be_true
13
- end
14
-
15
5
  it "should have 1 acts_as_span_definition" do
16
- SpanModel.should have(1).acts_as_span_definitions
6
+ expect(SpanModel.acts_as_span_definitions.size).to eq(1)
17
7
  end
18
-
8
+
19
9
  it "should set default options for acts_as_span_definition" do
20
10
  span_definition = SpanModel.acts_as_span_definitions[:default]
21
-
22
- span_definition.start_date_field.should == :start_date
23
- span_definition.end_date_field.should == :end_date
24
- span_definition.start_date_field_required.should be_false
25
- span_definition.end_date_field_required.should be_false
26
- span_definition.exclude_end.should be_false
27
- span_definition.span_overlap_scope.should be_nil
28
- span_definition.span_overlap_count.should be_nil
29
- span_definition.name.should == :default
11
+
12
+ expect(span_definition.start_field).to eq(:start_date)
13
+ expect(span_definition.end_field).to eq(:end_date)
14
+ expect(span_definition.exclude_end).to be_falsey
15
+ expect(span_definition.name).to eq(:default)
30
16
  end
31
-
17
+
32
18
  it "should return a SpanKlass w/ span" do
33
- SpanModel.span.should be_instance_of(ActsAsSpan::SpanKlass)
19
+ expect(SpanModel.span).to be_instance_of(ActsAsSpan::SpanKlass)
34
20
  end
35
21
 
36
22
  it "should return a SpanKlass w/ span_for(:default)" do
37
- SpanModel.span_for(:default).should be_instance_of(ActsAsSpan::SpanKlass)
23
+ expect(SpanModel.span_for(:default)).to be_instance_of(ActsAsSpan::SpanKlass)
38
24
  end
39
-
25
+
40
26
  it "should have (1) spans" do
41
- SpanModel.spans.should have(1).span
27
+ expect(SpanModel.spans.size).to eq(1)
42
28
  end
43
29
  end
44
-
30
+
45
31
  context "InstanceMethods" do
46
32
  let(:span_model) { SpanModel.new }
47
-
48
- it "should return true for acts_as_span?" do
49
- span_model.acts_as_span?.should be_true
50
- end
51
33
 
52
34
  it "should return a SpanInstance w/ span" do
53
- span_model.span.should be_instance_of(ActsAsSpan::SpanInstance)
35
+ expect(span_model.span).to be_instance_of(ActsAsSpan::SpanInstance)
54
36
  end
55
37
 
56
38
  it "should return a SpanInstance w/ span_for(:default)" do
57
- span_model.span_for(:default).should be_instance_of(ActsAsSpan::SpanInstance)
39
+ expect(span_model.span_for(:default)).to be_instance_of(ActsAsSpan::SpanInstance)
58
40
  end
59
-
41
+
60
42
  it "should have (1) spans" do
61
- span_model.spans.should have(1).span
43
+ expect(span_model.spans.size).to eq(1)
62
44
  end
63
45
  end
64
46
  end
@@ -1,128 +1,95 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "Span" do
4
- before(:each) do
5
- build_model :span_model do
6
- date :start_date
7
- date :end_date
8
-
9
- acts_as_span
10
- end
11
- end
12
-
13
- let(:span_model) { SpanModel.new(:start_date => Date.today, :end_date => nil) }
3
+ RSpec.describe "Span" do
4
+ let(:span_model) { SpanModel.new(:start_date => Date.current, :end_date => nil) }
14
5
  let(:span_klass) { SpanModel.span }
15
6
  let(:span_instance) { span_model.span }
16
-
7
+
17
8
  context "ClassMethods" do
18
9
  it "should delegate current" do
19
- span_klass.should_receive(:current).and_return(true)
20
-
10
+ expect(span_klass).to receive(:current).and_return(true)
11
+
21
12
  SpanModel.current
22
13
  end
23
-
14
+
24
15
  it "should delegate current_on" do
25
- span_klass.should_receive(:current_on).and_return(true)
26
-
16
+ expect(span_klass).to receive(:current_on).and_return(true)
17
+
27
18
  SpanModel.current_on
28
19
  end
29
-
20
+
30
21
  it "should delegate future" do
31
- span_klass.should_receive(:future).and_return(true)
32
-
22
+ expect(span_klass).to receive(:future).and_return(true)
23
+
33
24
  SpanModel.future
34
25
  end
35
-
26
+
36
27
  it "should delegate future_on" do
37
- span_klass.should_receive(:future_on).and_return(true)
38
-
28
+ expect(span_klass).to receive(:future_on).and_return(true)
29
+
39
30
  SpanModel.future_on
40
31
  end
41
-
32
+
42
33
  it "should delegate expired" do
43
- span_klass.should_receive(:expired).and_return(true)
44
-
34
+ expect(span_klass).to receive(:expired).and_return(true)
35
+
45
36
  SpanModel.expired
46
37
  end
47
-
38
+
48
39
  it "should delegate expired_on" do
49
- span_klass.should_receive(:expired_on).and_return(true)
50
-
40
+ expect(span_klass).to receive(:expired_on).and_return(true)
41
+
51
42
  SpanModel.expired_on
52
43
  end
53
44
  end
54
-
45
+
55
46
  context "InstanceMethods" do
56
- it "should delegate close!" do
57
- span_instance.should_receive(:close!).and_return(true)
58
-
59
- span_model.close!
60
- end
61
-
62
- it "should delegate close_on!" do
63
- span_instance.should_receive(:close_on!).and_return(true)
64
-
65
- span_model.close_on!
66
- end
67
-
68
47
  it "should delegate span_status" do
69
- span_instance.should_receive(:span_status).and_return(true)
70
-
48
+ expect(span_instance).to receive(:span_status).and_return(true)
49
+
71
50
  span_model.span_status
72
51
  end
73
-
52
+
74
53
  it "should delegate span_status_on" do
75
- span_instance.should_receive(:span_status_on).and_return(true)
76
-
54
+ expect(span_instance).to receive(:span_status_on).and_return(true)
55
+
77
56
  span_model.span_status_on
78
57
  end
79
-
80
- it "should delegate span_status_to_s" do
81
- span_instance.should_receive(:span_status_to_s).and_return(true)
82
-
83
- span_model.span_status_to_s
84
- end
85
-
86
- it "should delegate span_status_to_s_on" do
87
- span_instance.should_receive(:span_status_to_s_on).and_return(true)
88
-
89
- span_model.span_status_to_s_on
90
- end
91
-
58
+
92
59
  it "should delegate current?" do
93
- span_instance.should_receive(:current?).and_return(true)
94
-
60
+ expect(span_instance).to receive(:current?).and_return(true)
61
+
95
62
  span_model.current?
96
63
  end
97
-
64
+
98
65
  it "should delegate current_on?" do
99
- span_instance.should_receive(:current_on?).and_return(true)
100
-
66
+ expect(span_instance).to receive(:current_on?).and_return(true)
67
+
101
68
  span_model.current_on?
102
69
  end
103
-
70
+
104
71
  it "should delegate future?" do
105
- span_instance.should_receive(:future?).and_return(true)
106
-
72
+ expect(span_instance).to receive(:future?).and_return(true)
73
+
107
74
  span_model.future?
108
75
  end
109
-
76
+
110
77
  it "should delegate future_on?" do
111
- span_instance.should_receive(:future_on?).and_return(true)
112
-
78
+ expect(span_instance).to receive(:future_on?).and_return(true)
79
+
113
80
  span_model.future_on?
114
81
  end
115
-
82
+
116
83
  it "should delegate expired?" do
117
- span_instance.should_receive(:expired?).and_return(true)
118
-
84
+ expect(span_instance).to receive(:expired?).and_return(true)
85
+
119
86
  span_model.expired?
120
87
  end
121
-
88
+
122
89
  it "should delegate expired_on?" do
123
- span_instance.should_receive(:expired_on?).and_return(true)
124
-
90
+ expect(span_instance).to receive(:expired_on?).and_return(true)
91
+
125
92
  span_model.expired_on?
126
93
  end
127
94
  end
128
- end
95
+ end