standard-procedure-consolidate 0.3.9 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +8 -0
 - data/checksums/standard-procedure-consolidate-0.4.0.gem.sha512 +1 -0
 - data/checksums/standard-procedure-consolidate-0.4.1.gem.sha512 +1 -0
 - data/lib/consolidate/docx/image.rb +11 -3
 - data/lib/consolidate/docx/image_reference_node_builder.rb +64 -62
 - data/lib/consolidate/docx/merge.rb +147 -47
 - data/lib/consolidate/image.rb +4 -1
 - data/lib/consolidate/version.rb +1 -1
 - metadata +4 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 0ffce925315399bd4432936d929e995114acc2dea081f3835eb437fe2787f612
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: b64ae5181ae92d5e66be79e5861787c3355fe08870dbb4ee3ab8355ef4ce149d
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: e56547c32223cf66f807c804cdfff2897f63887729dcf1ff80d51c35a0615115f47b16347b582d58a6ae128c3ecad91a67ca128e0d7c89b6e55a3e88b2d5a6c9
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 4b351ad3a367dd4382abc18e18fbc978095fec92aa8b258a90feb82f2e0a65ffbcca26a8177383d75fab07d711a170b10b541e48c195c4b8b7db0eea2cfd1b26
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,3 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # [0.4.1] - 2024-12-18
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Replace image merge fields with blanks if the image data is not provided 
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            # [0.4.0] - 2024-12-16
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Image embedding works
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       1 
9 
     | 
    
         
             
            # [0.3.9] - 2024-12-4
         
     | 
| 
       2 
10 
     | 
    
         | 
| 
       3 
11 
     | 
    
         
             
            Image embedding - not fully tested but it seems to work in a few test cases
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            58d1597374e775340c60e3e49b9d65437909b482f7be3040fb9fdca5d8d4b4d3020508a9ee01e3521b2c552e1b853d0475335d1ca1c092b4172c1e9ac86df640
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            dfd2ec36154a632f86dd8f99a2b85c59ed6048dbb6b8100f84645ea1cf49e3e77ad73b3367ef89d46e055c860f1b1e82c5b0d0d37c969a19c2644a3e42ebbe21
         
     | 
| 
         @@ -13,12 +13,20 @@ module Consolidate 
     | 
|
| 
       13 
13 
     | 
    
         
             
                  def storage_path = "word/#{media_path}"
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                  # Convert width from pixels to EMU
         
     | 
| 
       16 
     | 
    
         
            -
                  def width = super *  
     | 
| 
      
 16 
     | 
    
         
            +
                  def width = super * emu_per_width_pixel
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                  # Convert height from pixels to EMU
         
     | 
| 
       19 
     | 
    
         
            -
                  def height = super *  
     | 
| 
      
 19 
     | 
    
         
            +
                  def height = super * emu_per_height_pixel
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                   
     | 
| 
      
 21 
     | 
    
         
            +
                  # Get the width of this image in EMU up to a maximum page width (also in EMU)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def clamped_width(maximum = 7_772_400) = [width, maximum].min
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  # Get the height of this image in EMU adjusted for a maximum page width (also in EMU)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def clamped_height(maximum = 7_772_400) = (height * clamped_width(maximum).to_f / width.to_f).to_i
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def emu_per_width_pixel = 914_400 / dpi[:x]
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def emu_per_height_pixel = 914_400 / dpi[:y]
         
     | 
| 
       22 
30 
     | 
    
         
             
                end
         
     | 
| 
       23 
31 
     | 
    
         
             
              end
         
     | 
| 
       24 
32 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,74 +5,67 @@ require "nokogiri" 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            module Consolidate
         
     | 
| 
       7 
7 
     | 
    
         
             
              module Docx
         
     | 
| 
       8 
     | 
    
         
            -
                class ImageReferenceNodeBuilder < Data.define(:field_name, :image, :node_id, :document)
         
     | 
| 
      
 8 
     | 
    
         
            +
                class ImageReferenceNodeBuilder < Data.define(:field_name, :image, :node_id, :image_number, :document)
         
     | 
| 
       9 
9 
     | 
    
         
             
                  def call
         
     | 
