<commit_before>require "active_support/core_ext/class/attribute"
require "active_support/core_ext/class/subclasses"
require "kalimba/persistence" # fallback to abstract backend
require "kalimba/validations"
require "kalimba/callbacks"
require "kalimba/reflection"
require "kalimba/attribute_assignment"
require "kalimba/localized_attributes"

module Kalimba
  class Resource
    include ActiveModel::AttributeMethods
    include ActiveModel::Dirty
    include ActiveModel::Conversion

    extend Kalimba::Reflection
    include Kalimba::AttributeAssignment
    include Kalimba::LocalizedAttributes

    include Kalimba::Persistence.backend

    # Subject URI if the resource
    attr_reader :subject

    # Hash{String => any} with the resource attributes
    #
    # @note
    #   Do not modify it directly, unless you know what you are doing!
    attr_accessor :attributes

    # Properties with their options
    #
    # @return [Hash{String => Hash}]
    class_attribute :properties, instance_writer: false, instance_reader: false
    self.properties = {}

    class << self
      # Create a new record with the given subject URI
      #
      # @note
      #   In the world of RDF a resource cannot be instantly defined as "new",
      #   because any arbitrary subject that you specify might be already present
      #   in the storage.
      #   So you can use ID of an existing resource as well.
      #
      #   Don't forget to {#reload} the resource, if you need its actual attributes
      #   (if any) pulled from the storage.
      #
      # @note
      #   The resource ID that you supply will be added as an URI
      #   fragment to base_uri (or raise an error if base_uri is not defined).
      #
      # @param [String] rid ID to use for the resource
      # @param [Hash<[Symbol, String] => Any>] params (see {RDFSResource#initialize})
      # @return [Object] instance of the model
      def for(rid, params = {})
        new(params.merge(:_subject => rid))
      end

      # Type URI of RDFS class
      #
      # @note Can be set only once
      #
      # @param [URI, String] uri
      # @return [URI]
      def type(uri = nil)
        if uri
          @type ||= URI(uri)
        else
          @type
        end
      end

      # Base URI for the resource
      #
      # @param [String, URI] uri
      # @return [URI]
      def base_uri(uri = nil)
        @base_uri ||= uri && URI(uri.to_s.sub(/\/?$/, "/"))
      end

      # Property declaration
      #
      # Model attributes should be declared using `property`.
      # Two mandatory parameters are `:predicate` and `:datatype`,
      # that can accept URIs as URI or String objects.
      # You can also use "NS::" namespaces provided by `xml_schema` gem.
      #
      # @param [Symbol, String] name
      # @param [Hash] params
      # @option params [String, URI] :predicate
      # @option params [String, URI, Symbol] :datatype
      # @option params [Boolean] :collection
      # @return [void]
      def property(name, params = {})
        name = name.to_s

        params[:predicate] = URI(params[:predicate])
        association_class = Kalimba::Resource.from_datatype(params[:datatype])
        if association_class
          params[:datatype] = association_class
          if params[:collection]
            define_collection(name, association_class)
          else
            define_resource(name, association_class)
          end
        else
          params[:datatype] = URI(params[:datatype])
        end

        self.properties[name] = params

        define_attribute_method name if self.is_a?(Class)

        class_eval <<-HERE, __FILE__, __LINE__
          def #{name}=(value)
            write_attribute "#{name}", value
          end
        HERE

        if localizable_property?(name)
          class_eval <<-HERE, __FILE__, __LINE__
            def localized_#{name.pluralize}
              @localized_#{name.pluralize} ||= {}
            end
          HERE
        end
      end

      # Collection definition
      #
      # "Has-many" relations/collections are declared with help of `has_many` method.
      # It accepts the same parameters as `property` (basically, it is an alias to
      # `property name, ..., collection: true`).
      # Additionally, you can specify `:datatype` as a name of another model,
      # as seen below. If you specify datatype as an URI, it will be automatically
      # resolved to either a model (having the same `type`) or anonymous class.
      #
      # @example
      #   has_many :friends, :predicate => "http://schema.org/Person", :datatype => :Person
      #
      # You don't have to treat `has_many` as an association with other models, however.
      # It is acceptable to declare a collection of strings or any other resources<commit_msg>removed obsolete check<commit_after>require "active_support/core_ext/class/attribute"
