standard-procedure-consolidate 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f61fdd9cdf73d8609574952bca3a57839983f74f100aea6f8b54a4248b526efa
4
- data.tar.gz: 0a64110c54d435f10c1465b96dd61e150c2ff56ae887788b5880d7bf489e93d5
3
+ metadata.gz: 1bd2015cc0f88bc4b16bae7d8ecd335fb7b28c2bc940f81b1479e4a58ecce647
4
+ data.tar.gz: 44905254b9536f40f839d64d0448c4fb40b1a3720fb4d9ba3e2251468175eb9b
5
5
  SHA512:
6
- metadata.gz: ac0a18d02265eb79b2c9ffda09b2a13825e520a08faef45c1a0f3fd29877b11abf46776554a7c7e2e4157e560f0269889a95f3a9dc3dc4f49b66bda51848e37c
7
- data.tar.gz: 1fce15f81e519792c058dc731cd298db46dc4163d7c0c6cd753c87c2ec7a672aa4b9e350d526d8a641ebdb13bd3dd98b1a9ebd8bb854cd6d0e2342899103b883
6
+ metadata.gz: 36dee64a5f21766e06e7b5eb213e5a5b4dee9ca04da8bde4b429c4d93c5bd49275226975c7e9887214ea5a3b5975c4f955b245ab45e0103656b928ab59854789
7
+ data.tar.gz: 687bba668eb1f137b67c82819561ec2e8c2c3bc9a54f03aa4b6ac76958ae3a15988af8db5f78e7e95adb59968b5764b32c37e71d257b7885d1eb0e10d6e3f56a
@@ -1,7 +1,23 @@
1
1
  // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
2
  // README at: https://github.com/devcontainers/templates/tree/main/src/ruby
3
3
  {
4
- "name": "Ruby",
5
- "image": "mcr.microsoft.com/devcontainers/ruby:1-3.2-bullseye",
6
- "postCreateCommand": "bundle install"
7
- }
4
+ "name": "Ruby",
5
+ "image": "mcr.microsoft.com/devcontainers/ruby:1-3.2-bullseye",
6
+ "postCreateCommand": "bundle install",
7
+ "customizations": {
8
+ "vscode": {
9
+ "extensions": [
10
+ "Shopify.ruby-extensions-pack",
11
+ "testdouble.vscode-standard-ruby",
12
+ "manuelpuyol.erb-linter",
13
+ "Shopify.ruby-lsp",
14
+ "aki77.rails-db-schema",
15
+ "miguel-savignano.ruby-symbols",
16
+ "sibiraj-s.vscode-scss-formatter",
17
+ "Thadeu.vscode-run-rspec-file",
18
+ "Cronos87.yaml-symbols",
19
+ "aliariff.vscode-erb-beautify"
20
+ ]
21
+ }
22
+ }
23
+ }
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.2
1
+ 3.2.5
data/.standard.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  # For available configuration options, see:
2
2
  # https://github.com/testdouble/standard
3
- ruby_version: 2.6
3
+ ruby_version: 3.2.5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.3.0] - 2024-11-21
2
+
3
+ Updated the code that examines the docx file for merge fields to deal with Word formatting tags being inserted in the middle of the merge fields.
4
+
1
5
  ## [0.2.0] - 2023-09-13
2
6
 
3
7
  Thrown away the mail-merge implementation and replaced it with a simple search/replace.
data/README.md CHANGED
@@ -78,7 +78,7 @@ Consolidate looks for word/document.xml files, plus any files that match word/he
78
78
 
79
79
  ## Development
80
80
 
81
- The repo contains a .devcontainer folder - this contains instructions for a development container that has everything needed to build the project. Once the container has started, you can use `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
81
+ The repo contains a .devcontainer folder - this contains instructions for a development container that has everything needed to build the project. Once the container has started, you can use `bin/setup` to install dependencies. Then, run `bundle exec rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
82
82
 
83
83
  `bundle exec rake install` will install the gem on your local machine (obviously not from within the devcontainer though). To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
84
84
 
data/Rakefile CHANGED
@@ -7,4 +7,4 @@ RSpec::Core::RakeTask.new(:spec)
7
7
 
8
8
  require "standard/rake"
9
9
 
