class Puppet::Pops::Types::StringConverter
Converts Puppet runtime objects to String under the control of a Format. Use from Puppet Language is via the function `new`.
@api private
Constants
- DEFAULT_ARRAY_DELIMITERS
- DEFAULT_ARRAY_FORMAT
- DEFAULT_CONTAINER_FORMATS
format used by default for values in a container (basically strings are quoted since they may contain a ','))
- DEFAULT_HASH_DELIMITERS
- DEFAULT_HASH_FORMAT
- DEFAULT_INDENTATION
- DEFAULT_PARAMETER_FORMAT
- DEFAULT_STRING_FORMATS
- FMT_KEYS
Public Class Methods
@api public
# File lib/puppet/pops/types/string_converter.rb 247 def self.convert(value, string_formats = :default) 248 singleton.convert(value, string_formats) 249 end
@api private
# File lib/puppet/pops/types/string_converter.rb 253 def initialize 254 @string_visitor = Visitor.new(self, "string", 3, 3) 255 end
Public Instance Methods
Converts the given value to a String, under the direction of formatting rules per type.
When converting to string it is possible to use a set of built in conversion rules.
A format is specified on the form:
´´´ %[Flags][.Precision]Format ´´´
`Width` is the number of characters into which the value should be fitted. This allocated space is padded if value is shorter. By default it is space padded, and the flag 0 will cause padding with 0 for numerical formats.
`Precision` is the number of fractional digits to show for floating point, and the maximum characters included in a string format.
Note that all data type supports the formats `s` and `p` with the meaning “default to-string” and “default-programmatic to-string”.
### Integer
| Format | Integer Formats | —— | ————— | d | Decimal, negative values produces leading '-' | x X | Hexadecimal in lower or upper case. Uses ..f/..F for negative values unless # is also used | o | Octal. Uses ..0 for negative values unless # is also used | b B | Binary with prefix 'b' or 'B'. Uses ..1/..1 for negative values unless # is also used | c | numeric value representing a Unicode value, result is a one unicode character string, quoted if alternative flag # is used | s | same as d, or d in quotes if alternative flag # is used | p | same as d | eEfgGaA | converts integer to float and formats using the floating point rules
Defaults to `d`
### Float
| Format | Float formats | —— | ————- | f | floating point in non exponential notation | e E | exponential notation with 'e' or 'E' | g G | conditional exponential with 'e' or 'E' if exponent < -4 or >= the precision | a A | hexadecimal exponential form, using 'x'/'X' as prefix and 'p'/'P' before exponent | s | converted to string using format p, then applying string formatting rule, alternate form # quotes result | p | f format with minimum significant number of fractional digits, prec has no effect | dxXobBc | converts float to integer and formats using the integer rules
Defaults to `p`
### String
| Format | String | —— | —— | s | unquoted string, verbatim output of control chars | p | programmatic representation - strings are quoted, interior quotes and control chars are escaped
- | C | each
-
name segment capitalized, quoted if alternative flag # is used
| c | capitalized string, quoted if alternative flag # is used | d | downcased string, quoted if alternative flag # is used | u | upcased string, quoted if alternative flag # is used | t | trims leading and trailing whitespace from the string, quoted if alternative flag # is used
Defaults to `s` at top level and `p` inside array or hash.
### Boolean
| Format | Boolean Formats | —- | ——————- | t T | 'true'/'false' or 'True'/'False' , first char if alternate form is used (i.e. 't'/'f' or 'T'/'F'). | y Y | 'yes'/'no', 'Yes'/'No', 'y'/'n' or 'Y'/'N' if alternative flag # is used | dxXobB | numeric value 0/1 in accordance with the given format which must be valid integer format | eEfgGaA | numeric value 0.0/1.0 in accordance with the given float format and flags | s | 'true' / 'false' | p | 'true' / 'false'
### Regexp
| Format | Regexp Formats (%/) | —- | —————— | s | / / delimiters, alternate flag replaces / delimiters with quotes | p | / / delimiters
### Undef
| Format | Undef formats | —— | ————- | s | empty string, or quoted empty string if alternative flag # is used | p | 'undef', or quoted '“undef”' if alternative flag # is used | n | 'nil', or 'null' if alternative flag # is used | dxXobB | 'NaN' | eEfgGaA | 'NaN' | v | 'n/a' | V | 'N/A' | u | 'undef', or 'undefined' if alternative # flag is used
### Default (value)
| Format | Default formats | —— | ————— | d D | 'default' or 'Default', alternative form # causes value to be quoted | s | same as d | p | same as d
### Binary (value)
| Format | Default formats | —— | ————— | s | binary as unquoted characters | p | 'Binary(“<base64strict>”)' | b | '<base64>' - base64 string with newlines inserted | B | '<base64strict>' - base64 strict string (without newlines inserted) | u | '<base64urlsafe>' - base64 urlsafe string | t | 'Binary' - outputs the name of the type only | T | 'BINARY' - output the name of the type in all caps only
The alternate form flag `#` will quote the binary or base64 text output The width and precision values are applied to the text part only in `%p` format.
### Array & Tuple
| Format | Array/Tuple Formats | —— | ————- | a | formats with `[ ]` delimiters and `,`, alternate form `#` indents nested arrays/hashes | s | same as a | p | same as a
See “Flags” `<[({|` for formatting of delimiters, and “Additional parameters for containers; Array and Hash” for more information about options.
The alternate form flag `#` will cause indentation of nested array or hash containers. If width is also set it is taken as the maximum allowed length of a sequence of elements (not including delimiters). If this max length is exceeded, each element will be indented.
### Hash & Struct
| Format | Hash/Struct Formats | —— | ————- | h | formats with `{ }` delimiters, `,` element separator and ` => ` inner element separator unless overridden by flags | s | same as h | p | same as h | a | converts the hash to an array of [k,v] tuples and formats it using array rule(s)
See “Flags” `<[({|` for formatting of delimiters, and “Additional parameters for containers; Array and Hash” for more information about options.
The alternate form flag `#` will format each hash key/value entry indented on a separate line.
### Type
| Format | Array/Tuple Formats | —— | ————- | s | The same as p, quoted if alternative flag # is used | p | Outputs the type in string form as specified by the Puppet Language
### Flags
| Flag | Effect | —— | —— | (space) | space instead of + for numeric output (- is shown), for containers skips delimiters | # | alternate format; prefix 0x/0x, 0 (octal) and 0b/0B for binary, Floats force decimal '.'. For g/G keep trailing 0. | + | show sign +/- depending on value's sign, changes x,X, o,b, B format to not use 2's complement form | - | left justify the value in the given width | 0 | pad with 0 instead of space for widths larger than value | <[({| | defines an enclosing pair <> [] () {} or | | when used with a container type
### Additional parameters for containers; Array and Hash
For containers (Array and Hash), the format is specified by a hash where the following keys can be set:
-
`'format'` - the format specifier for the container itself
-
`'separator'` - the separator string to use between elements, should not contain padding space at the end
-
`'separator2'` - the separator string to use between association of hash entries key/value
-
`'string_formats'´ - a map of type to format for elements contained in the container
Note that the top level format applies to Array and Hash objects contained/nested in an Array or a Hash.
Given format mappings are merged with (default) formats and a format specified for a narrower type wins over a broader.
@param mode [String, Symbol] :strict or :extended (or :default which is the same as :strict) @param string_formats [String, Hash] format tring, or a hash mapping type to a format string, and for Array and Hash types map to hash of details
# File lib/puppet/pops/types/string_converter.rb 480 def convert(value, string_formats = :default) 481 options = DEFAULT_STRING_FORMATS 482 483 value_type = TypeCalculator.infer_set(value) 484 if string_formats.is_a?(String) 485 # For Array and Hash, the format is given as a Hash where 'format' key is the format for the collection itself 486 if Puppet::Pops::Types::PArrayType::DEFAULT.assignable?(value_type) 487 # add the format given for the exact type 488 string_formats = { Puppet::Pops::Types::PArrayType::DEFAULT => {'format' => string_formats }} 489 elsif Puppet::Pops::Types::PHashType::DEFAULT.assignable?(value_type) 490 # add the format given for the exact type 491 string_formats = { Puppet::Pops::Types::PHashType::DEFAULT => {'format' => string_formats }} 492 else 493 # add the format given for the exact type 494 string_formats = { value_type => string_formats } 495 end 496 end 497 498 case string_formats 499 when :default 500 # do nothing, use default formats 501 502 when Hash 503 # Convert and validate user input 504 string_formats = validate_input(string_formats) 505 # Merge user given with defaults such that user options wins, merge is deep and format specific 506 options = Format.merge_string_formats(DEFAULT_STRING_FORMATS, string_formats) 507 else 508 raise ArgumentError, "string conversion expects a Default value or a Hash of type to format mappings, got a '#{string_formats.class}'" 509 end 510 511 _convert(value_type, value, options, DEFAULT_INDENTATION) 512 end
# File lib/puppet/pops/types/string_converter.rb 1010 def is_a_or_h?(x) 1011 x.is_a?(Array) || x.is_a?(Hash) 1012 end
# File lib/puppet/pops/types/string_converter.rb 1014 def is_container?(t) 1015 case t 1016 when PArrayType, PHashType, PStructType, PTupleType, PObjectType 1017 true 1018 else 1019 false 1020 end 1021 end
# File lib/puppet/pops/types/string_converter.rb 886 def puppet_double_quote(str) 887 bld = String.new('"') 888 str.each_codepoint do |codepoint| 889 case codepoint 890 when 0x09 891 bld << '\\t' 892 when 0x0a 893 bld << '\\n' 894 when 0x0d 895 bld << '\\r' 896 when 0x22 897 bld << '\\"' 898 when 0x24 899 bld << '\\$' 900 when 0x5c 901 bld << '\\\\' 902 else 903 if codepoint < 0x20 904 bld << sprintf('\\u{%X}', codepoint) 905 elsif codepoint <= 0x7f 906 bld << codepoint 907 else 908 bld << [codepoint].pack('U') 909 end 910 end 911 end 912 bld << '"' 913 bld 914 end
Performs a '%p' formatting of the given str such that the output conforms to Puppet syntax. An ascii string without control characters, dollar, single-qoute, or backslash, will be quoted using single quotes. All other strings will be quoted using double quotes.
@param [String] str the string that should be formatted @param [Boolean] enforce_double_quotes if true the result will be double quoted (even if single quotes would be possible) @return [String] the formatted string
@api public
# File lib/puppet/pops/types/string_converter.rb 850 def puppet_quote(str, enforce_double_quotes = false) 851 if enforce_double_quotes 852 return puppet_double_quote(str) 853 end 854 855 # Assume that the string can be single quoted 856 bld = String.new('\'') 857 bld.force_encoding(str.encoding) 858 escaped = false 859 str.each_codepoint do |codepoint| 860 # Control characters and non-ascii characters cannot be present in a single quoted string 861 return puppet_double_quote(str) if codepoint < 0x20 862 863 if escaped 864 bld << 0x5c << codepoint 865 escaped = false 866 else 867 if codepoint == 0x27 868 bld << 0x5c << codepoint 869 elsif codepoint == 0x5c 870 escaped = true 871 elsif codepoint <= 0x7f 872 bld << codepoint 873 else 874 bld << [codepoint].pack('U') 875 end 876 end 877 end 878 879 # If string ended with a backslash, then that backslash must be escaped 880 bld << 0x5c if escaped 881 882 bld << '\'' 883 bld 884 end
Basically string_PAnyType converts the value to a String and then formats it according to the resulting type
@api private
# File lib/puppet/pops/types/string_converter.rb 614 def string_PAnyType(val_type, val, format_map, _) 615 f = get_format(val_type, format_map) 616 Kernel.format(f.orig_fmt, val) 617 end
# File lib/puppet/pops/types/string_converter.rb 932 def string_PArrayType(val_type, val, format_map, indentation) 933 format = get_format(val_type, format_map) 934 sep = format.separator || DEFAULT_ARRAY_FORMAT.separator 935 string_formats = format.container_string_formats || DEFAULT_CONTAINER_FORMATS 936 delims = format.delimiter_pair(DEFAULT_ARRAY_DELIMITERS) 937 938 # Make indentation active, if array is in alternative format, or if nested in indenting 939 indentation = indentation.indenting(format.alt? || indentation.is_indenting?) 940 941 case format.format 942 when :a, :s, :p 943 buf = String.new 944 if indentation.breaks? 945 buf << "\n" 946 buf << indentation.padding 947 end 948 buf << delims[0] 949 950 # Make a first pass to format each element 951 children_indentation = indentation.increase(format.alt?) # tell children they are expected to indent 952 mapped = val.map do |v| 953 if children_indentation.first? 954 children_indentation = children_indentation.subsequent 955 end 956 val_t = TypeCalculator.infer_set(v) 957 _convert(val_t, v, is_container?(val_t) ? format_map : string_formats, children_indentation) 958 end 959 960 # compute widest run in the array, skip nested arrays and hashes 961 # then if size > width, set flag if a break on each element should be performed 962 if format.alt? && format.width 963 widest = val.each_with_index.reduce([0]) do | memo, v_i | 964 # array or hash breaks 965 if is_a_or_h?(v_i[0]) 966 memo << 0 967 else 968 memo[-1] += mapped[v_i[1]].length 969 end 970 memo 971 end 972 widest = widest.max 973 sz_break = widest > (format.width || Float::INFINITY) 974 else 975 sz_break = false 976 end 977 978 # output each element with breaks and padding 979 children_indentation = indentation.increase(format.alt?) 980 val.each_with_index do |v, i| 981 str_val = mapped[i] 982 if children_indentation.first? 983 children_indentation = children_indentation.subsequent 984 # if breaking, indent first element by one 985 if sz_break && !is_a_or_h?(v) 986 buf << ' ' 987 end 988 else 989 buf << sep 990 # if break on each (and breaking will not occur because next is an array or hash) 991 # or, if indenting, and previous was an array or hash, then break and continue on next line 992 # indented. 993 if (sz_break && !is_a_or_h?(v)) || (format.alt? && i > 0 && is_a_or_h?(val[i-1]) && !is_a_or_h?(v)) 994 buf.rstrip! unless buf[-1] == "\n" 995 buf << "\n" 996 buf << children_indentation.padding 997 end 998 end 999 # remove trailing space added by separator if followed by break 1000 buf.rstrip! if buf[-1] == ' ' && str_val[0] == "\n" 1001 buf << str_val 1002 end 1003 buf << delims[1] 1004 buf 1005 else 1006 raise FormatError.new('Array', format.format, 'asp') 1007 end 1008 end
@api private
# File lib/puppet/pops/types/string_converter.rb 761 def string_PBinaryType(val_type, val, format_map, _) 762 f = get_format(val_type, format_map) 763 substitute = f.alt? ? 'p' : 's' 764 case f.format 765 when :s 766 val_to_convert = val.binary_buffer 767 if !f.alt? 768 # Assume it is valid UTF-8 769 val_to_convert = val_to_convert.dup.force_encoding('UTF-8') 770 # If it isn't 771 unless val_to_convert.valid_encoding? 772 # try to convert and fail with details about what is wrong 773 val_to_convert = val.binary_buffer.encode('UTF-8') 774 end 775 else 776 val_to_convert = val.binary_buffer 777 end 778 Kernel.format(f.orig_fmt.gsub('s', substitute), val_to_convert) 779 780 when :p 781 # width & precision applied to string, not the the name of the type 782 "Binary(\"#{Kernel.format(f.orig_fmt.tr('p', 's'), val.to_s)}\")" 783 784 when :b 785 Kernel.format(f.orig_fmt.gsub('b', substitute), val.relaxed_to_s) 786 787 when :B 788 Kernel.format(f.orig_fmt.gsub('B', substitute), val.to_s) 789 790 when :u 791 Kernel.format(f.orig_fmt.gsub('u', substitute), val.urlsafe_to_s) 792 793 when :t 794 # Output as the type without any data 795 Kernel.format(f.orig_fmt.gsub('t', substitute), 'Binary') 796 797 when :T 798 # Output as the type without any data in all caps 799 Kernel.format(f.orig_fmt.gsub('T', substitute), 'BINARY') 800 801 else 802 raise FormatError.new('Binary', f.format, 'bButTsp') 803 end 804 end
@api private
# File lib/puppet/pops/types/string_converter.rb 655 def string_PBooleanType(val_type, val, format_map, indentation) 656 f = get_format(val_type, format_map) 657 case f.format 658 when :t 659 # 'true'/'false' or 't'/'f' if in alt mode 660 str_bool = val.to_s 661 apply_string_flags(f, f.alt? ? str_bool[0] : str_bool) 662 663 when :T 664 # 'True'/'False' or 'T'/'F' if in alt mode 665 str_bool = val.to_s.capitalize 666 apply_string_flags(f, f.alt? ? str_bool[0] : str_bool) 667 668 when :y 669 # 'yes'/'no' or 'y'/'n' if in alt mode 670 str_bool = val ? 'yes' : 'no' 671 apply_string_flags(f, f.alt? ? str_bool[0] : str_bool) 672 673 when :Y 674 # 'Yes'/'No' or 'Y'/'N' if in alt mode 675 str_bool = val ? 'Yes' : 'No' 676 apply_string_flags(f, f.alt? ? str_bool[0] : str_bool) 677 678 when :d, :x, :X, :o, :b, :B 679 # Boolean in numeric form, formated by integer rule 680 numeric_bool = val ? 1 : 0 681 string_formats = { Puppet::Pops::Types::PIntegerType::DEFAULT => f} 682 _convert(TypeCalculator.infer_set(numeric_bool), numeric_bool, string_formats, indentation) 683 684 when :e, :E, :f, :g, :G, :a, :A 685 # Boolean in numeric form, formated by float rule 686 numeric_bool = val ? 1.0 : 0.0 687 string_formats = { Puppet::Pops::Types::PFloatType::DEFAULT => f} 688 _convert(TypeCalculator.infer_set(numeric_bool), numeric_bool, string_formats, indentation) 689 690 when :s 691 apply_string_flags(f, val.to_s) 692 693 when :p 694 apply_string_flags(f, val.inspect) 695 696 else 697 raise FormatError.new('Boolean', f.format, 'tTyYdxXobBeEfgGaAsp') 698 end 699 end
# File lib/puppet/pops/types/string_converter.rb 619 def string_PDefaultType(val_type, val, format_map, _) 620 f = get_format(val_type, format_map) 621 apply_string_flags(f, case f.format 622 when :d, :s, :p 623 f.alt? ? '"default"' : 'default' 624 when :D 625 f.alt? ? '"Default"' : 'Default' 626 else 627 raise FormatError.new('Default', f.format, 'dDsp') 628 end) 629 end
@api private
# File lib/puppet/pops/types/string_converter.rb 742 def string_PFloatType(val_type, val, format_map, _) 743 f = get_format(val_type, format_map) 744 case f.format 745 when :d, :x, :X, :o, :b, :B 746 Kernel.format(f.orig_fmt, val.to_i) 747 748 when :e, :E, :f, :g, :G, :a, :A, :p 749 Kernel.format(f.orig_fmt, val) 750 751 when :s 752 float_str = f.alt? ? "\"#{Kernel.format('%p', val)}\"" : Kernel.format('%p', val) 753 Kernel.format(f.orig_fmt, float_str) 754 755 else 756 raise FormatError.new('Float', f.format, 'dxXobBeEfgGaAsp') 757 end 758 end
@api private
# File lib/puppet/pops/types/string_converter.rb 1035 def string_PHashType(val_type, val, format_map, indentation) 1036 format = get_format(val_type, format_map) 1037 sep = format.separator || DEFAULT_HASH_FORMAT.separator 1038 assoc = format.separator2 || DEFAULT_HASH_FORMAT.separator2 1039 string_formats = format.container_string_formats || DEFAULT_CONTAINER_FORMATS 1040 delims = format.delimiter_pair(DEFAULT_HASH_DELIMITERS) 1041 1042 if format.alt? 1043 sep = sep.rstrip unless sep[-1] == "\n" 1044 sep = "#{sep}\n" 1045 end 1046 1047 cond_break = '' 1048 padding = '' 1049 1050 case format.format 1051 when :a 1052 # Convert to array and use array rules 1053 array_hash = val.to_a 1054 _convert(TypeCalculator.infer_set(array_hash), array_hash, format_map, indentation) 1055 1056 when :h, :s, :p 1057 indentation = indentation.indenting(format.alt? || indentation.is_indenting?) 1058 buf = String.new 1059 if indentation.breaks? 1060 buf << "\n" 1061 buf << indentation.padding 1062 end 1063 1064 children_indentation = indentation.increase 1065 if format.alt? 1066 cond_break = "\n" 1067 padding = children_indentation.padding 1068 end 1069 buf << delims[0] 1070 buf << cond_break # break after opening delimiter if pretty printing 1071 buf << val.map do |k,v| 1072 key_type = TypeCalculator.infer_set(k) 1073 val_type = TypeCalculator.infer_set(v) 1074 key = _convert(key_type, k, is_container?(key_type) ? format_map : string_formats, children_indentation) 1075 val = _convert(val_type, v, is_container?(val_type) ? format_map : string_formats, children_indentation) 1076 "#{padding}#{key}#{assoc}#{val}" 1077 end.join(sep) 1078 if format.alt? 1079 buf << cond_break 1080 buf << indentation.padding 1081 end 1082 buf << delims[1] 1083 buf 1084 else 1085 raise FormatError.new('Hash', format.format, 'hasp') 1086 end 1087 end
@api private
# File lib/puppet/pops/types/string_converter.rb 717 def string_PIntegerType(val_type, val, format_map, _) 718 f = get_format(val_type, format_map) 719 case f.format 720 when :d, :x, :X, :o, :b, :B, :p 721 Kernel.format(f.orig_fmt, val) 722 723 when :e, :E, :f, :g, :G, :a, :A 724 Kernel.format(f.orig_fmt, val.to_f) 725 726 when :c 727 char = [val].pack("U") 728 char = f.alt? ? "\"#{char}\"" : char 729 Kernel.format(f.orig_fmt.tr('c','s'), char) 730 731 when :s 732 fmt = f.alt? ? 'p' : 's' 733 int_str = Kernel.format('%d', val) 734 Kernel.format(f.orig_fmt.gsub('s', fmt), int_str) 735 736 else 737 raise FormatError.new('Integer', f.format, 'dxXobBeEfgGaAspc') 738 end 739 end
@api private
# File lib/puppet/pops/types/string_converter.rb 1029 def string_PIteratorType(val_type, val, format_map, indentation) 1030 v = val.to_a 1031 _convert(TypeCalculator.infer_set(v), v, format_map, indentation) 1032 end
# File lib/puppet/pops/types/string_converter.rb 562 def string_PObjectType(val_type, val, format_map, indentation) 563 f = get_format(val_type, format_map) 564 case f.format 565 when :p 566 fmt = TypeFormatter.singleton 567 indentation = indentation.indenting(f.alt? || indentation.is_indenting?) 568 fmt = fmt.indented(indentation.level, 2) if indentation.is_indenting? 569 fmt.string(val) 570 when :s 571 val.to_s 572 when :q 573 val.inspect 574 else 575 raise FormatError.new('Object', f.format, 'spq') 576 end 577 end
# File lib/puppet/pops/types/string_converter.rb 579 def string_PObjectTypeExtension(val_type, val, format_map, indentation) 580 string_PObjectType(val_type.base_type, val, format_map, indentation) 581 end
@api private
# File lib/puppet/pops/types/string_converter.rb 917 def string_PRegexpType(val_type, val, format_map, _) 918 f = get_format(val_type, format_map) 919 case f.format 920 when :p 921 str_regexp = PRegexpType.regexp_to_s_with_delimiters(val) 922 f.orig_fmt == '%p' ? str_regexp : Kernel.format(f.orig_fmt.tr('p', 's'), str_regexp) 923 when :s 924 str_regexp = PRegexpType.regexp_to_s(val) 925 str_regexp = puppet_quote(str_regexp) if f.alt? 926 f.orig_fmt == '%s' ? str_regexp : Kernel.format(f.orig_fmt, str_regexp) 927 else 928 raise FormatError.new('Regexp', f.format, 'sp') 929 end 930 end
# File lib/puppet/pops/types/string_converter.rb 583 def string_PRuntimeType(val_type, val, format_map, indent) 584 # Before giving up on this, and use a string representation of the unknown 585 # object, a check is made to see if the object can present itself as 586 # a hash or an array. If it can, then that representation is used instead. 587 if val.is_a?(Hash) 588 hash = val.to_hash 589 # Ensure that the returned value isn't derived from Hash 590 return string_PHashType(val_type, hash, format_map, indent) if hash.instance_of?(Hash) 591 elsif val.is_a?(Array) 592 array = val.to_a 593 # Ensure that the returned value isn't derived from Array 594 return string_PArrayType(val_type, array, format_map, indent) if array.instance_of?(Array) 595 end 596 597 f = get_format(val_type, format_map) 598 case f.format 599 when :s 600 val.to_s 601 when :p 602 puppet_quote(val.to_s) 603 when :q 604 val.inspect 605 else 606 raise FormatError.new('Runtime', f.format, 'spq') 607 end 608 end
@api private
# File lib/puppet/pops/types/string_converter.rb 807 def string_PStringType(val_type, val, format_map, _) 808 f = get_format(val_type, format_map) 809 case f.format 810 when :s 811 Kernel.format(f.orig_fmt, val) 812 813 when :p 814 apply_string_flags(f, puppet_quote(val, f.alt?)) 815 816 when :c 817 c_val = val.capitalize 818 f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.tr('c', 's'), c_val) 819 820 when :C 821 c_val = val.split('::').map {|s| s.capitalize }.join('::') 822 f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.tr('C', 's'), c_val) 823 824 when :u 825 c_val = val.upcase 826 f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.tr('u', 's'), c_val) 827 828 when :d 829 c_val = val.downcase 830 f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.tr('d', 's'), c_val) 831 832 when :t # trim 833 c_val = val.strip 834 f.alt? ? apply_string_flags(f, puppet_quote(c_val)) : Kernel.format(f.orig_fmt.tr('t', 's'), c_val) 835 836 else 837 raise FormatError.new('String', f.format, 'cCudspt') 838 end 839 end
@api private
# File lib/puppet/pops/types/string_converter.rb 1090 def string_PStructType(val_type, val, format_map, indentation) 1091 string_PHashType(val_type, val, format_map, indentation) 1092 end
@api private
# File lib/puppet/pops/types/string_converter.rb 1024 def string_PTupleType(val_type, val, format_map, indentation) 1025 string_PArrayType(val_type, val, format_map, indentation) 1026 end
@api private
# File lib/puppet/pops/types/string_converter.rb 1095 def string_PTypeType(val_type, val, format_map, _) 1096 f = get_format(val_type, format_map) 1097 case f.format 1098 when :s 1099 str_val = f.alt? ? "\"#{val}\"" : val.to_s 1100 Kernel.format(f.orig_fmt, str_val) 1101 when :p 1102 Kernel.format(f.orig_fmt.tr('p', 's'), val.to_s) 1103 else 1104 raise FormatError.new('Type', f.format, 'sp') 1105 end 1106 end
@api private
# File lib/puppet/pops/types/string_converter.rb 1109 def string_PURIType(val_type, val, format_map, indentation) 1110 f = get_format(val_type, format_map) 1111 case f.format 1112 when :p 1113 fmt = TypeFormatter.singleton 1114 indentation = indentation.indenting(f.alt? || indentation.is_indenting?) 1115 fmt = fmt.indented(indentation.level, 2) if indentation.is_indenting? 1116 fmt.string(val) 1117 when :s 1118 str_val = val.to_s 1119 Kernel.format(f.orig_fmt, f.alt? ? puppet_quote(str_val) : str_val) 1120 else 1121 raise FormatError.new('URI', f.format, 'sp') 1122 end 1123 end
@api private
# File lib/puppet/pops/types/string_converter.rb 632 def string_PUndefType(val_type, val, format_map, _) 633 f = get_format(val_type, format_map) 634 apply_string_flags(f, case f.format 635 when :n 636 f.alt? ? 'null' : 'nil' 637 when :u 638 f.alt? ? 'undefined' : 'undef' 639 when :d, :x, :X, :o, :b, :B, :e, :E, :f, :g, :G, :a, :A 640 'NaN' 641 when :v 642 'n/a' 643 when :V 644 'N/A' 645 when :s 646 f.alt? ? '""' : '' 647 when :p 648 f.alt? ? '"undef"' : 'undef' 649 else 650 raise FormatError.new('Undef', f.format, 'nudxXobBeEfgGaAvVsp') 651 end) 652 end
Private Instance Methods
# A method only used for manual debugging as the default output of the formatting rules is # very hard to read otherwise. # # @api private def dump_string_formats(f, indent = 1)
return f.to_s unless f.is_a?(Hash) "{#{f.map {|k,v| "#{k.to_s} => #{dump_string_formats(v,indent+1)}"}.join(",\n#{' '*indent} ")}}"
end
# File lib/puppet/pops/types/string_converter.rb 523 def _convert(val_type, value, format_map, indentation) 524 @string_visitor.visit_this_3(self, val_type, value, format_map, indentation) 525 end
Performs post-processing of literals to apply width and precision flags
# File lib/puppet/pops/types/string_converter.rb 702 def apply_string_flags(f, literal_str) 703 if f.left || f.width || f.prec 704 fmt = String.new('%') 705 fmt << '-' if f.left 706 fmt << f.width.to_s if f.width 707 fmt << '.' << f.prec.to_s if f.prec 708 fmt << 's' 709 Kernel.format(fmt, literal_str) 710 else 711 literal_str 712 end 713 end
Maps the inferred type of o to a formatting rule
# File lib/puppet/pops/types/string_converter.rb 1126 def get_format(val_t, format_options) 1127 fmt = format_options.find {|k,_| k.assignable?(val_t) } 1128 return fmt[1] unless fmt.nil? 1129 return Format.new("%s") 1130 end
# File lib/puppet/pops/types/string_converter.rb 550 def validate_container_input(fmt) 551 if (fmt.keys - FMT_KEYS).size > 0 552 raise ArgumentError, "only #{FMT_KEYS.map {|k| "'#{k}'"}.join(', ')} are allowed in a container format, got #{fmt}" 553 end 554 result = Format.new(fmt['format']) 555 result.separator = fmt['separator'] 556 result.separator2 = fmt['separator2'] 557 result.container_string_formats = validate_input(fmt['string_formats']) 558 result 559 end
# File lib/puppet/pops/types/string_converter.rb 528 def validate_input(fmt) 529 return nil if fmt.nil? 530 unless fmt.is_a?(Hash) 531 raise ArgumentError, "expected a hash with type to format mappings, got instance of '#{fmt.class}'" 532 end 533 fmt.reduce({}) do | result, entry| 534 key, value = entry 535 unless key.is_a?(Types::PAnyType) 536 raise ArgumentError, "top level keys in the format hash must be data types, got instance of '#{key.class}'" 537 end 538 if value.is_a?(Hash) 539 result[key] = validate_container_input(value) 540 else 541 result[key] = Format.new(value) 542 end 543 result 544 end 545 end