<commit_before>#
# Myrrha -- the missing coercion framework for Ruby
#
module Myrrha
  
  #
  # Raised when a coercion fails
  #
  class Error < StandardError; end
  
  #
  # Builds a set of coercions rules. 
  #
  # Example:
  #
  #   rules = Myrrha.coercions do |c|
  #     c.coercion String, Integer, lambda{|s,t| Integer(s)}
  #     #
  #     # [...]
  #     #
  #     c.fallback String, lambda{|s,t| ... }
  #   end
  #
  def self.coercions(&block)
    Coercions.new(&block)
  end
    
  # 
  # Defines a set of coercion rules
  #
  class Coercions
    
    #
    # Creates an empty list of coercion rules
    #
    def initialize
      @rules = []
      @fallbacks = []
      yield(self) if block_given?
    end
    
    #
    # Appends the list of rules with new ones.
    #
    # New coercion and fallback rules will be put after the already existing 
    # ones, in both case. However, coercion rules always stay before fallback
    # ones.    
    #
    # Example:
    #
    #   rules = Myrrha.coercions do ... end
    #   rules.append do |r|
    #     r.coercion String, Float, lambda{|v,t| Float(t)}
    #   end
    #
    def append
      yield(self) if block_given?
    end
    
    #
    # Adds a coercion rule from a source to a target domain.
    #
    # The conversion can be provided through `converter` or via a block
    # directly. See main documentation about recognized converters.
    #
    # Example:
    #
    #   Myrrha.coercions do |r|
    #     
    #     # With an explicit proc
    #     r.coercion String, Integer, lambda{|v,t| 
    #       Integer(v)
    #     } 
    #
    #     # With an implicit proc
    #     r.coercion(String, Float) do |v,t| 
    #       Float(v)
    #     end
    #
    #   end
    #
    # @param source [Domain] a source domain (mimicing Domain) 
    # @param target [Domain] a target domain (mimicing Domain)
    # @param converter [Converter] an optional converter (mimic Converter)
    # @param convproc [Proc] used when converter is not specified
    # @return self
    #
    def coercion(source, target, converter = nil, &convproc)
      @rules << [source, target, converter || convproc]
      self
    end
    
    #
    # Adds a fallback rule for a source domain.
    #
    # Conventions about converters are exactly the same as with coercion.
    #
    # Example:
    #
    #   Myrrha.coercions do |r|
    #     
    #     # With an explicit proc 
    #     r.fallback String, lambda{|v,t| 
    #       # the user wants _v_ to be converted to a value of domain _t_
    #     }
    #
    #   end
    #
    # @param source [Domain] a source domain (mimic Domain) 
    # @param converter [Converter] an optional converter (mimic Converter)
    # @param convproc [Proc] used when converter is not specified
    # @return self
    #
    def fallback(source, converter = nil, &convproc)
      @fallbacks << [source, converter || convproc]
    end
    
    #
    # Coerces `value` to an element of `target_domain`
    #
    # This method tries each coercion rule, then each fallback in turn. Rules 
    # for which source and target domain match are executed until one succeeds.
    # A Myrrha::Error is raised if no rule matches or executes successfuly.
    #
    # @param [Object] value any ruby value
    # @param [Domain] target_domain a target domain to convert to (mimic Domain)
    # @return self
    #
    def coerce(value, target_domain)
      return value if belongs_to?(value, target_domain)
      error = nil
      @rules.each do |from,to,converter|
        next unless belongs_to?(value, from)
        next unless subdomain?(to, target_domain)
        begin
          return convert(value, target_domain, converter)
        rescue => ex
          error = ex.message unless error
        end
      end
      @fallbacks.each do |from,converter|
        next unless belongs_to?(value, from)
        begin
          return convert(value, target_domain, converter)
        rescue => ex
          error = ex.message unless error
        end
      end
      msg = "Unable to coerce `#{value}` to #{target_domain}"
      msg += " (#{error})" if error
      raise Error, msg
    end
    
    #
    # Returns true if `value` can be considered as a valid element of the 
    # domain `domain`, false otherwise.<commit_msg>Rules and fallbacks could be treated similarly<commit_after>#
