acts_as_span 0.0.5 → 0.0.6

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.
@@ -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