Class: Puppet::Pops::Types::PTypeAliasType

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

Overview

Describes a named alias for another Type. The alias is created with a name and an unresolved type expression. The type expression may in turn contain other aliases (including the alias that contains it) which means that an alias might contain self recursion. Whether or not that is the case is computed and remembered when the alias is resolved since guarding against self recursive constructs is relatively expensive.

Defined Under Namespace

Classes: AssertOtherTypeAcceptor, AssertSelfRecursionStatusAcceptor

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from PAnyType

#==, #callable?, #generalize, new_function, #normalize, #simple_name, simple_name, #to_alias_expanded_s

Methods inherited from TypedModelObject

_ptype, create_ptype, register_ptypes

Methods included from PuppetObject

#_ptype

Constructor Details

#initialize(name, type_expr, resolved_type = nil) ⇒ PTypeAliasType

Returns a new instance of PTypeAliasType.

Parameters:

  • name (String)

    The name of the type

  • type_expr (Model::PopsObject)

    The expression that describes the aliased type

  • resolved_type (PAnyType) (defaults to: nil)

    the resolve type (only used for the DEFAULT initialization)



3010
3011
3012
3013
3014
3015
# File 'lib/puppet/pops/types/types.rb', line 3010

def initialize(name, type_expr, resolved_type = nil)
  @name = name
  @type_expr = type_expr
  @resolved_type = resolved_type
  @self_recursion = false
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *arguments, &block) ⇒ Object

Delegates to resolved type



3177
3178
3179
3180
# File 'lib/puppet/pops/types/types.rb', line 3177

def method_missing(name, *arguments, &block)
  super if @resolved_type.equal?(PTypeReferenceType::DEFAULT)
  resolved_type.send(name, *arguments, &block)
end

Instance Attribute Details

#nameObject (readonly)



3005
3006
3007
# File 'lib/puppet/pops/types/types.rb', line 3005

def name
  @name
end

Class Method Details

.register_ptype(loader, ir) ⇒ Object



2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
# File 'lib/puppet/pops/types/types.rb', line 2994

def self.register_ptype(loader, ir)
  create_ptype(loader, ir, 'AnyType',
     'name' => PStringType::NON_EMPTY,
     'type_expr' => PAnyType::DEFAULT,
     'resolved_type' => {
       KEY_TYPE => POptionalType.new(PType::DEFAULT),
       KEY_VALUE => nil
     }
  )
end

Instance Method Details

#accept(visitor, guard) ⇒ Object



3152
3153
3154
3155
3156
3157
# File 'lib/puppet/pops/types/types.rb', line 3152

def accept(visitor, guard)
  guarded_recursion(guard, nil) do |g|
    super(visitor, g)
    @resolved_type.accept(visitor, g) unless @resolved_type.nil?
  end
end

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

Returns:

  • (Boolean)


3017
3018
3019
3020
3021
3022
3023
# File 'lib/puppet/pops/types/types.rb', line 3017

def assignable?(o, guard = nil)
  if @self_recursion
    guard ||= RecursionGuard.new
    return true if guard.add_this(self) == RecursionGuard::SELF_RECURSION_IN_BOTH
  end
  super(o, guard)
end

#callable_args?(callable, guard) ⇒ Boolean

Returns:

  • (Boolean)


3035
3036
3037
# File 'lib/puppet/pops/types/types.rb', line 3035

def callable_args?(callable, guard)
  guarded_recursion(guard, false) { |g| resolved_type.callable_args?(callable, g) }
end

#check_self_recursion(originator) ⇒ Object



3039
3040
3041
# File 'lib/puppet/pops/types/types.rb', line 3039

def check_self_recursion(originator)
  resolved_type.check_self_recursion(originator) unless originator.equal?(self)
end

#eql?(o) ⇒ Boolean

Returns:

  • (Boolean)


3148
3149
3150
# File 'lib/puppet/pops/types/types.rb', line 3148

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

#hashObject



3059
3060
3061
# File 'lib/puppet/pops/types/types.rb', line 3059

def hash
  @name.hash
end

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

Returns:

  • (Boolean)


3047
3048
3049
# File 'lib/puppet/pops/types/types.rb', line 3047

def instance?(o, guard = nil)
  really_instance?(o, guard) == 1
end

#iterable?(guard = nil) ⇒ Boolean

Returns:

  • (Boolean)


3051
3052
3053
# File 'lib/puppet/pops/types/types.rb', line 3051

def iterable?(guard = nil)
  guarded_recursion(guard, false) { |g| resolved_type.iterable?(g) }
end

#iterable_type(guard = nil) ⇒ Object



3055
3056
3057
# File 'lib/puppet/pops/types/types.rb', line 3055

def iterable_type(guard = nil)
  guarded_recursion(guard, nil) { |g| resolved_type.iterable_type(g) }
end

#kind_of_callable?(optional = true, guard = nil) ⇒ Boolean

Returns:

  • (Boolean)


