<commit_before>require 'active_support/concern'
require 'active_support/core_ext/class'
require 'active_support/inflector'
require 'active_model'

module Chronologic::Client::Event

  extend ActiveSupport::Concern

  included do
    # XXX Protect this?
    attr_accessor :new_record
    attr_accessor :objects, :events
    attr_accessor :cl_key, :timestamp

    attr_reader :timelines
    attr_reader :cl_url
  end

  module ClassMethods
    def attribute(name)
      self.class_eval <<-RUBY, __FILE__, __LINE__
        attr_accessor :attributes

        def #{name}
          @attributes[:#{name}]
        end

        def #{name}=(val)
          @dirty_attributes = true
          @attributes[:#{name}] = val
        end
      RUBY
    end

    def objects(name, klass)
      self.class_eval <<-RUBY, __FILE__, __LINE__
        # SLOW this potentially converts hashes to the klass every time.
        # Could memoize this sometime in the future.
        def #{name}
          objects.
            fetch('#{name}', {}).
            values.map { |obj|
              obj.is_a?(#{klass}) ? obj : #{klass}.new.from_cl(obj)
            }.sort
        end

        def add_#{name.to_s.singularize}(obj)
          @dirty_objects = true
          objects['#{name}'][obj.to_cl_key] = obj
        end

        def remove_#{name.to_s.singularize}(obj)
          @dirty_objects = true
          objects['#{name}'].delete(obj.to_cl_key)
        end
      RUBY
    end

    def events(name, klass)
      self.class_eval <<-RUBY, __FILE__, __LINE__
        def #{name}
          casted_events
        end

        def add_#{name.to_s.singularize}(obj)
          @dirty_events = true
          events[obj.to_cl_key] = obj
        end

        def remove_#{name.to_s.singularize}(obj)
          @dirty_events = true
          events.delete(obj.to_cl_key)
        end

        def event_class
          #{klass}
        end
      RUBY
    end

    def fetch(event_url)
      obj = connection.fetch(event_url)
      raise 'Event not found' if obj.nil?
      new.from(obj)
    end

    # HAX
    def connection
      Chronologic::Client::Connection.instance
    end
  end

  module InstanceMethods

    def initialize
      @attributes = {}
      @new_record = true
      @dirty_attributes = false
      @dirty_timelines = false
      @dirty_objects = false
      @dirty_events = false # XXX merge all these dirty flags
      @objects = Hash.new { |h, k| h[k] = {} }
      @events = Hash.new { |h, k| h[k] = {} }
      @timelines = []
      super
    end

    def connection
      Chronologic::Client::Connection.instance
    end

    def parent
      @attributes['parent']
    end

    def parent=(parent_key)
      @attributes['parent'] = parent_key
      add_timeline(parent_key)
    end

    def parent_key
      @attributes['parent']
    end

    def new_record?
      @new_record
    end

    def add_timeline(timeline)
      @dirty_timelines = true
      @timelines << timeline
    end

    def remove_timeline(timeline)
      @dirty_timelines = true
      @timelines.delete(timeline)
    end

    def dirty_timelines?
      @dirty_timelines
    end

    def cl_changed?
      @dirty_attributes || @dirty_objects || @dirty_timelines || @dirty_events
    end

    def cl_timestamp
      timestamp
    end

    def cl_attributes
      @attributes
    end

    def cl_objects
      objects.inject({}) { |hsh, (key, objs)| hsh.update(key => objs.keys) }
    end

    def cl_timelines
      timelines
    end

    def cl_subevents
      events.keys
    end

    def casted_events
      events.values.map { |obj|
        obj.is_a?(event_class) ? obj : event_class.new.from_cl(obj)
      }.sort
    end

    def mark_clean
      @dirty_attributes = false
      @dirty_objects    = false
      @dirty_timelines  = false
      @dirty_events     = false
    end

    def set_cl_url(url)
      @cl_url = url
    end

    def clear_new_record
      @new_record = false
    end

    def save
      return false unless cl_changed?
      save_subevents

      (new_record? ? publish : update).tap do |url|
        set_cl_url(url)
        clear_new_record
        mark_clean
      end
    end

    def save_subevents
      casted_events.each do |event|
        event.parent = cl_key<commit_msg>Save subevents _after_ the parent event.<commit_after>require 'active_support/concern'
require 'active_support/core_ext/class'
require 'active_support/inflector'
require 'active_model'

module Chronologic::Client::Event

  extend ActiveSupport::Concern

  included do
    # XXX Protect this?
    attr_accessor :new_record
    attr_accessor :objects, :events
    attr_accessor :cl_key, :timestamp

    attr_reader :timelines
    attr_reader :cl_url
  end

  module ClassMethods
    def attribute(name)
      self.class_eval <<-RUBY, __FILE__, __LINE__
        attr_accessor :attributes

        def #{name}
          @attributes[:#{name}]
        end

        def #{name}=(val)
          @dirty_attributes = true
          @attributes[:#{name}] = val
        end
      RUBY
    end

    def objects(name, klass)
      self.class_eval <<-RUBY, __FILE__, __LINE__
        # SLOW this potentially converts hashes to the klass every time.
        # Could memoize this sometime in the future.
        def #{name}
          objects.
            fetch('#{name}', {}).
            values.map { |obj|
              obj.is_a?(#{klass}) ? obj : #{klass}.new.from_cl(obj)
            }.sort
        end

        def add_#{name.to_s.singularize}(obj)
          @dirty_objects = true
          objects['#{name}'][obj.to_cl_key] = obj
        end

        def remove_#{name.to_s.singularize}(obj)
          @dirty_objects = true
          objects['#{name}'].delete(obj.to_cl_key)
        end
      RUBY
    end

    def events(name, klass)
      self.class_eval <<-RUBY, __FILE__, __LINE__
        def #{name}
          casted_events
        end

        def add_#{name.to_s.singularize}(obj)
          @dirty_events = true
          events[obj.to_cl_key] = obj
        end

        def remove_#{name.to_s.singularize}(obj)
          @dirty_events = true
          events.delete(obj.to_cl_key)
        end

        def event_class
          #{klass}
        end
      RUBY
    end

    def fetch(event_url)
      obj = connection.fetch(event_url)
      raise 'Event not found' if obj.nil?
      new.from(obj)
    end

    # HAX
    def connection
      Chronologic::Client::Connection.instance
    end
  end

  module InstanceMethods

    def initialize
      @attributes = {}
      @new_record = true
      @dirty_attributes = false
      @dirty_timelines = false
      @dirty_objects = false
      @dirty_events = false # XXX merge all these dirty flags
      @objects = Hash.new { |h, k| h[k] = {} }
      @events = Hash.new { |h, k| h[k] = {} }
      @timelines = []
      super
    end

    def connection
      Chronologic::Client::Connection.instance
    end

    def parent
      @attributes['parent']
    end

    def parent=(parent_key)
      @attributes['parent'] = parent_key
      add_timeline(parent_key)
    end

    def parent_key
      @attributes['parent']
    end

    def new_record?
      @new_record
    end

    def add_timeline(timeline)
      @dirty_timelines = true
      @timelines << timeline
    end

    def remove_timeline(timeline)
      @dirty_timelines = true
      @timelines.delete(timeline)
    end

    def dirty_timelines?
      @dirty_timelines
    end

    def cl_changed?
      @dirty_attributes || @dirty_objects || @dirty_timelines || @dirty_events
    end

    def cl_timestamp
      timestamp
    end

    def cl_attributes
      @attributes
    end

    def cl_objects
      objects.inject({}) { |hsh, (key, objs)| hsh.update(key => objs.keys) }
    end

    def cl_timelines
      timelines
    end

    def cl_subevents
      events.keys
    end

    def casted_events
      events.values.map { |obj|
        obj.is_a?(event_class) ? obj : event_class.new.from_cl(obj)
      }.sort
    end

    def mark_clean
      @dirty_attributes = false
      @dirty_objects    = false
      @dirty_timelines  = false
      @dirty_events     = false
    end

    def set_cl_url(url)
      @cl_url = url
    end

    def clear_new_record
      @new_record = false
    end

    def save
      return false unless cl_changed?

      result = (new_record? ? publish : update).tap do |url|
        set_cl_url(url)
        clear_new_record
        mark_clean
        url
      end

      save_subevents

      result
    end

    def save_subevents
      casted_events.each do |event|
        event.parent = cl_key
{'fraction_non_alphanumeric': 0.09005235602094241, 'fraction_numerical': 0.0, 'mean_word_length': 2.017199017199017, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 5, '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': '3374137', 'n_tokens_mistral': 2745, 'n_tokens_neox': 2670, 'n_words': 627}