puppet_pdf 0.1.3 → 0.2.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 +4 -4
- data/.gitignore +191 -7
- data/Gemfile.lock +13 -17
- data/README.md +36 -7
- data/javascript/pdf_creator.js +89 -0
- data/lib/puppet_pdf.rb +4 -4
- data/lib/puppet_pdf/helpers/controller.rb +40 -0
- data/lib/puppet_pdf/helpers/view.rb +39 -0
- data/lib/puppet_pdf/pdf_creator.rb +22 -7
- data/lib/puppet_pdf/railtie.rb +8 -0
- data/lib/puppet_pdf/version.rb +1 -1
- data/lib/utils/yarn_wrapper.rb +4 -2
- data/package.json +1 -2
- data/puppet_pdf.gemspec +4 -5
- metadata +32 -18
- data/javascript/pdf_from_html.js +0 -52
- data/javascript/pdf_from_url.js +0 -50
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 931e17a61d7981d219cf583c45dd464599a0f86e56edf87c3dad6c21bf2a4b65
|
|
4
|
+
data.tar.gz: d87e8e519952e5e197918f4884696ccf4856346c8d9e5b3d4d275dd41c4c4931
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 440037c96df342cf09b6be6084ffd330bcb79843b8a2ecfc1193a7fb1741872b29bdaa9e6bc2b5bfc9a56d5a3d6f648787102a7ddbf846215b1f83117f36ee0a
|
|
7
|
+
data.tar.gz: 629f58890f6d32abcb6e99d008d9cd57117e85a22c6637dc37cf8104e884257808c7f392ddc1e23bf0c0d88d566a0ef8a321908f809e9f7ff0e7e569b161fd81
|
data/.gitignore
CHANGED
|
@@ -1,13 +1,197 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Created by https://www.gitignore.io/api/vim,node,ruby,macos
|
|
2
|
+
# Edit at https://www.gitignore.io/?templates=vim,node,ruby,macos
|
|
3
|
+
|
|
4
|
+
### macOS ###
|
|
5
|
+
# General
|
|
6
|
+
.DS_Store
|
|
7
|
+
.AppleDouble
|
|
8
|
+
.LSOverride
|
|
9
|
+
|
|
10
|
+
# Icon must end with two \r
|
|
11
|
+
Icon
|
|
12
|
+
|
|
13
|
+
# Thumbnails
|
|
14
|
+
._*
|
|
15
|
+
|
|
16
|
+
# Files that might appear in the root of a volume
|
|
17
|
+
.DocumentRevisions-V100
|
|
18
|
+
.fseventsd
|
|
19
|
+
.Spotlight-V100
|
|
20
|
+
.TemporaryItems
|
|
21
|
+
.Trashes
|
|
22
|
+
.VolumeIcon.icns
|
|
23
|
+
.com.apple.timemachine.donotpresent
|
|
24
|
+
|
|
25
|
+
# Directories potentially created on remote AFP share
|
|
26
|
+
.AppleDB
|
|
27
|
+
.AppleDesktop
|
|
28
|
+
Network Trash Folder
|
|
29
|
+
Temporary Items
|
|
30
|
+
.apdisk
|
|
31
|
+
|
|
32
|
+
### Node ###
|
|
33
|
+
# Logs
|
|
34
|
+
logs
|
|
35
|
+
*.log
|
|
36
|
+
npm-debug.log*
|
|
37
|
+
yarn-debug.log*
|
|
38
|
+
yarn-error.log*
|
|
39
|
+
lerna-debug.log*
|
|
40
|
+
|
|
41
|
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
42
|
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
43
|
+
|
|
44
|
+
# Runtime data
|
|
45
|
+
pids
|
|
46
|
+
*.pid
|
|
47
|
+
*.seed
|
|
48
|
+
*.pid.lock
|
|
49
|
+
|
|
50
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
51
|
+
lib-cov
|
|
52
|
+
|
|
53
|
+
# Coverage directory used by tools like istanbul
|
|
54
|
+
coverage
|
|
55
|
+
*.lcov
|
|
56
|
+
|
|
57
|
+
# nyc test coverage
|
|
58
|
+
.nyc_output
|
|
59
|
+
|
|
60
|
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
61
|
+
.grunt
|
|
62
|
+
|
|
63
|
+
# Bower dependency directory (https://bower.io/)
|
|
64
|
+
bower_components
|
|
65
|
+
|
|
66
|
+
# node-waf configuration
|
|
67
|
+
.lock-wscript
|
|
68
|
+
|
|
69
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
70
|
+
build/Release
|
|
71
|
+
|
|
72
|
+
# Dependency directories
|
|
73
|
+
node_modules/
|
|
74
|
+
jspm_packages/
|
|
75
|
+
|
|
76
|
+
# TypeScript v1 declaration files
|
|
77
|
+
typings/
|
|
78
|
+
|
|
79
|
+
# TypeScript cache
|
|
80
|
+
*.tsbuildinfo
|
|
81
|
+
|
|
82
|
+
# Optional npm cache directory
|
|
83
|
+
.npm
|
|
84
|
+
|
|
85
|
+
# Optional eslint cache
|
|
86
|
+
.eslintcache
|
|
87
|
+
|
|
88
|
+
# Optional REPL history
|
|
89
|
+
.node_repl_history
|
|
90
|
+
|
|
91
|
+
# Output of 'npm pack'
|
|
92
|
+
*.tgz
|
|
93
|
+
|
|
94
|
+
# Yarn Integrity file
|
|
95
|
+
.yarn-integrity
|
|
96
|
+
|
|
97
|
+
# dotenv environment variables file
|
|
98
|
+
.env
|
|
99
|
+
.env.test
|
|
100
|
+
|
|
101
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
102
|
+
.cache
|
|
103
|
+
|
|
104
|
+
# next.js build output
|
|
105
|
+
.next
|
|
106
|
+
|
|
107
|
+
# nuxt.js build output
|
|
108
|
+
.nuxt
|
|
109
|
+
|
|
110
|
+
# vuepress build output
|
|
111
|
+
.vuepress/dist
|
|
112
|
+
|
|
113
|
+
# Serverless directories
|
|
114
|
+
.serverless/
|
|
115
|
+
|
|
116
|
+
# FuseBox cache
|
|
117
|
+
.fusebox/
|
|
118
|
+
|
|
119
|
+
# DynamoDB Local files
|
|
120
|
+
.dynamodb/
|
|
121
|
+
|
|
122
|
+
### Ruby ###
|
|
123
|
+
*.gem
|
|
124
|
+
*.rbc
|
|
125
|
+
/.config
|
|
4
126
|
/coverage/
|
|
5
|
-
/
|
|
127
|
+
/InstalledFiles
|
|
6
128
|
/pkg/
|
|
7
129
|
/spec/reports/
|
|
130
|
+
/spec/examples.txt
|
|
131
|
+
/test/tmp/
|
|
132
|
+
/test/version_tmp/
|
|
8
133
|
/tmp/
|
|
9
134
|
|
|
10
|
-
#
|
|
11
|
-
.
|
|
135
|
+
# Used by dotenv library to load environment variables.
|
|
136
|
+
# .env
|
|
137
|
+
|
|
138
|
+
# Ignore Byebug command history file.
|
|
139
|
+
.byebug_history
|
|
140
|
+
|
|
141
|
+
## Specific to RubyMotion:
|
|
142
|
+
.dat*
|
|
143
|
+
.repl_history
|
|
144
|
+
build/
|
|
145
|
+
*.bridgesupport
|
|
146
|
+
build-iPhoneOS/
|
|
147
|
+
build-iPhoneSimulator/
|
|
12
148
|
|
|
13
|
-
|
|
149
|
+
## Specific to RubyMotion (use of CocoaPods):
|
|
150
|
+
#
|
|
151
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
|
152
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
|
153
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
154
|
+
# vendor/Pods/
|
|
155
|
+
|
|
156
|
+
## Documentation cache and generated files:
|
|
157
|
+
/.yardoc/
|
|
158
|
+
/_yardoc/
|
|
159
|
+
/doc/
|
|
160
|
+
/rdoc/
|
|
161
|
+
|
|
162
|
+
## Environment normalization:
|
|
163
|
+
/.bundle/
|
|
164
|
+
/vendor/bundle
|
|
165
|
+
/lib/bundler/man/
|
|
166
|
+
|
|
167
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
168
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
169
|
+
# Gemfile.lock
|
|
170
|
+
# .ruby-version
|
|
171
|
+
# .ruby-gemset
|
|
172
|
+
|
|
173
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
174
|
+
.rvmrc
|
|
175
|
+
|
|
176
|
+
### Vim ###
|
|
177
|
+
# Swap
|
|
178
|
+
[._]*.s[a-v][a-z]
|
|
179
|
+
[._]*.sw[a-p]
|
|
180
|
+
[._]s[a-rt-v][a-z]
|
|
181
|
+
[._]ss[a-gi-z]
|
|
182
|
+
[._]sw[a-p]
|
|
183
|
+
|
|
184
|
+
# Session
|
|
185
|
+
Session.vim
|
|
186
|
+
Sessionx.vim
|
|
187
|
+
|
|
188
|
+
# Temporary
|
|
189
|
+
.netrwhist
|
|
190
|
+
*~
|
|
191
|
+
# Auto-generated tag files
|
|
192
|
+
tags
|
|
193
|
+
# Persistent undo
|
|
194
|
+
[._]*.un~
|
|
195
|
+
|
|
196
|
+
# End of https://www.gitignore.io/api/vim,node,ruby,macos# rspec failure tracking
|
|
197
|
+
.rspec_status
|
data/Gemfile.lock
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
puppet_pdf (0.
|
|
5
|
-
activerecord
|
|
6
|
-
railties
|
|
4
|
+
puppet_pdf (0.2.0)
|
|
5
|
+
activerecord (~> 5.0, >= 5.0.0.1)
|
|
6
|
+
railties (~> 5.2, >= 5.2.3)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
@@ -42,7 +42,7 @@ GEM
|
|
|
42
42
|
erubi (1.8.0)
|
|
43
43
|
i18n (1.6.0)
|
|
44
44
|
concurrent-ruby (~> 1.0)
|
|
45
|
-
jaro_winkler (1.5.
|
|
45
|
+
jaro_winkler (1.5.3)
|
|
46
46
|
loofah (2.2.3)
|
|
47
47
|
crass (~> 1.0.2)
|
|
48
48
|
nokogiri (>= 1.5.9)
|
|
@@ -51,14 +51,12 @@ GEM
|
|
|
51
51
|
minitest (5.11.3)
|
|
52
52
|
nokogiri (1.10.3)
|
|
53
53
|
mini_portile2 (~> 2.4.0)
|
|
54
|
-
parallel (1.
|
|
55
|
-
parser (2.6.
|
|
54
|
+
parallel (1.17.0)
|
|
55
|
+
parser (2.6.3.0)
|
|
56
56
|
ast (~> 2.4.0)
|
|
57
|
-
powerpack (0.1.2)
|
|
58
57
|
pry (0.12.2)
|
|
59
58
|
coderay (~> 1.1.0)
|
|
60
59
|
method_source (~> 0.9.0)
|
|
61
|
-
psych (3.1.0)
|
|
62
60
|
rack (2.0.7)
|
|
63
61
|
rack-test (1.1.0)
|
|
64
62
|
rack (>= 1.0, < 3)
|
|
@@ -88,32 +86,30 @@ GEM
|
|
|
88
86
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
89
87
|
rspec-support (~> 3.8.0)
|
|
90
88
|
rspec-support (3.8.0)
|
|
91
|
-
rubocop (0.
|
|
89
|
+
rubocop (0.72.0)
|
|
92
90
|
jaro_winkler (~> 1.5.1)
|
|
93
91
|
parallel (~> 1.10)
|
|
94
|
-
parser (>= 2.
|
|
95
|
-
powerpack (~> 0.1)
|
|
96
|
-
psych (>= 3.1.0)
|
|
92
|
+
parser (>= 2.6)
|
|
97
93
|
rainbow (>= 2.2.2, < 4.0)
|
|
98
94
|
ruby-progressbar (~> 1.7)
|
|
99
|
-
unicode-display_width (
|
|
100
|
-
ruby-progressbar (1.10.
|
|
95
|
+
unicode-display_width (>= 1.4.0, < 1.7)
|
|
96
|
+
ruby-progressbar (1.10.1)
|
|
101
97
|
thor (0.20.3)
|
|
102
98
|
thread_safe (0.3.6)
|
|
103
99
|
tzinfo (1.2.5)
|
|
104
100
|
thread_safe (~> 0.1)
|
|
105
|
-
unicode-display_width (1.
|
|
101
|
+
unicode-display_width (1.6.0)
|
|
106
102
|
|
|
107
103
|
PLATFORMS
|
|
108
104
|
ruby
|
|
109
105
|
|
|
110
106
|
DEPENDENCIES
|
|
111
107
|
bundler (~> 1.16)
|
|
112
|
-
pry
|
|
108
|
+
pry (~> 0.12.2)
|
|
113
109
|
puppet_pdf!
|
|
114
110
|
rake (~> 10.0)
|
|
115
111
|
rspec (~> 3.0)
|
|
116
|
-
rubocop
|
|
112
|
+
rubocop (~> 0.72.0)
|
|
117
113
|
|
|
118
114
|
BUNDLED WITH
|
|
119
115
|
1.17.3
|
data/README.md
CHANGED
|
@@ -26,24 +26,53 @@ Run this task to install some dependencies:
|
|
|
26
26
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
### Render in a controller
|
|
30
30
|
|
|
31
31
|
```ruby
|
|
32
|
-
|
|
32
|
+
class TasksController < ApplicationController
|
|
33
|
+
def pdf
|
|
34
|
+
render_pdf
|
|
35
|
+
end
|
|
36
|
+
end
|
|
33
37
|
```
|
|
34
38
|
|
|
35
|
-
to
|
|
39
|
+
You can pass some options to `render_pdf` like template, layout and the output filename. The available options are:
|
|
36
40
|
|
|
37
41
|
```ruby
|
|
38
|
-
|
|
42
|
+
{
|
|
43
|
+
template: String, # The template to be rendered. Default: 'controller_path/action_name'
|
|
44
|
+
layout: String, # Default: 'application'
|
|
45
|
+
filename: String, # Default: 'action_name.pdf'
|
|
46
|
+
header: String, # The header of the pdf. Default: '<header></header>'
|
|
47
|
+
footer: String, # The header of the pdf. Default: '<footer></footer>'
|
|
48
|
+
margins: Hash, # The margins of the pdf. Default: { top: 36, right: 36, bottom: 45, left: 36 }
|
|
49
|
+
loading_delay: Integer, # Time to load the page javascript in ms. Default: 1000
|
|
50
|
+
output_path: String # The output path of the pdf. Default: generated by Tempfile
|
|
51
|
+
}
|
|
39
52
|
```
|
|
40
53
|
|
|
41
|
-
to generate a pdf from an html.
|
|
42
54
|
|
|
55
|
+
### View Helpers
|
|
56
|
+
In you views you need to replace `stylesheet_link_tag` with `puppet_stylesheet_link_tag`, and `javascript_include_tag` with `puppet_javascript_script_tag`
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
```html
|
|
59
|
+
<!DOCTYPE html>
|
|
60
|
+
<html>
|
|
61
|
+
<head>
|
|
62
|
+
<title>PuppetPdfExample</title>
|
|
63
|
+
<%= csrf_meta_tags %>
|
|
64
|
+
<%= csp_meta_tag %>
|
|
65
|
+
|
|
66
|
+
<%= puppet_stylesheet_link_tag('application.css') %>
|
|
67
|
+
<%= puppet_javascript_script_tag('application.js') %>
|
|
68
|
+
</head>
|
|
69
|
+
|
|
70
|
+
<body>
|
|
71
|
+
<%= yield %>
|
|
72
|
+
</body>
|
|
73
|
+
</html>
|
|
74
|
+
```
|
|
45
75
|
|
|
46
|
-
And a pdf of the given url will be generated, and the path to this file is going to be returned.
|
|
47
76
|
|
|
48
77
|
## Contributing
|
|
49
78
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const puppeteer = require('puppeteer')
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
|
|
7
|
+
var log = fs.createWriteStream(path.resolve(__dirname, '/tmp/puppet_pdf.log'), { 'flags': 'a' })
|
|
8
|
+
process.stdout.write = process.stderr.write = log.write.bind(log)
|
|
9
|
+
|
|
10
|
+
const defaultOptions = {
|
|
11
|
+
header: "<header></header>",
|
|
12
|
+
footer: "<footer></footer>",
|
|
13
|
+
loadingDelay: 1000,
|
|
14
|
+
margin: { top: 36, right: 36, bottom: 45, left: 36 }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* argv[2] source The source of the pdf content.
|
|
20
|
+
* argv[3] options A JSON with the pdf creation options.
|
|
21
|
+
* The available options are:
|
|
22
|
+
* - outputPath
|
|
23
|
+
* - header
|
|
24
|
+
* - footer
|
|
25
|
+
* - loadingDelay
|
|
26
|
+
* - margin: { :top, :right, :bottom, :left }
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
29
|
+
async function createPdf() {
|
|
30
|
+
const source = process.argv[2]
|
|
31
|
+
const options = JSON.parse(process.argv[3])
|
|
32
|
+
|
|
33
|
+
if(Object.is(options.outputPath, undefined)) throw 'You must provide the outputPath option'
|
|
34
|
+
|
|
35
|
+
let browser
|
|
36
|
+
try {
|
|
37
|
+
const browser = await getBrowser()
|
|
38
|
+
const page = await getPageWithContent(browser, source)
|
|
39
|
+
|
|
40
|
+
await page.waitFor(getOption('loadingDelay', options))
|
|
41
|
+
await page.pdf({
|
|
42
|
+
path: options.outputPath,
|
|
43
|
+
format: 'A4',
|
|
44
|
+
margin: getOption('margin', options),
|
|
45
|
+
displayHeaderFooter: true,
|
|
46
|
+
headerTemplate: getOption('header', options),
|
|
47
|
+
footerTemplate: getOption('footer', options),
|
|
48
|
+
})
|
|
49
|
+
} catch (err) {
|
|
50
|
+
const formatedMessage = `\n ${err.message} at: ${getCurrentTimeFormated()}`
|
|
51
|
+
log.write(formatedMessage)
|
|
52
|
+
} finally {
|
|
53
|
+
if (browser) browser.close()
|
|
54
|
+
|
|
55
|
+
process.exit()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function getPageWithContent(browser, source) {
|
|
60
|
+
const page = await browser.newPage()
|
|
61
|
+
const pageOptions = { timeout: 900000, waitUntil: 'networkidle0' }
|
|
62
|
+
|
|
63
|
+
const contents = fs.readFileSync(source, 'utf8')
|
|
64
|
+
await page.setContent(contents, pageOptions)
|
|
65
|
+
|
|
66
|
+
return page
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getBrowser() {
|
|
70
|
+
return puppeteer.launch({
|
|
71
|
+
headless: true,
|
|
72
|
+
pipe: true,
|
|
73
|
+
args: ['--disable-gpu', '--full-memory-crash-report', '--unlimited-storage',
|
|
74
|
+
'--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getOption(key, options) {
|
|
79
|
+
return Object.is(options[key], undefined) ? defaultOptions[key] : options[key]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getCurrentTimeFormated() {
|
|
83
|
+
const date = new Date()
|
|
84
|
+
const dateFormatted = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
|
|
85
|
+
|
|
86
|
+
return `${dateFormatted}, ${date.toLocaleTimeString('en')}`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
createPdf()
|
data/lib/puppet_pdf.rb
CHANGED
|
@@ -4,14 +4,14 @@ require 'puppet_pdf/railtie' if defined?(Rails)
|
|
|
4
4
|
|
|
5
5
|
module PuppetPdf
|
|
6
6
|
def self.pdf_from_url(url, options = {})
|
|
7
|
-
pdf_creator(:
|
|
7
|
+
pdf_creator(:url, url, options).call
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def self.pdf_from_html(html, options = {})
|
|
11
|
-
pdf_creator(:
|
|
11
|
+
pdf_creator(:html, html, options).call
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
private_class_method def self.pdf_creator(
|
|
15
|
-
::PuppetPdf::PdfCreator.new(
|
|
14
|
+
private_class_method def self.pdf_creator(source_type, source, options)
|
|
15
|
+
::PuppetPdf::PdfCreator.new(source_type, source, options)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module PuppetPdf
|
|
2
|
+
module Helpers
|
|
3
|
+
module Controller
|
|
4
|
+
def render_pdf(args = {})
|
|
5
|
+
html = render_to_string(render_params(args))
|
|
6
|
+
|
|
7
|
+
html_path = create_file_and_get_path(html)
|
|
8
|
+
options = args.slice(:header, :footer, :margins, :loading_delay)
|
|
9
|
+
file_path = ::PuppetPdf::PdfCreator.new(html_path, options).call
|
|
10
|
+
|
|
11
|
+
send_file(file_path,
|
|
12
|
+
filename: args.fetch(:filename, "#{action_name}.pdf"),
|
|
13
|
+
disposition: :inline)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def render_params(params)
|
|
19
|
+
{
|
|
20
|
+
template: params.fetch(:template, default_template),
|
|
21
|
+
layout: params.fetch(:layout, 'application'),
|
|
22
|
+
locals: params.fetch(:locals, {})
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def default_template
|
|
27
|
+
File.join(controller_path, action_name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def create_file_and_get_path(content)
|
|
31
|
+
file = Tempfile.new(Time.now.to_i.to_s)
|
|
32
|
+
file_path = file.path
|
|
33
|
+
file.write(content)
|
|
34
|
+
file.close
|
|
35
|
+
|
|
36
|
+
file_path
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'active_support/core_ext/string/output_safety'
|
|
2
|
+
require 'open-uri'
|
|
3
|
+
|
|
4
|
+
module PuppetPdf
|
|
5
|
+
module Helpers
|
|
6
|
+
module View
|
|
7
|
+
def puppet_stylesheet_link_tag(asset)
|
|
8
|
+
asset_tag = <<~TAG
|
|
9
|
+
<style type='text/css'>
|
|
10
|
+
#{asset_content(asset)}
|
|
11
|
+
</style>
|
|
12
|
+
TAG
|
|
13
|
+
|
|
14
|
+
asset_tag
|
|
15
|
+
.force_encoding('utf-8')
|
|
16
|
+
.html_safe
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def puppet_javascript_script_tag(asset)
|
|
20
|
+
asset_tag = <<~TAG
|
|
21
|
+
<script type='application/javascript'>
|
|
22
|
+
#{asset_content(asset)}
|
|
23
|
+
</script>
|
|
24
|
+
TAG
|
|
25
|
+
|
|
26
|
+
asset_tag
|
|
27
|
+
.force_encoding('utf-8')
|
|
28
|
+
.html_safe
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def asset_content(asset)
|
|
34
|
+
url = asset_url(asset)
|
|
35
|
+
OpenURI.open_uri(url, &:read)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
require 'tempfile'
|
|
2
2
|
require 'utils/yarn_wrapper'
|
|
3
|
+
require 'json'
|
|
3
4
|
|
|
4
5
|
module PuppetPdf
|
|
5
6
|
class PdfCreator
|
|
6
7
|
include ::Utils::YarnWrapper
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
attr_reader :source, :options
|
|
10
|
+
|
|
11
|
+
def initialize(source, options = {})
|
|
9
12
|
validate_yarn_installation
|
|
10
13
|
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
|
|
14
|
+
@source = source
|
|
15
|
+
@options = options.tap do |opt|
|
|
16
|
+
opt[:output_path] = opt.fetch(:output_path, default_output_path)
|
|
17
|
+
end
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
def call
|
|
17
|
-
run_yarn(
|
|
18
|
-
output_path
|
|
21
|
+
run_yarn(:create_pdf, source, options_json)
|
|
22
|
+
options[:output_path]
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
private
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
def options_json
|
|
28
|
+
options
|
|
29
|
+
.each_with_object({}) { |(key, val), opts| opts[camelize(key)] = val }
|
|
30
|
+
.to_json
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def camelize(string)
|
|
34
|
+
string_arr = string.to_s.split('_')
|
|
35
|
+
head, *tail = string_arr
|
|
36
|
+
|
|
37
|
+
head.downcase + tail.map(&:capitalize).join
|
|
38
|
+
end
|
|
24
39
|
|
|
25
40
|
def default_output_path
|
|
26
41
|
file = Tempfile.new(["puppet_pdf_#{Time.now.to_i}", '.pdf'])
|
data/lib/puppet_pdf/railtie.rb
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
require 'puppet_pdf/helpers/controller'
|
|
2
|
+
require 'puppet_pdf/helpers/view'
|
|
3
|
+
|
|
1
4
|
module PuppetPdf
|
|
2
5
|
class Railtie < Rails::Railtie
|
|
3
6
|
rake_tasks do
|
|
4
7
|
load 'tasks/install_dependencies.rake'
|
|
5
8
|
end
|
|
9
|
+
|
|
10
|
+
initializer 'puppet_pdf.register_helpers' do |_|
|
|
11
|
+
ActionController::Base.send :prepend, PuppetPdf::Helpers::Controller
|
|
12
|
+
ActionView::Base.send :include, PuppetPdf::Helpers::View
|
|
13
|
+
end
|
|
6
14
|
end
|
|
7
15
|
end
|
data/lib/puppet_pdf/version.rb
CHANGED
data/lib/utils/yarn_wrapper.rb
CHANGED
|
@@ -10,8 +10,6 @@ module Utils
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def validate_yarn_installation
|
|
13
|
-
which_yarn_output = `which yarn`
|
|
14
|
-
|
|
15
13
|
raise 'Yarn not installed!' if which_yarn_output.empty?
|
|
16
14
|
end
|
|
17
15
|
|
|
@@ -22,6 +20,10 @@ module Utils
|
|
|
22
20
|
Shellwords.escape(Gem.loaded_specs['puppet_pdf'].full_gem_path)
|
|
23
21
|
end
|
|
24
22
|
|
|
23
|
+
def which_yarn_output
|
|
24
|
+
`which yarn`
|
|
25
|
+
end
|
|
26
|
+
|
|
25
27
|
def prepare_args(args)
|
|
26
28
|
args.map { |arg| Shellwords.escape(arg) }.join(' ')
|
|
27
29
|
end
|
data/package.json
CHANGED
data/puppet_pdf.gemspec
CHANGED
|
@@ -9,7 +9,6 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.email = ['fernandesanderson14@gmail.com']
|
|
10
10
|
|
|
11
11
|
spec.summary = 'Simple PDF generator based on Google Puppeteer'
|
|
12
|
-
spec.description = 'Simple PDF generator based on Google Puppeteer'
|
|
13
12
|
spec.homepage = 'https://github.com/andersonfernandes/puppet_pdf'
|
|
14
13
|
spec.license = 'MIT'
|
|
15
14
|
|
|
@@ -21,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
|
21
20
|
spec.require_paths = ['lib']
|
|
22
21
|
|
|
23
22
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
|
24
|
-
spec.add_development_dependency 'pry'
|
|
23
|
+
spec.add_development_dependency 'pry', '~> 0.12.2'
|
|
25
24
|
spec.add_development_dependency 'rake', '~> 10.0'
|
|
26
25
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
27
|
-
spec.add_development_dependency 'rubocop'
|
|
26
|
+
spec.add_development_dependency 'rubocop', '~> 0.72.0'
|
|
28
27
|
|
|
29
|
-
spec.add_dependency 'activerecord'
|
|
30
|
-
spec.add_dependency 'railties'
|
|
28
|
+
spec.add_dependency 'activerecord', '~> 5.0', '>= 5.0.0.1'
|
|
29
|
+
spec.add_dependency 'railties', '~> 5.2', '>= 5.2.3'
|
|
31
30
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: puppet_pdf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anderson Fernandes
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-07-
|
|
11
|
+
date: 2019-07-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -28,16 +28,16 @@ dependencies:
|
|
|
28
28
|
name: pry
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 0.12.2
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 0.12.2
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rake
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -70,45 +70,57 @@ dependencies:
|
|
|
70
70
|
name: rubocop
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
|
-
- - "
|
|
73
|
+
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
75
|
+
version: 0.72.0
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
|
-
- - "
|
|
80
|
+
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
82
|
+
version: 0.72.0
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: activerecord
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '5.0'
|
|
87
90
|
- - ">="
|
|
88
91
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
92
|
+
version: 5.0.0.1
|
|
90
93
|
type: :runtime
|
|
91
94
|
prerelease: false
|
|
92
95
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
96
|
requirements:
|
|
97
|
+
- - "~>"
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '5.0'
|
|
94
100
|
- - ">="
|
|
95
101
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
102
|
+
version: 5.0.0.1
|
|
97
103
|
- !ruby/object:Gem::Dependency
|
|
98
104
|
name: railties
|
|
99
105
|
requirement: !ruby/object:Gem::Requirement
|
|
100
106
|
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '5.2'
|
|
101
110
|
- - ">="
|
|
102
111
|
- !ruby/object:Gem::Version
|
|
103
|
-
version:
|
|
112
|
+
version: 5.2.3
|
|
104
113
|
type: :runtime
|
|
105
114
|
prerelease: false
|
|
106
115
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
116
|
requirements:
|
|
117
|
+
- - "~>"
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: '5.2'
|
|
108
120
|
- - ">="
|
|
109
121
|
- !ruby/object:Gem::Version
|
|
110
|
-
version:
|
|
111
|
-
description:
|
|
122
|
+
version: 5.2.3
|
|
123
|
+
description:
|
|
112
124
|
email:
|
|
113
125
|
- fernandesanderson14@gmail.com
|
|
114
126
|
executables: []
|
|
@@ -127,9 +139,10 @@ files:
|
|
|
127
139
|
- Rakefile
|
|
128
140
|
- bin/console
|
|
129
141
|
- bin/setup
|
|
130
|
-
- javascript/
|
|
131
|
-
- javascript/pdf_from_url.js
|
|
142
|
+
- javascript/pdf_creator.js
|
|
132
143
|
- lib/puppet_pdf.rb
|
|
144
|
+
- lib/puppet_pdf/helpers/controller.rb
|
|
145
|
+
- lib/puppet_pdf/helpers/view.rb
|
|
133
146
|
- lib/puppet_pdf/pdf_creator.rb
|
|
134
147
|
- lib/puppet_pdf/railtie.rb
|
|
135
148
|
- lib/puppet_pdf/version.rb
|
|
@@ -157,7 +170,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
157
170
|
- !ruby/object:Gem::Version
|
|
158
171
|
version: '0'
|
|
159
172
|
requirements: []
|
|
160
|
-
|
|
173
|
+
rubyforge_project:
|
|
174
|
+
rubygems_version: 2.7.7
|
|
161
175
|
signing_key:
|
|
162
176
|
specification_version: 4
|
|
163
177
|
summary: Simple PDF generator based on Google Puppeteer
|
data/javascript/pdf_from_html.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const puppeteer = require('puppeteer');
|
|
4
|
-
const fs = require('fs')
|
|
5
|
-
const path = require('path')
|
|
6
|
-
|
|
7
|
-
function getCurrentTimeFormated() {
|
|
8
|
-
const date = new Date();
|
|
9
|
-
const dateFormatted = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
|
|
10
|
-
|
|
11
|
-
return `${dateFormatted}, ${date.toLocaleTimeString('en')}`
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
var access = fs.createWriteStream(path.resolve(__dirname, '/tmp/puppeteer.log'), { 'flags': 'a' });
|
|
15
|
-
// Redirect stdout/stderr to puppeteer.log file
|
|
16
|
-
process.stdout.write = process.stderr.write = access.write.bind(access);
|
|
17
|
-
|
|
18
|
-
const pdf_from_html = async () => {
|
|
19
|
-
let browser;
|
|
20
|
-
try {
|
|
21
|
-
const browser = await puppeteer.launch({
|
|
22
|
-
headless: true,
|
|
23
|
-
pipe: true,
|
|
24
|
-
args: ['--disable-gpu', '--full-memory-crash-report', '--unlimited-storage',
|
|
25
|
-
'--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
|
26
|
-
});
|
|
27
|
-
const page = await browser.newPage();
|
|
28
|
-
|
|
29
|
-
var contents = fs.readFileSync(process.argv[2], 'utf8');
|
|
30
|
-
await page.setContent(contents, { timeout: 900000, waitUntil: 'networkidle0' });
|
|
31
|
-
await page.waitFor(1000);
|
|
32
|
-
await page.pdf({
|
|
33
|
-
path: process.argv[3],
|
|
34
|
-
format: 'A4',
|
|
35
|
-
margin: { top: 36, right: 36, bottom: 45, left: 36 },
|
|
36
|
-
displayHeaderFooter: true,
|
|
37
|
-
headerTemplate: "<div></div>",
|
|
38
|
-
footerTemplate: "<div></div>"
|
|
39
|
-
});
|
|
40
|
-
} catch (err) {
|
|
41
|
-
const formatedMessage = `\n ${err.message} at: ${getCurrentTimeFormated()}`;
|
|
42
|
-
access.write(formatedMessage)
|
|
43
|
-
} finally {
|
|
44
|
-
if (browser) {
|
|
45
|
-
browser.close();
|
|
46
|
-
}
|
|
47
|
-
process.exit();
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
pdf_from_html();
|
|
52
|
-
|
data/javascript/pdf_from_url.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const puppeteer = require('puppeteer');
|
|
4
|
-
const fs = require('fs')
|
|
5
|
-
const path = require('path')
|
|
6
|
-
|
|
7
|
-
function getCurrentTimeFormated() {
|
|
8
|
-
const date = new Date();
|
|
9
|
-
const dateFormatted = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
|
|
10
|
-
|
|
11
|
-
return `${dateFormatted}, ${date.toLocaleTimeString('en')}`
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
var access = fs.createWriteStream(path.resolve(__dirname, '/tmp/puppeteer.log'), { 'flags': 'a' });
|
|
15
|
-
// Redirect stdout/stderr to puppeteer.log file
|
|
16
|
-
process.stdout.write = process.stderr.write = access.write.bind(access);
|
|
17
|
-
|
|
18
|
-
const pdf_from_url = async () => {
|
|
19
|
-
let browser;
|
|
20
|
-
try {
|
|
21
|
-
const browser = await puppeteer.launch({
|
|
22
|
-
headless: true,
|
|
23
|
-
pipe: true,
|
|
24
|
-
args: ['--disable-gpu', '--full-memory-crash-report', '--unlimited-storage',
|
|
25
|
-
'--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
|
|
26
|
-
});
|
|
27
|
-
const page = await browser.newPage();
|
|
28
|
-
await page.goto(process.argv[2], { timeout: 90000, waitUntil: 'networkidle0' });
|
|
29
|
-
await page.waitFor(1000);
|
|
30
|
-
await page.pdf({
|
|
31
|
-
path: process.argv[3],
|
|
32
|
-
format: 'A4',
|
|
33
|
-
margin: { top: 36, right: 36, bottom: 45, left: 36 },
|
|
34
|
-
displayHeaderFooter: true,
|
|
35
|
-
headerTemplate: "<div></div>",
|
|
36
|
-
footerTemplate: "<div></div>"
|
|
37
|
-
});
|
|
38
|
-
} catch (err) {
|
|
39
|
-
const formatedMessage = `\n ${err.message} at: ${getCurrentTimeFormated()}`;
|
|
40
|
-
access.write(formatedMessage)
|
|
41
|
-
} finally {
|
|
42
|
-
if (browser) {
|
|
43
|
-
browser.close();
|
|
44
|
-
}
|
|
45
|
-
process.exit();
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
pdf_from_url();
|
|
50
|
-
|