Module: PqcAsn1::PEM

Defined in:
lib/pqc_asn1.rb,
lib/pqc_asn1.rb

Overview

Result returned by PEM.decode_auto.

An immutable value object with named attributes (+data+ and label). Use attribute access or pattern matching as the primary API:

result = PqcAsn1::PEM.decode_auto(pem)
result.data   # => binary String
result.label  # => "PUBLIC KEY"

to_a provides an explicit Array conversion when needed:

data, label = PqcAsn1::PEM.decode_auto(pem).to_a

Note: to_ary is intentionally absent. Implicit array coercion (e.g. via splat or Array()) is a footgun that causes DecodeResult objects to be silently destructured in unexpected contexts.

PEM armor encode/decode.

All methods are module functions defined by the C extension.

Examples:

Pattern matching

case PqcAsn1::PEM.decode_auto(pem)
in { label: "PUBLIC KEY", data: }
  PqcAsn1::DER.parse_spki(data)
end

Defined Under Namespace

Classes: DecodeResult

Class Method Summary collapse

Class Method Details

._c_decode_each ⇒ Object



730
# File 'lib/pqc_asn1.rb', line 730

alias_method :_c_decode_each, :decode_each

.decode(pem, label) ⇒ String

Decode a PEM block with the expected label.

Parameters:

  • pem (String) —

    PEM-encoded string

  • label (String) —

    expected PEM label

Returns:

  • (String) —

    frozen binary DER bytes (ASCII-8BIT)

Raises:



582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
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
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'lib/pqc_asn1.rb', line 582

module PEM
  class DecodeResult
    # @return [String] decoded DER bytes (ASCII-8BIT, frozen)
    attr_reader :data

    # @return [String] PEM label string (US-ASCII, frozen)
    attr_reader :label

    # @api private — constructed by PEM.decode_auto via C extension
    def initialize(data, label)
      @data = data
      @label = label
      freeze
    end

    # Explicit Array conversion: +data, label = PEM.decode_auto(pem).to_a+
    # @return [Array(String, String)]
    def to_a
      [@data, @label]
    end

    # @return [Hash{Symbol => String}]
    def to_h
      {data: @data, label: @label}
    end

    # Pattern-matching support (Ruby 2.7+).
    # When +keys+ is non-nil, only the requested keys are returned.
    # @param keys [Array<Symbol>, nil]
    # @return [Hash{Symbol => String}]
    def deconstruct_keys(keys)
      return to_h if keys.nil?

      keys.each_with_object({}) do |k, h|
        case k
        when :data then h[:data] = @data
        when :label then h[:label] = @label
        end
      end
    end

    # @param other [Object]
    # @return [Boolean]
    def ==(other)
      other.is_a?(DecodeResult) &&
        @data == other.data &&
        @label == other.label
    end

    alias_method :eql?, :==

    # @return [Integer]
    def hash
      [@data, @label].hash
    end

    # @return [String]
    def inspect
      "#<PqcAsn1::PEM::DecodeResult label=#{@label.inspect} data=#{@data.bytesize}B>"
    end
  end

  # decode_each is implemented in C (ext/pqc_asn1/pem.c) and attached
  # as a module function by init_pem() during Init_pqc_asn1_ext.
  # It iterates over all PEM blocks in a String or IO, yielding a
  # DecodeResult for each block found.
  #
  # For IO objects, a Ruby-level wrapper reads line-by-line and
  # accumulates PEM blocks incrementally, avoiding slurping the
  # entire stream into memory.
end

.decode_auto(pem) ⇒ PqcAsn1::PEM::DecodeResult

Decode a PEM block, auto-detecting the label.

Parameters:

  • pem (String) —

    PEM-encoded string

Returns:

Raises:



582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
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
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'lib/pqc_asn1.rb', line 582

