<commit_before>require 'uuidtools'
require 'chronic'

module Droom
  class Event < ActiveRecord::Base
    attr_accessible :start, :finish, :name, :description, :event_set_id, :created_by_id, :uuid, :all_day, :master_id, :url

    belongs_to :created_by, :class_name => 'User'

    has_many :invitations
    has_many :users, :through => :invitations

    has_many :attachments, :as => :attachee
    has_many :documents, :through => :attachments
  
    belongs_to :venue
    accepts_nested_attributes_for :venue

    belongs_to :event_set
    accepts_nested_attributes_for :event_set
  
    belongs_to :master, :class_name => 'Event'
    has_many :occurrences, :class_name => 'Event', :foreign_key => 'master_id', :dependent => :destroy
    has_many :recurrence_rules, :dependent => :destroy, :conditions => {:active => true}
    accepts_nested_attributes_for :recurrence_rules, :allow_destroy => true

    validates :start, :presence => true, :date => true
    validates :finish, :date => {:after => :start, :allow_nil => true}
    validates :uuid, :presence => true, :uniqueness => true
    validates :name, :presence_unless_recurrence => true

    before_validation :set_uuid
    after_save :update_occurrences
  
    default_scope :order => 'start ASC', :include => :venue
    scope :primary, { :conditions => "master_id IS NULL" }
    scope :recurrent, { :conditions => "master_id IS NOT NULL" }
  
    ## Event retrieval in various ways
    #
    # All of these methods return scopes.
    #
  
    scope :after, lambda { |datetime| # datetime. eg calendar.occurrences.after(Time.now)
      where(['start > ?', datetime])
    }
  
    scope :before, lambda { |datetime| # datetime. eg calendar.occurrences.before(Time.now)
      where(['start < ?', datetime])
    }
  
    scope :within, lambda { |period| # CalendarPeriod object
      where(['start > :start AND start < :finish', {:start => period.start, :finish => period.finish}])
    }

    scope :between, lambda { |start, finish| # datetimable objects. eg. Event.between(reader.last_login, Time.now)
      where(['start > :start AND start < :finish', {:start => start, :finish => finish}])
    }
  
    scope :future_and_current, lambda {
      where(['(finish > :now) OR (finish IS NULL AND start > :now)', {:now => Time.now}])
    }
  
    scope :unfinished, lambda { |start| # datetimable object.
      where(['start < :start AND finish > :start', {:start => start}])
    }
  
    scope :coincident_with, lambda { |start, finish| # datetimable objects.
      where(['(start < :finish AND finish > :start) OR (finish IS NULL AND start > :start AND start < :finish)', {:start => start, :finish => finish}])
    }

    scope :limited_to, lambda { |limit|
      limit(limit)
    }
  
    scope :at_venue, lambda { |venue| # EventVenue object
      where(["venue_id = ?", venue.id])
    }
  
    scope :except_these, lambda { |uuids| # array of uuid strings
      placeholders = uuids.map{'?'}.join(',')
      where(["uuid NOT IN (#{placeholders})", *uuids])
    }

    def self.in_the_last(period)           # seconds. eg calendar.occurrences.in_the_last(1.week)
      finish = Time.now
      start = finish - period
      between(start, finish)
    end

    def self.in_year(year)                 # just a number. eg calendar.occurrences.in_year(2010)
      start = DateTime.civil(year)
      finish = start + 1.year
      between(start, finish)
    end

    def self.in_month(year, month)          # numbers. eg calendar.occurrences.in_month(2010, 12)
      start = DateTime.civil(year, month)
      finish = start + 1.month
      between(start, finish)
    end
  
    def self.in_week(year, week)            # numbers, with a commercial week: eg calendar.occurrences.in_week(2010, 35)
      start = DateTime.commercial(year, week)
      finish = start + 1.week
      between(start, finish)
    end
  
    def self.on_day (year, month, day)      # numbers: eg calendar.occurrences.on_day(2010, 12, 12)
      start = DateTime.civil(year, month, day)
      finish = start + 1.day
      between(start, finish)
    end

    def self.future
      after(Time.now)
    end

    def self.past
      before(Time.now)
    end

    ## Instance methods
    #    
    # We store the start and end points of the event as a single DateTime value to make comparison simple.
    # The setters for date and time are overridden to pass strings through chronic's natural language parser
    # and to treat numbers as epoch seconds. These should all work as you'd expect:
    #
    #   event.start = "Tuesday at 11pm"
    #   event.start = "12/12/1969 at 10pm"
    #   event.start = "1347354111"
    #   event.start = Time.now + 1.hour
    #
    def start=(value)
      write_attribute :start, parse_date(value)
    end

    def finish=(value)
      write_attribute :finish, parse_date(value)
    end
    
    # For interface purposes we often want to separate date and time parts. These getters will return the 
    # corresponding Date or Time object.
    #
    # The `time_of_day` gem makes time handling a bit more intuitive by concealing the date part of a Time object.
    #
    def start_time
      start.time_of_day if start
    end

    def start_date
      start.to_date if start
    end
    
    def finish_time
      finish.time_of_day if finish
    end

    def finish_date
      finish.to_date if finish
    end
    
    # And these setters will adjust the current value so that its date or time part corresponds to the given
    # value. The value is passed through the same parsing mechanism as above, so:
    #
    #   event.start = "Tuesday at 11pm"       -> next Tuesday at 11pm
    #   event.start_time = "8pm"              -> next Tuesday at 8pm
    #   event.start_date = "Wednesday"        -> next Wednesday at 8pm
    #   event.start_date = "26 February 2016" -> 26/2/16 at 8pm
    #   event.start_time = "18:00"            -> 26/2/16 at 6pm
    #
    # If the time is set before the date, we default to that time today. Times default to 00:00 in the usual way.
    #
    def start_time=(value)
      start = (start_date || Date.today) + parse_date(value).time_of_day
    end
    
    def start_date=(value)
      start = parse_date(value).to_date + start_time
    end
  
    def finish_time=(value)
      finish = (finish_date || Date.today).to_date + parse_date(value).time_of_day
    end
    
    def finish_date=(value)
      finish = parse_date(value).to_date + finish_time
    end






    def duration
      if finish
        finish - start
      else
        0
      end
    end
