make_pdf-jekyll 0.0.2 → 0.0.4

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: 97065b7cf75979dc847f0d82e96bf54229ea7dc4329eab0216a899ac6c72496a
4
- data.tar.gz: cc8b2e3a7a25fb598079829a4198679214ac9a9e672a20c7e4fd1ea71f8cbf0e
3
+ metadata.gz: e5a21bc7883012692bab3b448615f5a40c58a37566c23d678e67f7f4cad520de
4
+ data.tar.gz: 905cf312025602478eebabd00a45477603f40e2785261297e5312321bf3c1d90
5
5
  SHA512:
6
- metadata.gz: 5926bb93054a88d248eef00b4c5aa06d00768f3c7ced9d1b79fdcb713de3e732922406f4d0b365cc933d956a912992307e18ee0ac1cbc6fc612f1feb1bf3033a
7
- data.tar.gz: 18ecbb2c38aabde9c0994fd6a4fb295a23d7b0cf1ef7c3cb7eabc5c508e0e587f7fc3484955f6a5248b0a24c0c8ca332295947ac263fd4803d7c9d3c3675fdc8
6
+ metadata.gz: 80b67fdfb51e5b34d3eebac122a4d6793d543c80c27ff9b416d63cee957928c229605a4ec4f81dd71099f0c403bfa74c4a5112ba93c1ded4cb0e4f7a1549e4a0
7
+ data.tar.gz: b30b0279151ba01a329c5f0e1d99c3ddc5e2677ba85704065c0fe187c080ad327cc5661bbd3014c6a94970b97df34aa527ce2525043fb87af009033c119a64d8
@@ -3,9 +3,48 @@ require "make_pdf/command_based"
3
3
  module MakePDF
4
4
  class Chrome < CommandBased::Writer
5
5
  COMMAND = 'chrome-headless-render-pdf'
6
+ DEFAULT_OPTIONS = { # options from 'chrome-headless-render-pdf --help'
7
+ "chrome-binary": nil,
8
+ "chrome-option": nil,
9
+ "remote-host": nil,
10
+ "remote-port": nil,
11
+ "no-margins": true,
12
+ "include-background": true,
13
+ "landscape": false,
14
+ "window-size": nil,
15
+ "paper-width": nil,
16
+ "paper-height": nil,
17
+ "page-ranges": nil,
18
+ "scale": nil,
19
+ "display-header-footer": false,
20
+ "header-template": nil,
21
+ "footer": nil,
22
+ "js-time-budget": nil,
23
+ "animation-time-budget": nil,
24
+ }
6
25
 
7
- def initialize(source_url, output_dif, **options)
8
- super(source_url, output_dif, command: COMMAND, **options)
26
+ def initialize(**options)
27
+ super(command: COMMAND, **options.merge(DEFAULT_OPTIONS))
28
+ end
29
+
30
+ def map_option_key(key, value)
31
+ case key
32
+ when 'source-url'
33
+ [ '--url', value ]
34
+ when 'output-filename'
35
+ [ '--pdf', value ]
36
+ when DEFAULT_OPTIONS.keys.method(:include?)
37
+ case value
38
+ when false, nil?
39
+ []
40
+ when true, ""
41
+ [ "--#{key.to_s}" ]
42
+ else
43
+ [ "--#{key.to_s}", value ]
44
+ end
45
+ else
46
+ []
47
+ end
9
48
  end
10
49
  end
11
50
  end
@@ -7,8 +7,15 @@ module MakePDF
7
7
  module Arguments
8
8
  attr_reader :base
9
9
 