# Myrrha -- the missing coercion framework for Ruby
#
module Myrrha
  
  #
  # Raised when a coercion fails
  #
  class Error < StandardError; end
  
  #
  # Builds a set of coercions rules. 
  #
  # Example:
  #
  #   rules = Myrrha.coercions do |c|
  #     c.coercion String, Integer, lambda{|s,t| Integer(s)}
  #     #
  #     # [...]
  #     #
  #     c.fallback String, lambda{|s,t| ... }
  #   end
  #
  def self.coercions(&block)
    Coercions.new(&block)
  end
    
  # 
  # Defines a set of coercion rules
  #
  class Coercions
    
    #
    # Creates an empty list of coercion rules
    #
    def initialize
      @rules = []
      @fallbacks = []
      yield(self) if block_given?
    end
    
    #
    # Appends the list of rules with new ones.
    #
    # New coercion and fallback rules will be put after the already existing 
    # ones, in both case. However, coercion rules always stay before fallback
    # ones.    
    #
    # Example:
    #
    #   rules = Myrrha.coercions do ... end
    #   rules.append do |r|
    #     r.coercion String, Float, lambda{|v,t| Float(t)}
    #   end
    #
    def append
      yield(self) if block_given?
    end
    
    #
    # Adds a coercion rule from a source to a target domain.
    #
    # The conversion can be provided through `converter` or via a block
    # directly. See main documentation about recognized converters.
    #
    # Example:
    #
    #   Myrrha.coercions do |r|
    #     
    #     # With an explicit proc
    #     r.coercion String, Integer, lambda{|v,t| 
    #       Integer(v)
    #     } 
    #
    #     # With an implicit proc
    #     r.coercion(String, Float) do |v,t| 
    #       Float(v)
    #     end
    #
    #   end
    #
    # @param source [Domain] a source domain (mimicing Domain) 
    # @param target [Domain] a target domain (mimicing Domain)
    # @param converter [Converter] an optional converter (mimic Converter)
    # @param convproc [Proc] used when converter is not specified
    # @return self
    #
    def coercion(source, target, converter = nil, &convproc)
      @rules << [source, target, converter || convproc]
      self
    end
    
    #
    # Adds a fallback rule for a source domain.
    #
    # Conventions about converters are exactly the same as with coercion.
    #
    # Example:
    #
    #   Myrrha.coercions do |r|
    #     
    #     # With an explicit proc 
    #     r.fallback String, lambda{|v,t| 
    #       # the user wants _v_ to be converted to a value of domain _t_
    #     }
    #
    #   end
    #
    # @param source [Domain] a source domain (mimic Domain) 
    # @param converter [Converter] an optional converter (mimic Converter)
    # @param convproc [Proc] used when converter is not specified
    # @return self
    #
    def fallback(source, converter = nil, &convproc)
      @fallbacks << [source, nil, converter || convproc]
    end
    
    #
    # Coerces `value` to an element of `target_domain`
    #
    # This method tries each coercion rule, then each fallback in turn. Rules 
    # for which source and target domain match are executed until one succeeds.
    # A Myrrha::Error is raised if no rule matches or executes successfuly.
    #
    # @param [Object] value any ruby value
    # @param [Domain] target_domain a target domain to convert to (mimic Domain)
    # @return self
    #
    def coerce(value, target_domain)
      return value if belongs_to?(value, target_domain)
      error = nil
      (@rules + @fallbacks).each do |from,to,converter|
        next unless from.nil? or belongs_to?(value, from)
        next unless to.nil?   or subdomain?(to, target_domain)
        begin
          return convert(value, target_domain, converter)
        rescue => ex
          error = ex.message unless error
        end
      end
      msg = "Unable to coerce `#{value}` to #{target_domain}"
      msg += " (#{error})" if error
      raise Error, msg
    end
    
    #
    # Returns true if `value` can be considered as a valid element of the 
    # domain `domain`, false otherwise.
{'fraction_non_alphanumeric': 0.09187195049387124, 'fraction_numerical': 0.0, 'mean_word_length': 2.0716374269005846, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 6, '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': '2702207', 'n_tokens_mistral': 2695, 'n_tokens_neox': 2585, 'n_words': 883}