<commit_msg>finish date defaults to start date<commit_after>require 'uuidtools'
require 'chronic'

module Droom
  class Event < ActiveRecord::Base
    attr_accessible :start, :finish, :name, :description, :event_set_id, :created_by_id, :uuid, :all_day, :master_id, :url

    belongs_to :created_by, :class_name => 'User'

    has_many :invitations
    has_many :users, :through => :invitations

    has_many :attachments, :as => :attachee
    has_many :documents, :through => :attachments
  
    belongs_to :venue
    accepts_nested_attributes_for :venue

    belongs_to :event_set
    accepts_nested_attributes_for :event_set
  
    belongs_to :master, :class_name => 'Event'
    has_many :occurrences, :class_name => 'Event', :foreign_key => 'master_id', :dependent => :destroy
    has_many :recurrence_rules, :dependent => :destroy, :conditions => {:active => true}
    accepts_nested_attributes_for :recurrence_rules, :allow_destroy => true

    validates :start, :presence => true, :date => true
    validates :finish, :date => {:after => :start, :allow_nil => true}
    validates :uuid, :presence => true, :uniqueness => true
    validates :name, :presence_unless_recurrence => true

    before_validation :set_uuid
    after_save :update_occurrences
  
    default_scope :order => 'start ASC', :include => :venue
    scope :primary, { :conditions => "master_id IS NULL" }
    scope :recurrent, { :conditions => "master_id IS NOT NULL" }
  
    ## Event retrieval in various ways
    #
    # All of these methods return scopes.
    #
  
    scope :after, lambda { |datetime| # datetime. eg calendar.occurrences.after(Time.now)
      where(['start > ?', datetime])
    }
  
    scope :before, lambda { |datetime| # datetime. eg calendar.occurrences.before(Time.now)
      where(['start < ?', datetime])
    }
  
    scope :within, lambda { |period| # CalendarPeriod object
      where(['start > :start AND start < :finish', {:start => period.start, :finish => period.finish}])
    }

    scope :between, lambda { |start, finish| # datetimable objects. eg. Event.between(reader.last_login, Time.now)
      where(['start > :start AND start < :finish', {:start => start, :finish => finish}])
    }
  
    scope :future_and_current, lambda {
      where(['(finish > :now) OR (finish IS NULL AND start > :now)', {:now => Time.now}])
    }
  
    scope :unfinished, lambda { |start| # datetimable object.
      where(['start < :start AND finish > :start', {:start => start}])
    }
  
    scope :coincident_with, lambda { |start, finish| # datetimable objects.
      where(['(start < :finish AND finish > :start) OR (finish IS NULL AND start > :start AND start < :finish)', {:start => start, :finish => finish}])
    }

    scope :limited_to, lambda { |limit|
      limit(limit)
    }
  
    scope :at_venue, lambda { |venue| # EventVenue object
      where(["venue_id = ?", venue.id])
    }
  
    scope :except_these, lambda { |uuids| # array of uuid strings
      placeholders = uuids.map{'?'}.join(',')
      where(["uuid NOT IN (#{placeholders})", *uuids])
    }

    def self.in_the_last(period)           # seconds. eg calendar.occurrences.in_the_last(1.week)
      finish = Time.now
      start = finish - period
      between(start, finish)
    end

    def self.in_year(year)                 # just a number. eg calendar.occurrences.in_year(2010)
      start = DateTime.civil(year)
      finish = start + 1.year
      between(start, finish)
    end

    def self.in_month(year, month)          # numbers. eg calendar.occurrences.in_month(2010, 12)
      start = DateTime.civil(year, month)
      finish = start + 1.month
      between(start, finish)
    end
  
    def self.in_week(year, week)            # numbers, with a commercial week: eg calendar.occurrences.in_week(2010, 35)
      start = DateTime.commercial(year, week)
      finish = start + 1.week
      between(start, finish)
    end
  
    def self.on_day (year, month, day)      # numbers: eg calendar.occurrences.on_day(2010, 12, 12)
      start = DateTime.civil(year, month, day)
      finish = start + 1.day
      between(start, finish)
    end

    def self.future
      after(Time.now)
    end

    def self.past
      before(Time.now)
    end

    ## Instance methods
    #    
    # We store the start and end points of the event as a single DateTime value to make comparison simple.
    # The setters for date and time are overridden to pass strings through chronic's natural language parser
    # and to treat numbers as epoch seconds. These should all work as you'd expect:
    #
    #   event.start = "Tuesday at 11pm"
    #   event.start = "12/12/1969 at 10pm"
    #   event.start = "1347354111"
    #   event.start = Time.now + 1.hour
    #
    def start=(value)
      write_attribute :start, parse_date(value)
    end

    def finish=(value)
      write_attribute :finish, parse_date(value)
    end
    
    # For interface purposes we often want to separate date and time parts. These getters will return the 
    # corresponding Date or Time object.
    #
    # The `time_of_day` gem makes time handling a bit more intuitive by concealing the date part of a Time object.
    #
    def start_time
      start.time_of_day if start
    end

    def start_date
      start.to_date if start
    end
    
    def finish_time
      finish.time_of_day if finish
    end

    def finish_date
      finish.to_date if finish
    end
    
    # And these setters will adjust the current value so that its date or time part corresponds to the given
    # value. The value is passed through the same parsing mechanism as above, so:
    #
    #   event.start = "Tuesday at 11pm"       -> next Tuesday at 11pm
    #   event.start_time = "8pm"              -> next Tuesday at 8pm
    #   event.start_date = "Wednesday"        -> next Wednesday at 8pm
    #   event.start_date = "26 February 2016" -> 26/2/16 at 8pm
    #   event.start_time = "18:00"            -> 26/2/16 at 6pm
    #
    # If the time is set before the date, we default to that time today. Times default to 00:00 in the usual way.
    #
    def start_time=(value)
      start = (start_date || Date.today) + parse_date(value).time_of_day
    end
    
    def start_date=(value)
      start = parse_date(value).to_date + start_time
    end
  
    def finish_time=(value)
      finish = (finish_date || start_date || Date.today).to_date + parse_date(value).time_of_day
    end
    
    def finish_date=(value)
      finish = parse_date(value).to_date + finish_time
    end






    def duration
      if finish
        finish - start
      else
        0
      end
    end

{'fraction_non_alphanumeric': 0.10743864447990274, 'fraction_numerical': 0.013068915735886331, 'mean_word_length': 2.686834733893557, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '483383', 'n_tokens_mistral': 4276, 'n_tokens_neox': 4019, 'n_words': 1234}