10
- def make_arguments(options = [], **more)
11
- options.concat(more.map { |key, value| "#{self.class.prefix}#{key}#{"=#{value}" unless value == true || value.nil?}" })
10
+ def make_arguments(*options, **more)
11
+ [
12
+ options.map { |val| val.to_s },
13
+ more
14
+ .transform_keys { |key| key.to_s.gsub('_','-') }
15
+ .filter_map do |key, value|
16
+ map_option_key(key, value.to_s)
17
+ end
18
+ ].flatten
12
19
  end
13
20
  end
14
21
 
@@ -20,35 +27,36 @@ module MakePDF
20
27
  '--'
21
28
  end
22
29
 
23
- def initialize(url, output_dir, command: COMMAND, **options)
24
- super(url, output_dir, **options)
30
+ def initialize(command: COMMAND, **options)
31
+ super(**options)
25
32
  @command = command
26
- @options = options
27
33
  end
28
34
 
29
- def write(file, base_path:, **options)
30
- logger.info("pdf-writer (#{command}): converting #{file}")
31
-
32
- url = source_url(file, base_path:, **options),
33
- output = output_for(file, base_path:, **options)
35
+ def write(source_url, output_filename, **options)
36
+ logger.info("converting #{source_url} with #{@command}")
34
37
  arguments = make_arguments(
35
38
  command: @command,
36
- url:,
37
- pdf: output
39
+ source_url:,
40
+ output_filename:,
41
+ **options
38
42
  )
39
- IO.popen([@command] + arguments, {:err =>[ :child, :out]}) do |pipe|
40
- std_out = pipe.read
43
+ logger.debug("Executing #{@command} #{arguments}")
44
+ std_out = IO.popen([@command] + arguments, {:err =>[ :child, :out]}) do |pipe|
45
+ pipe.read
41
46
  end
42
-
43
- raise std_out if ($? != 0)
44
- logger.info("pdf-writer (#{command}): Wrote #{output}")
47
+ status = $?
48
+ raise RuntimeError.new("Failure executing #{command} with #{arguments}.\n\noutput:\n\n---\n#{std_out}\n---\n") if status != 0
49
+ logger.info("pdf-writer: Wrote #{output_filename}")
45
50
  end
46
51
 
47
- def output_for(file, base_path:, version: [], **options)
48
- if @output.nil?
49
- path = File.dirname(file)
52
+ def output_for(file, output_base_path: ".", version: [], **options)
53
+ output_base_path = Pathname.new(output_base_path)
54
+ file = Pathname.new(file)
55
+
56
+ if @output_dir.nil?
57
+ path = output_base_path / file.dirname
50
58
  else
51
- path = File.expand_path(relative_path(file, base_path), @output)
59
+ path = File.expand_path(relative_path(file, output_base_path), @output_dir)
52
60
  end
53
61
 
54
62
  FileUtils.mkdir_p path
@@ -2,87 +2,152 @@ require 'jekyll'
2
2
  require 'make_pdf'
3
3
 
4
4
  module MakePDF
5
+ LOG_NAME = "make_pdf:"
5
6
 
6
7
  # MakePDF Jekyll plugin
7
8
  class Jekyll
9
+ attr_reader :reason
8
10
 
9
- class << self
10
- include PathManip
11
- attr_reader :file, :site, :current_doc, :options, :command, :output
11
+ def valid?
12
+ @reason.nil?
13
+ end
12
14
 
13
- def setup(current_doc)
14
- if @site.nil?
15
- @site = current_doc.site
16
- @options = @site.config['make-pdf'] || {}
17
- @opt_in = @options['write-by-default'] || false
18
- @base_url = @options['source'] || "file:/"
19
- @base_source = @site.dest
15
+ def check_failure(condition, message)
16
+ @reason = message if condition
17
+ condition
18
+ end
20
19
 
21
- ::Jekyll.logger.debug("make_pdf:", "Initialized with #{@options}. #{@base_source}")
22
- end
23
-
24
- current_options = @options.merge(current_doc.data)
25
- ::Jekyll::logger.debug("make-pdf", current_options)
26
- bail = lambda do |error|
27
- ::Jekyll.logger.debug("make_pdf:", error)
28
- false
20
+ def filter_options(document, **options)
21
+ document.data.filter_map do |key, value|
22
+ key = key.to_s
23
+ if key == "make-pdf"
24
+ possible = {
25
+ "" => true,
26
+ "true" => true,
27
+ "yes" => true,
28
+ "false" => false,
29
+ "no" => false
30
+ }
31
+
32
+ [ key, possible[value.downcase] ]
33
+ else
34
+ [ key.sub("make-pdf-", "").to_sym, value ] if key.start_with?("make-pdf-")
29
35
  end
36
+ end.to_h.merge(options)
37
+ end
30
38
 
31
- writer = current_options['writer']
32
- return bail.call("No writer defined for #{current_doc.name} (#{writer})") if writer.nil?
39
+ def initialize(current_doc, **options)
40
+ @file = current_doc.destination(@base_source)
41
+ @options = filter_options(current_doc, **options)
42
+ logger.debug("base_paths: input → #{@options[:input_base_path]} output → #{@options[:output_base_path]}")
33
43
 
34
- @writer = MakePDF.const_get(current_options['writer'].capitalize)
44
+ current_options = make_options(@options, site_options, filter_options(current_doc))
45
+ output_dir = @options[:output_dir] || path_of(site.dest).dirname
35
46
 
36
- file = current_doc.destination(@base_source)
37
- output_dir = @options['output_dir'] || path_of(file).dirname
47
+ logger.debug("options : #{current_options}")
38
48
 
39
- return bail.call("#{file} is not an html") if File.extname(file) != '.html'
40
- return bail.call("#{current_doc.name} has not opted in") if current_doc.data['make-pdf'].nil? && !@opt_in
41
- return bail.call("#{current_doc.name} has opted out")if current_doc.data['make-pdf'] == false
49
+ return if check_failure(File.extname(@file) != '.html', "#{@file} is not an html")
50
+ return if check_failure(current_options[:make_pdf].nil? && !@opt_in, "#{current_doc.name} has not opted in")
51
+ return if check_failure(current_options[:make_pdf] == false, "#{current_doc.name} has opted out")
42
52
 
43
- ::Jekyll.logger.info("make_pdf:", " processing #{current_doc.name}")
53
+ writer = current_options[:writer]
54
+ return if check_failure(writer.nil?, "No writer defined for #{current_doc.name} (#{writer})")
44
55
 
45
- @writer.new(file, output, logger: ::Jekyll.logger, **current_options)
46
- end
56
+ logger.info(" processing #{current_doc.name}")
57
+ @writer = MakePDF.const_get(writer.capitalize).new(logger:, **current_options)
58
+ end
47
59
 
48
- def process(current_doc)
49
- writer = setup(current_doc)
60
+ def targets
61
+ @options[:targets] || ""
62
+ end
50
63
 
51
- ::Jekyll::logger.debug("make_pdf:", " Ignoring #{current_doc.destination("")}")
52
- return if writer === false
64
+ def method_missing(method_name, *args, **options)
65
+ if not Jekyll.site_options.nil? and Jekyll.site_options.include?(method_name)
66
+ return Jekyll.site_options[method_name]
67
+ elsif Jekyll.respond_to?(method_name, false)
68
+ return Jekyll.send(method_name, *args, **options)
69
+ else
70
+ super
71
+ end
72
+ end
53
73
 
54
- options = current_doc.data['targets']&.split(';') || []
55
- file = current_doc.destination(@site.dest)
74
+ def render_option(**options)
75
+ logger.debug("MakePDF rendering options #{options}")
76
+
77
+ attempted = 0
78
+ begin
79
+ @writer.process(@file, **options.merge(@options))
80
+ rescue => error
81
+ attempted += 1
82
+ if attempted <= 2
83
+ logger.warn("Failed to generate #{@file} retrying #{attempted}")
84
+ logger.warn("ERROR: #{error}")
85
+ retry
86
+ else
87
+ logger.warn("Skipping generation of #{@file} with #{options}")
88
+ raise error
89
+ end
90
+ end
91
+ end
56
92
 
57
- render_option(writer, file, base_path: @site.dest, base_url: @base_url)
58
- options.each { |option| render_option(writer, file, base_path: @site.dest, base_url: @base_url, version: option.split(",")) }
93
+ def process(**options)
94
+ render_option(**options)
95
+ unless self.targets.nil?
96
+ self.targets.split(",").each do |option|
97
+ render_option(version: option.split(","), **options)
98
+ end
59
99
  end
100
+ end
60
101
 
61
- def render_option(writer, file, **options)
62
- ::Jekyll.logger.debug('MakePDF options:', options)
63
-
64
- raise "File #{file} is not accessible" unless File.readable?(file)
65
-
66
- attempted = 0
67
- begin
68
- writer.write(file, **options)
69
- rescue => error
70
- attempted += 1
71
- if attempted <= 2
72
- ::Jekyll.logger.warn("MakePDF: Failed to generate #{file} retrying #{attempted}")
73
- ::Jekyll.logger.warn("MakePDF: ERROR: #{error}")
74
- retry
75
- else
76
- ::Jekyll.logger.error("MakePDF: Skipping generation of #{file} with #{options}")
77
- raise error
102
+ class << self
103
+ include PathManip
104
+ attr_reader :site_options, :site
105
+
106
+ def make_options(options, *more_options)
107
+ return {} if options.nil?
108
+
109
+ [ options, more_options ].flatten
110
+ .reduce(:merge)
111
+ .transform_keys do |key|
112
+ key.to_s.sub("-", "_").to_sym
78
113
  end
114
+ end
115
+
116
+ def logger(**options)
117
+ @logger ||= MakePDF::Logger.new(**options)
118
+ end
119
+
120
+ def setup(site, **options)
121
+ return unless @site.nil?
122
+
123
+ config = site.config["make-pdf"]||{}
124
+ logger(logger: ::Jekyll.logger, level: (config["log-map-level"] || :debug).to_sym, verbose: config['log-verbose'])
125
+ @site = site
126
+ @site_options = {
127
+ :output_base_path => site.source,
128
+ :input_base_path => site.dest,
129
+ :input_scheme => "file"
130
+ }.merge(make_options(@site.config["make-pdf"], options))
131
+ logger.debug("Initialized with #{self.site_options}.")
132
+ end
133
+
134
+ def process(current_doc, **options)
135
+ setup(current_doc.site, **options) if @site.nil?
136
+
137
+ processor = self.new(current_doc)
138
+
139
+ unless processor.valid?
140
+ logger.debug "Ignoring #{current_doc.name} ⇒ #{processor.reason}"
141
+ return false
79
142
  end
143
+
144
+ processor.process(**@site_options)
80
145
  end
81
146
  end
82
147
  end
148
+ end
83
149
 
84
- ::Jekyll.logger.info('MakePDF:', "loaded")
85
- ::Jekyll::Hooks.register [:pages, :documents, :posts], :post_write do |doc|
86
- MakePDF::Jekyll.process(doc)
87
- end
150
+ ::Jekyll.logger.info("Loaded #{MakePDF::LOG_NAME} plugin")
151
+ ::Jekyll::Hooks.register [:pages, :documents, :posts], :post_write do |doc|
152
+ MakePDF::Jekyll.process(doc)
88
153
  end
data/lib/make_pdf.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'selenium-webdriver'
3
+ require 'fileutils'
4
4
 
5
5
  module MakePDF
6
6
  module PathManip
@@ -22,51 +22,111 @@ module MakePDF
22
22
  end
23
23
 
24
24
  class Logger
25
- def debug(*args)
25
+ LEVELS = [ :debug, :info, :warn, :error ]
26
+
27
+ def level
28
+ @min_level || 0
26
29
  end
27
30
 
28
- alias info debug
29
- alias warn debug
30
- alias error debug
31
+ def initialize(logger: nil, level: :debug, verbose: false)
32
+ @logger = logger
33
+ @min_level = LEVELS.index(level) || 2
34
+ @verbose = verbose
35
+ write(:debug, "logging at least level #{LEVELS[@min_level].to_s} with #{logger}")
36
+ end
37
+
38
+ def write(level, *args)
39
+ print("#{level.to_s} : ", *args.map do |msg|
40
+ if (msg.size > 80)
41
+ msg[0..79] + "…"
42
+ else
43
+ msg
44
+ end
45
+ end.join("\n"), "\n")
46
+ return
47
+ end
48
+
49
+ def verbose(*args)
50
+ if (@verbose)
51
+ @logger.send(LEVELS[self.level], LOG_NAME, *args)
52
+ end
53
+ end
54
+
55
+ def method_missing(method_name, *args, **options)
56
+ if @logger.nil? and LEVELS.include?(method_name)
57
+ return write(method_name, *args)
58
+ end
59
+
60
+ if accepts?(method_name)
61
+ @logger.send(LEVELS[[LEVELS.index(method_name), self.level].max], LOG_NAME, *args, **options)
62
+ else
63
+ super
64
+ end
65
+ end
66
+
67
+ def accepts?(method_name)
68
+ LEVELS.include?(method_name) and @logger.respond_to?(method_name, false)
69
+ end
70
+
71
+ def respond_to_missing?(method_name, include_private = false)
72
+ accepts?(method_name) || super
73
+ end
31
74
  end
32
75
 
33
76
  class PDFWriter
34
77
  include PathManip
35
78
  attr_reader :output_dir, :source_url, :logger
36
79
 
37
- def initialize(source_url, output_dir, logger: Logger.new() ,**options)
38
- @source_url = source_url
39
- @output_dir = path_of(output_dir)
80
+ def initialize(input_base_path:, output_base_path:, input_scheme: "file", logger: Logger.new() ,**options)
40
81
  @logger = logger
41
- @options = options
82
+ @options = options.merge({ input_base_path:, output_base_path:, input_scheme: })
83
+ end
84
+
85
+ def make_source_url(file, input_base_path:, output_base_path:, input_scheme: , **options)
86
+ target_file = relative_path(file, input_base_path:, **options)
87
+ if (input_scheme != "file")
88
+ return input_scheme + "://" + output_base_path + target_file.to_s
89
+ else
90
+ return input_base_path + target_file.to_s
91
+ end
42
92
  end
43
93
 
44
- def source_url(file, base_path:Pathname.new("."), base_url: "file:/", version: [], separator: ",", **options)
45
- file_path = path_of(file)
94
+ def relative_path(file, input_base_path:, **options)
95
+ base_path = Pathname.new(input_base_path)
96
+ result = Pathname.new(file).relative_path_from(base_path).dirname
97
+ @logger.verbose("relative_path(#{file}, #{input_base_path}) → base_path: #{base_path} ⇒ #{result}")
98
+ result
99
+ end
46
100
 
47
- options = unless version.empty?
48
- "##{version.join(separator)}"
49
- else
50
- ""
51
- end
52
- "#{base_url}#{relative_path(file_path, base_path)}/#{file_path.basename}#{options}"
101
+ def make_pdf_filename(file, input_base_path:, **options)
102
+ base_path = relative_path(file, input_base_path:, **options)
103
+ filename = Pathname.new(file).basename.sub_ext(".pdf")
104
+ result = base_path / filename
105
+ @logger.verbose("make_pdf_filename(#{file}, #{input_base_path}) → base_path: #{base_path}, filename: #{filename} ⇒ #{result}")
106
+ result
53
107
  end
54
108
 
55
- def output_for(file, version, **options)
56
- output = path_of(file).basename(".pdf").to_s
57
- path_of(@output_dir, output + version.join("_") + ".pdf")
109
+ def make_output_filename(file, input_base_path:, output_base_path:, output_dir: ".", **options)
110
+ @logger.verbose("make_output_filename(#{file}, #{input_base_path}, #{output_base_path})")
111
+ filename = make_pdf_filename(file, input_base_path:, **options)
112
+ output_base_path = Pathname.new(output_base_path)
113
+ output = output_base_path / Pathname.new(output_dir) / filename
114
+ FileUtils::mkdir_p(output.dirname)
115
+ @logger.debug("filename: #{filename} ⇒ #{output}")
116
+ output
58
117
  end
59
118
 
60
119
  def process(file, version: [], **options)
61
120
  options = @options.merge(options)
121
+ output_filename = make_output_filename(file, version: version, **options)
62
122
  write(
63
- source_url(file, vesrsion: version, **options),
64
- output_for(file, version: version, **options),
123
+ make_source_url(file, vesrsion: version, **options),
124
+ output_filename,
65
125
  **options
66
126
  )
127
+ output_filename
67
128
  end
68
129
  end
69
-
70
130
  end
71
131
 
72
132
  Dir[File.join(__dir__, 'make_pdf/', '**', '*.rb')].each do |file|
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: make_pdf-jekyll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Bogado da Silva Lins
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-08-27 00:00:00.000000000 Z
11
12
  dependencies: []
12
13
  description: Allows that some documents, or pages to have a pdf version pre generated.
13
14
  email: 'victor@bogado.net '
@@ -24,6 +25,7 @@ homepage: https://rubygems.org/gems/make_pdf-jekyll
24
25
  licenses:
25
26
  - MIT
26
27
  metadata: {}
28
+ post_install_message:
27
29
  rdoc_options: []
28
30
  require_paths:
29
31
  - lib
@@ -38,7 +40,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
40
  - !ruby/object:Gem::Version
39
41
  version: '0'
40
42
  requirements: []
41
- rubygems_version: 3.6.7
43
+ rubygems_version: 3.3.25
44
+ signing_key:
42
45
  specification_version: 4
43
46
  summary: Create PDF along side of HTML files for site.
44
47
  test_files: []