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?, #callable_with?, create, #create, #generalize, new_function, #normalize, #roundtrip_with_string?, #simple_name, simple_name, #to_alias_expanded_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(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)



3384
3385
3386
3387
3388
3389
# File 'lib/puppet/pops/types/types.rb', line 3384

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



3556
3557
3558
3559
# File 'lib/puppet/pops/types/types.rb', line 3556

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

Instance Attribute Details

#loaderObject (readonly)



3379
3380
3381
# File 'lib/puppet/pops/types/types.rb', line 3379

def loader
  @loader
end

#nameObject (readonly)



3379
3380
3381
# File 'lib/puppet/pops/types/types.rb', line 3379

def name
  @name
end

Class Method Details

.register_ptype(loader, ir) ⇒ Object



3369
3370
3371
3372
3373
3374
3375
3376
3377
# File 'lib/puppet/pops/types/types.rb', line 3369

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(PTypeType::DEFAULT),
                 KEY_VALUE => nil
               })
end

Instance Method Details

#accept(visitor, guard) ⇒ Object



3531
3532
3533
3534
3535
3536
# File 'lib/puppet/pops/types/types.rb', line 3531

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)


3391
3392
3393
3394
3395
3396
3397
3398
# File 'lib/puppet/pops/types/types.rb', line 3391

def assignable?(o, guard = nil)
  if @self_recursion
    guard ||= RecursionGuard.new
    guard.with_this(self) { |state| state == RecursionGuard::SELF_RECURSION_IN_BOTH ? true : super(o, guard) }
  else
    super(o, guard)
  end
end

#callable_args?(callable, guard) ⇒ Boolean

Returns:

  • (Boolean)


3411
3412
3413
# File 'lib/puppet/pops/types/types.rb', line 3411

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

#check_self_recursion(originator) ⇒ Object



3415
3416
3417
# File 'lib/puppet/pops/types/types.rb', line 3415

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

#eql?(o) ⇒ Boolean

Returns:

  • (Boolean)


3527
3528
3529
# File 'lib/puppet/pops/types/types.rb', line 3527

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

#hashObject



3435
3436
3437
# File 'lib/puppet/pops/types/types.rb', line 3435

def hash
  @name.hash
end

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

Returns:

  • (Boolean)


3423
3424
3425
# File 'lib/puppet/pops/types/types.rb', line 3423

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

#iterable?(guard = nil) ⇒ Boolean

Returns:

  • (Boolean)


3427
3428
3429
# File 'lib/puppet/pops/types/types.rb', line 3427

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

#iterable_type(guard = nil) ⇒ Object



3431
3432
3433
# File 'lib/puppet/pops/types/types.rb', line 3431

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)


3419
3420
3421
# File 'lib/puppet/pops/types/types.rb', line 3419

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)


3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
# File 'lib/puppet/pops/types/types.rb', line 3562

def really_instance?(o, guard = nil)
  if @self_recursion
    guard ||= RecursionGuard.new
    guard.with_that(o) do
      guard.with_this(self) { |state| state == RecursionGuard::SELF_RECURSION_IN_BOTH ? 0 : resolved_type.really_instance?(o, guard) }
    end
  else
    resolved_type.really_instance?(o, guard)
  end
end

#resolve(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:



3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
# File 'lib/puppet/pops/types/types.rb', line 3486

def resolve(loader)
  @loader = 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(loader)
      else
        @resolved_type = TypeParser.singleton.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(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



3405
3406
3407
3408
3409
# File 'lib/puppet/pops/types/types.rb', line 3405

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)


3551
3552
3553
# File 'lib/puppet/pops/types/types.rb', line 3551

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

#self_recursion?Boolean

Returns:

  • (Boolean)


3538
3539
3540
# File 'lib/puppet/pops/types/types.rb', line 3538

def self_recursion?
  @self_recursion
end

#set_self_recursion_statusObject



3468
3469
3470
3471
3472
3473
3474
3475
3476
# File 'lib/puppet/pops/types/types.rb', line 3468

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



3546
3547
3548
# File 'lib/puppet/pops/types/types.rb', line 3546

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



3575
3576
3577
# File 'lib/puppet/pops/types/types.rb', line 3575

def type_expr
  nil
end