10
- task default: %i[spec standard]
10
+ task default: %i[standard:fix spec]
@@ -0,0 +1 @@
1
+ 098078b13e3bb4e3370cbc6bdb0195300489dfb33a5c27a201a4c5f1f0184bba73557264e674f49da41dbc62ad991e8ae99bef1debf417a5b1a363b1d56829f1
@@ -11,6 +11,15 @@ module Consolidate
11
11
  path
12
12
  end
13
13
 
14
+ def initialize(path, verbose: false, &block)
15
+ @verbose = verbose
16
+ @output = {}
17
+ @zip = Zip::File.open(path)
18
+ @documents = load_documents
19
+ block&.call self
20
+ end
21
+
22
+ # Helper method to display the contents of the document and the merge fields from the CLI
14
23
  def examine
15
24
  documents = document_names.join(", ")
16
25
  fields = field_names.join(", ")
@@ -18,23 +27,21 @@ module Consolidate
18
27
  puts "Merge fields: #{fields}"
19
28
  end
20
29
 
30
+ # Read all documents within the docx and extract any merge fields
21
31
  def field_names
22
- documents.collect do |name, document|
23
- (document / "//w:t").collect do |text_node|
24
- next unless (matches = text_node.content.match(/{{\s*(\S+)\s*}}/))
25
- field_name = matches[1].strip
26
- puts "...field #{field_name} found in #{name}" if verbose
27
- field_name
28
- end.compact
29
- end.flatten
32
+ tag_nodes.collect do |tag_node|
33
+ field_name_from tag_node
34
+ end.compact.uniq
30
35
  end
31
36
 
37
+ # List the documents stored within this docx
32
38
  def document_names
33
39
  @zip.entries.collect { |entry| entry.name }
34
40
  end
35
41
 
36
- def data fields = {}
37
- fields = fields.transform_keys(&:to_s)
42
+ # Substitute the data from the merge fields with the values provided
43
+ def data mapping = {}
44
+ mapping = mapping.transform_keys(&:to_s)
38
45
 
39
46
  if verbose
40
47
  puts "...substitutions..."
@@ -44,13 +51,13 @@ module Consolidate
44
51
  end
45
52
 
46
53
  @documents.each do |name, document|
47
- result = document.dup
48
- result = substitute result, fields, name
54
+ output_document = substitute document.dup, mapping: mapping, document_name: name
49
55
 
50
- @output[name] = result.serialize save_with: 0
56
+ @output[name] = output_document.serialize save_with: 0
51
57
  end
52
58
  end
53
59
 
60
+ # Write the new document to the given path
54
61
  def write_to path
55
62
  puts "...writing to #{path}" if verbose
56
63
  Zip::File.open(path, Zip::File::CREATE) do |out|
@@ -62,7 +69,7 @@ module Consolidate
62
69
  end
63
70
  end
64
71
 
65
- protected
72
+ private
66
73
 
67
74
  attr_reader :verbose
68
75
  attr_reader :zip
@@ -70,42 +77,62 @@ module Consolidate
70
77
  attr_reader :documents
71
78
  attr_accessor :output
72
79
 
73
- def initialize(path, verbose: false, &block)
74
- raise "No block given" unless block
75
- @verbose = verbose
76
- @output = {}
77
- @documents = {}
78
- begin
79
- @zip = Zip::File.open(path)
80
- @zip.entries.each do |entry|
81
- next unless entry.name.match?(/word\/(document|header|footer|footnotes|endnotes).?\.xml/)
82
- puts "...reading #{entry.name}" if verbose
83
- xml = @zip.get_input_stream entry
84
- @documents[entry.name] = Nokogiri::XML(xml) { |x| x.noent }
85
- end
86
- yield self
87
- ensure
88
- @zip.close
80
+ def load_documents
81
+ @zip.entries.each_with_object({}) do |entry, documents|
82
+ next unless entry.name.match?(/word\/(document|header|footer|footnotes|endnotes).?\.xml/)
83
+ puts "...reading #{entry.name}" if verbose
84
+ xml = @zip.get_input_stream entry
85
+ documents[entry.name] = Nokogiri::XML(xml) { |x| x.noent }
89
86
  end
87
+ ensure
88
+ @zip.close
90
89
  end
91
90
 
