docx-builder 0.2.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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