docx-builder 0.2.3 → 0.4.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: 208b51187c9e384db0e9d585552b8696e0a868709d2ee7348ae57e3d96566e1e
4
- data.tar.gz: 54cdcbe11f62f7dcb3ab6fdcd4575f8d2ca09f876da8c0a8e7c8a57209313b42
3
+ metadata.gz: 04a3f8e6aceab4a926778161073b38cbed31c533e52ac924e83bf70fddc2a61c
4
+ data.tar.gz: 7746ba4203d23e18182a803082927bb50ec14d9dfed43b52c5bee557c86ba94b
5
5
  SHA512:
6
- metadata.gz: 43f1e1c08dd0f604ba920ad88c139e4797e4b8a6ed7b9d2edf2f5d363c92b19bb9e1b889e32f3a6f4b4deb9c5920e8d197a2815320b167b6049ec8a0636506ae
7
- data.tar.gz: 3b71f7b11e68f1c8e19616265401c4f03d392fbd503ab34aef98f8d237ff5a08545108593c4f53daf3e4d1e5e195905326bd9e005b91ec422eea87b2e014f24f
6
+ metadata.gz: 03e659b8e2c8f9ce9d8468f7752d2aa29bc0e55c63687ee97fa16fd1e5e029107773bf6ccbc4d5d4837de69b92a7e34b886f5fbfa8efb3587811e293cb6527f3
7
+ data.tar.gz: 144b48158964a4410792d43bf69386de53f291b329f34b66bca1fed8e909182dfd4284f162986601e6771ef0ba979d13c35b262a77fb99ba2cef863f39f7c718
@@ -0,0 +1,27 @@
1
+ name: CD - Publish
2
+ on:
3
+ push:
4
+ branches:
5
+ - master
6
+
7
+ jobs:
8
+
9
+ publish:
10
+ name: Publish gem
11
+ runs-on: ubuntu-18.04
12
+
13
+ steps:
14
+ - name: Checkout code
15
+ uses: actions/checkout@v2
16
+
17
+ - name: Set up ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.7.2
21
+
22
+ - name: Release gem
23
+ uses: discourse/publish-rubygems-action@v2
24
+ env:
25
+ RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
26
+ GIT_EMAIL: automated_release@cashme.com.br
27
+ GIT_NAME: Automated Release
@@ -6,69 +6,46 @@ on:
6
6
 
7
7
  jobs:
8
8
 
9
- # lint:
10
- # name: Linters verification
11
- # runs-on: ubuntu-18.04
12
-
13
- # steps:
14
-
15
- # - name: Checkout code
16
- # uses: actions/checkout@v2
17
-
18
- # - name: Checkout deployment repo
19
- # uses: actions/checkout@v2
20
- # with:
21
- # repository: cash-me/deployment
22
- # ssh-key: ${{ secrets.DEPLOYMENT_KEY }}
23
- # path: '.github/deployment'
24
-
25
- # - uses: ruby/setup-ruby@v1
26
- # with:
27
- # ruby-version: 2.7.2
9
+ lint:
10
+ name: Linters verification
11
+ runs-on: ubuntu-18.04
28
12
 
29
- # - name: Ruby gem cache
30
- # uses: actions/cache@v1
31
- # with:
32
- # path: vendor/bundle
33
- # key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
34
- # restore-keys: |
35
- # ${{ runner.os }}-gems-
13
+ steps:
14
+ - name: Checkout code
15
+ uses: actions/checkout@v2
36
16
 
37
- # - name: Linters
38
- # uses: ./.github/deployment/actions/linters/rails
17
+ - name: Set up ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.7.2
21
+ bundler-cache: true # Run "bundle install", and cache the result automatically.
39
22
 
40
- # test:
41
- # name: Run tests
42
- # needs: lint
43
- # runs-on: ubuntu-18.04
23
+ - name: Run security checks
24
+ run: bundle exec bundler-audit --update
44
25
 
45
- # services:
46
- # postgres:
47
- # image: postgres:11.6
48
- # ports: ["5432:5432"]
49
- # options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
26
+ - name: Run rubocop
27
+ run: bundle exec rubocop
50
28
 
51
- # steps:
52
- # - uses: actions/checkout@v2
29
+ test:
30
+ name: Run tests
31
+ needs: lint
32
+ runs-on: ubuntu-18.04
53
33
 
54
- # - name: Checkout deployment repo
55
- # uses: actions/checkout@v2
56
- # with:
57
- # repository: cash-me/deployment
58
- # ssh-key: ${{ secrets.DEPLOYMENT_KEY }}
59
- # path: '.github/deployment'
34
+ steps:
35
+ - name: Checkout code
36
+ uses: actions/checkout@v2
60
37
 
61
- # - uses: ruby/setup-ruby@v1
62
- # with:
63
- # ruby-version: 2.7.2
38
+ - name: Set up ruby
39
+ uses: ruby/setup-ruby@v1
40
+ with:
41
+ ruby-version: 2.7.2
42
+ bundler-cache: true
64
43
 
