Class: Puppet::Pops::Types::TypeMismatchDescriber Private

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/pops/types/type_mismatch_describer.rb

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Defined Under Namespace

Classes: UnresolvedTypeFinder

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.describe_signatures(closure, signatures, args_tuple) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



505
506
507
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 505

def self.describe_signatures(closure, signatures, args_tuple)
  singleton.describe_signatures(closure, signatures, args_tuple)
end

.singletonObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



509
510
511
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 509

def self.singleton
  @singleton ||= new
end

.validate_default_parameter(subject, param_name, param_type, value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



501
502
503
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 501

def self.validate_default_parameter(subject, param_name, param_type, value)
  singleton.validate_default_parameter(subject, param_name, param_type, value)
end

.validate_parameters(subject, params_struct, given_hash, missing_ok = false) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



497
498
499
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 497

def self.validate_parameters(subject, params_struct, given_hash, missing_ok = false)
  singleton.validate_parameters(subject, params_struct, given_hash, missing_ok)
end

Instance Method Details

#describe(expected, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



999
1000
1001
1002
1003
1004
1005
1006
1007
1008
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 999

def describe(expected, actual, path)
  ures_finder = UnresolvedTypeFinder.new
  expected.accept(ures_finder, nil)
  unresolved = ures_finder.unresolved
  if unresolved
    [UnresolvedTypeReference.new(path, unresolved)]
  else
    internal_describe(expected.normalize, expected, actual, path)
  end
end

#describe_argument_tuple(expected, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



892
893
894
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 892

def describe_argument_tuple(expected, actual, path)
  describe_tuple(expected, expected, actual, path, CountMismatch)
end

#describe_mismatch(name, expected, actual, tense = :ignored) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Describe a confirmed mismatch using present tense

Parameters:

  • name (String)

    name of mismatch

  • expected (PAnyType)

    expected type

  • actual (PAnyType)

    actual type

  • tense (Symbol) (defaults to: :ignored)

    deprecated and ignored



550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 550

def describe_mismatch(name, expected, actual, tense = :ignored)
  tense_deprecated unless tense == :ignored
  errors = describe(expected, actual, [SubjectPathElement.new(name)])
  case errors.size
  when 0
    ''
  when 1
    errors[0].format.strip
  else
    errors.map(&:format).join("\n ")
  end
end

#describe_no_block_arguments(signature, atypes, path, expected_size, actual_size, arg_count) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 718

def describe_no_block_arguments(signature, atypes, path, expected_size, actual_size, arg_count)
  # not assignable if the number of types in actual is outside number of types in expected
  if expected_size.assignable?(actual_size)
    etypes = signature.type.param_types.types
    enames = signature.parameter_names
    arg_count.times do |index|
      adx = index >= etypes.size ? etypes.size - 1 : index
      etype = etypes[adx]
      unless etype.assignable?(atypes[index])
        descriptions = describe(etype, atypes[index], path + [ParameterPathElement.new(enames[adx])])
        return descriptions unless descriptions.empty?
      end
    end
    EMPTY_ARRAY
  else
    [CountMismatch.new(path, expected_size, actual_size)]
  end
end

#describe_PAnyType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



979
980
981
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 979

def describe_PAnyType(expected, original, actual, path)
  expected.assignable?(actual) ? EMPTY_ARRAY : [TypeMismatch.new(path, original, actual)]
end

#describe_PArrayType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 797

def describe_PArrayType(expected, original, actual, path)
  descriptions = []
  element_type = expected.element_type || PAnyType::DEFAULT
  case actual
  when PTupleType
    types = actual.types
    expected_size = expected.size_type || PCollectionType::DEFAULT_SIZE
    actual_size = actual.size_type || PIntegerType.new(types.size, types.size)
    if expected_size.assignable?(actual_size)
      types.each_with_index do |type, idx|
        descriptions.concat(describe(element_type, type, path + [ArrayPathElement.new(idx)])) unless element_type.assignable?(type)
      end
    else
      descriptions << SizeMismatch.new(path, expected_size, actual_size)
    end
  when PArrayType
    expected_size = expected.size_type
    actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE
    if expected_size.nil? || expected_size.assignable?(actual_size)
      descriptions << TypeMismatch.new(path, original, PArrayType.new(actual.element_type))
    else
      descriptions << SizeMismatch.new(path, expected_size, actual_size)
    end
  else
    descriptions << TypeMismatch.new(path, original, actual)
  end
  descriptions
end

#describe_PCallableType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 945

def describe_PCallableType(expected, original, actual, path)
  if actual.is_a?(PCallableType)
    # nil param_types means, any other Callable is assignable
    if expected.param_types.nil? && expected.return_type.nil?
      EMPTY_ARRAY
    else
      # NOTE: these tests are made in reverse as it is calling the callable that is constrained
      # (it's lower bound), not its upper bound
      param_errors = describe_argument_tuple(expected.param_types, actual.param_types, path)
      if param_errors.empty?
        this_return_t = expected.return_type || PAnyType::DEFAULT
        that_return_t = actual.return_type || PAnyType::DEFAULT
        if this_return_t.assignable?(that_return_t)
          # names are ignored, they are just information
          # Blocks must be compatible
          this_block_t = expected.block_type || PUndefType::DEFAULT
          that_block_t = actual.block_type || PUndefType::DEFAULT
          if that_block_t.assignable?(this_block_t)
            EMPTY_ARRAY
          else
            [TypeMismatch.new(path + [BlockPathElement.new], this_block_t, that_block_t)]
          end
        else
          [TypeMismatch.new(path + [ReturnTypeElement.new], this_return_t, that_return_t)]
        end
      else
        param_errors
      end
    end
  else
    [TypeMismatch.new(path, original, actual)]
  end
end

#describe_PEnumType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



785
786
787
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 785

def describe_PEnumType(expected, original, actual, path)
  [PatternMismatch.new(path, original, actual)]
end

#describe_PHashType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 826

def describe_PHashType(expected, original, actual, path)
  descriptions = []
  key_type = expected.key_type || PAnyType::DEFAULT
  value_type = expected.value_type || PAnyType::DEFAULT
  case actual
  when PStructType
    elements = actual.elements
    expected_size = expected.size_type || PCollectionType::DEFAULT_SIZE
    actual_size = PIntegerType.new(elements.count { |a| !a.key_type.assignable?(PUndefType::DEFAULT) }, elements.size)
    if expected_size.assignable?(actual_size)
      elements.each do |a|
        descriptions.concat(describe(key_type, a.key_type, path + [EntryKeyPathElement.new(a.name)])) unless key_type.assignable?(a.key_type)
        descriptions.concat(describe(value_type, a.value_type, path + [EntryValuePathElement.new(a.name)])) unless value_type.assignable?(a.value_type)
      end
    else
      descriptions << SizeMismatch.new(path, expected_size, actual_size)
    end
  when PHashType
    expected_size = expected.size_type
    actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE
    if expected_size.nil? || expected_size.assignable?(actual_size)
      descriptions << TypeMismatch.new(path, original, PHashType.new(actual.key_type, actual.value_type))
    else
      descriptions << SizeMismatch.new(path, expected_size, actual_size)
    end
  else
    descriptions << TypeMismatch.new(path, original, actual)
  end
  descriptions
end

#describe_POptionalType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



779
780
781
782
783
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 779

def describe_POptionalType(expected, original, actual, path)
  return EMPTY_ARRAY if actual.is_a?(PUndefType) || expected.optional_type.nil?

  internal_describe(expected.optional_type, original.is_a?(PTypeAliasType) ? original : expected, actual, path)
end

#describe_PPatternType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



789
790
791
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 789

def describe_PPatternType(expected, original, actual, path)
  [PatternMismatch.new(path, original, actual)]
end

#describe_PStructType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 857

def describe_PStructType(expected, original, actual, path)
  elements = expected.elements
  descriptions = []
  case actual
  when PStructType
    h2 = actual.hashed_elements.clone
    elements.each do |e1|
      key = e1.name
      e2 = h2.delete(key)
      if e2.nil?
        descriptions << MissingKey.new(path, key) unless e1.key_type.assignable?(PUndefType::DEFAULT)
      else
        descriptions.concat(describe(e1.key_type, e2.key_type, path + [EntryKeyPathElement.new(key)])) unless e1.key_type.assignable?(e2.key_type)
        descriptions.concat(describe(e1.value_type, e2.value_type, path + [EntryValuePathElement.new(key)])) unless e1.value_type.assignable?(e2.value_type)
      end
    end
    h2.each_key { |key| descriptions << ExtraneousKey.new(path, key) }
  when PHashType
    actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE
    expected_size = PIntegerType.new(elements.count { |e| !e.key_type.assignable?(PUndefType::DEFAULT) }, elements.size)
    if expected_size.assignable?(actual_size)
      descriptions << TypeMismatch.new(path, original, PHashType.new(actual.key_type, actual.value_type))
    else
      descriptions << SizeMismatch.new(path, expected_size, actual_size)
    end
  else
    descriptions << TypeMismatch.new(path, original, actual)
  end
  descriptions
end

#describe_PTupleType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



888
889
890
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 888

def describe_PTupleType(expected, original, actual, path)
  describe_tuple(expected, original, actual, path, SizeMismatch)
end

#describe_PTypeAliasType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



793
794
795
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 793

def describe_PTypeAliasType(expected, original, actual, path)
  internal_describe(expected.resolved_type.normalize, expected, actual, path)
end

#describe_PVariantType(expected, original, actual, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 737

def describe_PVariantType(expected, original, actual, path)
  variant_descriptions = []
  types = expected.types
  types = [PUndefType::DEFAULT] + types if original.is_a?(POptionalType)
  types.each_with_index do |vt, index|
    d = describe(vt, actual, path + [VariantPathElement.new(index)])
    return EMPTY_ARRAY if d.empty?

    variant_descriptions << d
  end
  descriptions = merge_descriptions(path.length, SizeMismatch, variant_descriptions)
  if original.is_a?(PTypeAliasType) && descriptions.size == 1
    # All variants failed in this alias so we report it as a mismatch on the alias
    # rather than reporting individual failures of the variants
    [TypeMismatch.new(path, original, actual)]
  else
    descriptions
  end
end

#describe_signature_arguments(signature, args_tuple, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 676

def describe_signature_arguments(signature, args_tuple, path)
  params_tuple = signature.type.param_types
  params_size_t = params_tuple.size_type || TypeFactory.range(*params_tuple.size_range)

  case args_tuple
  when PTupleType
    arg_types = args_tuple.types
  when PArrayType
    arg_types = Array.new(params_tuple.types.size, args_tuple.element_type || PUndefType::DEFAULT)
  else
    return [TypeMismatch.new(path, params_tuple, args_tuple)]
  end

  if arg_types.last.kind_of_callable?
    # Check other arguments
    arg_count = arg_types.size - 1
    describe_no_block_arguments(signature, arg_types, path, params_size_t, TypeFactory.range(arg_count, arg_count), arg_count)
  else
    args_size_t = TypeFactory.range(*args_tuple.size_range)
    describe_no_block_arguments(signature, arg_types, path, params_size_t, args_size_t, arg_types.size)
  end
end

#describe_signature_block(signature, args_tuple, path) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 699

def describe_signature_block(signature, args_tuple, path)
  param_block_t = signature.block_type
  arg_block_t = args_tuple.is_a?(PTupleType) ? args_tuple.types.last : nil
  if TypeCalculator.is_kind_of_callable?(arg_block_t)
    # Can't pass a block to a callable that doesn't accept one
    if param_block_t.nil?
      [UnexpectedBlock.new(path)]
    else
      # Check that the block is of the right type
      describe(param_block_t, arg_block_t, path + [BlockPathElement.new])
    end
  elsif param_block_t.nil? || param_block_t.assignable?(PUndefType::DEFAULT)
    # Check that the block is optional
    EMPTY_ARRAY
  else
    [MissingRequiredBlock.new(path)]
  end
end

#describe_signatures(closure, signatures, args_tuple, tense = :ignored) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 632

def describe_signatures(closure, signatures, args_tuple, tense = :ignored)
  tense_deprecated unless tense == :ignored
  error_arrays = []
  signatures.each_with_index do |signature, index|
    error_arrays << describe_signature_arguments(signature, args_tuple, [SignaturePathElement.new(index)])
  end

  # Skip block checks if all signatures have argument errors
  unless error_arrays.all? { |a| !a.empty? }
    block_arrays = []
    signatures.each_with_index do |signature, index|
      block_arrays << describe_signature_block(signature, args_tuple, [SignaturePathElement.new(index)])
    end
    bc_count = block_arrays.count { |a| !a.empty? }
    if bc_count == block_arrays.size
      # Skip argument errors when all alternatives have block errors
      error_arrays = block_arrays
    elsif bc_count > 0
      # Merge errors giving argument errors precedence over block errors
      error_arrays.each_with_index { |a, index| error_arrays[index] = block_arrays[index] if a.empty? }
    end
  end
  return nil if error_arrays.empty?

  label = closure == 'lambda' ? 'block' : "'#{closure}'"
  errors = merge_descriptions(0, CountMismatch, error_arrays)
  if errors.size == 1
    "#{label}#{errors[0].format}"
  else
    if signatures.size == 1
      sig = signatures[0]
      result = ["#{label} expects (#{signature_string(sig)})"]
      result.concat(error_arrays[0].map { |e| "  rejected:#{e.chop_path(0).format}" })
    else
      result = ["The function #{label} was called with arguments it does not accept. It expects one of:"]
      signatures.each_with_index do |sg, index|
        result << "  (#{signature_string(sg)})"
        result.concat(error_arrays[index].map { |e| "    rejected:#{e.chop_path(0).format}" })
      end
    end
    result.join("\n")
  end
end

#describe_struct_signature(params_struct, param_hash, missing_ok = false) ⇒ Array<Mismatch>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Validates that all entries in the param_hash exists in the given param_struct, that their type conforms with the corresponding param_struct element and that all required values are provided. An error message is created for each problem found.

Parameters:

  • params_struct (PStructType)

    Struct to use for validation

  • param_hash (Hash<String,Object>)

    The parameters to validate

  • missing_ok (Boolean) (defaults to: false)

    Do not generate errors on missing parameters

Returns:

  • (Array<Mismatch>)

    An array of found errors. An empty array indicates no errors.



603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 603

def describe_struct_signature(params_struct, param_hash, missing_ok = false)
  param_type_hash = params_struct.hashed_elements
  result = param_hash.each_key.reject { |name| param_type_hash.include?(name) }.map { |name| InvalidParameter.new(nil, name) }

  params_struct.elements.each do |elem|
    name = elem.name
    value = param_hash[name]
    value_type = elem.value_type
    if param_hash.include?(name)
      if Puppet::Pops::Types::TypeFactory.deferred.implementation_class == value.class
        if (df_return_type = get_deferred_function_return_type(value))
          result << describe(value_type, df_return_type, [ParameterPathElement.new(name)]) unless value_type.generalize.assignable?(df_return_type.generalize)
        else
          warning_text = _("Deferred function %{function_name} has no return_type, unable to guarantee value type during compilation.") %
                         { function_name: value.name }
          Puppet.warn_once('deprecations',
                           "#{value.name}_deferred_warning",
                           warning_text)
        end
      else
        result << describe(value_type, TypeCalculator.singleton.infer_set(value), [ParameterPathElement.new(name)]) unless value_type.instance?(value)
      end
    else
      result << MissingParameter.new(nil, name) unless missing_ok || elem.key_type.is_a?(POptionalType)
    end
  end
  result
end

#describe_tuple(expected, original, actual, path, size_mismatch_class) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 896

def describe_tuple(expected, original, actual, path, size_mismatch_class)
  return EMPTY_ARRAY if expected == actual || expected.types.empty? && actual.is_a?(PArrayType)

  expected_size = expected.size_type || TypeFactory.range(*expected.size_range)

  case actual
  when PTupleType
    actual_size = actual.size_type || TypeFactory.range(*actual.size_range)

    # not assignable if the number of types in actual is outside number of types in expected
    if expected_size.assignable?(actual_size)
      etypes = expected.types
      descriptions = []
      unless etypes.empty?
        actual.types.each_with_index do |atype, index|
          adx = index >= etypes.size ? etypes.size - 1 : index
          descriptions.concat(describe(etypes[adx], atype, path + [ArrayPathElement.new(adx)]))
        end
      end
      descriptions
    else
      [size_mismatch_class.new(path, expected_size, actual_size)]
    end
  when PArrayType
    t2_entry = actual.element_type

    if t2_entry.nil?
      # Array of anything can not be assigned (unless tuple is tuple of anything) - this case
      # was handled at the top of this method.
      #
      [TypeMismatch.new(path, original, actual)]
    else
      expected_size = expected.size_type || TypeFactory.range(*expected.size_range)
      actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE
      if expected_size.assignable?(actual_size)
        descriptions = []
        expected.types.each_with_index do |etype, index|
          descriptions.concat(describe(etype, actual.element_type, path + [ArrayPathElement.new(index)]))
        end
        descriptions
      else
        [size_mismatch_class.new(path, expected_size, actual_size)]
      end
    end
  else
    [TypeMismatch.new(path, original, actual)]
  end
end

#max(a, b) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Why oh why Ruby do you not have a standard Math.max ?



1094
1095
1096
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 1094

def max(a, b)
  a >= b ? a : b
end

#merge_descriptions(varying_path_position, size_mismatch_class, variant_descriptions) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 757

def merge_descriptions(varying_path_position, size_mismatch_class, variant_descriptions)
  descriptions = variant_descriptions.flatten
  [size_mismatch_class, MissingRequiredBlock, UnexpectedBlock, TypeMismatch].each do |mismatch_class|
    mismatches = descriptions.select { |desc| desc.is_a?(mismatch_class) }
    next unless mismatches.size == variant_descriptions.size

    # If they all have the same canonical path, then we can compact this into one
    generic_mismatch = mismatches.inject do |prev, curr|
      break nil unless prev.canonical_path == curr.canonical_path

      prev.merge(prev.path, curr)
    end
    next if generic_mismatch.nil?

    # Report the generic mismatch and skip the rest
    descriptions = [generic_mismatch]
    break
  end
  descriptions = descriptions.uniq
  descriptions.size == 1 ? [descriptions[0].chop_path(varying_path_position)] : descriptions
end

#optional(index, required_count) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



1099
1100
1101
1102
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 1099

def optional(index, required_count)
  count = index + 1
  count > required_count
end

#signature_string(signature) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Produces a string for the signature(s)



1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 1041

def signature_string(signature)
  param_types = signature.type.param_types
  param_names = signature.parameter_names

  from, to = param_types.size_range
  if from == 0 && to == 0
    # No parameters function
    return ''
  end

  required_count = from
  types =
    case param_types
    when PTupleType
      param_types.types
    when PArrayType
      [param_types.element_type]
    end

  # join type with names (types are always present, names are optional)
  # separate entries with comma
  #
  param_names = Array.new(types.size, '') if param_names.empty?
  limit = param_names.size
  result = param_names.each_with_index.map do |name, index|
    type = types[index] || types[-1]
    indicator = ''
    if to == Float::INFINITY && index == limit - 1
      # Last is a repeated_param.
      indicator = from == param_names.size ? '+' : '*'
    elsif optional(index, required_count)
      indicator = '?'
      type = type.optional_type if type.is_a?(POptionalType)
    end
    "#{type} #{name}#{indicator}"
  end.join(', ')

  # If there is a block, include it
  case signature.type.block_type
  when POptionalType
    result << ', ' unless result == ''
    result << "#{signature.type.block_type.optional_type} #{signature.block_name}?"
  when PCallableType
    result << ', ' unless result == ''
    result << "#{signature.type.block_type} #{signature.block_name}"
  when NilClass
    # nothing
  end
  result
end

#tense_deprecatedObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



513
514
515
516
517
518
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 513

def tense_deprecated
  # TRANSLATORS TypeMismatchDescriber is a class name and 'tense' is a method name and should not be translated
  message = _("Passing a 'tense' argument to the TypeMismatchDescriber is deprecated and ignored.")
  message += ' ' + _("Everything is now reported using present tense")
  Puppet.warn_once('deprecations', 'typemismatch#tense', message)
end

#validate_default_parameter(subject, param_name, param_type, value, tense = :ignored) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parameters:

  • subject (String)

    string to be prepended to the exception message

  • param_name (String)

    parameter name

  • param_type (PAnyType)

    parameter type

  • value (Object)

    value to be validated against the given type

  • tense (Symbol) (defaults to: :ignored)

    deprecated and ignored



569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 569

def validate_default_parameter(subject, param_name, param_type, value, tense = :ignored)
  tense_deprecated unless tense == :ignored
  unless param_type.instance?(value)
    errors = describe(param_type, TypeCalculator.singleton.infer_set(value).generalize, [ParameterPathElement.new(param_name)])
    case errors.size
    when 0
      # do nothing
    when 1
      raise Puppet::ParseError, "#{subject}:#{errors[0].format}"
    else
      errors_str = errors.map(&:format).join("\n ")
      raise Puppet::ParseError, "#{subject}:\n #{errors_str}"
    end
  end
end

#validate_parameters(subject, params_struct, given_hash, missing_ok = false, tense = :ignored) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Validates that all entries in the give_hash exists in the given param_struct, that their type conforms with the corresponding param_struct element and that all required values are provided.

Parameters:

  • subject (String)

    string to be prepended to the exception message

  • params_struct (PStructType)

    Struct to use for validation

  • given_hash (Hash<String,Object>)

    the parameters to validate

  • missing_ok (Boolean) (defaults to: false)

    Do not generate errors on missing parameters

  • tense (Symbol) (defaults to: :ignored)

    deprecated and ignored



529
530
531
532
533
534
535
536
537
538
539
540
541
# File 'lib/puppet/pops/types/type_mismatch_describer.rb', line 529

def validate_parameters(subject, params_struct, given_hash, missing_ok = false, tense = :ignored)
  tense_deprecated unless tense == :ignored
  errors = describe_struct_signature(params_struct, given_hash, missing_ok).flatten
  case errors.size
  when 0
    # do nothing
  when 1
    raise Puppet::ParseError, "#{subject}:#{errors[0].format}"
  else
    errors_str = errors.map(&:format).join("\n ")
    raise Puppet::ParseError, "#{subject}:\n #{errors_str}"
  end
end