Class: Puppet::Pops::Types::PHashType

Inherits:
PCollectionType show all
Defined in:
lib/puppet/pops/types/types.rb

Constant Summary collapse

DEFAULT =
PHashType.new(nil, nil)
KEY_PAIR_TUPLE_SIZE =
PIntegerType.new(2,2)
DEFAULT_KEY_PAIR_TUPLE =
PTupleType.new([PUnitType::DEFAULT, PUnitType::DEFAULT], KEY_PAIR_TUPLE_SIZE)
EMPTY =
PHashType.new(PUnitType::DEFAULT, PUnitType::DEFAULT, PIntegerType.new(0, 0))

Constants inherited from PCollectionType

Puppet::Pops::Types::PCollectionType::DEFAULT_SIZE, Puppet::Pops::Types::PCollectionType::NOT_EMPTY_SIZE, Puppet::Pops::Types::PCollectionType::ZERO_SIZE

Instance Attribute Summary collapse

Attributes inherited from PCollectionType

#size_type

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from PCollectionType

#has_empty_range?, #size_range

Methods inherited from PAnyType

#==, #assignable?, #callable?, #callable_args?, #callable_with?, #check_self_recursion, create, #create, #kind_of_callable?, #loader, #name, #new_function, #really_instance?, #roundtrip_with_string?, #simple_name, simple_name, #to_alias_expanded_s, #to_s

Methods inherited from TypedModelObject

_pcore_type, create_ptype, register_ptypes

Methods included from PuppetObject

#_pcore_all_contents, #_pcore_contents, #_pcore_init_hash, #_pcore_type

Constructor Details

#initialize(key_type, value_type, size_type = nil) ⇒ PHashType

Returns a new instance of PHashType.



2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
# File 'lib/puppet/pops/types/types.rb', line 2583

def initialize(key_type, value_type, size_type = nil)
  super(size_type)
  if !size_type.nil? && size_type.from == 0 && size_type.to == 0
    @key_type = PUnitType::DEFAULT
    @value_type = PUnitType::DEFAULT
  else
    @key_type = key_type.nil? ? PAnyType::DEFAULT : key_type
    @value_type = value_type.nil? ? PAnyType::DEFAULT : value_type
  end
end

Instance Attribute Details

#key_typeObject



2581
2582
2583
# File 'lib/puppet/pops/types/types.rb', line 2581

def key_type
  @key_type
end

#value_typeObject



2581
2582
2583
# File 'lib/puppet/pops/types/types.rb', line 2581

def value_type
  @value_type
end

Class Method Details

.array_as_hash(value) ⇒ Object



2671
2672
2673
2674
2675
2676
# File 'lib/puppet/pops/types/types.rb', line 2671

def self.array_as_hash(value)
  return value unless value.is_a?(Array)
  result = {}
  value.each_with_index {|v, idx| result[idx] = array_as_hash(v) }
  result
end

.new_function(type) ⇒ Object

Returns a new function that produces a Hash



2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
# File 'lib/puppet/pops/types/types.rb', line 2680

def self.new_function(type)
  @new_function ||= Puppet::Functions.create_loaded_function(:new_hash, type.loader) do
    local_types do
      type 'KeyValueArray = Array[Tuple[Any,Any],1]'
      type 'TreeArray = Array[Tuple[Array,Any],1]'
      type 'NewHashOption = Enum[tree, hash_tree]'
    end

    dispatch :from_tree do
      param           'TreeArray',       :from
      optional_param  'NewHashOption',   :build_option
    end

    dispatch :from_tuples do
      param           'KeyValueArray',  :from
    end

    dispatch :from_array do
      param           'Any',  :from
    end

    def from_tuples(tuple_array)
      Hash[tuple_array]
    end

    def from_tree(tuple_array, build_option = nil)
      if build_option.nil?
        return from_tuples(tuple_array)
      end
      # only remaining possible options is 'tree' or 'hash_tree'

      all_hashes = build_option == 'hash_tree'
      result = {}
      tuple_array.each do |entry|
        path = entry[0]
        value = entry[1]
        if path.empty?
          # root node (index [] was included - values merge into the result)
          # An array must be changed to a hash first as this is the root
          # (Cannot return an array from a Hash.new)
          if value.is_a?(Array)
            value.each_with_index {|v, idx| result[idx] = v }
          else
            result.merge!(value)
          end
        else
          r = path[0..-2].reduce(result) {|memo, idx| (memo.is_a?(Array) || memo.has_key?(idx)) ? memo[idx] : memo[idx] = {}}
          r[path[-1]]= (all_hashes ? PHashType.array_as_hash(value) : value)
        end
      end
      result
    end

    def from_array(from)
      case from
      when NilClass
        throw :undefined_value
      when Array
        if from.size == 0
          {}
        else
          unless from.size % 2 == 0
            raise TypeConversionError.new("odd number of arguments for Hash")
          end
          Hash[*from]
        end
      when Hash
        from
      else
        if PIterableType::DEFAULT.instance?(from)
          Hash[*Iterable.on(from).to_a]
        else
          t = Puppet::Pops::Types::TypeCalculator.singleton.infer(from).generalize
          raise TypeConversionError.new("Value of type '#{t}' cannot be converted to Hash")
        end
      end
    end
  end
