radiant-event_calendar-extension 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitmodules +0 -0
- data/README.md +198 -0
- data/Rakefile +139 -0
- data/VERSION +1 -0
- data/app/controllers/admin/calendars_controller.rb +18 -0
- data/app/controllers/admin/event_venues_controller.rb +3 -0
- data/app/controllers/admin/events_controller.rb +9 -0
- data/app/controllers/admin/icals_controller.rb +26 -0
- data/app/controllers/events_controller.rb +201 -0
- data/app/models/calendar.rb +57 -0
- data/app/models/event.rb +409 -0
- data/app/models/event_calendar_page.rb +138 -0
- data/app/models/event_occurrence.rb +89 -0
- data/app/models/event_recurrence_rule.rb +85 -0
- data/app/models/event_venue.rb +17 -0
- data/app/models/ical.rb +132 -0
- data/app/views/admin/calendars/_actions.html.haml +6 -0
- data/app/views/admin/calendars/_form.html.haml +56 -0
- data/app/views/admin/calendars/edit.html.haml +11 -0
- data/app/views/admin/calendars/help.html.erb +22 -0
- data/app/views/admin/calendars/index.html.haml +60 -0
- data/app/views/admin/calendars/new.html.haml +10 -0
- data/app/views/admin/calendars/show.html.haml +36 -0
- data/app/views/admin/event_venues/_event_venue.html.haml +18 -0
- data/app/views/admin/event_venues/_form.html.haml +44 -0
- data/app/views/admin/event_venues/edit.html.haml +32 -0
- data/app/views/admin/event_venues/index.html.haml +33 -0
- data/app/views/admin/event_venues/new.html.haml +32 -0
- data/app/views/admin/event_venues/remove.html.haml +17 -0
- data/app/views/admin/events/_event.html.haml +47 -0
- data/app/views/admin/events/_form.html.haml +116 -0
- data/app/views/admin/events/_list_head.html.haml +18 -0
- data/app/views/admin/events/edit.html.haml +6 -0
- data/app/views/admin/events/index.html.haml +23 -0
- data/app/views/admin/events/new.html.haml +6 -0
- data/app/views/admin/events/remove.html.haml +17 -0
- data/app/views/admin/icals/refresh.html.haml +11 -0
- data/app/views/admin/icals/refresh_all.html.haml +0 -0
- data/app/views/events/_defacet.html.haml +2 -0
- data/app/views/events/_event.html.haml +29 -0
- data/app/views/events/_event_postscript.html.haml +0 -0
- data/app/views/events/_faceting.html.haml +27 -0
- data/app/views/events/_minicalendar.html.haml +49 -0
- data/app/views/events/_other_page_parts.html.haml +0 -0
- data/app/views/events/_views.html.haml +6 -0
- data/app/views/events/index.html.haml +56 -0
- data/app/views/events/index.ics.erb +7 -0
- data/app/views/events/index.rss.builder +20 -0
- data/config/routes.rb +13 -0
- data/db/migrate/001_create_calendar_and_events.rb +21 -0
- data/db/migrate/002_calendar_add_ical_url.rb +9 -0
- data/db/migrate/003_add_calendar_category.rb +9 -0
- data/db/migrate/004_add_slug.rb +9 -0
- data/db/migrate/005_add_subscription_refresh_history.rb +11 -0
- data/db/migrate/006_create_icals.rb +13 -0
- data/db/migrate/007_move_subscriptions_to_ical.rb +15 -0
- data/db/migrate/008_clean_out_calendar.rb +12 -0
- data/db/migrate/009_basic_authentication.rb +12 -0
- data/db/migrate/010_refresh_interval.rb +9 -0
- data/db/migrate/011_more_properties.rb +8 -0
- data/db/migrate/20090818133511_simpler_ical_columns.rb +17 -0
- data/db/migrate/20090819130919_ownership.rb +17 -0
- data/db/migrate/20090820073805_site_scope.rb +13 -0
- data/db/migrate/20091118100725_event_status.rb +9 -0
- data/db/migrate/20100216080944_more_event_data.rb +31 -0
- data/db/migrate/20100218131410_recurrence_parts.rb +19 -0
- data/db/migrate/20100219102227_venues_and_categories.rb +23 -0
- data/db/migrate/20100221180539_recurrence_rules.rb +34 -0
- data/db/migrate/20100222182112_occurrences.rb +13 -0
- data/event_calendar_extension.rb +32 -0
- data/lib/calendar_period.rb +151 -0
- data/lib/event_calendar_admin_ui.rb +78 -0
- data/lib/event_calendar_tags.rb +1021 -0
- data/lib/event_search.rb +22 -0
- data/lib/event_statuses.rb +24 -0
- data/lib/tasks/event_calendar_extension_tasks.rake +29 -0
- data/pkg/radiant-event_calendar-extension-1.0.0.gem +0 -0
- data/public/icals/blank +0 -0
- data/public/images/admin/calendar.png +0 -0
- data/public/images/event_calendar/calendarlinkbg.png +0 -0
- data/public/images/event_calendar/event_shadow.png +0 -0
- data/public/images/event_calendar/ical16.png +0 -0
- data/public/images/event_calendar/maplinkbg.png +0 -0
- data/public/images/event_calendar/one_event.png +0 -0
- data/public/images/event_calendar/several_events.png +0 -0
- data/public/javascripts/admin/event_calendar.js +240 -0
- data/public/stylesheets/sass/admin/event_calendar.sass +266 -0
- data/public/stylesheets/sass/admin/modules/_grid.sass +56 -0
- data/public/stylesheets/sass/constants.sass +80 -0
- data/public/stylesheets/sass/event_calendar.sass +203 -0
- data/radiant-event_calendar-extension.gemspec +166 -0
- data/spec/datasets/calendar_events_dataset.rb +43 -0
- data/spec/datasets/calendar_pages_dataset.rb +8 -0
- data/spec/datasets/calendar_sites_dataset.rb +6 -0
- data/spec/datasets/calendars_dataset.rb +34 -0
- data/spec/datasets/recurrence_dataset.rb +7 -0
- data/spec/files/dummy.ics +59 -0
- data/spec/files/ny.ics +36 -0
- data/spec/lib/event_calendar_page_spec.rb +24 -0
- data/spec/models/calendar_spec.rb +11 -0
- data/spec/models/event_spec.rb +98 -0
- data/spec/models/ical_spec.rb +63 -0
- data/spec/models/recurrence_rule_spec.rb +82 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +36 -0
- metadata +238 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddSubscriptionRefreshHistory < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :calendars, :last_refresh_count, :integer
|
4
|
+
add_column :calendars, :last_refresh_date, :datetime
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.down
|
8
|
+
remove_column :calendars, :last_refresh_count
|
9
|
+
remove_column :calendars, :last_refresh_date
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateIcals < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :icals do |t|
|
4
|
+
t.column :calendar_id, :integer
|
5
|
+
t.column :ical_url, :string
|
6
|
+
t.column :last_refresh_count, :integer
|
7
|
+
t.column :last_refresh_date, :datetime
|
8
|
+
end
|
9
|
+
end
|
10
|
+
def self.down
|
11
|
+
drop_table :icals
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class MoveSubscriptionsToIcal < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
Calendar.find(:all).each do |c|
|
5
|
+
Ical.create(:ical_url=>c.ical_url, :last_refresh_date=>c.last_refresh_date, :last_refresh_count=>c.last_refresh_count, :calendar_id=>c.id)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
Ical.find(:all).each do |c|
|
11
|
+
Calendar.create(:ical_url=>c.ical_url, :last_refresh_date=>c.last_refresh_date, :last_refresh_count=>c.last_refresh_count, :calendar_id=>c.id)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CleanOutCalendar < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
remove_column :calendars, :ical_url
|
4
|
+
remove_column :calendars, :last_refresh_date
|
5
|
+
remove_column :calendars, :last_refresh_count
|
6
|
+
end
|
7
|
+
def self.down
|
8
|
+
add_colum :calendars, :ical_url, :string
|
9
|
+
add_column :calendars, :last_refresh_date, :datetime
|
10
|
+
add_column :calendars, :last_refresh_count, :integer
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class BasicAuthentication < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :icals, :ical_username, :string
|
4
|
+
add_column :icals, :ical_password, :string
|
5
|
+
add_column :icals, :ical_use_https, :boolean
|
6
|
+
end
|
7
|
+
def self.down
|
8
|
+
remove_column :icals, :ical_username
|
9
|
+
remove_column :icals, :ical_password
|
10
|
+
remove_column :icals, :ical_use_https
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class RefreshInterval < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :icals, :ical_refresh_interval, :integer
|
4
|
+
Radiant::Config['event_calendar.default_refresh_interval'] = 3600
|
5
|
+
end
|
6
|
+
def self.down
|
7
|
+
remove_column :icals, :ical_refresh_interval
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class SimplerIcalColumns < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
rename_column :icals, :ical_url, :url
|
4
|
+
rename_column :icals, :ical_username, :username
|
5
|
+
rename_column :icals, :ical_password, :password
|
6
|
+
rename_column :icals, :ical_use_https, :use_https
|
7
|
+
rename_column :icals, :ical_refresh_interval, :refresh_interval
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
rename_column :icals, :url, :ical_url
|
12
|
+
rename_column :icals, :username, :ical_username
|
13
|
+
rename_column :icals, :password, :ical_password
|
14
|
+
rename_column :icals, :use_https, :ical_use_https
|
15
|
+
rename_column :icals, :refresh_interval, :ical_refresh_interval
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Ownership < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :calendars, :created_by, :integer
|
4
|
+
add_column :calendars, :updated_by, :integer
|
5
|
+
add_column :calendars, :created_at, :datetime
|
6
|
+
add_column :calendars, :updated_at, :datetime
|
7
|
+
add_column :calendars, :lock_version, :integer
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
remove_column :calendars, :created_by
|
12
|
+
remove_column :calendars, :updated_by
|
13
|
+
remove_column :calendars, :created_at
|
14
|
+
remove_column :calendars, :updated_at
|
15
|
+
remove_column :calendars, :lock_version
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class SiteScope < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :calendars, :site_id, :integer
|
4
|
+
add_column :events, :site_id, :integer
|
5
|
+
add_column :icals, :site_id, :integer
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
remove_column :calendars, :site_id
|
10
|
+
remove_column :events, :site_id
|
11
|
+
remove_column :icals, :site_id
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class MoreEventData < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :events, :uuid, :string
|
4
|
+
add_column :events, :recurrence_rule, :string
|
5
|
+
add_column :events, :all_day, :boolean
|
6
|
+
add_column :events, :priority, :string
|
7
|
+
add_column :events, :keywords, :string
|
8
|
+
add_column :events, :contact, :string
|
9
|
+
add_column :events, :postcode, :string
|
10
|
+
add_column :events, :lock_version, :integer
|
11
|
+
add_column :events, :created_by_id, :integer
|
12
|
+
add_column :events, :created_at, :datetime
|
13
|
+
add_column :events, :updated_by_id, :integer
|
14
|
+
add_column :events, :updated_at, :datetime
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
remove_column :events, :uuid
|
19
|
+
remove_column :events, :recurrence_rule
|
20
|
+
remove_column :events, :all_day
|
21
|
+
remove_column :events, :priority
|
22
|
+
remove_column :events, :keywords
|
23
|
+
remove_column :events, :contact
|
24
|
+
remove_column :events, :postcode
|
25
|
+
remove_column :events, :lock_version
|
26
|
+
remove_column :events, :created_by_id
|
27
|
+
remove_column :events, :created_at
|
28
|
+
remove_column :events, :updated_by_id
|
29
|
+
remove_column :events, :updated_at
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class RecurrenceParts < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
remove_column :events, :recurrence_rule
|
4
|
+
add_column :events, :recurrence_period, :string
|
5
|
+
add_column :events, :recurrence_basis, :string
|
6
|
+
add_column :events, :recurrence_limit, :datetime
|
7
|
+
add_column :events, :recurrence_count, :integer
|
8
|
+
add_column :events, :recurrence_interval, :integer
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
remove_column :events, :recurrence_period
|
13
|
+
remove_column :events, :recurrence_basis
|
14
|
+
remove_column :events, :recurrence_limit
|
15
|
+
remove_column :events, :recurrence_count
|
16
|
+
remove_column :events, :recurrence_interval
|
17
|
+
add_column :events, :recurrence_rule, :string
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class VenuesAndCategories < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :event_venues do |t|
|
4
|
+
t.column :title, :string
|
5
|
+
t.column :address, :string
|
6
|
+
t.column :url, :string
|
7
|
+
t.column :description, :text
|
8
|
+
t.column :postcode, :string
|
9
|
+
t.column :created_by, :integer
|
10
|
+
t.column :updated_by, :integer
|
11
|
+
t.column :created_at, :datetime
|
12
|
+
t.column :updated_at, :datetime
|
13
|
+
t.column :lock_version, :integer
|
14
|
+
t.column :site_id, :integer
|
15
|
+
end
|
16
|
+
add_column :events, :event_venue_id, :integer
|
17
|
+
add_index :events, :event_venue_id
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.down
|
21
|
+
drop_table :event_venues
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class RecurrenceRules < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :event_recurrence_rules do |t|
|
4
|
+
t.column :event_id, :integer
|
5
|
+
t.column :active, :boolean, :default => false
|
6
|
+
t.column :period, :string
|
7
|
+
t.column :basis, :string
|
8
|
+
t.column :interval, :integer, :default => 1
|
9
|
+
t.column :limiting_date, :datetime
|
10
|
+
t.column :limiting_count, :integer
|
11
|
+
t.column :created_by, :integer
|
12
|
+
t.column :updated_by, :integer
|
13
|
+
t.column :created_at, :datetime
|
14
|
+
t.column :updated_at, :datetime
|
15
|
+
t.column :lock_version, :integer
|
16
|
+
t.column :site_id, :integer
|
17
|
+
end
|
18
|
+
add_index :event_recurrence_rules, :event_id
|
19
|
+
remove_column :events, :recurrence_period
|
20
|
+
remove_column :events, :recurrence_basis
|
21
|
+
remove_column :events, :recurrence_limit
|
22
|
+
remove_column :events, :recurrence_count
|
23
|
+
remove_column :events, :recurrence_interval
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.down
|
27
|
+
drop_table :event_recurrence_rules
|
28
|
+
add_column :events, :recurrence_period, :string
|
29
|
+
add_column :events, :recurrence_basis, :string
|
30
|
+
add_column :events, :recurrence_limit, :datetime
|
31
|
+
add_column :events, :recurrence_count, :integer
|
32
|
+
add_column :events, :recurrence_interval, :integer
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Occurrences < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :events, :master_id, :integer
|
4
|
+
Event.reset_column_information
|
5
|
+
Event.find(:all).each do |event|
|
6
|
+
event.send :update_occurrences
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
remove_column :events, :master_id
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class EventCalendarExtension < Radiant::Extension
|
2
|
+
version "1.0.0"
|
3
|
+
description "An event calendar extension that administers events locally or draws them from any ical or CalDAV publishers (Google Calendar, .Mac, Darwin Calendar Server, etc.)"
|
4
|
+
url "http://radiant.spanner.org/event_calendar"
|
5
|
+
|
6
|
+
def activate
|
7
|
+
Page.send :include, EventCalendarTags # defines a wide range of events: tags for use on normal and calendar pages
|
8
|
+
Status.send :include, EventStatuses # adds support for draft and submitted events
|
9
|
+
UserActionObserver.instance.send :add_observer!, Calendar # adds ownership and update hooks to the calendar data
|
10
|
+
UserActionObserver.instance.send :add_observer!, Event # adds ownership and update hooks to the event data
|
11
|
+
|
12
|
+
if Radiant::Config.table_exists? && !Radiant::Config["event_calendar.icals_path"]
|
13
|
+
Radiant::Config["event_calendar.icals_path"] = "icals"
|
14
|
+
end
|
15
|
+
|
16
|
+
unless defined? admin.calendar
|
17
|
+
Radiant::AdminUI.send :include, EventCalendarAdminUI
|
18
|
+
admin.calendar = Radiant::AdminUI.load_default_calendar_regions
|
19
|
+
admin.event = Radiant::AdminUI.load_default_event_regions
|
20
|
+
admin.event_venue = Radiant::AdminUI.load_default_event_venue_regions
|
21
|
+
end
|
22
|
+
|
23
|
+
if respond_to?(:tab)
|
24
|
+
tab("Content") do
|
25
|
+
add_item("Calendar", '/admin/event_calendar')
|
26
|
+
end
|
27
|
+
else
|
28
|
+
admin.tabs.add "Calendar", '/admin/event_calendar', :after => "Snippets", :visibility => [:all]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
class CalendarPeriod
|
2
|
+
include ActionView::Helpers::DateHelper
|
3
|
+
|
4
|
+
attr_writer :start, :finish
|
5
|
+
|
6
|
+
def self.between(from=nil,to=nil)
|
7
|
+
raise StandardError, "CalendarPeriod.between requires either start or finish datetime" unless from || to
|
8
|
+
period = self.new
|
9
|
+
period.start = from
|
10
|
+
period.finish = to
|
11
|
+
period
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.from(from, duration=nil)
|
15
|
+
to = from + duration if duration
|
16
|
+
between(from, to)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.to(to, duration=nil)
|
20
|
+
from = to - duration if duration
|
21
|
+
between(from, to)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.default
|
25
|
+
between(Time.now, nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
def default?
|
29
|
+
finish.nil? && (Time.now - start).to_i.abs < 1.minute
|
30
|
+
end
|
31
|
+
|
32
|
+
def start
|
33
|
+
@start.to_datetime if @start
|
34
|
+
end
|
35
|
+
|
36
|
+
def finish
|
37
|
+
@finish.to_datetime if @finish
|
38
|
+
end
|
39
|
+
|
40
|
+
def duration
|
41
|
+
if bounded?
|
42
|
+
finish - start
|
43
|
+
else
|
44
|
+
'indefinite'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def duration=(s)
|
49
|
+
if start
|
50
|
+
finish = start + s
|
51
|
+
elsif finish
|
52
|
+
start = finish - s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def bounded?
|
57
|
+
start && finish
|
58
|
+
end
|
59
|
+
|
60
|
+
def unbounded?
|
61
|
+
!bounded?
|
62
|
+
end
|
63
|
+
|
64
|
+
# descriptions
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
"#{distance_of_time_in_words(start, finish)} from #{start}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def inspect
|
71
|
+
detailed = "%-1I:%M%p %d/%m/%Y"
|
72
|
+
%{#{describe_start(detailed)} to #{describe_finish(detailed)}}
|
73
|
+
end
|
74
|
+
|
75
|
+
[:day, :week, :month, :year].each do |period|
|
76
|
+
define_method "is_#{period}?".intern do
|
77
|
+
bounded? && start == start.send("beginning_of_#{period}".intern) && finish == start.send("end_of_#{period}".intern)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def describe_start(date_format=nil)
|
82
|
+
if start
|
83
|
+
unless date_format
|
84
|
+
date_format = "%d %B"
|
85
|
+
date_format += " %Y" unless start.year == Time.now.year
|
86
|
+
end
|
87
|
+
start.to_datetime.strftime(date_format)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def describe_finish(date_format=nil)
|
92
|
+
if finish
|
93
|
+
unless date_format
|
94
|
+
date_format = "%d %B"
|
95
|
+
date_format += " %Y" unless finish.year == Time.now.year
|
96
|
+
end
|
97
|
+
finish.to_datetime.strftime(date_format)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def description
|
102
|
+
return "on #{start.mday} #{monthname} #{start.year}" if is_day?
|
103
|
+
return "in week #{start.cweek} of #{start.year}" if is_week?
|
104
|
+
return "in #{monthname} #{start.year}" if is_month?
|
105
|
+
return "in #{start.year}" if is_year?
|
106
|
+
return "from #{describe_start} onwards" unless finish
|
107
|
+
return "until #{describe_finish}" unless start
|
108
|
+
"between #{describe_start} and #{describe_finish}"
|
109
|
+
end
|
110
|
+
|
111
|
+
def monthname
|
112
|
+
i = start ? start.month : finish.month
|
113
|
+
Date::MONTHNAMES[i]
|
114
|
+
end
|
115
|
+
|
116
|
+
# to expand the period to full calendar months
|
117
|
+
# @period.pad!
|
118
|
+
|
119
|
+
def pad!
|
120
|
+
start = start.beginning_of_month if start
|
121
|
+
finish = finish.end_of_month if finish
|
122
|
+
end
|
123
|
+
|
124
|
+
# to shift the period forward one month
|
125
|
+
# @period += 1.month
|
126
|
+
|
127
|
+
def +(s)
|
128
|
+
start = start + s if start
|
129
|
+
finish = finish + s if finish
|
130
|
+
end
|
131
|
+
|
132
|
+
# to shift the period back one month
|
133
|
+
# @period -= 1.month
|
134
|
+
|
135
|
+
def -(s)
|
136
|
+
start = start - s if start
|
137
|
+
finish = finish - s if finish
|
138
|
+
end
|
139
|
+
|
140
|
+
# to extend the period by one month
|
141
|
+
# @period << 1.month
|
142
|
+
|
143
|
+
def <<(s)
|
144
|
+
if bounded?
|
145
|
+
finish += s
|
146
|
+
else
|
147
|
+
duration = s
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|