You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: serializer.rb
    path of file: ./repos/puppet/lib/puppet/pops/serialization
    
    the code of the file until where you have to start completion: # frozen_string_literal: true

require_relative 'extension'

module Puppet::Pops
module Serialization
  # The serializer is capable of writing, arrays, maps, and complex objects using an underlying protocol writer. It takes care of
  # tabulating and disassembling complex objects.
  # @api public
  class Serializer
    # Provides access to the writer.
    # @api private
    attr_reader :writer

    # @param writer [AbstractWriter] the writer that is used for writing primitive values
    # @param options [{String, Object}] serialization options
    # @option options [Boolean] :type_by_reference `true` if Object types are serialized by name only.
    # @api public
    def initialize(writer, options = EMPTY_HASH)
      # Hash#compare_by_identity is intentionally not used since we only need to map
      # object ids to their size and we don't want to store entire objects in memory
      @written = {}
      @writer = writer
      @options = options
    end

    # Tell the underlying writer to finish
    # @api public
    def finish
      @writer.finish
    end

    # Write an object
    # @param [Object] value the object to write
    # @api public
    def write(value)
      case value
      when In
    
    def write_tabulated_first_time(value)
      if value.instance_of?(Symbol) ||
         value.instance_of?(Regexp) ||
         value.instance_of?(SemanticPuppet::Version) ||
         value.instance_of?(SemanticPuppet::VersionRange) ||
         value.instance_of?(Time::Timestamp) ||
         value.instance_of?(Time::Timespan) ||
         value.instance_of?(Types::PBinaryType::Binary) ||
         value.is_a?(URI)
        push_written(value)
        @writer.write(value)
      elsif value.instance_of?(Array)
        push_written(value)
        start_array(value.size)
        value.each { |elem| write(elem) }
      elsif value.instance_of?(Hash)
        push_written(value)
        start_map(value.size)
        value.each_pair { |key, val| write(key); write(val) }
      elsif value.instance_of?(Types::PSensitiveType::Sensitive)
        start_sensitive
        write(value.unwrap)
      elsif value.instance_of?(Types::PTypeReferenceType)
        push_written(value)
        @writer.write(value)
      elsif value.is_a?(Types::PuppetObject)
        value._pcore_type.write(value, self)
      else
        impl_class = value.class
        type = Loaders.implementation_registry.type_for_module(impl_class)
        raise SerializationError, _("No Puppet Type found for %{klass}") % { klass: impl_class.name } unless type.is_a?(Types::PObjectType)

        type.write(value, self)
      end