end

.register_ptype(loader, ir) ⇒ Object



2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
# File 'lib/puppet/pops/types/types.rb', line 2568

def self.register_ptype(loader, ir)
  create_ptype(loader, ir, 'CollectionType',
    'key_type' => {
      KEY_TYPE => POptionalType.new(PTypeType::DEFAULT),
      KEY_VALUE => PAnyType::DEFAULT
    },
    'value_type' => {
      KEY_TYPE => POptionalType.new(PTypeType::DEFAULT),
      KEY_VALUE => PAnyType::DEFAULT
    }
  )
end

Instance Method Details

#accept(visitor, guard) ⇒ Object



2594
2595
2596
2597
2598
# File 'lib/puppet/pops/types/types.rb', line 2594

def accept(visitor, guard)
  super
  @key_type.accept(visitor, guard)
  @value_type.accept(visitor, guard)
end

#element_typeObject



2600
2601
2602
2603
2604
2605
2606
# File 'lib/puppet/pops/types/types.rb', line 2600

def element_type
  if Puppet[:strict] != :off
    Puppet.warn_once('deprecations', 'Puppet::Pops::Types::PHashType#element_type',
      'Puppet::Pops::Types::PHashType#element_type is deprecated, use #value_type instead')
  end
  @value_type
end

#eql?(o) ⇒ Boolean

Returns:

  • (Boolean)


2657
2658
2659
# File 'lib/puppet/pops/types/types.rb', line 2657

def eql?(o)
  super && @key_type == o.key_type && @value_type == o.value_type
end

#generalizeObject



2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
# File 'lib/puppet/pops/types/types.rb', line 2608

def generalize
  if self == DEFAULT || self == EMPTY
    self
  else
    key_t = @key_type
    key_t = key_t.generalize
    value_t = @value_type
    value_t = value_t.generalize
    @size_type.nil? && @key_type.equal?(key_t) && @value_type.equal?(value_t) ? self : PHashType.new(key_t, value_t, nil)
  end
end

#hashObject



2630
2631
2632
# File 'lib/puppet/pops/types/types.rb', line 2630

def hash
  super ^ @key_type.hash ^ @value_type.hash
end

#instance?(o, guard = nil) ⇒ Boolean

Returns:

  • (Boolean)


2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
# File 'lib/puppet/pops/types/types.rb', line 2634

def instance?(o, guard = nil)
  # The inferred type of a class derived from Hash is either Runtime or Object. It's not assignable to the Hash type.
  return false unless o.instance_of?(Hash)
  if o.keys.all? {|key| @key_type.instance?(key, guard) } && o.values.all? {|value| @value_type.instance?(value, guard) }
    size_t = size_type
    size_t.nil? || size_t.instance?(o.size, guard)
  else
    false
  end
end

#is_the_empty_hash?Boolean

Returns:

  • (Boolean)


2661
2662
2663
# File 'lib/puppet/pops/types/types.rb', line 2661

def is_the_empty_hash?
  self == EMPTY
end

#iterable?(guard = nil) ⇒ Boolean

Returns:

  • (Boolean)


2645
2646
2647
# File 'lib/puppet/pops/types/types.rb', line 2645

def iterable?(guard = nil)
  true
end

#iterable_type(guard = nil) ⇒ Object



2649
2650
2651
2652
2653
2654
2655
# File 'lib/puppet/pops/types/types.rb', line 2649

def iterable_type(guard = nil)
  if self == DEFAULT || self == EMPTY
    PIterableType.new(DEFAULT_KEY_PAIR_TUPLE)
  else
    PIterableType.new(PTupleType.new([@key_type, @value_type], KEY_PAIR_TUPLE_SIZE))
  end
end

#normalize(guard = nil) ⇒ Object



2620
2621
2622
2623
2624
2625
2626
2627
2628
# File 'lib/puppet/pops/types/types.rb', line 2620

def normalize(guard = nil)
  if self == DEFAULT || self == EMPTY
    self
  else
    key_t = @key_type.normalize(guard)
    value_t = @value_type.normalize(guard)
    @size_type.nil? && @key_type.equal?(key_t) && @value_type.equal?(value_t) ? self : PHashType.new(key_t, value_t, @size_type)
  end
end

#resolve(loader) ⇒ Object



2665
2666
2667
2668
2669
# File 'lib/puppet/pops/types/types.rb', line 2665

def resolve(loader)
  rkey_type = @key_type.resolve(loader)
  rvalue_type = @value_type.resolve(loader)
  rkey_type.equal?(@key_type) && rvalue_type.equal?(@value_type) ? self : self.class.new(rkey_type, rvalue_type, @size_type)
end