<commit_before>﻿/* 
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 * 
 * Copyright (c) 2015, MPL <NAME> <EMAIL>
 */

using System;

namespace Pablo
{
    /// <summary>
    /// Represents a managed property.
    /// </summary>
    public sealed class HierarchicalProperty
    {
        readonly Func<string, object> _parser;
        readonly Func<object> _defaultFactory;
        readonly Func<object, object> _cloner;

        /// <summary>
        /// The name of the property.
        /// </summary>
        public string Name { get; }

        /// <summary>
        /// The type of the property.
        /// </summary>
        public Type Type { get; }

        /// <summary>
        /// Indicates whether this property can be inherited.
        /// </summary>
        public bool IsInheritable { get; }

        /// <summary>
        /// The type that registered this property.
        /// </summary>
        public Type Owner { get; }

        /// <summary>
        /// Get the default value of this property.
        /// </summary>
        /// <exception cref="PropertyException">Default generation failed</exception>
        public object Default
        {
            get
            {
                // Automatically instantiate the default value if the property is value type
                // and no generator is specified.
                if (_defaultFactory == null)
                    return Type.IsValueType ? Activator.CreateInstance(Type) : null;

                object defaultObject;

                try
                {
                    defaultObject = _defaultFactory();
                }
                catch (Exception e)
                {
                    // The factory method threw an exception.
                    throw new PropertyException("The default generator function threw an exception.", e, this);
                }
                // Makes sure the factory generated an object of the correct type.
                if (!Type.IsInstanceOfType(defaultObject))
                    throw new PropertyException("The default generator function return type does not match the property type", null, this);
                return defaultObject;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is parsable.
        /// </summary>
        /// <value><c>true</c> if this instance is parsable; otherwise, <c>false</c>.</value>
        public bool IsParsable
        {
            get
            {
                // The underlying type in case it's nullable
                var underlyingType = Nullable.GetUnderlyingType(Type);
                // Has parser method
                return _parser != null
                // Is String
                || Type == typeof(string)
                // Is primitive 
                || Type.IsPrimitive
                // Or Convert understands it
                || Type == typeof(DateTime)
                || Type == typeof(DateTimeOffset)
                // Is Enum
                || Type.IsEnum
                // Is Nullable with...
                || (underlyingType != null
                // Primitive underlying type
                && (underlyingType.IsPrimitive
                // Or underlying type understood by convert
                || underlyingType == typeof(DateTime)
                || underlyingType == typeof(DateTimeOffset)));
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is cloneable.
        /// </summary>
        /// <value><c>true</c> if this instance is cloneable; otherwise, <c>false</c>.</value>
        public bool IsCloneable => _cloner != null
                                   // Is String
                                   || Type == typeof(string)
                                   // Is value type 
                                   || Type.IsValueType
                                   // Is Enum
                                   || Type.IsEnum
                                   // Implements ICloneable
                                   || typeof(ICloneable).IsAssignableFrom(Type);

        /// <summary>
        /// Initializes a new instance of the <see cref="Pablo.HierarchicalProperty"/> class.
        /// </summary>
        internal HierarchicalProperty(Type owner,
                                      string name,
                                      Type type,
                                      bool inheritable,
                                      Func<string, object> parser,
                                      Func<object> defaultFactory,
                                      Func<object, object> cloner)
        {
            if (owner == null)
                throw new ArgumentNullException(nameof(owner));

            if (type == null)
                throw new ArgumentNullException(nameof(type));

            if (name == null)
                throw new ArgumentNullException(nameof(name));

            if (string.IsNullOrWhiteSpace(name))
                throw new ArgumentException("name must have value. null or whitespace is not acceptable.", nameof(name));

            Name = name;
            Type = type;
            IsInheritable = inheritable;
            Owner = owner;
            _parser = parser;
            _defaultFactory = defaultFactory;
            _cloner = cloner;
        }

        /// <summary>
        /// Parses an instance of this property from the provided string.
        /// </summary>
        /// <exception cref="ArgumentNullException">s is null</exception>
        /// <exception cref="PropertyException">Parsing failed</exception>
        public object Parse(string s)
        {
            if (s == null)
                throw new ArgumentNullException(nameof(s));

            // Automate parsing (or throw exception) in case a method is not provided.
            if (_parser == null)
            {
                // Return the s itself if the property is string too.
                if (Type == typeof(string))
                    return s;

                try
                {
                    // Parse as enum if the property is enum.
                    if (Type.IsEnum)
                        return Enum.Parse(Type, s, true);

                    // In case the property is nullable...
                    var nullableType = Nullable.GetUnderlyingType(Type);
                    if (nullableType != null) // Make sure it's nullable.
                        if (nullableType.IsPrimitive || // Make sure its a type that Convert understands.
                            nullableType == typeof(DateTime) ||
                            nullableType == typeof(DateTimeOffset))
                            return Convert.ChangeType(s, nullableType);<commit_msg>Improvement to xml documentations of HierarchicalProperty<commit_after>﻿/* 
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 * 
 * Copyright (c) 2015, MPL <NAME> <EMAIL>
 */

using System;

namespace Pablo
{
    /// <summary>
    /// Represents a managed property.
    /// </summary>
    public sealed class HierarchicalProperty
    {
        /// <summary>
        /// The parser function used to parse properties represented by this <see cref="HierarchicalProperty"/>.
        /// </summary>
        readonly Func<string, object> _parser;

        /// <summary>
        /// The parser function used to generate default values for properties represented by this <see cref="HierarchicalProperty"/>.
        /// </summary>
        readonly Func<object> _defaultFactory;

        /// <summary>
        /// The parser function used to clone properties represented by this <see cref="HierarchicalProperty"/>.
        /// </summary>
        readonly Func<object, object> _cloner;

        /// <summary>
        /// The name of the <see cref="HierarchicalProperty"/>.
        /// </summary>
        public string Name { get; }

        /// <summary>
        /// The type of the <see cref="HierarchicalProperty"/>.
        /// </summary>
        public Type Type { get; }

        /// <summary>
        /// Indicates whether this <see cref="HierarchicalProperty"/> can be inherited.
        /// </summary>
        public bool IsInheritable { get; }

        /// <summary>
        /// The type that registered this <see cref="HierarchicalProperty"/>.
        /// </summary>
        public Type Owner { get; }

        /// <summary>
        /// Get the default value of this <see cref="HierarchicalProperty"/>.
        /// </summary>
        /// <exception cref="PropertyException">Default generation failed</exception>
        public object Default
        {
            get
            {
                // Automatically instantiate the default value if the property is value type
                // and no generator is specified.
                if (_defaultFactory == null)
                    return Type.IsValueType ? Activator.CreateInstance(Type) : null;

                object defaultObject;

                try
                {
                    defaultObject = _defaultFactory();
                }
                catch (Exception e)
                {
                    // The factory method threw an exception.
                    throw new PropertyException("The default generator function threw an exception.", e, this);
                }
                // Makes sure the factory generated an object of the correct type.
                if (!Type.IsInstanceOfType(defaultObject))
                    throw new PropertyException("The default generator function return type does not match the property type", null, this);
                return defaultObject;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is parsable.
        /// </summary>
        /// <value><c>true</c> if this instance is parsable; otherwise, <c>false</c>.</value>
        public bool IsParsable
        {
            get
            {
                // The underlying type in case it's nullable
                var underlyingType = Nullable.GetUnderlyingType(Type);
                // Has parser method
                return _parser != null
                // Is String
                || Type == typeof(string)
                // Is primitive 
                || Type.IsPrimitive
                // Or Convert understands it
                || Type == typeof(DateTime)
                || Type == typeof(DateTimeOffset)
                // Is Enum
                || Type.IsEnum
                // Is Nullable with...
                || (underlyingType != null
                // Primitive underlying type
                && (underlyingType.IsPrimitive
                // Or underlying type understood by convert
                || underlyingType == typeof(DateTime)
                || underlyingType == typeof(DateTimeOffset)));
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is cloneable.
        /// </summary>
        /// <value><c>true</c> if this instance is cloneable; otherwise, <c>false</c>.</value>
        public bool IsCloneable => _cloner != null
                                   // Is String
                                   || Type == typeof(string)
                                   // Is value type 
                                   || Type.IsValueType
                                   // Is Enum
                                   || Type.IsEnum
                                   // Implements ICloneable
                                   || typeof(ICloneable).IsAssignableFrom(Type);

        /// <summary>
        /// Initializes a new instance of the <see cref="HierarchicalProperty"/> class.
        /// </summary>
        internal HierarchicalProperty(Type owner,
                                      string name,
                                      Type type,
                                      bool inheritable,
                                      Func<string, object> parser,
                                      Func<object> defaultFactory,
                                      Func<object, object> cloner)
        {
            if (owner == null)
                throw new ArgumentNullException(nameof(owner));

            if (type == null)
                throw new ArgumentNullException(nameof(type));

            if (name == null)
                throw new ArgumentNullException(nameof(name));

            if (string.IsNullOrWhiteSpace(name))
                throw new ArgumentException("name must have value. null or whitespace is not acceptable.", nameof(name));

            Name = name;
            Type = type;
            IsInheritable = inheritable;
            Owner = owner;
            _parser = parser;
            _defaultFactory = defaultFactory;
            _cloner = cloner;
        }

        /// <summary>
        /// Parses an instance of this <see cref="HierarchicalProperty"/> from the provided <see cref="string"/>.
        /// </summary>
        /// <exception cref="ArgumentNullException">s is null</exception>
        /// <exception cref="PropertyException">Parsing failed</exception>
        public object Parse(string s)
        {
            if (s == null)
                throw new ArgumentNullException(nameof(s));

            // Automate parsing (or throw exception) in case a method is not provided.
            if (_parser == null)
            {
                // Return the s itself if the property is string too.
                if (Type == typeof(string))
                    return s;

                try
                {
                    // Parse as enum if the property is enum.
                    if (Type.IsEnum)
                        return Enum.Parse(Type, s, true);

                    // In case the property is nullable...
                    var nullableType = Nullable.GetUnderlyingType(Type);
                    if (nullableType != null) // Make sure it's nullable.
                        if (nullableType.IsPrimitive || // Make sure its a type that Convert understands.
                            nullableType == typeof(DateTime) ||
                            nullableType == typeof(DateTimeOffset))
                            return Convert.ChangeType(s, nullableType);
{'fraction_non_alphanumeric': 0.09270433351618211, 'fraction_numerical': 0.0010970927043335162, 'mean_word_length': 1.2742866053329176, 'pattern_counts': {'":': 0, '<': 113, '<?xml version=': 0, '>': 115, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2363836', 'n_tokens_mistral': 3383, 'n_tokens_neox': 3162, 'n_words': 1066}