gkhtmltopdf 0.9.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbc9b80ee14f3f1a0eae169fbd5b1b48a3a14f79bccf8c23cb445720ccf256ac
4
- data.tar.gz: 84596639fd0dfc5a82a5d9e16373d7b00652688f747a6c8e6fd71a9eb9280038
3
+ metadata.gz: 450c50b4a300eb003c28a7d3df213ed05ec5ec0626172ef178966f693af4cf5d
4
+ data.tar.gz: 0a80041e7a625a55ba11f7636b25a2ebee2a2500e3a6df9d0d8e60c49300a4c9
5
5
  SHA512:
6
- metadata.gz: 587c445948f7c8552a51ad81bf98e94fb6d76d8699faa59cfbf4138633585b9a3b64cd2ad0a307723908473d7f3258434346771bc6f4921b88628f07da101b81
7
- data.tar.gz: 8d5edab4799522f1121a0fc2801fff8d5133a0cd58f4a98398f65b90b40dcabda48de29ebe442341e562b2ed27c045b7d312d01a78432bb72ef1e561057a56c2
6
+ metadata.gz: ca97c9e7eeb874af9258869c4ead4d3dfbdd68f641afed5baaa66f5bdbf20dc1fd9b851039ba7fdc231df8f7ecd7b01b2b5768dddeace29c0c42608c469725ec
7
+ data.tar.gz: 2feea957d0d915498bb92378a6ff734ffce7922da83f1cadb4765090eb09d5d3030b38525c3295ec31fe1826453f34a4bfde5f0343aad8fef9d6fc943ac6234c
data/CHANGELOG.md CHANGED
@@ -2,18 +2,34 @@
2
2
 
3
3
  All noteworthy changes to this project will be documented in this file.
4
4
 
5
+ ## 1.0.0 / 2026-03-19
6
+
7
+ - Added serial processing for multiple files and URLs.
8
+ - 複数ファイル&URLの直列処理追加
9
+ - Separated the Gkhtmltopdf::Error into many.
10
+ - エラーを分離
11
+ - Add and Fixed test.
12
+ - テスト追加&修正
13
+
5
14
  ## 0.9.0 / 2026-03-13
6
15
 
7
16
  - Achieved 100% test coverage.🎉
17
+ - テストカバレッジ100%!
8
18
  - Fixed github url.
19
+ - github URL 修正
9
20
 
10
21
  ## 0.8.0 / 2026-03-10
11
22
 
12
23
  - Added parallel processing support with automatic free port checking.
24
+ - 空きポートの処理追加による並列実行追加
13
25
  - Added print options.
26
+ - プリントオプションの追加
14
27
  - Added Dockerfile (Debian compatibility verified).
28
+ - Dockerfile追加(Debian互換検証)
15
29
  - Added error message display when PATH errors occur.
30
+ - PATH関連のエラーメッセージ追加
16
31
 
17
32
  ## 0.1.0 / 2026-01-09
18
33
 
19
34
  - Initial release.
35
+ - 初期リリース
data/Dockerfile CHANGED
@@ -3,6 +3,9 @@ FROM ruby:3.2-slim
3
3
  RUN apt-get update
4
4
  RUN apt-get install -y git wget xz-utils build-essential libyaml-dev
5
5
 
6
+ # Install Noto Fonts
7
+ RUN apt-get install -y fonts-noto
8
+
6
9
  # Install Firefox
7
10
  RUN apt-get install -y firefox-esr
8
11
 
data/README.md CHANGED
@@ -12,40 +12,45 @@ This gem converts HTML to PDF using Firefox's Geckodriver.
12
12
  ### 1. Install
13
13
 
