acts_as_event_owner 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -110,6 +110,15 @@ h3. One-time event
110
110
  :start_at => Time.parse("4:00pm")
111
111
  </pre>
112
112
 
113
+ h3. Every day at 08:00, 13:00, and 18:00
114
+
115
+ <pre>
116
+ EventSpecification.create :description => 'walk the dog',
117
+ :start_at => Time.parse("8:00am"),
118
+ :repeat => :per_hour,
119
+ :target => [8,13,18]
120
+ </pre>
121
+
113
122
  h3. Every day
114
123
 
115
124
  <pre>
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{acts_as_event_owner}
8
- s.version = "1.1.2"
8
+ s.version = "1.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Danny Burkes"]
12
- s.date = %q{2010-12-27}
12
+ s.date = %q{2011-01-18}
13
13
  s.description = %q{Simple calendar events for any ActiveRecord model}
14
14
  s.email = %q{dburkes@netable.com}
15
15
  s.extra_rdoc_files = [
@@ -15,17 +15,22 @@ module ActsAsEventOwner
15
15
 
16
16
  before_validation :set_defaults
17
17
  validates_presence_of :description
18
- validates_inclusion_of :repeat, :in => [:daily,:weekly,:monthly,:yearly], :allow_nil => true
18
+ validates_inclusion_of :repeat, :in => [:by_hour,:daily,:weekly,:monthly,:yearly], :allow_nil => true
19
19
  validates_inclusion_of :on_the, :in => ON_THE.keys, :allow_nil => true
20
20
  validates_numericality_of :frequency, :allow_nil => true
21
21
  validates_presence_of :start_at
22
22
  validate :validate_recurrence_rules
23
+ after_validation :set_defaults_after_validation
23
24
 
24
25
  attr_accessor :generate
25
26
  after_create :auto_generate_events
26
27
 
27
28
  def validate_recurrence_rules
28
29
  case self.repeat
30
+ when :by_hour
31
+ errors.add(:target, "must be an array") if !self.target.present? || !self.target.is_a?(Array)
32
+ [:on, :on_the].each {|v| errors.add(v, :present) if self.send(v)}
33
+
29
34
  when :daily
30
35
  [:on, :on_the, :target].each {|v| errors.add(v, :present) if self.send(v)}
31
36
 
@@ -58,8 +63,15 @@ module ActsAsEventOwner
58
63
  return nil if !self.valid? || self.repeat.nil?
59
64
 
60
65
  components = []
66
+ repeat = self.repeat
67
+ frequency = self.frequency
61
68
 
62
69
  case self.repeat
70
+ when :by_hour
71
+ repeat = "DAILY"
72
+ components << "BYHOUR=#{self.target.join(',')}"
73
+ frequency = nil
74
+
63
75
  when :daily
64
76
 
65
77
  when :weekly
@@ -77,8 +89,8 @@ module ActsAsEventOwner
77
89
  components << "BYSETPOS=#{ON_THE[self.on_the]};BYDAY=#{byday}" if self.on_the
78
90
  end
79
91
 
80
- components.unshift "INTERVAL=#{self.frequency}" if self.frequency
81
- components.unshift "FREQ=#{self.repeat.to_s.upcase}"
92
+ components.unshift "INTERVAL=#{frequency}" if frequency
93
+ components.unshift "FREQ=#{repeat.to_s.upcase}"
82
94
  components << "UNTIL=#{self.until.strftime("%Y%m%dT%H%M%SZ")}" if self.until
83
95
  components.join(';')
84
96
  end
@@ -139,6 +151,19 @@ module ActsAsEventOwner
139
151
  self.generate = { :from => self.start_at, :to => self.start_at + 30.days } if self.generate.nil?
140
152
  end
141
153
 
154
+ def set_defaults_after_validation
155
+ if self.errors.empty? && self.repeat == :by_hour
156
+ current_start_hour = self.start_at.hour
157
+ closest_repeat_hour = self.target.detect {|h| h > current_start_hour}
158
+ if closest_repeat_hour
159
+ self.start_at = Time.utc(self.start_at.year, self.start_at.month, self.start_at.day, closest_repeat_hour)
160
+ else
161
+ tomorrow = self.start_at + 24.hours
162
+ self.start_at = Time.utc(tomorrow.year, tomorrow.month, tomorrow.day, self.target.first)
163
+ end
164
+ end
165
+ end
166
+
142
167
  def byday
143
168
  self.target.is_a?(Array) ? self.target.join(',').upcase : BYDAYS[self.target]
144
169
  end
@@ -1,3 +1,3 @@
1
1
  module ActsAsEventOwner
2
- VERSION = "1.1.2" unless defined? ActsAsEventOwner::VERSION
2
+ VERSION = "1.1.3" unless defined? ActsAsEventOwner::VERSION
3
3
  end
@@ -51,6 +51,45 @@ describe ActsAsEventOwner::EventSpecification do
51
51
  end
52
52
  end
53
53
 
54
+ describe "events recurring multiple times per day" do
55
+ it "passes validations" do
56
+ new_event_specification(:repeat => :by_hour, :target => [8, 12, 16]).should be_valid
57
+ end
58
+
59
+ it "defaults start_at to the first occurrence" do
60
+ now = Time.now
61
+ Time.stub!(:now).and_return(Time.utc(2011, 1, 15, 8, 23))
62
+ create_event_specification(:repeat => :by_hour, :target => [8, 12, 16], :generate => false).start_at.utc.should == Time.utc(2011, 1, 15, 12, 00)
63
+
64
+ Time.stub!(:now).and_return(Time.utc(2011, 1, 15, 23, 23))
65
+ create_event_specification(:repeat => :by_hour, :target => [8, 12, 16], :generate => false).start_at.utc.should == Time.utc(2011, 1, 16, 8, 00)
66
+ end
67
+
68
+ it "does not support invalid recurrence specifications" do
69
+ spec = new_event_specification(:repeat => :by_hour)
70
+ spec.should_not be_valid
71
+ spec.errors[:target].should be_present
72
+
73
+ spec = new_event_specification(:repeat => :by_hour, :on_the => :first)
74
+ spec.should_not be_valid
75
+ spec.errors[:on_the].should be_present
76
+
77
+ spec = new_event_specification(:repeat => :by_hour, :on => [1,2])
78
+ spec.should_not be_valid
79
+ spec.errors[:on].should be_present
80
+
81
+ spec = new_event_specification(:repeat => :by_hour, :target => 8)
82
+ spec.should_not be_valid
83
+ spec.errors[:target].should be_present
84
+ end
85
+
86
+ it "generates an RRULE" do
87
+ # every day at 08:00, 12:00, and 16:00
88
+ new_event_specification(:repeat => :by_hour, :target => [8,12,16]).to_rrule.should == "FREQ=DAILY;BYHOUR=8,12,16"
89
+ end
90
+
91
+ end
92
+
54
93
  describe "events recurring daily" do
55
94
  it "passes validations" do
56
95
  new_event_specification(:repeat => :daily).should be_valid
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 1
8
- - 2
9
- version: 1.1.2
8
+ - 3
9
+ version: 1.1.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Danny Burkes
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-27 00:00:00 -08:00
17
+ date: 2011-01-18 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency