<commit_before>module RDF; class Literal
  ##
  # Shared methods and class ancestry for date, time, and dateTime literal classes.
  #
  # @since 3.1
  class Temporal < Literal
    # Matches either -10:00 or -P1H0M forms
    ZONE_GRAMMAR  = %r(\A
       (?:(?<si>[+-])(?<hr>\d{2}):(?:(?<mi>\d{2}))?)
      |(?:(?<si>-)?PT(?<hr>\d{1,2})H(?:(?<mi>\d{1,2})M)?)
    \z)x.freeze

    ##
    # Compares this literal to `other` for sorting purposes.
    #
    # @param  [Object] other
    # @return [Integer] `-1`, `0`, or `1`
    def <=>(other)
      # If lexically invalid, use regular literal testing
      return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)
      return super unless other.is_a?(self.class)
      @object <=> other.object
    end

    ##
    # Returns `true` if this literal is equal to `other`.
    #
    # @param  [Object] other
    # @return [Boolean] `true` or `false`
    # @since  0.3.0
    def ==(other)
      # If lexically invalid, use regular literal testing
      return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)

      case other
      when self.class
        self.object == other.object
      when Literal::Temporal
        false
      else
        super
      end
    end

    ##
    # Converts this literal into its canonical lexical representation.
    # with date and time normalized to UTC.
    #
    # @return [RDF::Literal] `self`
    # @see    http://www.w3.org/TR/xmlschema11-2/#dateTime
    def canonicalize!
      if self.valid? && @zone && @zone != '+00:00'
        adjust_to_timezone!
      else
        @string = nil
      end
      self
    end

    ##
    # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone.
    #
    # @return [RDF::Literal]
    def tz
      RDF::Literal(@zone == "+00:00" ? 'Z' : @zone)
    end

    ##
    # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option.
    #
    # @return [Boolean]
    # @since 1.1.6
    def timezone?
      # Can only know there's a timezone from the string represntation
      md = to_s.match(self.class.const_get(:GRAMMAR))
      md && !!md[2]
    end
    alias_method :tz?, :timezone?
    alias_method :has_tz?, :timezone?
    alias_method :has_timezone?, :timezone?

    ##
    # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil`
    # if lexical form of literal does not include a timezone.
    #
    # From [fn:timezone-from-date](https://www.w3.org/TR/xpath-functions/#func-timezone-from-date).
    #
    # @return [RDF::Literal]
    # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-date
    def timezone
      if @zone
        md = @zone.match(ZONE_GRAMMAR)
        si, hr, mi = md[:si], md[:hr].to_i, md[:mi].to_i
        si = nil unless si == "-"
        res = "#{si}PT#{hr}H#{"#{mi}M" if mi > 0}"
        RDF::Literal(res, datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration"))
      end
    end

    ##
    # Returns `true` if the value adheres to the defined grammar of the
    # datatype.
    #
    # Special case for date and dateTime, for which '0000' is not a valid year
    #
    # @return [Boolean]
    # @since  0.2.1
    def valid?
      super && object && value !~ %r(\A0000)
    end

    ##
    # Does the literal representation include millisectonds?
    #
    # @return [Boolean]
    # @since 1.1.6
    def milliseconds?
      object.strftime("%L").to_i > 0
    end
    alias_method :has_milliseconds?, :milliseconds?
    alias_method :has_ms?, :milliseconds?
    alias_method :ms?, :milliseconds?

    ##
    # Returns the `timezone` of the literal. If the
    ##
    # Returns the value as a string.
    #
    # @return [String]
    def to_s
      @string || (@object.strftime(self.class.const_get(:FORMAT)).sub('.000', '') + self.tz)
    end

    ##
    # Adjust the timezone.
    #
    # From [fn:adjust-dateTime-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone)
    #
    # @overload adjust_to_timezone!
    #   Adjusts the timezone to UTC.
    #
    #   @return [Temporal] `self`
    #   @raise [RangeError] if `zone < -14*60` or `zone > 14*60`
    # @overload adjust_to_timezone!(zone)
    #   If `zone` is nil, then the timzeone component is removed.
    #
    #   Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`.
    #
    #   @param [String] zone (nil) In the form of {ZONE_GRAMMAR}.
    #   @return [Temporal] `self`
    #   @raise [RangeError] if `zone < -14*60` or `zone > 14*60`
    # @see https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone
    def adjust_to_timezone!(*args)
      zone = args.empty? ? '+00:00' : args.first
      if zone.nil?
        # Remove timezone component
        @object = self.class.new(@object.strftime(self.class.const_get(:FORMAT))).object<commit_msg>In Temporal#to_s, set `@string` if it is nil.<commit_after>module RDF; class Literal
  ##
  # Shared methods and class ancestry for date, time, and dateTime literal classes.
  #
  # @since 3.1
  class Temporal < Literal
    # Matches either -10:00 or -P1H0M forms
    ZONE_GRAMMAR  = %r(\A
       (?:(?<si>[+-])(?<hr>\d{2}):(?:(?<mi>\d{2}))?)
      |(?:(?<si>-)?PT(?<hr>\d{1,2})H(?:(?<mi>\d{1,2})M)?)
    \z)x.freeze

    ##
    # Compares this literal to `other` for sorting purposes.
    #
    # @param  [Object] other
    # @return [Integer] `-1`, `0`, or `1`
    def <=>(other)
      # If lexically invalid, use regular literal testing
      return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)
      return super unless other.is_a?(self.class)
      @object <=> other.object
    end

    ##
    # Returns `true` if this literal is equal to `other`.
    #
    # @param  [Object] other
    # @return [Boolean] `true` or `false`
    # @since  0.3.0
    def ==(other)
      # If lexically invalid, use regular literal testing
      return super unless self.valid? && (!other.respond_to?(:valid?) || other.valid?)

      case other
      when self.class
        self.object == other.object
      when Literal::Temporal
        false
      else
        super
      end
    end

    ##
    # Converts this literal into its canonical lexical representation.
    # with date and time normalized to UTC.
    #
    # @return [RDF::Literal] `self`
    # @see    http://www.w3.org/TR/xmlschema11-2/#dateTime
    def canonicalize!
      if self.valid? && @zone && @zone != '+00:00'
        adjust_to_timezone!
      else
        @string = nil
      end
      self
    end

    ##
    # Returns the timezone part of arg as a simple literal. Returns the empty string if there is no timezone.
    #
    # @return [RDF::Literal]
    def tz
      RDF::Literal(@zone == "+00:00" ? 'Z' : @zone)
    end

    ##
    # Does the literal representation include a timezone? Note that this is only possible if initialized using a string, or `:lexical` option.
    #
    # @return [Boolean]
    # @since 1.1.6
    def timezone?
      # Can only know there's a timezone from the string represntation
      md = to_s.match(self.class.const_get(:GRAMMAR))
      md && !!md[2]
    end
    alias_method :tz?, :timezone?
    alias_method :has_tz?, :timezone?
    alias_method :has_timezone?, :timezone?

    ##
    # Returns the timezone part of arg as an xsd:dayTimeDuration, or `nil`
    # if lexical form of literal does not include a timezone.
    #
    # From [fn:timezone-from-date](https://www.w3.org/TR/xpath-functions/#func-timezone-from-date).
    #
    # @return [RDF::Literal]
    # @see https://www.w3.org/TR/xpath-functions/#func-timezone-from-date
    def timezone
      if @zone
        md = @zone.match(ZONE_GRAMMAR)
        si, hr, mi = md[:si], md[:hr].to_i, md[:mi].to_i
        si = nil unless si == "-"
        res = "#{si}PT#{hr}H#{"#{mi}M" if mi > 0}"
        RDF::Literal(res, datatype: RDF::URI("http://www.w3.org/2001/XMLSchema#dayTimeDuration"))
      end
    end

    ##
    # Returns `true` if the value adheres to the defined grammar of the
    # datatype.
    #
    # Special case for date and dateTime, for which '0000' is not a valid year
    #
    # @return [Boolean]
    # @since  0.2.1
    def valid?
      super && object && value !~ %r(\A0000)
    end

    ##
    # Does the literal representation include millisectonds?
    #
    # @return [Boolean]
    # @since 1.1.6
    def milliseconds?
      object.strftime("%L").to_i > 0
    end
    alias_method :has_milliseconds?, :milliseconds?
    alias_method :has_ms?, :milliseconds?
    alias_method :ms?, :milliseconds?

    ##
    # Returns the `timezone` of the literal. If the
    ##
    # Returns the value as a string.
    #
    # @return [String]
    def to_s
      @string ||= (@object.strftime(self.class.const_get(:FORMAT)).sub('.000', '') + self.tz)
    end

    ##
    # Adjust the timezone.
    #
    # From [fn:adjust-dateTime-to-timezone](https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone)
    #
    # @overload adjust_to_timezone!
    #   Adjusts the timezone to UTC.
    #
    #   @return [Temporal] `self`
    #   @raise [RangeError] if `zone < -14*60` or `zone > 14*60`
    # @overload adjust_to_timezone!(zone)
    #   If `zone` is nil, then the timzeone component is removed.
    #
    #   Otherwise, the timezone is set based on the difference between the current timezone offset (if any) and `zone`.
    #
    #   @param [String] zone (nil) In the form of {ZONE_GRAMMAR}.
    #   @return [Temporal] `self`
    #   @raise [RangeError] if `zone < -14*60` or `zone > 14*60`
    # @see https://www.w3.org/TR/xpath-functions/#func-adjust-dateTime-to-timezone
    def adjust_to_timezone!(*args)
      zone = args.empty? ? '+00:00' : args.first
      if zone.nil?
        # Remove timezone component
        @object = self.class.new(@object.strftime(self.class.const_get(:FORMAT))).object
{'fraction_non_alphanumeric': 0.14322890601541388, 'fraction_numerical': 0.016815133620258233, 'mean_word_length': 2.485176142309034, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 27, 'https://': 8, 'lorem ipsum': 0, 'www.': 12, 'xml': 2}, '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': '226250', 'n_tokens_mistral': 3539, 'n_tokens_neox': 3379, 'n_words': 918}