3043
3044
3045
# File 'lib/puppet/pops/types/types.rb', line 3043

def kind_of_callable?(optional=true, guard = nil)
  guarded_recursion(guard, false) { |g| resolved_type.kind_of_callable?(optional, g) }
end

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

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.

Returns:

  • (Boolean)


3183
3184
3185
3186
3187
3188
3189
3190
# File 'lib/puppet/pops/types/types.rb', line 3183

def really_instance?(o, guard = nil)
  if @self_recursion
    guard ||= RecursionGuard.new
    guard.add_that(o)
    return 0 if guard.add_this(self) == RecursionGuard::SELF_RECURSION_IN_BOTH
  end
  resolved_type.really_instance?(o, guard)
end

#resolve(type_parser, loader) ⇒ PTypeAliasType

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.

Called from the TypeParser once it has found a type using the Loader. The TypeParser will interpret the contained expression and the resolved type is remembered. This method also checks and remembers if the resolve type contains self recursion.

Parameters:

  • type_parser (TypeParser)

    type parser that will interpret the type expression

  • loader (Loader::Loader)

    loader to use when loading type aliases

Returns:



3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
# File 'lib/puppet/pops/types/types.rb', line 3109

def resolve(type_parser, loader)
  if @resolved_type.nil?
    # resolved to PTypeReferenceType::DEFAULT during resolve to avoid endless recursion
    @resolved_type = PTypeReferenceType::DEFAULT
    @self_recursion = true # assumed while it being found out below
    begin
      if @type_expr.is_a?(PTypeReferenceType)
        @resolved_type = @type_expr.resolve(type_parser, loader)
      else
        @resolved_type = type_parser.interpret(@type_expr, loader).normalize
      end

      # Find out if this type is recursive. A recursive type has performance implications
      # on several methods and this knowledge is used to avoid that for non-recursive
      # types.
      guard = RecursionGuard.new
      real_type_asserter = AssertOtherTypeAcceptor.new
      accept(real_type_asserter, guard)
      unless real_type_asserter.other_type_detected?
        raise ArgumentError, "Type alias '#{name}' cannot be resolved to a real type"
      end
      @self_recursion = guard.recursive_this?(self)
      # All aliases involved must re-check status since this alias is now resolved
      if @self_recursion
        accept(AssertSelfRecursionStatusAcceptor.new, RecursionGuard.new)
        when_self_recursion_detected
      end
    rescue
      @resolved_type = nil
      raise
    end
  else
    # An alias may appoint an Object type that isn't resolved yet. The default type
    # reference is used to prevent endless recursion and should not be resolved here.
    @resolved_type.resolve(type_parser, loader) unless @resolved_type.equal?(PTypeReferenceType::DEFAULT)
  end
  self
end

#resolved_typePAnyType

Returns the resolved type. The type must have been resolved by a call prior to calls to this method or an error will be raised.

Returns:

  • (PAnyType)

    The resolved type of this alias.

Raises:

  • (Puppet::Error)

    unless the type has been resolved prior to calling this method



3030
3031
3032
3033
# File 'lib/puppet/pops/types/types.rb', line 3030

def resolved_type
  raise Puppet::Error, "Reference to unresolved type #{@name}" unless @resolved_type
  @resolved_type
end

#respond_to_missing?(name, include_private) ⇒ Boolean

Delegates to resolved type

Returns:

  • (Boolean)


3172
3173
3174
# File 'lib/puppet/pops/types/types.rb', line 3172

def respond_to_missing?(name, include_private)
  resolved_type.respond_to?(name, include_private)
end

#self_recursion?Boolean

Returns:

  • (Boolean)


3159
3160
3161
# File 'lib/puppet/pops/types/types.rb', line 3159

def self_recursion?
  @self_recursion
end

#set_self_recursion_statusObject



3092
3093
3094
3095
3096
3097
3098
3099
# File 'lib/puppet/pops/types/types.rb', line 3092

def set_self_recursion_status
  return if @self_recursion || @resolved_type.is_a?(PTypeReferenceType)
  @self_recursion = true
  guard = RecursionGuard.new
  accept(NoopTypeAcceptor::INSTANCE, guard)
  @self_recursion = guard.recursive_this?(self)
  when_self_recursion_detected if @self_recursion # no difference
end

#to_sString

Returns the expanded string the form of the alias, e.g. <alias name> = <resolved type>

Returns:

  • (String)

    the expanded form of this alias



3167
3168
3169
# File 'lib/puppet/pops/types/types.rb', line 3167

def to_s
  TypeFormatter.singleton.alias_expanded_string(self)
end

#type_exprObject

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.

Returns ‘nil` to prevent serialization of the type_expr used when first initializing this instance.

Returns:

  • ‘nil` to prevent serialization of the type_expr used when first initializing this instance



3194
3195
3196
# File 'lib/puppet/pops/types/types.rb', line 3194

def type_expr
  nil
end