14
14
  1. [Firefox](https://www.firefox.com)
15
- - for Ubuntu
16
- ```Ubuntu
17
- $ apt install -y firefox
18
- ```
19
- - for Debian
20
- ```bash
21
- $ apt install -y firefox-esr
22
- ```
15
+ - Ubuntu
16
+ ```bash
17
+ $ apt install -y firefox
18
+ $ apt install -y fonts-noto # recommended
19
+ ```
20
+ - Debian
21
+ ```bash
22
+ $ apt install -y firefox-esr
23
+ $ apt install -y fonts-noto # recommended
24
+ ```
25
+
23
26
  2. [geckodriver](https://github.com/mozilla/geckodriver)
24
- - for Linux(Ubuntu / Debian)
25
- ```bash
26
- $ wget "https://github.com/mozilla/geckodriver/releases/download/v0.36.0/geckodriver-v0.36.0-linux64.tar.gz" -O /tmp/geckodriver.tar.gz
27
- $ tar -xzf /tmp/geckodriver.tar.gz -C /usr/local/bin
28
- ```
27
+ - Linux (Ubuntu / Debian)
28
+ ```bash
29
+ $ wget "https://github.com/mozilla/geckodriver/releases/download/v0.36.0/geckodriver-v0.36.0-linux64.tar.gz" -O /tmp/geckodriver.tar.gz
30
+ $ tar -xzf /tmp/geckodriver.tar.gz -C /usr/local/bin
31
+ ```
32
+
29
33
  3. gem install
30
- - bundler
31
- ```bash
32
- $ bundle add gkhtmltopdf
33
- ```
34
- - other
35
- ```bash
36
- $ gem install gkhtmltopdf
37
- ```
34
+ - bundler
35
+ ```bash
36
+ $ bundle add gkhtmltopdf
37
+ ```
38
+ - other
39
+ ```bash
40
+ $ gem install gkhtmltopdf
41
+ ```
38
42
 
39
43
  ---
40
44
 
41
45
  ### 2. Using
42
46
 
43
- #### ruby
47
+ #### Ruby
44
48
 
45
49
  > **⚠️ Security Warning for Web Frameworks (e.g., Ruby on Rails):**
46
50
  > If you are accepting URLs from untrusted users, you must implement strict SSRF protection. Do not pass user-input URLs directly without network-level isolation. Please read the [SSRF](#what-is-ssrf) section below for details.
47
51
 
48
52
  ```ruby
53
+ require 'gkhtmltopdf'
49
54
  # over network
50
55
  Gkhtmltopdf.convert('https://example.com', 'example_com.pdf')
51
56
  # local file
@@ -54,7 +59,19 @@ Gkhtmltopdf.convert('file:///foo/bar/test.html', 'local.pdf')
54
59
  Gkhtmltopdf.convert('https://f6a.net/oss/', 'with_bg.pdf', print_options: {background: true})
55
60
  ```
56
61
 
57
- #### shell
62
+ Additionally, in version 1.0.0 we added the following syntax.
63
+ If you want to generate multiple PDFs faster, use this:
64
+
65
+ ```ruby
66
+ require 'gkhtmltopdf'
67
+ Gkhtmltopdf.open do |gkh2p|
68
+ gkh2p.save_pdf('https://example.com', 'example_com.pdf')
69
+ gkh2p.save_pdf('file:///foo/bar/test.html', 'local.pdf')
70
+ gkh2p.save_pdf('https://f6a.net/oss/', 'with_bg.pdf', print_options: {background: true})
71
+ end
72
+ ```
73
+
74
+ #### Shell
58
75
 
59
76
  ```bash
60
77
  # over network
@@ -88,6 +105,33 @@ Attackers could potentially generate PDFs of internal network resources (e.g., `
88
105
 
89
106
  ---
90
107
 
108
+ ## Errors
109
+
110
+ The following errors inherit `Gkhtmltopdf::Error`, so you can handle them as follows:
111
+
112
+ ```ruby
113
+ begin
114
+ Gkhtmltopdf.convert('ftp://example.com', 'example_com.pdf')
115
+ rescue Gkhtmltopdf::Error => e
116
+ puts e.class # -> Gkhtmltopdf::URLSchemeInvalid
117
+ puts e.message # -> Invalid URL scheme: (ftp)
118
+ end
119
+ ```
120
+
121
+ ### Gkhtmltopdf::PathUnresolvedError
122
+
123
+ Firefox or Geckodriver path unresolved. Follow the installation steps in [1. Install](#1-install) to set up.
124
+
125
+ ### Gkhtmltopdf::URLSchemeInvalid
126
+
127
+ Raised when the URL scheme is invalid (e.g., `ftp://`, `about://`) or the hostname is missing (e.g., `f6a.net`).
128
+
129
+ ### Gkhtmltopdf::BrowserError
130
+
131
+ Response from Firefox/Geckodriver is not as expected.
132
+
133
+ ---
134
+
91
135
  ## Acknowledgments & Third-Party Licenses
92
136
 
93
137
  This gem acts as a wrapper and communicates with the following external open-source tools.
data/TODO.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TODO
2
2
 
3
- ## 完了
3
+ ## 完了 v0.9.0
4
4
 
5
5
  - [x] 並列処理対応(自動空きportチェック)
6
6
  - [x] 印刷オプションの追加
@@ -8,11 +8,18 @@
8
8
  - [x] PATHエラー時の表示追加
9
9
  - [x] 入力値検証
10
10
  - [x] テストカバレッジ100%
11
+ - [x] RubyGemsで公開
12
+ - [x] 多言語対応について
11
13
 
12
- ## 未了
14
+ ## 完了 v1.0.0
15
+
16
+ - [x] 複数ファイル&URLの直列実行による高速化
17
+ - [x] エラー処理
18
+ - [x] 起動時の待機時間オプション
19
+
20
+ ## 今後検討
13
21
 
14
- - [ ] RubyGemsで公開
15
22
  - [ ] UA設定機能
16
- - [ ] ポート範囲設定
17
- - [ ] 複数ファイル&URLの直列実行による高速化
18
- - [ ] configファイルからオプションを設定
23
+ - [ ] ポート範囲設定?
24
+ - [ ] configファイルからオプションを設定?
25
+ - [ ] YARD追加
data/exe/gkhtmltopdf CHANGED
@@ -34,10 +34,14 @@ parser = OptionParser.new do |opts|
34
34
  options[:firefox_path] = v
35
35
  end
36
36
 
37
- opts.on("--geckodriver-path [PATH]", "geckodriver custom PATH") do |v|
37
+ opts.on("--geckodriver-path [PATH]", "Geckodriver custom PATH") do |v|
38
38
  options[:geckodriver_path] = v
39
39
  end
40
40
 
41
+ opts.on("--launch-max-wait-time [NUM]", Integer, "Launch max wait time (approx: NUM * 0.1sec)") do |v|
42
+ options[:wait_time] = v
43
+ end
44
+
41
45
  opts.on("-v", "--version", "display version") do
42
46
  puts "Gkhtmltopdf version #{Gkhtmltopdf::VERSION}"
43
47
  exit
@@ -69,9 +73,9 @@ begin
69
73
  init_options = {}
70
74
  init_options[:firefox_path] = options.delete(:firefox_path) if options[:firefox_path]
71
75
  init_options[:geckodriver_path] = options.delete(:geckodriver_path) if options[:geckodriver_path]
76
+ init_options[:wait_time] = options.delete(:wait_time) if options[:wait_time]
72
77
 
73
- converter = Gkhtmltopdf::Converter.new(**init_options)
74
- converter.convert(input_url, output_path, print_options: options[:print_options])
78
+ Gkhtmltopdf.convert(input_url, output_path, print_options: options[:print_options], **init_options)
75
79
 
76
80
  puts "✅ Completed PDF generation!"
77
81
 
data/lib/errors.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Gkhtmltopdf
2
+ class Error < StandardError; end
3
+
4
+ class PathUnresolvedError < Error
5
+ def initialize(name)
6
+ message = "#{name} is not found. Please ensure #{name} is installed and either in your PATH or specify the path during initialization."
7
+ super(message)
8
+ end
9
+ end
10
+
11
+ class BrowserError < Error; end
12
+
13
+ class URLSchemeInvalid < Error
14
+ def initialize(url_scheme)
15
+ message = "Invalid URL scheme: (#{url_scheme})"
16
+ super(message)
17
+ end
18
+ end
19
+ end
@@ -6,35 +6,35 @@ require 'socket'
6
6
 
7
7
  module Gkhtmltopdf
8
8
  class Converter
9
- def initialize(geckodriver_path: nil, firefox_path: nil, port: nil)
9
+ def open(geckodriver_path: nil, firefox_path: nil, wait_time: nil, port: nil)
10
10
  @geckodriver_path = resolve_geckodriver_path!(geckodriver_path)
11
11
  @firefox_path = resolve_firefox_path!(firefox_path)
12
12
  @port = port || get_free_port
13
13
  @base_url = "http://127.0.0.1:#{@port}"
14
+ @pid = spawn("#{@geckodriver_path} --port #{@port}", out: File::NULL, err: File::NULL)
15
+ wait_time ||= 20
16
+ wait_for_gk(wait_time)
17
+ create_session!
14
18
  end
15
19
 
16
- def convert(url, output_path, print_options: {})
17
- validate_url_scheme!(url)
18
-
19
- pid = spawn("#{@geckodriver_path} --port #{@port}", out: File::NULL, err: File::NULL)
20
- wait_for_server
21
-
22
- session_id = nil
20
+ def close
21
+ delete_session! if @session_id
23
22
  begin
24
- session_id = create_session
25
- navigate(session_id, url)
26
-
27
- pdf_base64 = print_pdf(session_id, print_options)
28
- File.binwrite(output_path, Base64.decode64(pdf_base64))
29
- ensure
30
- delete_session(session_id) if session_id
31
- begin
32
- Process.kill('TERM', pid)
33
- Process.wait(pid)
34
- rescue Errno::ESRCH, Errno::ECHILD
35
- # nothing to do if the process is already terminated
23
+ unless @pid.nil?
24
+ Process.kill('TERM', @pid)
25
+ Process.wait(@pid)
36
26
  end
27
+ rescue Errno::ESRCH, Errno::ECHILD
28
+ # nothing to do if the process is already terminated
37
29
  end
30
+ nil
31
+ end
32
+
33
+ def save_pdf(url, output_path, print_options: {})
34
+ validate_url_scheme!(url)
35
+ navigate(url)
36
+ pdf_base64 = print_pdf(print_options)
37
+ File.binwrite(output_path, Base64.decode64(pdf_base64))
38
38
  end
39
39
 
40
40
  private
@@ -49,7 +49,7 @@ module Gkhtmltopdf
49
49
  def resolve_geckodriver_path!(provided_path)
50
50
  path = provided_path || find_default_geckodriver
51
51
  unless path
52
- raise Error, "Geckodriver is not found. Please ensure Geckodriver is installed and either in your PATH or specify the path during initialization."
52
+ raise PathUnresolvedError, 'Geckodriver'
53
53
  end
54
54
  path
55
55
  end
@@ -57,7 +57,7 @@ module Gkhtmltopdf
57
57
  def resolve_firefox_path!(provided_path)
58
58
  path = provided_path || find_default_firefox
59
59
  unless path
60
- raise Error, "Firefox is not found. Please ensure Firefox is installed and either in your PATH or specify the path during initialization."
60
+ raise PathUnresolvedError, 'Firefox'
61
61
  end
62
62
  path
63
63
  end
@@ -89,16 +89,16 @@ module Gkhtmltopdf
89
89
  common_paths.find { |path| File.executable?(path) && !File.directory?(path) }
90
90
  end
91
91
 
92
- def wait_for_server
93
- 10.times do
92
+ def wait_for_gk(num)
93
+ num.times do
94
94
  begin
95
95
  Net::HTTP.get(URI("#{@base_url}/status"))
96
96
  return
97
97
  rescue Errno::ECONNREFUSED
98
- sleep 0.2
98
+ sleep 0.1
99
99
  end
100
100
  end
101
- raise Error, "Failed to launch geckodriver (port #{@port})"
101
+ raise BrowserError, "Failed to launch geckodriver (port #{@port})"
102
102
  end
103
103
 
104
104
  def post(path, payload)
@@ -110,11 +110,11 @@ module Gkhtmltopdf
110
110
  begin
111
111
  JSON.parse(res.body)
112
112
  rescue JSON::ParserError
113
- raise Error, "Invalid geckodriver response (Status: #{res.code}): #{res.body}"
113
+ raise BrowserError, "Invalid json response (Status: #{res.code}): #{res.body}"
114
114
  end
115
115
  end
116
116
 
117
- def create_session
117
+ def create_session!
118
118
  firefox_options = { args: ["-headless"] }
119
119
  firefox_options[:binary] = @firefox_path if @firefox_path != 'firefox'
120
120
 
@@ -129,16 +129,16 @@ module Gkhtmltopdf
129
129
 
130
130
  response = post("/session", payload)
131
131
  value = response["value"]
132
- raise Error, "Failed to launch Firefox: #{value}" if value["error"]
132
+ raise BrowserError, "Failed to create session: #{value}" if value["error"]
133
133
 
134
- value["sessionId"]
134
+ @session_id = value["sessionId"]
135
135
  end
136
136
 
137
- def navigate(session_id, url)
138
- post("/session/#{session_id}/url", { url: url })
137
+ def navigate(url)
138
+ post("/session/#{@session_id}/url", { url: url })
139
139
  end
140
140
 
141
- def print_pdf(session_id, user_options)
141
+ def print_pdf(user_options)
142
142
  default_options = {
143
143
  background: false,
144
144
  shrinkToFit: true,
@@ -149,25 +149,26 @@ module Gkhtmltopdf
149
149
 
150
150
  payload = default_options.merge(user_options)
151
151
 
152
- response = post("/session/#{session_id}/print", payload)
152
+ response = post("/session/#{@session_id}/print", payload)
153
153
  value = response["value"]
154
- raise Error, "Failed to generate PDF: #{value}" if value["error"]
154
+ raise BrowserError, "Failed to generate PDF: #{value}" if value["error"]
155
155
 
156
156
  value
157
157
  end
158
158
 
159
- def delete_session(session_id)
160
- uri = URI("#{@base_url}/session/#{session_id}")
159
+ def delete_session!
160
+ uri = URI("#{@base_url}/session/#{@session_id}")
161
161
  req = Net::HTTP::Delete.new(uri)
162
162
  Net::HTTP.start(uri.hostname, uri.port) { |http| http.request(req) }
163
+ @session_id = nil
163
164
  end
164
165
 
165
166
  def validate_url_scheme!(url_string)
166
167
  parsed_url = URI.parse(url_string)
167
168
  allowed_schemes = ['http', 'https', 'file']
168
- raise Error, 'URL scheme is nil' if parsed_url.scheme.nil?
169
+ raise URLSchemeInvalid, nil if parsed_url.scheme.nil?
169
170
  unless allowed_schemes.include?(parsed_url.scheme)
170
- raise Error, "Invalid URL scheme: #{parsed_url.scheme}"
171
+ raise URLSchemeInvalid, parsed_url.scheme
171
172
  end
172
173
  end
173
174
  end
@@ -0,0 +1,19 @@
1
+ module Gkhtmltopdf
2
+ class DSL
3
+ def initialize
4
+ @converter = Converter.new
5
+ end
6
+
7
+ def open(options)
8
+ @converter.open(**options)
9
+ end
10
+
11
+ def close
12
+ @converter.close
13
+ end
14
+
15
+ def save_pdf(url, output_path, print_options: {})
16
+ @converter.save_pdf(url, output_path, print_options: print_options)
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gkhtmltopdf
4
- VERSION = "0.9.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/gkhtmltopdf.rb CHANGED
@@ -1,13 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "gkhtmltopdf/version"
4
- require_relative "gkhtmltopdf/converter"
3
+ require_relative 'gkhtmltopdf/version'
4
+ require_relative 'gkhtmltopdf/converter'
5
+ require_relative 'gkhtmltopdf/dsl'
6
+ require_relative 'errors'
5
7
 
6
8
  module Gkhtmltopdf
7
- class Error < StandardError; end
8
-
9
- def self.convert(url, output_path, geckodriver_path: nil, firefox_path: nil, port: nil, print_options: {})
10
- converter = Converter.new(geckodriver_path: geckodriver_path, firefox_path: firefox_path, port: port)
11
- converter.convert(url, output_path, print_options: print_options)
9
+ def self.convert(url, output_path, geckodriver_path: nil, firefox_path: nil, wait_time: nil, port: nil, print_options: {})
10
+ converter = DSL.new
11
+ converter.open(geckodriver_path: geckodriver_path, firefox_path: firefox_path, wait_time: wait_time, port: port)
12
+ converter.save_pdf(url, output_path, print_options: print_options)
13
+ ensure
14
+ converter.close
15
+ end
16
+
17
+ def self.open(geckodriver_path: nil, firefox_path: nil, wait_time: nil, port: nil, &block)
18
+ converter = DSL.new
19
+ converter.open(geckodriver_path: geckodriver_path, firefox_path: firefox_path, wait_time: wait_time, port: port)
20
+ yield converter
21
+ ensure
22
+ converter.close
12
23
  end
13
24
  end
@@ -1,14 +1,36 @@
1
1
  require 'spec_helper'
2
- require 'gkhtmltopdf'
3
2
 
4
3
  RSpec.describe Gkhtmltopdf::Converter do
5
- let(:converter) { Gkhtmltopdf::Converter.allocate }
4
+ let(:converter) { Gkhtmltopdf::Converter.new }
5
+ after { converter.close }
6
+ describe '#open' do
7
+ subject { converter.open }
8
+ it {
9
+ subject
10
+ expect(converter.instance_variable_get(:@geckodriver_path)).to be_a(String)
11
+ expect(converter.instance_variable_get(:@firefox_path)).to be_a(String)
12
+ expect(converter.instance_variable_get(:@port)).to be_a(Integer)
13
+ expect(converter.instance_variable_get(:@base_url)).to be_a(String)
14
+ expect(converter.instance_variable_get(:@pid)).to be_a(Integer)
15
+ expect(converter.instance_variable_get(:@session_id)).to be_a(String)
16
+ }
17
+ end
18
+ describe '#save_pdf' do
19
+ before { converter.open }
20
+ subject { converter.save_pdf(url, output_path) }
21
+ let(:url) { "file://#{file_fixture('test.html')}" }
22
+ let(:output_path) { File.join(Dir.mktmpdir, 'output.pdf') }
23
+ it {
24
+ expect { subject }.to change { Dir.glob(output_path).count }.from(0).to(1)
25
+ expect(File.binread(output_path)).to include('/FontName')
26
+ }
27
+ end
6
28
  describe '#resolve_geckodriver_path!' do
7
29
  subject { converter.send(:resolve_geckodriver_path!, nil) }
8
30
  context 'geckodriver is not available' do
9
31
  before { allow(File).to receive(:executable?).and_return(false) }
10
32
  it 'raises an error' do
11
- expect { subject }.to raise_error(Gkhtmltopdf::Error, /\AGeckodriver is not found./)
33
+ expect { subject }.to raise_error(Gkhtmltopdf::PathUnresolvedError, /\AGeckodriver is not found./)
12
34
  end
13
35
  end
14
36
  end
@@ -18,29 +40,45 @@ RSpec.describe Gkhtmltopdf::Converter do
18
40
  context 'firefox is not available' do
19
41
  before { allow(File).to receive(:executable?).and_return(false) }
20
42
  it 'raises an error' do
21
- expect { subject }.to raise_error(Gkhtmltopdf::Error, /\AFirefox is not found./)
43
+ expect { subject }.to raise_error(Gkhtmltopdf::PathUnresolvedError, /\AFirefox is not found./)
22
44
  end
23
45
  end
24
46
  end
25
- describe '#wait_for_server' do
26
- subject { converter.send(:wait_for_server) }
47
+
48
+ describe '#wait_for_gk' do
49
+ subject { converter.send(:wait_for_gk, 0) }
27
50
  context 'fail launch geckodriver' do
28
51
  before { allow(Net::HTTP).to receive(:get).and_raise(Errno::ECONNREFUSED, 'Dummy error') }
29
52
  it 'raises an error' do
30
- expect { subject }.to raise_error(Gkhtmltopdf::Error, /\AFailed to launch geckodriver \(port \)\Z/)
53
+ expect { subject }.to raise_error(Gkhtmltopdf::BrowserError, /\AFailed to launch geckodriver \(port \)\Z/)
31
54
  end
32
55
  end
33
56
  end
57
+
34
58
  describe '#post' do
35
- let(:converter) { Gkhtmltopdf::Converter.new }
36
59
  subject { converter.send(:post, '/dummy', {test: :value}) }
37
60
  context 'Invalid json response from geckodriver' do
38
61
  before {
62
+ converter.instance_variable_set(:@base_url, 'http://test')
39
63
  allow(Net::HTTP).to receive(:start).and_return(Struct.new(:code, :body).new('200', 'invalid_json: 0123'))
40
64
  }
41
65
  it 'raises an error' do
42
- expect { subject }.to raise_error(Gkhtmltopdf::Error, 'Invalid geckodriver response (Status: 200): invalid_json: 0123')
66
+ expect { subject }.to raise_error(Gkhtmltopdf::BrowserError, 'Invalid json response (Status: 200): invalid_json: 0123')
43
67
  end
44
68
  end
45
69
  end
70
+
71
+ describe '#validate_url_scheme!' do
72
+ subject { converter.send(:validate_url_scheme!, url_string) }
73
+ let(:url_string) { 'http://f6a.net' }
74
+ it { expect { subject }.not_to raise_error }
75
+ context 'scheme is nil' do
76
+ let(:url_string) { 'f6a.net' }
77
+ it { expect { subject }.to raise_error(Gkhtmltopdf::URLSchemeInvalid, 'Invalid URL scheme: ()') }
78
+ end
79
+ context 'invalid scheme' do
80
+ let(:url_string) { 'about://version' }
81
+ it { expect { subject }.to raise_error(Gkhtmltopdf::URLSchemeInvalid, 'Invalid URL scheme: (about)') }
82
+ end
83
+ end
46
84
  end
@@ -1,15 +1,11 @@
1
1
  require 'spec_helper'
2
- require 'gkhtmltopdf'
3
- require 'tmpdir'
4
- require 'base64'
5
2
 
6
3
  RSpec.describe Gkhtmltopdf do
7
4
  describe '.convert' do
8
5
  let(:url) { 'https://f6a.net/oss/' }
9
6
  let(:output) { File.join(Dir.mktmpdir, 'output.pdf') }
10
- let(:hash) { {} }
11
7
 
12
- subject { Gkhtmltopdf.convert(url, output, **hash) }
8
+ subject { Gkhtmltopdf.convert(url, output) }
13
9
 
14
10
  it 'successful conversion' do
15
11
  expect { subject }.not_to raise_error
@@ -18,7 +14,29 @@ RSpec.describe Gkhtmltopdf do
18
14
  context 'invalid URL' do
19
15
  let(:url) { 'ftp://example.com' }
20
16
  it 'raises an error' do
21
- expect { subject }.to raise_error(Gkhtmltopdf::Error, 'Invalid URL scheme: ftp')
17
+ expect { subject }.to raise_error(Gkhtmltopdf::URLSchemeInvalid, 'Invalid URL scheme: (ftp)')
18
+ end
19
+ end
20
+ end
21
+ describe '.open' do
22
+ let(:url) { 'https://f6a.net/oss/' }
23
+ let(:output_path) { Dir.mktmpdir }
24
+
25
+ subject do
26
+ Gkhtmltopdf.open do |gk|
27
+ (1..3).each { |n| gk.save_pdf("#{url}?test=#{n}", File.join(output_path, "#{n}.pdf")) }
28
+ end
29
+ end
30
+
31
+ it 'successful conversion' do
32
+ expect { subject }.to change { Dir.glob(File.join(output_path, '*.pdf')).count }.from(0).to(3)
33
+ expect { subject }.not_to raise_error
34
+ end
35
+
36
+ context 'invalid URL' do
37
+ let(:url) { 'ftp://example.com' }
38
+ it 'raises an error' do
39
+ expect { subject }.to raise_error(Gkhtmltopdf::URLSchemeInvalid, 'Invalid URL scheme: (ftp)')
22
40
  end
23
41
  end
24
42
  end
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,15 @@ SimpleCov.start do
10
10
  )
11
11
  end
12
12
 
13
+ require 'gkhtmltopdf'
14
+ require 'tmpdir'
15
+ require 'base64'
16
+ module FileFixtureHelper
17
+ def file_fixture(filename)
18
+ File.join(File.expand_path('fixtures', __dir__), filename)
19
+ end
20
+ end
21
+
13
22
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
14
23
  # The generated `.rspec` file contains `--require spec_helper` which will cause
15
24
  # this file to always be loaded, without a need to explicitly require it in any
@@ -104,4 +113,6 @@ RSpec.configure do |config|
104
113
  # # test failures related to randomization by passing the same `--seed` value
105
114
  # # as the one that triggered the failure.
106
115
  # Kernel.srand config.seed
116
+
117
+ config.include FileFixtureHelper
107
118
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gkhtmltopdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuki Sakane
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-03-12 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: base64
@@ -85,8 +84,10 @@ files:
85
84
  - Rakefile
86
85
  - TODO.md
87
86
  - exe/gkhtmltopdf
87
+ - lib/errors.rb
88
88
  - lib/gkhtmltopdf.rb
89
89
  - lib/gkhtmltopdf/converter.rb
90
+ - lib/gkhtmltopdf/dsl.rb
90
91
  - lib/gkhtmltopdf/version.rb
91
92
  - spec/fixtures/test.html
92
93
  - spec/gkhtmltopdf/converter_spec.rb
@@ -98,6 +99,7 @@ licenses:
98
99
  metadata:
99
100
  homepage_uri: https://f6a.net/oss/
100
101
  source_code_uri: https://github.com/fantasia-tech/gkhtmltopdf-rb
102
+ changelog_uri: https://github.com/fantasia-tech/gkhtmltopdf-rb/blob/main/CHANGELOG.md
101
103
  post_install_message: "=====================================================================\nGkhtmltopdf
102
104
  has been installed successfully. \U0001F389\n\n⚠️ Caution\nRequired: To run this
103
105
  gem, you need to have `firefox` and `geckodriver` installed and added to your PATH.\n\ncheck
@@ -119,8 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
121
  requirements:
120
122
  - Firefox
121
123
  - Geckodriver
122
- rubygems_version: 3.4.19
123
- signing_key:
124
+ rubygems_version: 4.0.8
124
125
  specification_version: 4
125
126
  summary: Gkhtmltopdf is mean Gecko HTML to PDF converter.
126
127
  test_files: []