| 
       10 
     | 
    
         
            -
                    Nokogiri::XML::Node.new("w: 
     | 
| 
       11 
     | 
    
         
            -
                       
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                           
     | 
| 
       23 
     | 
    
         
            -
                           
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                              graphic_frame_locks["noChangeAspect"] = "1"
         
     | 
| 
       31 
     | 
    
         
            -
                            end
         
     | 
| 
      
 10 
     | 
    
         
            +
                    Nokogiri::XML::Node.new("w:drawing", document).tap do |drawing|
         
     | 
| 
      
 11 
     | 
    
         
            +
                      drawing["xmlns:a"] = "http://schemas.openxmlformats.org/drawingml/2006/main"
         
     | 
| 
      
 12 
     | 
    
         
            +
                      drawing << Nokogiri::XML::Node.new("wp:inline", document).tap do |inline|
         
     | 
| 
      
 13 
     | 
    
         
            +
                        inline["distT"] = "0"
         
     | 
| 
      
 14 
     | 
    
         
            +
                        inline["distB"] = "0"
         
     | 
| 
      
 15 
     | 
    
         
            +
                        inline["distL"] = "0"
         
     | 
| 
      
 16 
     | 
    
         
            +
                        inline["distR"] = "0"
         
     | 
| 
      
 17 
     | 
    
         
            +
                        inline << Nokogiri::XML::Node.new("wp:extent", document).tap do |extent|
         
     | 
| 
      
 18 
     | 
    
         
            +
                          extent["cx"] = image.clamped_width(max_width_from(document))
         
     | 
| 
      
 19 
     | 
    
         
            +
                          extent["cy"] = image.clamped_height(max_width_from(document))
         
     | 
| 
      
 20 
     | 
    
         
            +
                        end
         
     | 
| 
      
 21 
     | 
    
         
            +
                        inline << Nokogiri::XML::Node.new("wp:effectExtent", document).tap do |effect_extent|
         
     | 
| 
      
 22 
     | 
    
         
            +
                          effect_extent["l"] = "0"
         
     | 
| 
      
 23 
     | 
    
         
            +
                          effect_extent["t"] = "0"
         
     | 
| 
      
 24 
     | 
    
         
            +
                          effect_extent["r"] = "0"
         
     | 
| 
      
 25 
     | 
    
         
            +
                          effect_extent["b"] = "0"
         
     | 
| 
      
 26 
     | 
    
         
            +
                        end
         
     | 
| 
      
 27 
     | 
    
         
            +
                        inline << Nokogiri::XML::Node.new("wp:cNvGraphicFramePr", document).tap do |c_nv_graphic_frame_pr|
         
     | 
| 
      
 28 
     | 
    
         
            +
                          c_nv_graphic_frame_pr << Nokogiri::XML::Node.new("a:graphicFrameLocks", document).tap do |graphic_frame_locks|
         
     | 
| 
      
 29 
     | 
    
         
            +
                            graphic_frame_locks["noChangeAspect"] = true
         
     | 
| 
       32 
30 
     | 
    
         
             
                          end
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                                   
     | 
| 
       44 
     | 
    
         
            -
                                   
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                                    end
         
     | 
| 
       48 
     | 
    
         
            -
                                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                        end
         
     | 
| 
      
 32 
     | 
    
         
            +
                        inline << Nokogiri::XML::Node.new("a:graphic", document).tap do |graphic|
         
     | 
| 
      
 33 
     | 
    
         
            +
                          graphic["xmlns:a"] = "http://schemas.openxmlformats.org/drawingml/2006/main"
         
     | 
| 
      
 34 
     | 
    
         
            +
                          graphic << Nokogiri::XML::Node.new("a:graphicData", document).tap do |graphic_data|
         
     | 
| 
      
 35 
     | 
    
         
            +
                            graphic_data["uri"] = "http://schemas.openxmlformats.org/drawingml/2006/picture"
         
     | 
| 
      
 36 
     | 
    
         
            +
                            graphic_data << Nokogiri::XML::Node.new("pic:pic", document).tap do |pic|
         
     | 
| 
      
 37 
     | 
    
         
            +
                              pic["xmlns:pic"] = "http://schemas.openxmlformats.org/drawingml/2006/picture"
         
     | 
| 
      
 38 
     | 
    
         
            +
                              pic << Nokogiri::XML::Node.new("pic:nvPicPr", document).tap do |nv_pic_pr|
         
     | 
| 
      
 39 
     | 
    
         
            +
                                nv_pic_pr << Nokogiri::XML::Node.new("pic:cNvPr", document).tap do |c_nv_pr|
         
     | 
| 
      
 40 
     | 
    
         
            +
                                  c_nv_pr["id"] = image_number
         
     | 
| 
      
 41 
     | 
    
         
            +
                                  c_nv_pr["name"] = image.name
         
     | 
| 
      
 42 
     | 
    
         
            +
                                  c_nv_pr["descr"] = image.name
         
     | 
| 
      
 43 
     | 
    
         
            +
                                  c_nv_pr["hidden"] = false
         
     | 
| 
      
 44 
     | 
    
         
            +
                                  c_nv_pr << Nokogiri::XML::Node.new("pic:cNvPicPr", document)
         
     | 
| 
       49 
45 
     | 
    
         
             
                                end
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                                    blip << Nokogiri::XML::Node.new("a:extLst", document)
         
     | 
| 
       55 
     | 
    
         
            -
                                  end
         
     | 
| 
       56 
     | 
    
         
            -
                                  blip_fill << Nokogiri::XML::Node.new("a:stretch", document).tap do |stretch|
         
     | 
| 
       57 
     | 
    
         
            -
                                    stretch << Nokogiri::XML::Node.new("a:fillRect", document)
         
     | 
| 
       58 
     | 
    
         
            -
                                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                              end
         
     | 
| 
      
 47 
     | 
    
         
            +
                              pic << Nokogiri::XML::Node.new("pic:blipFill", document).tap do |blip_fill|
         
     | 
| 
      
 48 
     | 
    
         
            +
                                blip_fill << Nokogiri::XML::Node.new("a:blip", document).tap do |blip|
         
     | 
| 
      
 49 
     | 
    
         
            +
                                  blip["r:embed"] = node_id
         
     | 
| 
       59 
50 
     | 
    
         
             
                                end
         
     | 
| 
       60 
     | 
    
         
            -
                                 
     | 
| 
       61 
     | 
    
         
            -
                                   
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                                blip_fill << Nokogiri::XML::Node.new("a:stretch", document).tap do |stretch|
         
     | 
| 
      
 52 
     | 
    
         
            +
                                  stretch << Nokogiri::XML::Node.new("a:fillRect", document)
         
     | 
| 
      
 53 
     | 
    
         
            +
                                end
         
     | 
| 
      
 54 
     | 
    
         
            +
                              end
         
     | 
| 
      
 55 
     | 
    
         
            +
                              pic << Nokogiri::XML::Node.new("pic:spPr", document).tap do |sp_pr|
         
     | 
| 
      
 56 
     | 
    
         
            +
                                sp_pr << Nokogiri::XML::Node.new("a:xfrm", document).tap do |xfrm|
         
     | 
| 
      
 57 
     | 
    
         
            +
                                  xfrm << Nokogiri::XML::Node.new("a:off", document).tap do |off|
         
     | 
| 
      
 58 
     | 
    
         
            +
                                    off["x"] = "0"
         
     | 
| 
      
 59 
     | 
    
         
            +
                                    off["y"] = "0"
         
     | 
| 
       70 
60 
     | 
    
         
             
                                  end
         
     | 
| 
       71 
     | 
    
         
            -
                                   
     | 
| 
       72 
     | 
    
         
            -
                                     
     | 
| 
       73 
     | 
    
         
            -
                                     
     | 
| 
      
 61 
     | 
    
         
            +
                                  xfrm << Nokogiri::XML::Node.new("a:ext", document).tap do |ext|
         
     | 
| 
      
 62 
     | 
    
         
            +
                                    ext["cx"] = image.clamped_width(max_width_from(document))
         
     | 
| 
      
 63 
     | 
    
         
            +
                                    ext["cy"] = image.clamped_height(max_width_from(document))
         
     | 
| 
       74 
64 
     | 
    
         
             
                                  end
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
                                end
         
     | 
| 
      
 66 
     | 
    
         
            +
                                sp_pr << Nokogiri::XML::Node.new("a:prstGeom", document).tap do |prst_geom|
         
     | 
| 
      
 67 
     | 
    
         
            +
                                  prst_geom["prst"] = "rect"
         
     | 
| 
      
 68 
     | 
    
         
            +
                                  prst_geom << Nokogiri::XML::Node.new("a:avLst", document)
         
     | 
| 
       76 
69 
     | 
    
         
             
                                end
         
     | 
| 
       77 
70 
     | 
    
         
             
                              end
         
     | 
| 
       78 
71 
     | 
    
         
             
                            end
         
     | 
| 
         @@ -81,6 +74,15 @@ module Consolidate 
     | 
|
| 
       81 
74 
     | 
    
         
             
                      end
         
     | 
| 
       82 
75 
     | 
    
         
             
                    end
         
     | 
| 
       83 
76 
     | 
    
         
             
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  DEFAULT_PAGE_WIDTH = 12_240
         
     | 
| 
      
 79 
     | 
    
         
            +
                  TWENTIETHS_OF_A_POINT_TO_EMU = 635
         
     | 
| 
      
 80 
     | 
    
         
            +
                  DEFAULT_PAGE_WIDTH_IN_EMU = DEFAULT_PAGE_WIDTH * TWENTIETHS_OF_A_POINT_TO_EMU
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  private def max_width_from document
         
     | 
| 
      
 83 
     | 
    
         
            +
                    page_width = (document.at_xpath("//w:sectPr/w:pgSz/@w:w")&.value || DEFAULT_PAGE_WIDTH).to_i
         
     | 
| 
      
 84 
     | 
    
         
            +
                    page_width * TWENTIETHS_OF_A_POINT_TO_EMU
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
       84 
86 
     | 
    
         
             
                end
         
     | 
| 
       85 
87 
     | 
    
         
             
              end
         
     | 
| 
       86 
88 
     | 
    
         
             
            end
         
     | 
| 
         @@ -20,13 +20,16 @@ module Consolidate 
     | 
|
| 
       20 
20 
     | 
    
         
             
                    @zip = Zip::File.open(path)
         
     | 
| 
       21 
21 
     | 
    
         
             
                    @documents = load_documents
         
     | 
| 
       22 
22 
     | 
    
         
             
                    @relations = load_relations
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @contents_xml = load_and_update_contents_xml
         
     | 
| 
       23 
24 
     | 
    
         
             
                    @output = {}
         
     | 
| 
       24 
25 
     | 
    
         
             
                    @images = {}
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @mapping = {}
         
     | 
| 
       25 
27 
     | 
    
         
             
                  end
         
     | 
| 
       26 
28 
     | 
    
         | 
| 
       27 
29 
     | 
    
         
             
                  # Helper method to display the contents of the document and the merge fields from the CLI
         
     | 
| 
       28 
30 
     | 
    
         
             
                  def examine
         
     | 
| 
       29 
31 
     | 
    
         
             
                    puts "Documents: #{document_names.join(", ")}"
         
     | 
| 
      
 32 
     | 
    
         
            +
                    puts "Content documents: #{content_document_names.join(", ")}"
         
     | 
| 
       30 
33 
     | 
    
         
             
                    puts "Merge fields: #{text_field_names.join(", ")}"
         
     | 
| 
       31 
34 
     | 
    
         
             
                    puts "Image fields: #{image_field_names.join(", ")}"
         
     | 
| 
       32 
35 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -38,29 +41,48 @@ module Consolidate 
     | 
|
| 
       38 
41 
     | 
    
         
             
                  def image_field_names = @image_field_names ||= tag_nodes.collect { |tag_node| image_field_names_from tag_node }.flatten.compact.uniq
         
     | 
| 
       39 
42 
     | 
    
         | 
| 
       40 
43 
     | 
    
         
             
                  # List the documents stored within this docx
         
     | 
| 
       41 
     | 
    
         
            -
                  def document_names = @zip.entries. 
     | 
| 
      
 44 
     | 
    
         
            +
                  def document_names = @zip.entries.map(&:name)
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  # List the content within this docx
         
     | 
| 
      
 47 
     | 
    
         
            +
                  def content_document_names = @documents.keys
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  # List the field names that are present in the merge data
         
     | 
| 
      
 50 
     | 
    
         
            +
                  def merge_field_names = @mapping.keys
         
     | 
| 
       42 
51 
     | 
    
         | 
| 
       43 
52 
     | 
    
         
             
                  # Set the merge data and erform the substitution - creating copies of any documents that contain merge tags and replacing the tags with the supplied data
         
     | 
| 
       44 
53 
     | 
    
         
             
                  def data mapping = {}
         
     | 
| 
       45 
     | 
    
         
            -
                    mapping = mapping.transform_keys(&:to_s)
         
     | 
| 
       46 
     | 
    
         
            -
                     
     | 
| 
      
 54 
     | 
    
         
            +
                    @mapping = mapping.transform_keys(&:to_s)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if verbose
         
     | 
| 
      
 56 
     | 
    
         
            +
                      puts "...mapping data"
         
     | 
| 
      
 57 
     | 
    
         
            +
                      puts @mapping.keys.select { |field_name| text_field_names.include?(field_name) }.map { |field_name| "...   #{field_name} => #{@mapping[field_name]}" }.join("\n")
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
       47 
59 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
                    @images =  
     | 
| 
      
 60 
     | 
    
         
            +
                    @images = load_images_and_link_relations
         
     | 
| 
       49 
61 
     | 
    
         | 
| 
       50 
62 
     | 
    
         
             
                    @documents.each do |name, document|
         
     | 
| 
       51 
     | 
    
         
            -
                      @output[name] = substitute(document.dup,  
     | 
| 
      
 63 
     | 
    
         
            +
                      @output[name] = substitute(document.dup, document_name: name).serialize save_with: 0
         
     | 
| 
       52 
64 
     | 
    
         
             
                    end
         
     | 
| 
       53 
65 
     | 
    
         
             
                  end
         
     | 
| 
       54 
66 
     | 
    
         | 
| 
       55 
67 
     | 
    
         
             
                  def write_to path
         
     | 
| 
       56 
68 
     | 
    
         
             
                    puts "...writing to #{path}" if verbose
         
     | 
| 
       57 
69 
     | 
    
         
             
                    Zip::File.open(path, Zip::File::CREATE) do |out|
         
     | 
| 
      
 70 
     | 
    
         
            +
                      @output[contents_xml] = @contents_xml.serialize save_with: 0
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
       58 
72 
     | 
    
         
             
                      @images.each do |field_name, image|
         
     | 
| 
       59 
     | 
    
         
            -
                         
     | 
| 
      
 73 
     | 
    
         
            +
                        next if image.nil?
         
     | 
| 
      
 74 
     | 
    
         
            +
                        puts "...  writing image #{field_name} to #{image.storage_path}" if verbose
         
     | 
| 
       60 
75 
     | 
    
         
             
                        out.get_output_stream(image.storage_path) { |o| o.write image.contents }
         
     | 
| 
       61 
76 
     | 
    
         
             
                      end
         
     | 
| 
       62 
77 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                      @ 
     | 
| 
      
 78 
     | 
    
         
            +
                      @relations.each do |relation_name, relations|
         
     | 
| 
      
 79 
     | 
    
         
            +
                        puts "...  writing relations #{relation_name}" if verbose
         
     | 
| 
      
 80 
     | 
    
         
            +
                        out.get_output_stream(relation_name) { |o| o.write relations }
         
     | 
| 
      
 81 
     | 
    
         
            +
                      end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                      @zip.reject do |entry|
         
     | 
| 
      
 84 
     | 
    
         
            +
                        @relations.key? entry.name
         
     | 
| 
      
 85 
     | 
    
         
            +
                      end.each do |entry|
         
     | 
| 
       64 
86 
     | 
    
         
             
                        puts "...  writing updated document to #{entry.name}" if verbose
         
     | 
| 
       65 
87 
     | 
    
         
             
                        out.get_output_stream(entry.name) { |o| o.write(@output[entry.name] || @relations[entry.name] || @zip.read(entry.name)) }
         
     | 
| 
       66 
88 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -71,25 +93,7 @@ module Consolidate 
     | 
|
| 
       71 
93 
     | 
    
         | 
| 
       72 
94 
     | 
    
         
             
                  attr_reader :verbose
         
     | 
| 
       73 
95 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
                  def  
     | 
| 
       75 
     | 
    
         
            -
                    @zip.entries.each_with_object({}) do |entry, results|
         
     | 
| 
       76 
     | 
    
         
            -
                      next unless entry.name.match?(/word\/(document|header|footer|footnotes|endnotes).?\.xml/)
         
     | 
| 
       77 
     | 
    
         
            -
                      puts "...reading document #{entry.name}" if verbose
         
     | 
| 
       78 
     | 
    
         
            -
                      contents = @zip.get_input_stream entry
         
     | 
| 
       79 
     | 
    
         
            -
                      results[entry.name] = Nokogiri::XML(contents) { |x| x.noent }
         
     | 
| 
       80 
     | 
    
         
            -
                    end
         
     | 
| 
       81 
     | 
    
         
            -
                  end
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                  def load_relations
         
     | 
| 
       84 
     | 
    
         
            -
                    @zip.entries.each_with_object({}) do |entry, results|
         
     | 
| 
       85 
     | 
    
         
            -
                      next unless entry.name.match?(/word\/_rels\/.*.rels/)
         
     | 
| 
       86 
     | 
    
         
            -
                      puts "...reading relation #{entry.name}" if verbose
         
     | 
| 
       87 
     | 
    
         
            -
                      contents = @zip.get_input_stream entry
         
     | 
| 
       88 
     | 
    
         
            -
                      results[entry.name] = Nokogiri::XML(contents) { |x| x.noent }
         
     | 
| 
       89 
     | 
    
         
            -
                    end
         
     | 
| 
       90 
     | 
    
         
            -
                  ensure
         
     | 
| 
       91 
     | 
    
         
            -
                    @zip.close
         
     | 
| 
       92 
     | 
    
         
            -
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                  def contents_xml = "[Content_Types].xml"
         
     | 
| 
       93 
97 
     | 
    
         | 
| 
       94 
98 
     | 
    
         
             
                  # Regex to find merge fields that contain text
         
     | 
| 
       95 
99 
     | 
    
         
             
                  def text_tag = /\{\{\s*(?!.*_image\b)(\S+)\s*\}\}/i
         
     | 
| 
         @@ -113,30 +117,61 @@ module Consolidate 
     | 
|
| 
       113 
117 
     | 
    
         
             
                  # Extract the image field name(s) from the paragraph
         
     | 
| 
       114 
118 
     | 
    
         
             
                  def image_field_names_from(tag_node) = (matches = tag_node.content.scan(image_tag)).empty? ? nil : matches.flatten.map(&:strip)
         
     | 
| 
       115 
119 
     | 
    
         | 
| 
      
 120 
     | 
    
         
            +
                  # Unique number for each image field
         
     | 
| 
      
 121 
     | 
    
         
            +
                  def relation_number_for(field_name) = @mapping.keys.index(field_name) + 1000
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
       116 
123 
     | 
    
         
             
                  # Identifier to use when linking a merge field to the actual image file contents
         
     | 
| 
       117 
124 
     | 
    
         
             
                  def relation_id_for(field_name) = "rId#{field_name}"
         
     | 
| 
       118 
125 
     | 
    
         | 
| 
      
 126 
     | 
    
         
            +
                  # Empty elations document for documents that do not already have one
         
     | 
| 
      
 127 
     | 
    
         
            +
                  def default_relations_document = %(<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"></Relationships>)
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  def load_documents
         
     | 
| 
      
 130 
     | 
    
         
            +
                    @zip.entries.each_with_object({}) do |entry, results|
         
     | 
| 
      
 131 
     | 
    
         
            +
                      next unless entry.name.match?(/word\/(document|header|footer|footnotes|endnotes).?\.xml/)
         
     | 
| 
      
 132 
     | 
    
         
            +
                      puts "...reading document #{entry.name}" if verbose
         
     | 
| 
      
 133 
     | 
    
         
            +
                      contents = @zip.get_input_stream entry
         
     | 
| 
      
 134 
     | 
    
         
            +
                      results[entry.name] = Nokogiri::XML(contents) { |x| x.noent }
         
     | 
| 
      
 135 
     | 
    
         
            +
                    end
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                  def load_relations
         
     | 
| 
      
 139 
     | 
    
         
            +
                    @zip.entries.each_with_object({}) do |entry, results|
         
     | 
| 
      
 140 
     | 
    
         
            +
                      next unless entry.name.match?(/word\/(document|header|footer|footnotes|endnotes).?\.xml/)
         
     | 
| 
      
 141 
     | 
    
         
            +
                      relation_document = entry.name.gsub("word/", "word/_rels/").gsub(".xml", ".xml.rels")
         
     | 
| 
      
 142 
     | 
    
         
            +
                      puts "...reading or building relations for #{relation_document}" if verbose
         
     | 
| 
      
 143 
     | 
    
         
            +
                      contents = @zip.find_entry(relation_document) ? @zip.get_input_stream(relation_document) : default_relations_document
         
     | 
| 
      
 144 
     | 
    
         
            +
                      results[relation_document] = Nokogiri::XML(contents) { |x| x.noent }
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 147 
     | 
    
         
            +
                    @zip.close
         
     | 
| 
      
 148 
     | 
    
         
            +
                  end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
       119 
150 
     | 
    
         
             
                  # Create relation links for each image field and store the image data
         
     | 
| 
       120 
     | 
    
         
            -
                  def  
     | 
| 
       121 
     | 
    
         
            -
                     
     | 
| 
      
 151 
     | 
    
         
            +
                  def load_images_and_link_relations
         
     | 
| 
      
 152 
     | 
    
         
            +
                    load_images.tap do |images|
         
     | 
| 
       122 
153 
     | 
    
         
             
                      link_relations_to images
         
     | 
| 
       123 
154 
     | 
    
         
             
                    end
         
     | 
| 
       124 
155 
     | 
    
         
             
                  end
         
     | 
| 
       125 
156 
     | 
    
         | 
| 
       126 
157 
     | 
    
         
             
                  # Build a mapping of image paths to the image data so that the image data can be stored in the output docx
         
     | 
| 
       127 
     | 
    
         
            -
                  def  
     | 
| 
      
 158 
     | 
    
         
            +
                  def load_images
         
     | 
| 
       128 
159 
     | 
    
         
             
                    image_field_names.each_with_object({}) do |field_name, result|
         
     | 
| 
       129 
     | 
    
         
            -
                      result[field_name] = Consolidate::Docx::Image.new(mapping[field_name])
         
     | 
| 
      
 160 
     | 
    
         
            +
                      result[field_name] = @mapping[field_name].nil? ? nil : Consolidate::Docx::Image.new(@mapping[field_name])
         
     | 
| 
      
 161 
     | 
    
         
            +
                      puts "...   #{field_name} => #{result[field_name]&.media_path}" if verbose
         
     | 
| 
       130 
162 
     | 
    
         
             
                    end
         
     | 
| 
       131 
163 
     | 
    
         
             
                  end
         
     | 
| 
       132 
164 
     | 
    
         | 
| 
       133 
165 
     | 
    
         
             
                  # Update all relation documents to include a relationship for each image field and its stored image path
         
     | 
| 
       134 
166 
     | 
    
         
             
                  def link_relations_to images
         
     | 
| 
       135 
167 
     | 
    
         
             
                    @relations.each do |name, xml|
         
     | 
| 
      
 168 
     | 
    
         
            +
                      puts "...   linking images in #{name}" if verbose
         
     | 
| 
       136 
169 
     | 
    
         
             
                      images.each do |field_name, image|
         
     | 
| 
      
 170 
     | 
    
         
            +
                        # Has an actual image file been supplied?
         
     | 
| 
      
 171 
     | 
    
         
            +
                        next if image.nil? 
         
     | 
| 
       137 
172 
     | 
    
         
             
                        # Is this image already referenced in this relationship document?
         
     | 
| 
       138 
     | 
    
         
            -
                        next unless xml.at_xpath("//Relationship[@Target 
     | 
| 
       139 
     | 
    
         
            -
                        puts "... 
     | 
| 
      
 173 
     | 
    
         
            +
                        next unless xml.at_xpath("//Relationship[@Target=\"#{image.media_path}\"]").nil?
         
     | 
| 
      
 174 
     | 
    
         
            +
                        puts "...      #{relation_id_for(field_name)} => #{image.media_path}" if verbose
         
     | 
| 
       140 
175 
     | 
    
         
             
                        xml.root << Nokogiri::XML::Node.new("Relationship", xml).tap do |relation|
         
     | 
| 
       141 
176 
     | 
    
         
             
                          relation["Id"] = relation_id_for(field_name)
         
     | 
| 
       142 
177 
     | 
    
         
             
                          relation["Type"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
         
     | 
| 
         @@ -146,32 +181,38 @@ module Consolidate 
     | 
|
| 
       146 
181 
     | 
    
         
             
                    end
         
     | 
| 
       147 
182 
     | 
    
         
             
                  end
         
     | 
| 
       148 
183 
     | 
    
         | 
| 
      
 184 
     | 
    
         
            +
                  def load_and_update_contents_xml
         
     | 
| 
      
 185 
     | 
    
         
            +
                    puts "...reading and updating #{contents_xml}" if verbose
         
     | 
| 
      
 186 
     | 
    
         
            +
                    content = @zip.get_input_stream(contents_xml)
         
     | 
| 
      
 187 
     | 
    
         
            +
                    Nokogiri::XML(content) { |x| x.noent }.tap do |document|
         
     | 
| 
      
 188 
     | 
    
         
            +
                      add_content_relations_to document
         
     | 
| 
      
 189 
     | 
    
         
            +
                    end
         
     | 
| 
      
 190 
     | 
    
         
            +
                  end
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
       149 
192 
     | 
    
         
             
                  # Go through the given document, replacing any merge fields with the values provided
         
     | 
| 
       150 
193 
     | 
    
         
             
                  # and storing the results in a new document
         
     | 
| 
       151 
     | 
    
         
            -
                  def substitute document, document_name 
     | 
| 
      
 194 
     | 
    
         
            +
                  def substitute document, document_name:
         
     | 
| 
      
 195 
     | 
    
         
            +
                    puts "...substituting fields in #{document_name}" if verbose && tag_nodes_for(document).any?
         
     | 
| 
      
 196 
     | 
    
         
            +
                    substitute_text document, document_name: document_name
         
     | 
| 
      
 197 
     | 
    
         
            +
                    substitute_images document, document_name: document_name
         
     | 
| 
      
 198 
     | 
    
         
            +
                  end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                  def substitute_text document, document_name:
         
     | 
| 
       152 
201 
     | 
    
         
             
                    tag_nodes_for(document).each do |tag_node|
         
     | 
| 
       153 
     | 
    
         
            -
                       
     | 
| 
       154 
     | 
    
         
            -
                      image_field_names = image_field_names_from(tag_node) || []
         
     | 
| 
      
 202 
     | 
    
         
            +
                      field_names = text_field_names_from(tag_node) || []
         
     | 
| 
       155 
203 
     | 
    
         | 
| 
       156 
204 
     | 
    
         
             
                      # Extract the properties (formatting) nodes if they exist
         
     | 
| 
       157 
205 
     | 
    
         
             
                      paragraph_properties = tag_node.search ".//w:pPr"
         
     | 
| 
       158 
206 
     | 
    
         
             
                      run_properties = tag_node.at_xpath ".//w:rPr"
         
     | 
| 
       159 
207 
     | 
    
         | 
| 
       160 
     | 
    
         
            -
                      # Get the current contents, then substitute any text fields 
     | 
| 
      
 208 
     | 
    
         
            +
                      # Get the current contents, then substitute any text fields
         
     | 
| 
       161 
209 
     | 
    
         
             
                      text = tag_node.content
         
     | 
| 
       162 
210 
     | 
    
         | 
| 
       163 
     | 
    
         
            -
                       
     | 
| 
       164 
     | 
    
         
            -
                        field_value = mapping[field_name].to_s
         
     | 
| 
       165 
     | 
    
         
            -
                        puts "...substituting #{field_name} with #{field_value} 
     | 
| 
      
 211 
     | 
    
         
            +
                      field_names.each do |field_name|
         
     | 
| 
      
 212 
     | 
    
         
            +
                        field_value = @mapping[field_name].to_s
         
     | 
| 
      
 213 
     | 
    
         
            +
                        puts "...   substituting '#{field_name}' with '#{field_value}'" if verbose
         
     | 
| 
       166 
214 
     | 
    
         
             
                        text = text.gsub(tag_for(field_name), field_value)
         
     | 
| 
       167 
215 
     | 
    
         
             
                      end
         
     | 
| 
       168 
     | 
    
         
            -
                      image_nodes = image_field_names.collect do |field_name|
         
     | 
| 
       169 
     | 
    
         
            -
                        image = @images[field_name]
         
     | 
| 
       170 
     | 
    
         
            -
                        puts "...substituting #{field_name} in #{document_name}" if verbose
         
     | 
| 
       171 
     | 
    
         
            -
                        # Remove the merge tag and create an image reference node to be added to this node
         
     | 
| 
       172 
     | 
    
         
            -
                        text = text.gsub(tag_for(field_name), "")
         
     | 
| 
       173 
     | 
    
         
            -
                        ImageReferenceNodeBuilder.new(field_name: field_name, image: image, node_id: relation_id_for(field_name), document: document).call
         
     | 
| 
       174 
     | 
    
         
            -
                      end
         
     | 
| 
       175 
216 
     | 
    
         | 
| 
       176 
217 
     | 
    
         
             
                      # Create a new text node with the substituted text
         
     | 
| 
       177 
218 
     | 
    
         
             
                      text_node = Nokogiri::XML::Node.new("w:t", tag_node.document)
         
     | 
| 
         @@ -182,7 +223,46 @@ module Consolidate 
     | 
|
| 
       182 
223 
     | 
    
         
             
                      run_node << run_properties unless run_properties.nil?
         
     | 
| 
       183 
224 
     | 
    
         
             
                      run_node << text_node
         
     | 
| 
       184 
225 
     | 
    
         
             
                      # Add the paragraph properties and the run node to the tag node
         
     | 
| 
       185 
     | 
    
         
            -
                      tag_node.children = Nokogiri::XML::NodeSet.new(document, paragraph_properties.to_a + [run_node] 
     | 
| 
      
 226 
     | 
    
         
            +
                      tag_node.children = Nokogiri::XML::NodeSet.new(document, paragraph_properties.to_a + [run_node])
         
     | 
| 
      
 227 
     | 
    
         
            +
                    rescue => ex
         
     | 
| 
      
 228 
     | 
    
         
            +
                      # Have to mangle the exception message otherwise it outputs the entire document
         
     | 
| 
      
 229 
     | 
    
         
            +
                      puts ex.message.to_s[0..255]
         
     | 
| 
      
 230 
     | 
    
         
            +
                      puts ex.backtrace.first
         
     | 
| 
      
 231 
     | 
    
         
            +
                    end
         
     | 
| 
      
 232 
     | 
    
         
            +
                    document
         
     | 
| 
      
 233 
     | 
    
         
            +
                  end
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                  # Go through the given document, replacing any merge fields with the values provided
         
     | 
| 
      
 236 
     | 
    
         
            +
                  # and storing the results in a new document
         
     | 
| 
      
 237 
     | 
    
         
            +
                  def substitute_images document, document_name:
         
     | 
| 
      
 238 
     | 
    
         
            +
                    tag_nodes_for(document).each do |tag_node|
         
     | 
| 
      
 239 
     | 
    
         
            +
                      field_names = image_field_names_from(tag_node) || []
         
     | 
| 
      
 240 
     | 
    
         
            +
                      # Extract the properties (formatting) nodes if they exist
         
     | 
| 
      
 241 
     | 
    
         
            +
                      paragraph_properties = tag_node.search ".//w:pPr"
         
     | 
| 
      
 242 
     | 
    
         
            +
                      run_properties = tag_node.at_xpath ".//w:rPr"
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                      pieces = tag_node.content.split(image_tag)
         
     | 
| 
      
 245 
     | 
    
         
            +
                      # Split the content into pieces - either text or an image merge field
         
     | 
| 
      
 246 
     | 
    
         
            +
                      # Then replace the text with text nodes or the image merge fields with drawing nodes
         
     | 
| 
      
 247 
     | 
    
         
            +
                      replacement_nodes = pieces.collect do |piece|
         
     | 
| 
      
 248 
     | 
    
         
            +
                        field_name = piece.strip
         
     | 
| 
      
 249 
     | 
    
         
            +
                        if field_names.include? field_name
         
     | 
| 
      
 250 
     | 
    
         
            +
                          image = @images[field_name]
         
     | 
| 
      
 251 
     | 
    
         
            +
                          # if no image was provided then insert blank text
         
     | 
| 
      
 252 
     | 
    
         
            +
                          # otherwise insert a w:drawing node that references the image contents
         
     | 
| 
      
 253 
     | 
    
         
            +
                          if image.nil? 
         
     | 
| 
      
 254 
     | 
    
         
            +
                            puts "...   substituting '#{field_name}' with blank as no image was provided" if verbose
         
     | 
| 
      
 255 
     | 
    
         
            +
                            Nokogiri::XML::Node.new("w:t", document) { |t| t.content = "" }
         
     | 
| 
      
 256 
     | 
    
         
            +
                          else
         
     | 
| 
      
 257 
     | 
    
         
            +
                            puts "...   substituting '#{field_name}' with '<#{relation_id_for(field_name)}/>'" if verbose
         
     | 
| 
      
 258 
     | 
    
         
            +
                            ImageReferenceNodeBuilder.new(field_name: field_name, image: image, node_id: relation_id_for(field_name), image_number: relation_number_for(field_name), document: document).call
         
     | 
| 
      
 259 
     | 
    
         
            +
                          end
         
     | 
| 
      
 260 
     | 
    
         
            +
                        else
         
     | 
| 
      
 261 
     | 
    
         
            +
                          Nokogiri::XML::Node.new("w:t", document) { |t| t.content = piece }
         
     | 
| 
      
 262 
     | 
    
         
            +
                        end
         
     | 
| 
      
 263 
     | 
    
         
            +
                      end
         
     | 
| 
      
 264 
     | 
    
         
            +
                      run_nodes = (replacement_nodes.map { |node| Nokogiri::XML::Node.new("w:r", document) { |run_node| run_node.children = node } } + [run_properties]).compact
         
     | 
| 
      
 265 
     | 
    
         
            +
                      tag_node.children = Nokogiri::XML::NodeSet.new(document, paragraph_properties.to_a + run_nodes)
         
     | 
| 
       186 
266 
     | 
    
         
             
                    rescue => ex
         
     | 
| 
       187 
267 
     | 
    
         
             
                      # Have to mangle the exception message otherwise it outputs the entire document
         
     | 
| 
       188 
268 
     | 
    
         
             
                      puts ex.message.to_s[0..255]
         
     | 
| 
         @@ -190,6 +270,26 @@ module Consolidate 
     | 
|
| 
       190 
270 
     | 
    
         
             
                    end
         
     | 
| 
       191 
271 
     | 
    
         
             
                    document
         
     | 
| 
       192 
272 
     | 
    
         
             
                  end
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
                  CONTENT_RELATIONS = {
         
     | 
| 
      
 275 
     | 
    
         
            +
                    jpeg: "image/jpg",
         
     | 
| 
      
 276 
     | 
    
         
            +
                    png: "image/png",
         
     | 
| 
      
 277 
     | 
    
         
            +
                    bmp: "image/bmp",
         
     | 
| 
      
 278 
     | 
    
         
            +
                    gif: "image/gif",
         
     | 
| 
      
 279 
     | 
    
         
            +
                    tif: "image/tif",
         
     | 
| 
      
 280 
     | 
    
         
            +
                    pdf: "application/pdf",
         
     | 
| 
      
 281 
     | 
    
         
            +
                    mov: "application/movie"
         
     | 
| 
      
 282 
     | 
    
         
            +
                  }.freeze
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
                  def add_content_relations_to document
         
     | 
| 
      
 285 
     | 
    
         
            +
                    CONTENT_RELATIONS.each do |file_type, content_type|
         
     | 
| 
      
 286 
     | 
    
         
            +
                      next unless document.at_xpath("//Default[@Extension=\"#{file_type}\"]").nil?
         
     | 
| 
      
 287 
     | 
    
         
            +
                      document.root << Nokogiri::XML::Node.new("Default", document).tap do |relation|
         
     | 
| 
      
 288 
     | 
    
         
            +
                        relation["Extension"] = file_type
         
     | 
| 
      
 289 
     | 
    
         
            +
                        relation["ContentType"] = content_type
         
     | 
| 
      
 290 
     | 
    
         
            +
                      end
         
     | 
| 
      
 291 
     | 
    
         
            +
                    end
         
     | 
| 
      
 292 
     | 
    
         
            +
                  end
         
     | 
| 
       193 
293 
     | 
    
         
             
                end
         
     | 
| 
       194 
294 
     | 
    
         
             
              end
         
     | 
| 
       195 
295 
     | 
    
         
             
            end
         
     | 
    
        data/lib/consolidate/image.rb
    CHANGED
    
    | 
         @@ -2,7 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Consolidate
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Image
         
     | 
| 
       5 
     | 
    
         
            -
                attr_reader :name, :width, :height
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :name, :width, :height, :aspect_ratio, :dpi
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                def initialize name:, width:, height:, path: nil, url: nil, contents: nil
         
     | 
| 
       8 
8 
     | 
    
         
             
                  @name = name
         
     | 
| 
         @@ -11,6 +11,9 @@ module Consolidate 
     | 
|
| 
       11 
11 
     | 
    
         
             
                  @path = path
         
     | 
| 
       12 
12 
     | 
    
         
             
                  @url = url
         
     | 
| 
       13 
13 
     | 
    
         
             
                  @contents = contents
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @aspect_ratio = width.to_f / height.to_f
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #  TODO: Read this from the contents
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @dpi = {x: 72, y: 72}
         
     | 
| 
       14 
17 
     | 
    
         
             
                end
         
     | 
| 
       15 
18 
     | 
    
         | 
| 
       16 
19 
     | 
    
         
             
                def to_s = name
         
     | 
    
        data/lib/consolidate/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: standard-procedure-consolidate
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.4.1
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Rahoul Baruah
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2024-12- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2024-12-18 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: rubyzip
         
     | 
| 
         @@ -64,6 +64,8 @@ files: 
     | 
|
| 
       64 
64 
     | 
    
         
             
            - checksums/standard-procedure-consolidate-0.3.0.gem.sha512
         
     | 
| 
       65 
65 
     | 
    
         
             
            - checksums/standard-procedure-consolidate-0.3.1.gem.sha512
         
     | 
| 
       66 
66 
     | 
    
         
             
            - checksums/standard-procedure-consolidate-0.3.9.gem.sha512
         
     | 
| 
      
 67 
     | 
    
         
            +
            - checksums/standard-procedure-consolidate-0.4.0.gem.sha512
         
     | 
| 
      
 68 
     | 
    
         
            +
            - checksums/standard-procedure-consolidate-0.4.1.gem.sha512
         
     | 
| 
       67 
69 
     | 
    
         
             
            - exe/consolidate
         
     | 
| 
       68 
70 
     | 
    
         
             
            - exe/examine
         
     | 
| 
       69 
71 
     | 
    
         
             
            - lib/consolidate.rb
         
     |