RubyXL

```Ruby
def output_workbook
    # ∟テンプレートを読み込む
    @wb = RubyXL::Parser.parse(tmp_file_path)
    tmp_sheet_name = @wb[0].sheet_name
    # テンプレートの印刷範囲reference取得
    ref_area = nil
    ref_title = nil
    tmp_defined_names = @wb.defined_names
    if !tmp_defined_names.nil?
      tmp_defined_names.each do |defined_name|
        if defined_name.name == "_xlnm.Print_Titles"
          ref_title = defined_name.reference
        end
        if defined_name.name == "_xlnm.Print_Area"
          ref_area = defined_name.reference
        end
      end
    end

    sheet_count = 3
    2.upto(sheet_count) { |i|
      # 図形もコピー処理↓↓
      indx = i - 1
      sheet_name = tmp_sheet_name + i.to_s # ダミー
      @wb.add_worksheet(sheet_name)
      excel_render(@wb.worksheets[0], @wb.worksheets[indx])
      @wb.worksheets[indx].sheet_views[0].tab_selected = false
      # 図形もコピー↑↑
      # 印刷範囲、印刷タイトル設定処理↓↓
      if !ref_title.nil?
        # 印刷タイトル
        ref_ref = ref_title.gsub("#{tmp_sheet_name}", "#{sheet_name}")
        @wb.defined_names << RubyXL::DefinedName.new({:name => "_xlnm.Print_Titles", :local_sheet_id => "#{indx}", :reference => ref_ref})
      end
      if !ref_area.nil?
        # 印刷範囲
        ref_ref = ref_area.gsub("#{tmp_sheet_name}", "#{sheet_name}")
        @wb.defined_names << RubyXL::DefinedName.new({:name => "_xlnm.Print_Area", :local_sheet_id => "#{indx}", :reference => ref_ref})
      end
      # 印刷範囲、印刷タイトル設定処理↑↑
    }

    # データ書き込み処理（略する・・・・・）
    # 出力処理
    @wb.calc_pr.full_calc_on_load = true
    @wb.calc_pr.calc_completed = true
    @wb.calc_pr.calc_on_save = true
    @wb.calc_pr.force_full_calc = true
    stream = @wb.stream.read
    send_data(
      stream,
      filename: out_file_name,
      disposition: 'attachment'
    )
end

# ここから、シートコピー処理のPrivateイベント
  def excel_render(template, worksheet)
    @template = template
    @worksheet = worksheet
    @worksheet.conditional_formatting = @template.conditional_formatting
    max_col_num = 0
    @template.each_with_index do |row, row_num|
      row&.cells&.each_with_index do |cell, col_num|
        max_col_num = [max_col_num, col_num].max
        next if cell.nil?
        cell_render(cell, row_num, col_num)
      end
      row_height_auto(row_num)
    end
    (max_col_num + 1).times do |col_num|
      col_width_auto(col_num)
    end
    merge_cells
    copy_related_files
    copy_settings
  end

  def merge_cells
    if !@template.merged_cells.nil?
      @template.merged_cells.each do |merged_cell|
        c = merged_cell.ref.col_range
        r = merged_cell.ref.row_range
        @worksheet.merge_cells(r.first, c.first, r.last, c.last)
      end
    end
  end

  def copy_related_files
    @worksheet.relationship_container = RubyXL::OOXMLRelationshipsFile.new
    @worksheet.relationship_container.related_files = {}
    template_relationships = @template.relationship_container.relationships
    if !template_relationships.nil?
      template_relationships.each do |relationship|
        @worksheet.relationship_container.relationships << relationship
      end
    end
    @worksheet.drawing          = @template.drawing
    @worksheet.legacy_drawing   = @template.legacy_drawing
    @worksheet.data_validations = @template.data_validations
    @worksheet.custom_properties = @template.custom_properties
  end

  def copy_settings
    @worksheet.sheet_views     = @template.sheet_views
    @worksheet.sheet_format_pr = @template.sheet_format_pr
    @worksheet.phonetic_pr     = @template.phonetic_pr
    @worksheet.print_options   = @template.print_options
    @worksheet.page_margins    = @template.page_margins
    @worksheet.page_setup      = @template.page_setup
    @worksheet.header_footer = @template.header_footer # 印刷ヘッダー/フッター
  end

  def cell_render(template_cell, row_num, col_num)
    cell = @worksheet.add_cell(row_num, col_num, template_cell.value)
    cell.style_index = template_cell.style_index
    cell.formula = template_cell.formula
  end

  def row_height_auto(row_num)
    @worksheet.change_row_height(row_num, @template.get_row_height(row_num))
    if !@template.sheet_data[row_num].nil?
      @worksheet.sheet_data[row_num].custom_height = @template.sheet_data[row_num].custom_height
    end
  end

  def col_width_auto(col_num)
    # 隠し行処理
    @worksheet.change_column_width_raw(col_num, @template.get_column_width_raw(col_num))
    if !@template.cols[col_num].nil?
      i_min = @template.cols[col_num].min - 1
      i_max = @template.cols[col_num].max - 1
      (i_min..i_max).each { |col_idx|
        @worksheet.cols << @template.cols[col_num].deep_dup
      }
    end
  end
```