92
- def substitute document, fields, document_name
93
- (document / "//w:t").each do |text_node|
94
- next unless (matches = text_node.content.match(/{{\s*(\S+)\s*}}/))
95
- field_name = matches[1].strip
96
- if fields.has_key? field_name
97
- field_value = fields[field_name]
98
- puts "...substituting #{field_name} with #{field_value} in #{document_name}" if verbose
99
- text_node.content = text_node.content.gsub(matches[1], field_value).gsub("{{", "").gsub("}}", "")
100
- elsif verbose
101
- puts "...found #{field_name} but no replacement value"
102
- end
91
+ # Collect all the nodes that contain merge fields
92
+ def tag_nodes
93
+ documents.collect do |name, document|
94
+ tag_nodes_for document
95
+ end.flatten
96
+ end
97
+
98
+ # go through all w:t (Word Text???) nodes of the document
99
+ # find any nodes that contain "{{"
100
+ # then find the ancestor node that also includes the ending "}}"
101
+ # This collection of nodes contains all the merge fields for this document
102
+ def tag_nodes_for document
103
+ (document / "//w:t").collect do |node|
104
+ (node.children.any? { |child| child.content.include? "{{" }) ? enclosing_node_for_start_tag(node) : nil
105
+ end.compact
106
+ end
107
+
108
+ # Extract the merge field name from the node
109
+ def field_name_from(tag_node)
110
+ return nil unless (matches = tag_node.content.match(/{{\s*(\S+)\s*}}/))
111
+ field_name = matches[1].strip
112
+ puts "...field #{field_name} found in #{name}" if verbose
113
+ field_name.to_s
114
+ end
115
+
116
+ # Go through the given document, replacing any merge fields with the values provided
117
+ # and storing the results in a new document
118
+ def substitute document, document_name:, mapping: {}
119
+ tag_nodes_for(document).each do |tag_node|
120
+ field_name = field_name_from tag_node
121
+ next unless mapping.has_key? field_name
122
+ field_value = mapping[field_name]
123
+ puts "...substituting #{field_name} with #{field_value} in #{document_name}" if verbose
124
+ tag_node.content = tag_node.content.gsub(field_name, field_value).gsub(/{{\s*/, "").gsub(/\s*}}/, "")
125
+ rescue => ex
126
+ # Have to mangle the exception message otherwise it outputs the entire document
127
+ puts ex.message.to_s[0..255]
103
128
  end
104
129
  document
105
130
  end
106
131
 
107
- def close
108
- zip.close
132
+ # Find the ancestor node that contains both the start {{ text and the end }} text enclosing the merge field
133
+ def enclosing_node_for_start_tag(node)
134
+ return node if node.content.include? "}}"
135
+ node.parent.nil? ? nil : enclosing_node_for_start_tag(node.parent)
109
136
  end
110
137
  end
111
138
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Consolidate
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
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.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rahoul Baruah
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-13 00:00:00.000000000 Z
11
+ date: 2024-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -48,7 +48,6 @@ extensions: []
48
48
  extra_rdoc_files: []
49
49
  files:
50
50
  - ".devcontainer/devcontainer.json"
51
- - ".nova/Configuration.json"
52
51
  - ".rspec"
53
52
  - ".ruby-version"
54
53
  - ".standard.yml"
@@ -62,6 +61,7 @@ files:
62
61
  - checksums/standard-procedure-consolidate-0.1.3.gem.sha512
63
62
  - checksums/standard-procedure-consolidate-0.1.4.gem.sha512
64
63
  - checksums/standard-procedure-consolidate-0.2.0.gem.sha512
64
+ - checksums/standard-procedure-consolidate-0.3.0.gem.sha512
65
65
  - exe/consolidate
66
66
  - exe/examine
67
67
  - lib/consolidate.rb
@@ -77,7 +77,7 @@ metadata:
77
77
  homepage_uri: https://github.com/standard-procedure/standard-procedure-consolidate
78
78
  source_code_uri: https://github.com/standard-procedure/standard-procedure-consolidate
79
79
  changelog_uri: https://github.com/standard-procedure/standard-procedure-consolidate/blob/main/CHANGELOG.md
80
- post_install_message:
80
+ post_install_message:
81
81
  rdoc_options: []
82
82
  require_paths:
83
83
  - lib
@@ -92,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
94
  requirements: []
95
- rubygems_version: 3.4.10
96
- signing_key:
95
+ rubygems_version: 3.4.19
96
+ signing_key:
97
97
  specification_version: 4
98
98
  summary: Simple ruby mailmerge for Microsoft Word .docx files.
99
99
  test_files: []
@@ -1,3 +0,0 @@
1
- {
2
-
3
- }