65
- # - name: Tests
66
- # uses: ./.github/deployment/actions/tests/rails
67
- # with:
68
- # cc_reporter_id: ${{ secrets.CC_TEST_REPORTER_ID }}
44
+ - name: Run tests
45
+ run: bundle exec rake
69
46
 
70
47
  ci-workflow:
71
- # needs: test
48
+ needs: test
72
49
  runs-on: ubuntu-18.04
73
50
  steps:
74
- - run: exit 0
51
+ - run: exit 0
data/.gitignore CHANGED
@@ -15,4 +15,4 @@
15
15
  docx-builder-*.gem
16
16
 
17
17
  # Ignore files created by Word
18
- ~$*.docx
18
+ ~$*.docx
data/.rspec CHANGED
File without changes
data/.rubocop.yml CHANGED
@@ -1,10 +1,18 @@
1
+ Gemspec/RequiredRubyVersion:
2
+ Enabled: false
3
+
4
+ Layout/LineLength:
5
+ Max: 160
6
+
7
+ Metrics/BlockLength:
8
+ CountAsOne: ['array', 'hash']
9
+ CountComments: false
10
+ Max: 50
11
+
1
12
  Style/StringLiterals:
2
13
  Enabled: true
3
- EnforcedStyle: double_quotes
14
+ EnforcedStyle: single_quotes
4
15
 
5
16
  Style/StringLiteralsInInterpolation:
6
17
  Enabled: true
7
- EnforcedStyle: double_quotes
8
-
9
- Layout/LineLength:
10
- Max: 120
18
+ EnforcedStyle: single_quotes
data/CODE_OF_CONDUCT.md CHANGED
File without changes
data/Gemfile CHANGED
@@ -1,20 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in docx-builder.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
9
- gem "rspec", "~> 3.0"
8
+ gem 'nokogiri', '~> 1.13.2'
9
+ gem 'rake', '~> 13.0'
10
10
  gem 'rubyzip', require: 'zip'
11
- gem "rubocop", "~> 0.80"
12
- gem "nokogiri", "~> 1.11.1"
13
11
 
14
12
  group :test do
15
- gem "byebug"
13
+ gem 'bundler-audit'
14
+ gem 'byebug'
15
+
16
+ gem 'rspec', '~> 3.0'
17
+ gem 'rubocop', '~> 0.80'
16
18
  end
17
19
 
18
20
  group :development do
19
- gem "bump"
21
+ gem 'bump'
20
22
  end
data/Gemfile.lock CHANGED
@@ -1,40 +1,43 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- docx-builder (0.2.3)
4
+ docx-builder (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.2)
10
10
  bump (0.10.0)
11
+ bundler-audit (0.9.1)
12
+ bundler (>= 1.2.0, < 3)
13
+ thor (~> 1.0)
11
14
  byebug (11.1.3)
12
- diff-lcs (1.4.4)
13
- mini_portile2 (2.5.0)
14
- nokogiri (1.11.3)
15
- mini_portile2 (~> 2.5.0)
15
+ diff-lcs (1.5.0)
16
+ mini_portile2 (2.8.0)
17
+ nokogiri (1.13.6)
18
+ mini_portile2 (~> 2.8.0)
16
19
  racc (~> 1.4)
17
- parallel (1.20.1)
18
- parser (3.0.1.0)
20
+ parallel (1.22.1)
21
+ parser (3.1.2.0)
19
22
  ast (~> 2.4.1)
20
- racc (1.5.2)
21
- rainbow (3.0.0)
22
- rake (13.0.3)
23
- regexp_parser (2.1.1)
23
+ racc (1.6.0)
24
+ rainbow (3.1.1)
25
+ rake (13.0.6)
26
+ regexp_parser (2.5.0)
24
27
  rexml (3.2.5)
25
- rspec (3.10.0)
26
- rspec-core (~> 3.10.0)
27
- rspec-expectations (~> 3.10.0)
28
- rspec-mocks (~> 3.10.0)
29
- rspec-core (3.10.1)
30
- rspec-support (~> 3.10.0)
31
- rspec-expectations (3.10.1)
28
+ rspec (3.11.0)
29
+ rspec-core (~> 3.11.0)
30
+ rspec-expectations (~> 3.11.0)
31
+ rspec-mocks (~> 3.11.0)
32
+ rspec-core (3.11.0)
33
+ rspec-support (~> 3.11.0)
34
+ rspec-expectations (3.11.0)
32
35
  diff-lcs (>= 1.2.0, < 2.0)
33
- rspec-support (~> 3.10.0)
34
- rspec-mocks (3.10.2)
36
+ rspec-support (~> 3.11.0)
37
+ rspec-mocks (3.11.1)
35
38
  diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.10.0)
37
- rspec-support (3.10.2)
39
+ rspec-support (~> 3.11.0)
40
+ rspec-support (3.11.0)
38
41
  rubocop (0.93.1)
39
42
  parallel (~> 1.10)
40
43
  parser (>= 2.7.1.5)
@@ -44,20 +47,22 @@ GEM
44
47
  rubocop-ast (>= 0.6.0)
45
48
  ruby-progressbar (~> 1.7)
46
49
  unicode-display_width (>= 1.4.0, < 2.0)