require "active_support/core_ext/class/subclasses"
require "kalimba/persistence" # fallback to abstract backend
require "kalimba/validations"
require "kalimba/callbacks"
require "kalimba/reflection"
require "kalimba/attribute_assignment"
require "kalimba/localized_attributes"

module Kalimba
  class Resource
    include ActiveModel::AttributeMethods
    include ActiveModel::Dirty
    include ActiveModel::Conversion

    extend Kalimba::Reflection
    include Kalimba::AttributeAssignment
    include Kalimba::LocalizedAttributes

    include Kalimba::Persistence.backend

    # Subject URI if the resource
    attr_reader :subject

    # Hash{String => any} with the resource attributes
    #
    # @note
    #   Do not modify it directly, unless you know what you are doing!
    attr_accessor :attributes

    # Properties with their options
    #
    # @return [Hash{String => Hash}]
    class_attribute :properties, instance_writer: false, instance_reader: false
    self.properties = {}

    class << self
      # Create a new record with the given subject URI
      #
      # @note
      #   In the world of RDF a resource cannot be instantly defined as "new",
      #   because any arbitrary subject that you specify might be already present
      #   in the storage.
      #   So you can use ID of an existing resource as well.
      #
      #   Don't forget to {#reload} the resource, if you need its actual attributes
      #   (if any) pulled from the storage.
      #
      # @note
      #   The resource ID that you supply will be added as an URI
      #   fragment to base_uri (or raise an error if base_uri is not defined).
      #
      # @param [String] rid ID to use for the resource
      # @param [Hash<[Symbol, String] => Any>] params (see {RDFSResource#initialize})
      # @return [Object] instance of the model
      def for(rid, params = {})
        new(params.merge(:_subject => rid))
      end

      # Type URI of RDFS class
      #
      # @note Can be set only once
      #
      # @param [URI, String] uri
      # @return [URI]
      def type(uri = nil)
        if uri
          @type ||= URI(uri)
        else
          @type
        end
      end

      # Base URI for the resource
      #
      # @param [String, URI] uri
      # @return [URI]
      def base_uri(uri = nil)
        @base_uri ||= uri && URI(uri.to_s.sub(/\/?$/, "/"))
      end

      # Property declaration
      #
      # Model attributes should be declared using `property`.
      # Two mandatory parameters are `:predicate` and `:datatype`,
      # that can accept URIs as URI or String objects.
      # You can also use "NS::" namespaces provided by `xml_schema` gem.
      #
      # @param [Symbol, String] name
      # @param [Hash] params
      # @option params [String, URI] :predicate
      # @option params [String, URI, Symbol] :datatype
      # @option params [Boolean] :collection
      # @return [void]
      def property(name, params = {})
        name = name.to_s

        params[:predicate] = URI(params[:predicate])
        association_class = Kalimba::Resource.from_datatype(params[:datatype])
        if association_class
          params[:datatype] = association_class
          if params[:collection]
            define_collection(name, association_class)
          else
            define_resource(name, association_class)
          end
        else
          params[:datatype] = URI(params[:datatype])
        end

        self.properties[name] = params

        define_attribute_method name

        class_eval <<-HERE, __FILE__, __LINE__
          def #{name}=(value)
            write_attribute "#{name}", value
          end
        HERE

        if localizable_property?(name)
          class_eval <<-HERE, __FILE__, __LINE__
            def localized_#{name.pluralize}
              @localized_#{name.pluralize} ||= {}
            end
          HERE
        end
      end

      # Collection definition
      #
      # "Has-many" relations/collections are declared with help of `has_many` method.
      # It accepts the same parameters as `property` (basically, it is an alias to
      # `property name, ..., collection: true`).
      # Additionally, you can specify `:datatype` as a name of another model,
      # as seen below. If you specify datatype as an URI, it will be automatically
      # resolved to either a model (having the same `type`) or anonymous class.
      #
      # @example
      #   has_many :friends, :predicate => "http://schema.org/Person", :datatype => :Person
      #
      # You don't have to treat `has_many` as an association with other models, however.
      # It is acceptable to declare a collection of strings or any other resources
{'fraction_non_alphanumeric': 0.09015025041736227, 'fraction_numerical': 0.0, 'mean_word_length': 2.3821453775582215, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3707368', 'n_tokens_mistral': 2653, 'n_tokens_neox': 2617, 'n_words': 919}