module PEM
  class DecodeResult
    # @return [String] decoded DER bytes (ASCII-8BIT, frozen)
    attr_reader :data

    # @return [String] PEM label string (US-ASCII, frozen)
    attr_reader :label

    # @api private — constructed by PEM.decode_auto via C extension
    def initialize(data, label)
      @data = data
      @label = label
      freeze
    end

    # Explicit Array conversion: +data, label = PEM.decode_auto(pem).to_a+
    # @return [Array(String, String)]
    def to_a
      [@data, @label]
    end

    # @return [Hash{Symbol => String}]
    def to_h
      {data: @data, label: @label}
    end

    # Pattern-matching support (Ruby 2.7+).
    # When +keys+ is non-nil, only the requested keys are returned.
    # @param keys [Array<Symbol>, nil]
    # @return [Hash{Symbol => String}]
    def deconstruct_keys(keys)
      return to_h if keys.nil?

      keys.each_with_object({}) do |k, h|
        case k
        when :data then h[:data] = @data
        when :label then h[:label] = @label
        end
      end
    end

    # @param other [Object]
    # @return [Boolean]
    def ==(other)
      other.is_a?(DecodeResult) &&
        @data == other.data &&
        @label == other.label
    end

    alias_method :eql?, :==

    # @return [Integer]
    def hash
      [@data, @label].hash
    end

    # @return [String]
    def inspect
      "#<PqcAsn1::PEM::DecodeResult label=#{@label.inspect} data=#{@data.bytesize}B>"
    end
  end

  # decode_each is implemented in C (ext/pqc_asn1/pem.c) and attached
  # as a module function by init_pem() during Init_pqc_asn1_ext.
  # It iterates over all PEM blocks in a String or IO, yielding a
  # DecodeResult for each block found.
  #
  # For IO objects, a Ruby-level wrapper reads line-by-line and
  # accumulates PEM blocks incrementally, avoiding slurping the
  # entire stream into memory.
end

.decode_each(input) {|result| ... } ⇒ nil, Enumerator

Iterate over PEM blocks in a String or IO.

For IO objects, reads line-by-line and decodes each PEM block as it completes, avoiding reading the entire stream into memory. For Strings, delegates directly to the C implementation.

Parameters:

  • input (String, #each_line) —

    PEM text or IO

Yield Parameters:

Returns:

  • (nil, Enumerator)


741
742
743
744
745
746
747
748
749
750
# File 'lib/pqc_asn1.rb', line 741

def decode_each(input, &block)
  if input.respond_to?(:each_line) && !input.is_a?(String)
    return _io_decode_each_enum(input) unless block

    _io_decode_each(input, &block)
    nil
  else
    _c_decode_each(input, &block)
  end
end

.encode(data, label) ⇒ String

PEM-encode binary data with the given label.

Parameters:

  • data (String, PqcAsn1::SecureBuffer) —

    raw DER bytes

  • label (String) —

    PEM label (e.g. "PUBLIC KEY", "PRIVATE KEY")

Returns:

  • (String) —

    frozen US-ASCII PEM string



582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
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
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'lib/pqc_asn1.rb', line 582

module PEM
  class DecodeResult
    # @return [String] decoded DER bytes (ASCII-8BIT, frozen)
    attr_reader :data

    # @return [String] PEM label string (US-ASCII, frozen)
    attr_reader :label

    # @api private — constructed by PEM.decode_auto via C extension
    def initialize(data, label)
      @data = data
      @label = label
      freeze
    end

    # Explicit Array conversion: +data, label = PEM.decode_auto(pem).to_a+
    # @return [Array(String, String)]
    def to_a
      [@data, @label]
    end

    # @return [Hash{Symbol => String}]
    def to_h
      {data: @data, label: @label}
    end

    # Pattern-matching support (Ruby 2.7+).
    # When +keys+ is non-nil, only the requested keys are returned.
    # @param keys [Array<Symbol>, nil]
    # @return [Hash{Symbol => String}]
    def deconstruct_keys(keys)
      return to_h if keys.nil?

      keys.each_with_object({}) do |k, h|
        case k
        when :data then h[:data] = @data
        when :label then h[:label] = @label
        end
      end
    end

    # @param other [Object]
    # @return [Boolean]
    def ==(other)
      other.is_a?(DecodeResult) &&
        @data == other.data &&
        @label == other.label
    end

    alias_method :eql?, :==

    # @return [Integer]
    def hash
      [@data, @label].hash
    end

    # @return [String]
    def inspect
      "#<PqcAsn1::PEM::DecodeResult label=#{@label.inspect} data=#{@data.bytesize}B>"
    end
  end

  # decode_each is implemented in C (ext/pqc_asn1/pem.c) and attached
  # as a module function by init_pem() during Init_pqc_asn1_ext.
  # It iterates over all PEM blocks in a String or IO, yielding a
  # DecodeResult for each block found.
  #
  # For IO objects, a Ruby-level wrapper reads line-by-line and
  # accumulates PEM blocks incrementally, avoiding slurping the
  # entire stream into memory.
end