47
- rubocop-ast (1.4.1)
48
- parser (>= 2.7.1.5)
50
+ rubocop-ast (1.18.0)
51
+ parser (>= 3.1.1.0)
49
52
  ruby-progressbar (1.11.0)
50
- rubyzip (2.3.0)
51
- unicode-display_width (1.7.0)
53
+ rubyzip (2.3.2)
54
+ thor (1.2.1)
55
+ unicode-display_width (1.8.0)
52
56
 
53
57
  PLATFORMS
54
58
  ruby
55
59
 
56
60
  DEPENDENCIES
57
61
  bump
62
+ bundler-audit
58
63
  byebug
59
64
  docx-builder!
60
- nokogiri (~> 1.11.1)
65
+ nokogiri (~> 1.13.2)
61
66
  rake (~> 13.0)
62
67
  rspec (~> 3.0)
63
68
  rubocop (~> 0.80)
data/LICENSE.txt CHANGED
File without changes
data/README.md CHANGED
@@ -1,8 +1,36 @@
1
1
  # Docx::Builder
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/docx/builder`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Gem used to create docx files based on a template.
4
+ Our idea is quite similar to an erb file (in fact, we use an erb file behind :P)
5
+ The only difference is:
6
+ * When we want to write conditions and loops, we write the code between "{{" and "}}"
7
+ * When we want to print a variable, we write it between "{{%" and "%}}"
4
8
 
5
- TODO: Delete this and the text above, and describe your gem
9
+ For example, in our template file example.docx we could have:
10
+
11
+ ```
12
+ {{ items.each do |item| }}
13
+ Insert here some text: {{% item.property %}}
14
+ {{ end }}
15
+ ```
16
+
17
+ ## Helpers
18
+
19
+ ### Table
20
+
21
+ In order to render a table on docx template, we wrote:
22
+
23
+ ```
24
+ {{t config t}}
25
+ ```
26
+
27
+ where "config" is a hash that contains two properties:
28
+
29
+ * columns: an array of hashes. Each element represents a column and may have the following information:
30
+ * name (required): attribute name;
31
+ * width (required): specifies the value of the preferred width of the column (according to the officeopenxml documentation, it's in twentieths of a point or 1/1440 of an inch)
32
+ * description (optional): attribute description used on table's header; if not specified, its name will be used as a description
33
+ * rows: an array of hashes. Each element represents a row and all of its properties must appear in the columns' array.
6
34
 
7
35
  ## Installation
8
36
 
@@ -22,18 +50,45 @@ Or install it yourself as:
22
50
 
23
51
  ## Usage
24
52
 
53
+ ```ruby
54
+ builder = Docx::Builder::Template.new('/path/to/input.docx')
55
+ new_xml = builder.render(variables_hash)
56
+ builder.save('/path/to/output.docx', new_xml)
57
+ # or memory_stream = builder.save_as_buffer(new_xml)
25
58
  ```
26
- template_file = File.open('spec/files/example.docx', 'r')
27
- builder = Docx::Builder::Template.new(template_file)
28
- new_xml = builder.render({ numero_contrato: 101 })
29
- builder.save('tmp/output.docx', new_xml)
30
- ```
31
-
32
- ## Development
33
59
 
