sheet_filler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 76f271701b3229509c114a985599d7c4950d905f
4
+ data.tar.gz: b354a6e661094bc177a35fb8c3510e8aaa22869b
5
+ SHA512:
6
+ metadata.gz: 78dec1d32829fde0d431bdf0d12718f02141863a98e936bf98d263feb1d27d6a12ae3f1ea14304e0e6dd7cb7e39843104b11df2d14752f82a4c0d5466d53e6b8
7
+ data.tar.gz: 324213a7bf551730de471fb6e4be550108b97ed8ef33b105f87fdeda0ef4f7f773adbf343f86e0497d64f908434e6616f179e542fc0126098e9d45970bda1b17
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ bigbang_services
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sheet_filler.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/circle.yml ADDED
@@ -0,0 +1,7 @@
1
+ dependencies:
2
+ pre:
3
+ - gem install bundler
4
+ - sudo apt-get update; sudo apt-get install pdftk
5
+ machine:
6
+ services:
7
+ - redis
@@ -0,0 +1,39 @@
1
+ require "zip"
2
+
3
+ module SheetFiller
4
+ module Doc
5
+ class Parser
6
+ REGEX_CODE =
7
+ /w:tbl.*?\((\d+)*\) > w:tr.*?(?:\((\d+)*\))? > w:tc(?::nth-of-type\((\d+)*\))?/
8
+
9
+ def self.to_xml(input_form)
10
+ zip = Zip::File.open(input_form)
11
+ xml = zip.find_entry("word/document.xml")
12
+ doc = Nokogiri::XML.parse(xml.get_input_stream)
13
+ doc.root.search("//w:instrText").remove
14
+ end
15
+
16
+ def self.fields(input_form)
17
+ doc = to_xml(input_form)
18
+ (doc/"//w:tr/w:tc").map do |element|
19
+ text = element.text
20
+ list = (element/".//w:result")
21
+ unless list.empty?
22
+ option = list.attribute("val").value.to_i
23
+ text +=
24
+ (element/".//w:listEntry")[option].attribute("val").value
25
+ end
26
+ text.delete!(" ") # word strange space char
27
+ OpenStruct.new(name: cell_code(element), text: text)
28
+ end
29
+ end
30
+
31
+ def self.cell_code(field)
32
+ css_path = field.css_path.match(REGEX_CODE)
33
+ tr = css_path[2] || 0
34
+ tc = css_path[3] || 0
35
+ code = "field_#{css_path[1]}_#{tr}_#{tc}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,68 @@
1
+ require "zip"
2
+
3
+ module SheetFiller
4
+ module Doc
5
+ class WordXmlFile
6
+ def initialize(path)
7
+ @zip = Zip::File.open(path)
8
+ xml = @zip.read("word/document.xml")
9
+ @doc = Nokogiri::XML(xml) { |xml| xml.noent }
10
+ end
11
+
12
+ def fill_form(form_data)
13
+ (@doc/"//w:tr/w:tc").each do |field|
14
+ if form_data_code = form_data[Doc::Parser.cell_code(field)].try(:to_s)
15
+ checkbox = (field/".//w:checkBox")
16
+ if checkbox.empty?
17
+ if text_node = (field/".//w:t").first
18
+ text_node.inner_html = form_data_code
19
+ end
20
+ else
21
+ (checkbox/".//w:default")[0].attribute("val").value = form_data_code
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def replace(form_data)
28
+ (@doc/"//w:checkBox").each do |checkbox|
29
+ WordXmlFile.replace_check_box(form_data, checkbox)
30
+ end
31
+
32
+ (@doc/"//w:p").each do |field|
33
+ WordXmlFile.replace_text_field(form_data, field)
34
+ end
35
+ end
36
+
37
+ def self.replace_text_field(form_data, field)
38
+ text_nodeset = (field/".//w:t")
39
+ text = text_nodeset.inner_html
40
+ if text_nodeset &&
41
+ key = form_data.keys.detect { |key| text.include?(key) }
42
+ text_nodeset.each { |node| node.inner_html = "" }
43
+ text_nodeset.first.inner_html = text.gsub(key, form_data[key].to_s)
44
+ end
45
+ end
46
+
47
+ def self.replace_check_box(form_data, checkbox)
48
+ name = checkbox.parent.children.detect { |child| child.name == "name" }
49
+ if form_data["checkBox:#{name.attributes["val"].to_s}"]
50
+ (checkbox/".//w:default")[0].attribute("val").value = "1"
51
+ end
52
+ end
53
+
54
+ def save(path)
55
+ @replace = {"word/document.xml" => @doc.serialize(save_with: 0)}
56
+ Zip::File.open(path, Zip::File::CREATE) do |zip_file|
57
+ @zip.each do |entry|
58
+ filename = entry.name
59
+ zip_file.get_output_stream(filename) do |output|
60
+ output.write(@replace[filename] || @zip.read(filename))
61
+ end
62
+ end
63
+ end
64
+ @zip.close
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,29 @@
1
+ require "sheet_filler/doc/word_xml_file"
2
+
3
+ module SheetFiller
4
+ module Doc
5
+ class Wrapper < Struct.new(:form_path, :output_path, :type)
6
+ def parser
7
+ @parser ||= WordXmlFile.new(form_path)
8
+ end
9
+
10
+ def parse_fields(data)
11
+ if type == "fill_form"
12
+ Parser.fields(form_path).map(&:name)
13
+ else
14
+ data
15
+ end
16
+ end
17
+
18
+ def fill(data)
19
+ if type == "fill_form"
20
+ parser.fill_form(data)
21
+ else
22
+ parser.replace(data)
23
+ end
24
+ parser.save(output_path)
25
+ output_path
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ require "sheet_filler/sheet_data"
2
+
3
+ module SheetFiller
4
+ class Filler
5
+ extend Forwardable
6
+ def_delegators :@form, :fill_form
7
+
8
+ def self.run(data, sheet_data, output_path)
9
+ sheet_file = sheet_data["sheet_file"]
10
+ output_path << File.extname(sheet_file)
11
+ filler = Filler.new(sheet_file,
12
+ sheet_data["sheet_fields"], output_path, sheet_data["filling_type"])
13
+ filler.fill_form(data)
14
+ end
15
+
16
+ def initialize(sheet_filepath, sheet_fields, output, type)
17
+ parser =
18
+ case File.extname(sheet_filepath)
19
+ when ".pdf"
20
+ Pdf::Wrapper.new(sheet_filepath, output)
21
+ else
22
+ Doc::Wrapper.new(sheet_filepath, output, type)
23
+ end
24
+ sheet_data = SheetFiller::SheetData.new(sheet_fields)
25
+ @form = Form.new(parser, sheet_data)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,80 @@
1
+ require "active_support"
2
+ require "active_support/core_ext"
3
+
4
+ module SheetFiller
5
+ class Form < Struct.new(:parser, :sheet_data)
6
+ def process(raw_data)
7
+ populate_data(raw_data)
8
+ form_data = @data.map do |field_code, value|
9
+ if field = sheet_data.by_code(field_code)
10
+ [field["name"], value]
11
+ end
12
+ end
13
+ form_data = Hash[form_data.compact]
14
+ raw_data.each { |key, value| form_data["-#{key}-"] = value }
15
+ form_data
16
+ end
17
+
18
+ def fill_form(raw_data)
19
+ form_data = process(raw_data)
20
+ parser.fill(form_data)
21
+ end
22
+
23
+ def populate_data(form_data)
24
+ @data = form_data
25
+ fields = parser.parse_fields(sheet_data.field_names)
26
+ @blocks = fields.map do |name|
27
+ if field = sheet_data.by_name(name)
28
+ field_code = field["code"]
29
+ @data[field_code] = form_data[field_code]
30
+ [field_code, field["parser_block"]]
31
+ end
32
+ end
33
+ process_blocks
34
+ end
35
+
36
+ private
37
+ def mask_money(value)
38
+ extend ActiveSupport::NumberHelper
39
+ return if !value || value == 0
40
+ number_to_currency(value,
41
+ precision: 2, unit: "", separator: ",", delimiter: ".")
42
+ end
43
+
44
+ def first_of(field)
45
+ !@data[field].blank? ? @data[field] : @data["2_#{field}"]
46
+ end
47
+
48
+ def second_of(field)
49
+ first = first_of(field)
50
+ second = @data["2_#{field}"]
51
+ second if first.blank? || second != first
52
+ end
53
+
54
+ def value(val)
55
+ val ? val : 0
56
+ end
57
+
58
+ def process_blocks
59
+ @blocks.each do |field, block|
60
+ next if block.blank?
61
+ value = @data[field]
62
+ fields = evaluate_block(block, value) if block
63
+ fields = { field => fields } unless fields.is_a? Hash
64
+ @data.merge!(fields) if fields
65
+ end
66
+ end
67
+
68
+ def evaluate_block(block, params)
69
+ begin
70
+ eval(block)
71
+ rescue Exception => exception
72
+ logger = Logger.new(STDERR)
73
+ logger.error(
74
+ "Error: #{exception.backtrace.join("\n")}\n
75
+ Block: #{block}\n
76
+ Params: #{params}")
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,26 @@
1
+ module SheetFiller
2
+ class Generator
3
+ attr_reader :account_data, :output_dir
4
+
5
+ def initialize(account_data, output_dir)
6
+ @account_data = account_data
7
+ @output_dir = output_dir
8
+ end
9
+
10
+ def generate_sheets(sheets)
11
+ sheets.map do |data|
12
+ output_path = File.join(output_dir,
13
+ "#{data["id"]}_#{File.basename(data["file"], ".*")}")
14
+ Filler.run(account_data.clone, data["default_data"], output_path)
15
+ end
16
+ end
17
+
18
+ def generate_terms(funds)
19
+ funds.map do |data|
20
+ output_path = File.join(output_dir,
21
+ data["fund_name"].gsub(" ", "_"))
22
+ Filler.run(data.clone, data["default_data"], output_path)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ require "zip"
2
+
3
+ module SheetFiller
4
+ class Packager
5
+ def self.pack(files)
6
+ zipfile_name = get_zipfile_name
7
+ Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
8
+ files.each do |file|
9
+ filename = File.basename(file)
10
+ zipfile.add(filename, file)
11
+ end
12
+ end
13
+ files.each { |file| File.delete(file) }
14
+ zipfile_name
15
+ end
16
+
17
+ def self.get_zipfile_name
18
+ zipfile_name = "/tmp/fichas_#{Time.now.to_i}.zip"
19
+ File.delete(zipfile_name) if File.exists? zipfile_name
20
+ zipfile_name
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ require "pdftk_forms"
2
+
3
+ module SheetFiller
4
+ module Pdf
5
+ class Parser
6
+ def initialize(form, output)
7
+ @wrapper = PdftkForms::Wrapper.new
8
+ @path = form
9
+ @output = output
10
+ end
11
+
12
+ def parse_fields(data)
13
+ @wrapper.fields(@path).map do |field|
14
+ field.attributes["FieldName"]
15
+ end
16
+ end
17
+
18
+ def fill(data)
19
+ @wrapper.fill_form(@path, @output, data)
20
+ @output
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require "pdftk_forms"
2
+
3
+ module SheetFiller
4
+ module Pdf
5
+ class Wrapper < Struct.new(:form_path, :output_path)
6
+ def parser
7
+ @parser ||= PdftkForms::Wrapper.new
8
+ end
9
+
10
+ def parse_fields(data)
11
+ parser.fields(form_path).map { |field| field.attributes["FieldName"] }
12
+ end
13
+
14
+ def fill(data)
15
+ parser.fill_form(form_path, output_path, data)
16
+ output_path
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ module SheetFiller
2
+ class SheetData
3
+ def initialize(data)
4
+ @data = data
5
+ end
6
+
7
+ def field_names
8
+ @data.map { |data| data["name"] }
9
+ end
10
+
11
+ def by_name(name)
12
+ find("name", name)
13
+ end
14
+
15
+ def by_code(code)
16
+ find("code", code)
17
+ end
18
+
19
+ private
20
+ def find(attr, value)
21
+ @data.detect { |field| field[attr] == value }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module SheetFiller
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,10 @@
1
+ require "sheet_filler/version"
2
+ require "sheet_filler/filler"
3
+ require "sheet_filler/form"
4
+ require "sheet_filler/generator"
5
+ require "sheet_filler/packager"
6
+ require "sheet_filler/doc/wrapper"
7
+ require "sheet_filler/pdf/wrapper"
8
+ require "sheet_filler/doc/parser"
9
+ require "sheet_filler/pdf/parser"
10
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sheet_filler/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sheet_filler"
8
+ spec.version = SheetFiller::VERSION
9
+ spec.authors = ["Adriano Bacha"]
10
+ spec.email = ["abacha@gmail.com"]
11
+
12
+ spec.summary = "Preenchedor de fichas PDF & Doc"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
15
+ f.match(%r{^(test|spec|features)/})
16
+ end
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.14"
20
+ spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency "rspec", "~> 3.0"
22
+ spec.add_runtime_dependency "pdftk_forms", "~> 0.1.0"
23
+ spec.add_runtime_dependency "rubyzip", "~> 1.0"
24
+ spec.add_runtime_dependency "activesupport", ">= 5.0"
25
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sheet_filler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adriano Bacha
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pdftk_forms
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubyzip
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '5.0'
97
+ description:
98
+ email:
99
+ - abacha@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".ruby-gemset"
107
+ - ".ruby-version"
108
+ - Gemfile
109
+ - Rakefile
110
+ - circle.yml
111
+ - lib/sheet_filler.rb
112
+ - lib/sheet_filler/doc/parser.rb
113
+ - lib/sheet_filler/doc/word_xml_file.rb
114
+ - lib/sheet_filler/doc/wrapper.rb
115
+ - lib/sheet_filler/filler.rb
116
+ - lib/sheet_filler/form.rb
117
+ - lib/sheet_filler/generator.rb
118
+ - lib/sheet_filler/packager.rb
119
+ - lib/sheet_filler/pdf/parser.rb
120
+ - lib/sheet_filler/pdf/wrapper.rb
121
+ - lib/sheet_filler/sheet_data.rb
122
+ - lib/sheet_filler/version.rb
123
+ - sheet_filler.gemspec
124
+ homepage:
125
+ licenses: []
126
+ metadata: {}
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 2.4.8
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Preenchedor de fichas PDF & Doc
147
+ test_files: []