34
- After checking out the repo, run `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.
60
+ An exemple of table configuration should be:
35
61
 
36
- To install this gem onto your local machine, run `bundle exec rake install`. 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).
62
+ ```ruby
63
+ users_table = {
64
+ columns: [
65
+ {
66
+ name: :name,
67
+ description: 'Name',
68
+ width: 1150
69
+ },
70
+ {
71
+ name: :email,
72
+ description: 'Mail address',
73
+ width: 1150
74
+ }
75
+ ],
76
+ rows: [
77
+ {
78
+ name: 'João',
79
+ email: 'joao@example.com'
80
+ },
81
+ {
82
+ name: 'José',
83
+ email: 'jose@example.com'
84
+ },
85
+ {
86
+ name: 'Felipe',
87
+ email: 'felipe@example.com'
88
+ }
89
+ ]
90
+ }
91
+ ```
37
92
 
38
93
  ## Contributing
39
94
 
data/Rakefile CHANGED
@@ -1,12 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require "rubocop/rake_task"
9
-
10
- RuboCop::RakeTask.new
11
-
12
- task default: %i[spec rubocop]
8
+ task default: 'spec'
data/bin/console CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "docx/builder"
4
+ require 'bundler/setup'
5
+ require 'docx/builder'
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
@@ -11,5 +11,5 @@ require "docx/builder"
11
11
  # require "pry"
12
12
  # Pry.start
13
13
 
14
- require "irb"
14
+ require 'irb'
15
15
  IRB.start(__FILE__)
data/docx-builder.gemspec CHANGED
@@ -1,33 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/docx/builder/version"
3
+ require_relative 'lib/docx/builder/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "docx-builder"
6
+ spec.name = 'docx-builder'
7
7
  spec.version = Docx::Builder::VERSION
8
- spec.authors = ["Tecnologia Cashme"]
9
- spec.email = ["tecnologia@cashme.com.br"]
8
+ spec.authors = ['Tecnologia Cashme']
9
+ spec.email = ['tecnologia@cashme.com.br']
10
10
 
11
- spec.summary = "Builds a new docx file using ERB template"
12
- spec.description = "Builds a new docx file using ERB template"
13
- spec.homepage = "https://github.com/cash-me/docx-builder"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
11
+ spec.summary = 'Builds a new docx file using ERB template'
12
+ spec.description = 'Builds a new docx file using ERB template'
13
+ spec.homepage = 'https://github.com/cash-me/docx-builder'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
16
16
 
17
17
  # spec.metadata["allowed_push_host"] = "Set to 'http://mygemserver.com'"
18
18
 
19
- spec.metadata["homepage_uri"] = spec.homepage
20
- spec.metadata["source_code_uri"] = "https://github.com/cash-me/docx-builder"
21
- spec.metadata["changelog_uri"] = "https://github.com/cash-me/docx-builder/CHANGELOG.md"
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = 'https://github.com/cash-me/docx-builder'
21
+ spec.metadata['changelog_uri'] = 'https://github.com/cash-me/docx-builder/CHANGELOG.md'
22
22
 
23
23
  # Specify which files should be added to the gem when it is released.
24
24
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
25
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
26
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
27
  end
28
- spec.bindir = "exe"
28
+ spec.bindir = 'exe'
29
29
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
- spec.require_paths = ["lib"]
30
+ spec.require_paths = ['lib']
31
31
 
32
32
  # Uncomment to register a new dependency of your gem
33
33
  # spec.add_dependency "example-gem", "~> 1.0"
@@ -1,41 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Docx
2
- module Builder
3
- module Cleaners
4
- def self.starting_tags_without_spaces_cleaner(str)
5
- str && str.gsub(/\{\s*\{\s*%/, '{{%')
6
- end
7
-
8
- def self.ending_tags_without_spaces_cleaner(str)
9
- str && str.gsub(/%\s*\}\s*\}/, '%}}')
10
- end
11
-
12
- def self.single_quote_cleaner(str)
13
- str && str.gsub(/\‘/, '\'').gsub(/\’/, '\'')
14
- end
15
-
16
- def self.var_without_duplicated_spaces_cleaner(str)
17
- str && str.gsub(/\s+/, ' ')
18
- end
19
-
20
- def self.var_without_spaces_inside_brackets_cleaner(str)
21
- str && str.gsub(/\[(.*?)\]/) { |match| match.gsub(/\s/, '')}
22
- end
23
-
24
- def self.no_spaces_around_undeline_cleaner(str)
25
- str && str.gsub(/\s*\_\s*/, "_")
26
- end
27
-
28
- def self.join_dots_and_brackets_cleaner(str)
29
- str && str.gsub(/\s*\.\s*/, '.').gsub(/\s*\[\s*/, '[').gsub(/\s*\]/, ']')
30
- end
31
-
32
- def self.question_method_cleaner(str)
33
- if str && str =~ /\A\{\{\s+if\s*(.*?)\s*\?\s+\}\}\Z/
34
- "{{ if #{$1}\? }}"
35
- else
36
- str
37
- end
38
- end
4
+ module Builder
5
+ # Methods used for cleaning variables inside template
6
+ module Cleaners
7
+ def self.starting_tags_without_spaces_cleaner(str)
8
+ str&.gsub(/\{\s*\{\s*%/, '{{%')
9
+ end
10
+
11
+ def self.ending_tags_without_spaces_cleaner(str)
12
+ str&.gsub(/%\s*\}\s*\}/, '%}}')
13
+ end
14
+
15
+ def self.single_quote_cleaner(str)
16
+ str&.gsub(/‘/, '\'')&.gsub(/’/, '\'')
17
+ end
18
+
19
+ def self.var_without_duplicated_spaces_cleaner(str)
20
+ str&.gsub(/\s+/, ' ')
21
+ end
22
+
23
+ def self.var_without_spaces_inside_brackets_cleaner(str)
24
+ str&.gsub(/\[(.*?)\]/) { |match| match.gsub(/\s/, '') }
25
+ end
26
+
27
+ def self.no_spaces_around_undeline_cleaner(str)
28
+ str&.gsub(/\s*_\s*/, '_')
29
+ end
30
+
31
+ def self.join_dots_and_brackets_cleaner(str)
32
+ str && str.gsub(/\s*\.\s*/, '.').gsub(/\s*\[\s*/, '[').gsub(/\s*\]/, ']')
33
+ end
34
+
35
+ def self.question_method_cleaner(str)
36
+ if str && str =~ /\A\{\{\s+if\s*(.*?)\s*\?\s+\}\}\Z/
37
+ "{{ if #{Regexp.last_match(1)}\? }}"
38
+ else
39
+ str
39
40
  end
41
+ end
40
42
  end
43
+ end
41
44
  end
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docx
4
- module Builder
5
- class Configuration
6
- attr_accessor :null_placeholder
7
- attr_accessor :logger
4
+ module Builder
5
+ # Configuration for docx-builder gem
6
+ #
7
+ # There are two available settings:
8
+ # * null_placeholder: string placeholder to be put when the variable is null
9
+ # * logger: the logger object itself
10
+ class Configuration
11
+ attr_accessor :null_placeholder, :logger
8
12
 
9
- def initialize
10
- @null_placeholder = ''
11
- @logger = Docx::Logger.new(STDOUT)
12
- end
13
- end
13
+ def initialize
14
+ @null_placeholder = ''
15
+ @logger = Docx::Logger.new($stdout)
16
+ end
14
17
  end
15
- end
18
+ end
19
+ end
@@ -1,14 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docx
4
- module Builder
5
- module Decoder
6
- def self.to_xml(path)
7
- Zip::File.open(path) do |file|
8
- @zipfile = file
9
- end
10
- @zipfile
11
- end
12
- end
13
- end
4
+ module Builder
5
+ # Unzips a docx file into a series of XML files
6
+ module Decoder
7
+ def self.to_xml(path)
8
+ Zip::File.open(path) do |file|
9
+ @zipfile = file
10
+ end
11
+ @zipfile
12
+ end
13
+ end
14
+ end
14
15
  end
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docx
4
- module Builder
5
- module Encoder
6
- def self.build_new_document_xml(original_document, new_document_sections)
7
- output = Zip::OutputStream.write_buffer(StringIO.new) do |out|
8
- original_document.each do |entry|
9
- entry_name = entry.name
10
- out.put_next_entry(entry_name)
11
- out.write(new_document_sections[entry_name] || entry.get_input_stream.read)
12
- end
13
- end
14
- output.string
15
- end
16
- end
17
- end
4
+ module Builder
5
+ # Rebuild the docx file using the new xml strings for header and document
6
+ module Encoder
7
+ def self.build_docx_buffer(original_document, new_document_sections)
8
+ Zip::OutputStream.write_buffer(StringIO.new) do |out|
9
+ original_document.each do |entry|
10
+ entry_name = entry.name
11
+ out.put_next_entry(entry_name)
12
+ out.write(new_document_sections[entry_name] || entry.get_input_stream.read)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
18
  end
@@ -1,54 +1,79 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Docx
2
- module Builder
3
- class Template
4
- def initialize(path)
5
- @document = Docx::Builder::Decoder.to_xml(path)
6
- @sections = ["word/document.xml"]
7
- @document.each do |file|
8
- if file.name.include? "word/header"
9
- @sections.push(file.name)
10
- end
11
- end
12
- end
13
-
14
- def render(data)
15
- @sections.map do |section|
16
- Docx::Builder.logger.debug("Cleaning template variables for section #{section}")
17
- cleaned_document = clean(@document.read(section))
18
- Docx::Builder.logger.debug("Replacing template tags ('{{%' -> '<%') for section #{section}")
19
- erb_template = build_erb_template(cleaned_document)
20
- Docx::Builder.logger.debug("Rendering template for section #{section} with data")
21
- processed_document = render_erb_template(erb_template, data)
22
- [section, processed_document]
23
- end.to_h
24
- end
25
-
26
- def clean(document)
27
- document.force_encoding(Encoding::UTF_8) if document.respond_to?(:force_encoding)
28
- Docx::Builder::XmlProcessor.clean_variables(document)
29
- end
30
-
31
- def build_erb_template(document)
32
- ret = document.gsub(/\{\{%/, '<%=').gsub(/%\}\}/, '%>')
33
- ret = ret.gsub(/\{\{/, '<%').gsub(/\}\}/, '%>')
34
- ret
35
- end
36
-
37
- def render_erb_template(document, data)
38
- erb_template = ERB.new(document)
39
- ret = erb_template.result_with_hash(data)
40
- ret
41
- end
42
-
43
- # creates xml template keys in input docx (template file)
44
- def save(path, new_document)
45
- Docx::Builder.logger.info("Saving output file into path #{path.to_s}")
46
- File.open(path, 'wb') do |f|
47
- new_document_xml_string = Docx::Builder::Encoder.build_new_document_xml(@document, new_document)
48
- f.write(new_document_xml_string)
49
- end
50
- @document.close
51
- end
52
- end
4
+ module Builder
5
+ # Represents a docx erb template
6
+ class Template
7
+ attr_reader :document, :sections
8
+
9
+ def initialize(path)
10
+ @document = Docx::Builder::Decoder.to_xml(path)
11
+ @sections = ['word/document.xml']
12
+ @document.each do |file|
13
+ @sections.push(file.name) if file.name.include? 'word/header'
14
+ end
15
+ end
16
+
17
+ # Renders the hash data in the template xml
18
+ def render(data)
19
+ @sections.map do |section|
20
+ Docx::Builder.logger.debug("Cleaning template variables for section #{section}")
21
+ cleaned_document = clean(@document.read(section))
22
+ Docx::Builder.logger.debug("Replacing template tags ('{{%' -> '<%') for section #{section}")
23
+ erb_template = build_erb_template(cleaned_document)
24
+ Docx::Builder.logger.debug("Rendering template for section #{section} with data")
25
+ processed_document = render_erb_template(erb_template, data)
26
+ [section, processed_document]
27
+ end.to_h
28
+ end
29
+
30
+ # Cleans the xml nodes in the middle of the variables
31
+ def clean(document)
32
+ document.force_encoding(Encoding::UTF_8) if document.respond_to?(:force_encoding)
33
+ Docx::Builder::XmlProcessor.clean_variables(document)
34
+ end
35
+
36
+ # Replaces the docx-builder's tags for those ones currently used in erb files
37
+ def build_erb_template(document)
38
+ ret = document.gsub(/\{\{%/, '<%=').gsub(/%\}\}/, '%>')
39
+ ret = ret.gsub(/\{\{t\s(.*)\st\}\}/) { |_| build_dynamic_table(Regexp.last_match(1)) }
40
+ ret.gsub(/\{\{/, '<%').gsub(/\}\}/, '%>')
41
+ end
42
+
43
+ def render_erb_template(document, data)
44
+ erb_template = ERB.new(document)
45
+ erb_template.result_with_hash(data)
46
+ end
47
+
48
+ # Saves the rendered template in a file
49
+ def save(path, new_document)
50
+ Docx::Builder.logger.info("Saving output file into path #{path}")
51
+ File.open(path, 'wb') do |f|
52
+ buffer = Docx::Builder::Encoder.build_docx_buffer(@document, new_document)
53
+ f.write(buffer.string)
54
+ end
55
+ @document.close
56
+ end
57
+
58
+ # Saves the rendered template in a memory stream (StringIO)
59
+ def save_as_buffer(new_document)
60
+ Docx::Builder.logger.info('Saving output file as buffer')
61
+ buffer = Docx::Builder::Encoder.build_docx_buffer(@document, new_document)
62
+ @document.close
63
+ buffer
64
+ end
65
+
66
+ private
67
+
68
+ def build_dynamic_table(variable)
69
+ template = read_xml_template(:table)
70
+ template.gsub('data', variable)
71
+ end
72
+
73
+ def read_xml_template(filename)
74
+ path = File.join(File.dirname(__FILE__), "../../../templates/#{filename}.xml.erb")
75
+ File.readlines(path).map(&:strip).join('')
76
+ end
53
77
  end
78
+ end
54
79
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Docx
4
4
  module Builder
5
- VERSION = "0.2.3"
5
+ VERSION = '0.4.0'
6
6
  end
7
7
  end
@@ -1,40 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Docx
2
- module Builder
3
- class XmlProcessor
4
- def self.clean_variables(document)
5
- document.gsub(/\{\{.*?\}\}/m) do |match|
6
- ret = match.include?('>') ? join_variable_tags(match) : match
7
- ret = clean_spaces_inside_variables(ret)
8
- ret = insert_null_placeholder(ret)
9
- ret
10
- end
11
- end
12
-
13
- def self.join_variable_tags(match)
14
- before = match.gsub(/<(.*)/m, '')
15
- inside = match.scan(/<w:t.*?>([^>]*?)<.w:t>/m).join
16
- after = match.gsub(/.*>([^>]+)$/m, "\\1")
17
- [before, inside, after].join(' ')
18
- end
19
-
20
- def self.clean_spaces_inside_variables(match)
21
- ret = match.dup
22
- cleaner_methods = Docx::Builder::Cleaners.methods.grep /_cleaner/
23
- cleaner_methods.each do |clean_method|
24
- ret = Docx::Builder::Cleaners.send(clean_method, ret)
25
- end
26
- Docx::Builder.logger.debug("Returning cleaned variable: #{ret}")
27
- ret
28
- end
4
+ module Builder
5
+ # Class responsible for dealing with xml nodes in-between the variables
6
+ class XmlProcessor
7
+ def self.clean_variables(document)
8
+ document.gsub(/\{\{.*?\}\}/m) do |match|
9
+ ret = match.include?('>') ? join_variable_tags(match) : match
10
+ Docx::Builder.logger.debug("Before cleaning: #{ret}")
11
+ ret = clean_spaces_inside_variables(ret)
12
+ ret = insert_null_placeholder(ret)
13
+ Docx::Builder.logger.debug("After cleaning: #{ret}")
14
+ ret
15
+ end
16
+ end
17
+
18
+ def self.join_variable_tags(match)
19
+ before = match.gsub(/<(.*)/m, '')
20
+ inside = match.scan(/<w:t.*?>([^>]*?)<.w:t>/m).join
21
+ after = match.gsub(/.*>([^>]+)$/m, '\\1')
22
+ [before, inside, after].join(' ')
23
+ end
24
+
25
+ def self.clean_spaces_inside_variables(match)
26
+ ret = match.dup
27
+ cleaner_methods = Docx::Builder::Cleaners.methods.grep(/_cleaner/)
28
+ cleaner_methods.each do |clean_method|
29
+ ret = Docx::Builder::Cleaners.send(clean_method, ret)
30
+ end
31
+ ret
32
+ end
29
33
 
30
- def self.insert_null_placeholder(expression)
31
- placeholder = Docx::Builder.configuration.null_placeholder
32
- expression.gsub(/\{\{%\s(.+)\s%\}\}/) do |m|
33
- "{{% (#{$1} || '#{placeholder}') %}}"
34
- end
35
- end
34
+ def self.insert_null_placeholder(expression)
35
+ placeholder = Docx::Builder.configuration.null_placeholder
36
+ expression.gsub(/\{\{%\s(.+)\s%\}\}/) do |_m|
37
+ "{{% (#{Regexp.last_match(1)} || '#{placeholder}') %}}"
36
38
  end
37
-
38
- # {{% devedor[:pessoa_fisica][:cedula_identidade] %}},
39
+ end
39
40
  end
41
+ end
40
42
  end
data/lib/docx/builder.rb CHANGED
@@ -4,29 +4,40 @@ require 'rubygems'
4
4
  require 'zip'
5
5
  require 'nokogiri'
6
6
 
7
- require_relative "logger"
8
- require_relative "builder/version"
9
- require_relative "builder/decoder"
10
- require_relative "builder/encoder"
7
+ require_relative 'logger'
8
+ require_relative 'builder/version'
9
+ require_relative 'builder/decoder'
10
+ require_relative 'builder/encoder'
11
11
  require_relative 'builder/cleaners'
12
- require_relative "builder/xml_processor"
13
- require_relative "builder/template"
14
- require_relative "builder/configuration"
12
+ require_relative 'builder/xml_processor'
13
+ require_relative 'builder/template'
14
+ require_relative 'builder/configuration'
15
15
 
16
16
  module Docx
17
- module Builder
18
- class << self
19
- def configuration
20
- @configuration ||= Configuration.new
21
- end
17
+ # Main module of the gem
18
+ #
19
+ # @example configuring string placeholder
20
+ # Docx::Builder.configure do |config|
21
+ # config.null_placeholder = 'XXXX'
22
+ # end
23
+ #
24
+ # @example configuring log level
25
+ # Docx::Builder.configure do |config|
26
+ # config.logger.level = 1 #info
27
+ # end
28
+ module Builder
29
+ class << self
30
+ def configuration
31
+ @configuration ||= Configuration.new
32
+ end
22
33
 
23
- def logger
24
- configuration.logger
25
- end
34
+ def logger
35
+ configuration.logger
36
+ end
26
37
 
27
- def configure
28
- yield(configuration)
29
- end
30
- end
38
+ def configure
39
+ yield(configuration)
40
+ end
31
41
  end
32
- end
42
+ end
43
+ end
data/lib/docx/logger.rb CHANGED
@@ -1,19 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
 
3
5
  module Docx
4
- class Logger < ::Logger
5
- def initialize(*args, **kwargs)
6
- super
7
- @formatter = SimpleFormatter.new
8
- @level = ENV['LOG_LEVEL'].to_i if ENV.keys.include?('LOG_LEVEL')
9
- end
6
+ # Simple logger for the gem
7
+ #
8
+ # Available levels (from 0 to 5):
9
+ # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
10
+ class Logger < ::Logger
11
+ def initialize(*args, **kwargs)
12
+ super
13
+ @formatter = SimpleFormatter.new
14
+ @level = ENV['LOG_LEVEL'].to_i if ENV.keys.include?('LOG_LEVEL')
15
+ end
10
16
 
11
- # Simple formatter which only displays the message
12
- class SimpleFormatter < ::Logger::Formatter
13
- # This method is invoked when a log event occurs
14
- def call(severity, timestamp, progname, msg)
15
- "#{String === msg ? msg : msg.inspect}\n"
16
- end
17
- end
17
+ # Simple formatter which only displays the message
18
+ class SimpleFormatter < ::Logger::Formatter
19
+ # This method is invoked when a log event occurs
20
+ def call(_severity, _timestamp, _progname, msg)
21
+ "#{msg.is_a?(String) ? msg : msg.inspect}\n"
22
+ end
18
23
  end
19
- end
24
+ end
25
+ end
@@ -0,0 +1,102 @@
1
+ <w:tbl>
2
+ <w:tblPr>
3
+ <w:tblW w:w="10006" w:type="dxa"/>
4
+ <w:tblInd w:w="-626" w:type="dxa"/>
5
+ <w:tblCellMar>
6
+ <w:left w:w="70" w:type="dxa"/>
7
+ <w:right w:w="70" w:type="dxa"/>
8
+ </w:tblCellMar>
9
+ <w:tblLook w:val="04A0" w:firstRow="1" w:lastRow="0" w:firstColumn="1" w:lastColumn="0" w:noHBand="0" w:noVBand="1"/>
10
+ </w:tblPr>
11
+ <w:tblGrid>
12
+ <% data[:columns].each do |column| %>
13
+ <w:gridCol w:w="<%= column[:width] %>"/>
14
+ <% end %>
15
+ </w:tblGrid>
16
+ <w:tr w:rsidR="00080F99" w:rsidRPr="00E71341" w:rsidTr="00E653AF">
17
+ <w:trPr>
18
+ <w:trHeight w:val="315"/>
19
+ </w:trPr>
20
+ <% data[:columns].each do |column| %>
21
+ <w:tc>
22
+ <w:tcPr>
23
+ <w:tcW w:w="<%= column[:width] %>" w:type="dxa"/>
24
+ <w:tcBorders>
25
+ <w:top w:val="single" w:sz="4" w:space="0" w:color="000000"/>
26
+ <w:left w:val="single" w:sz="4" w:space="0" w:color="000000"/>
27
+ <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
28
+ <w:right w:val="single" w:sz="4" w:space="0" w:color="000000"/>
29
+ </w:tcBorders>
30
+ <w:shd w:val="clear" w:color="000000" w:fill="FFFFFF"/>
31
+ <w:noWrap/>
32
+ <w:vAlign w:val="center"/>
33
+ <w:hideMark/>
34
+ </w:tcPr>
35
+ <w:p w:rsidR="00080F99" w:rsidRPr="00E71341" w:rsidRDefault="00080F99" w:rsidP="00E653AF">
36
+ <w:pPr>
37
+ <w:jc w:val="center"/>
38
+ <w:rPr>
39
+ <w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
40
+ <w:b/>
41
+ <w:bCs/>
42
+ <w:color w:val="000000"/>
43
+ <w:lang w:val="pt-BR" w:eastAsia="pt-BR"/>
44
+ </w:rPr>
45
+ </w:pPr>
46
+ <w:r w:rsidRPr="00E71341">
47
+ <w:rPr>
48
+ <w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
49
+ <w:b/>
50
+ <w:bCs/>
51
+ <w:color w:val="000000"/>
52
+ <w:lang w:val="pt-BR" w:eastAsia="pt-BR"/>
53
+ </w:rPr>
54
+ <w:t><%= column[:description] %></w:t>
55
+ </w:r>
56
+ </w:p>
57
+ </w:tc>
58
+ <% end %>
59
+ </w:tr>
60
+ <% data[:rows].each do |row| %>
61
+ <w:tr w:rsidR="00080F99" w:rsidRPr="00E71341" w:rsidTr="00E653AF">
62
+ <w:trPr>
63
+ <w:trHeight w:val="315"/>
64
+ </w:trPr>
65
+ <% data[:columns].each do |column| %>
66
+ <w:tc>
67
+ <w:tcPr>
68
+ <w:tcW w:w="<%= column[:width] %>" w:type="dxa"/>
69
+ <w:tcBorders>
70
+ <w:top w:val="single" w:sz="4" w:space="0" w:color="000000"/>
71
+ <w:left w:val="single" w:sz="4" w:space="0" w:color="000000"/>
72
+ <w:bottom w:val="single" w:sz="4" w:space="0" w:color="000000"/>
73
+ <w:right w:val="single" w:sz="4" w:space="0" w:color="000000"/>
74
+ </w:tcBorders>
75
+ <w:shd w:val="clear" w:color="000000" w:fill="FFFFFF"/>
76
+ <w:noWrap/>
77
+ <w:vAlign w:val="center"/>
78
+ <w:hideMark/>
79
+ </w:tcPr>
80
+ <w:p w:rsidR="00080F99" w:rsidRPr="00E71341" w:rsidRDefault="005549E3" w:rsidP="00E653AF">
81
+ <w:pPr>
82
+ <w:jc w:val="center"/>
83
+ <w:rPr>
84
+ <w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
85
+ <w:color w:val="000000"/>
86
+ <w:lang w:val="pt-BR" w:eastAsia="pt-BR"/>
87
+ </w:rPr>
88
+ </w:pPr>
89
+ <w:r>
90
+ <w:rPr>
91
+ <w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
92
+ <w:color w:val="000000"/>
93
+ <w:lang w:val="pt-BR" w:eastAsia="pt-BR"/>
94
+ </w:rPr>
95
+ <w:t><%= row[column[:name]] %></w:t>
96
+ </w:r>
97
+ </w:p>
98
+ </w:tc>
99
+ <% end %>
100
+ </w:tr>
101
+ <% end %>
102
+ </w:tbl>
data/tmp/.gitkeep CHANGED
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docx-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tecnologia Cashme
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-07 00:00:00.000000000 Z
11
+ date: 2022-06-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Builds a new docx file using ERB template
14
14
  email:
@@ -17,6 +17,7 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - ".github/workflows/cd.yaml"
20
21
  - ".github/workflows/ci.yaml"
21
22
  - ".gitignore"
22
23
  - ".rspec"
@@ -39,7 +40,7 @@ files:
39
40
  - lib/docx/builder/version.rb
40
41
  - lib/docx/builder/xml_processor.rb
41
42
  - lib/docx/logger.rb
42
- - publish.sh
43
+ - templates/table.xml.erb
43
44
  - tmp/.gitkeep
44
45
  homepage: https://github.com/cash-me/docx-builder
45
46
  licenses:
@@ -63,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
64
  - !ruby/object:Gem::Version
64
65
  version: '0'
65
66
  requirements: []
66
- rubygems_version: 3.3.9
67
+ rubygems_version: 3.1.6
67
68
  signing_key:
68
69
  specification_version: 4
69
70
  summary: Builds a new docx file using ERB template
data/publish.sh DELETED
@@ -1 +0,0 @@
1
- bundle exec rake release