sghtmltopdf 0.4.0-aarch64-linux → 0.5.1-aarch64-linux

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: a44aaf047687b49c64558bc29dbf047c625708e484e1f78771f8dcf2e1d594bc
4
- data.tar.gz: bf7dd74950f85a78df6bdc8c888319f890250bdd908acf4f3e90bcf9a72a63dc
3
+ metadata.gz: 35fd52de515952053bbd3f16b2b8bc8b06a1271afbfa70ef7968d8c71e3e0831
4
+ data.tar.gz: 5edee4a9f35c7997f572d74faf106046b16d8f92b0c47f8527a0d78c289e1b58
5
5
  SHA512:
6
- metadata.gz: 520dafa89a98b182ccb51784157ce8c19126c62ca2a22e80ebd065860a941ac4f17821572ab66be5938a427ef467499f7959df230c016621acb9924db5ee7e6f
7
- data.tar.gz: 54dd99c0f46f42d4399ca8717161ebdb63e5caf39716e7240c350a9a34430c918225f9d1717a04df429476e3f8bca1c92857d5505e3bd263305b78725bde34b1
6
+ metadata.gz: b215282c4ba6e4a67c40f04bf5ee4ae7d1aa67528e4e044b10ba359c237fb93114acea7884775acf86aaa36ffe2b89ff103522858b6cc719918eace286906534
7
+ data.tar.gz: 3c578b24199edb331c9d8bc117f75fc7c779e77da2929596d3c35d72fa771217d4c1b57a4859086624b4424ac49422293560ebdb99a364ee11e695a8b015eb15
data/README.md CHANGED
@@ -13,10 +13,10 @@ The engine runs inside your process through a native extension (magnus + rb-sys)
13
13
  gem "sghtmltopdf"
14
14
  ```
15
15
 
16
- Precompiled native gems are published for `x86_64-linux`, `aarch64-linux`, `x86_64-linux-musl`, `aarch64-linux-musl`, and `arm64-darwin`.
16
+ Precompiled native gems are published for `x86_64-linux`, `aarch64-linux`, `x86_64-linux-musl`, `aarch64-linux-musl`, `arm64-darwin`, and `x86_64-darwin`.
17
17
  There is no build step on those platforms.
18
18
 
19
- Elsewhere (Intel Mac, Windows) the gem cannot run in-process — the source gem does not carry the Rust core and will refuse to build with an explanatory message.
19
+ Elsewhere (Windows) the gem cannot run in-process — the source gem does not carry the Rust core and will refuse to build with an explanatory message.
20
20
  Point those environments at a separate `sghtmltopdf server` process instead; see [Delegating to a server](#delegating-to-a-server).
21
21
 
22
22
  Requires Ruby >= 3.2.
@@ -38,6 +38,31 @@ Sghtmltopdf.render_to_file(html, "invoice.pdf", page_size: "A4")
38
38
  Sghtmltopdf.render(html) { |bytes| io.write(bytes) }
39
39
  ```
40
40
 
41
+ ## Header and footer HTML
42
+
43
+ Pass markup directly without creating temporary files:
44
+
45
+ ```ruby
46
+ Sghtmltopdf.render(html,
47
+ header_html_content: '<div>Invoice [title]</div>',
48
+ footer_html_content: '<div>Page [page] of [topage]</div>')
49
+ ```
50
+
51
+ These options work with `render`, block output, `render_to_file`, global
52
+ configuration, and server delegation. The shared CLI options are
53
+ `--header-html-content` and `--footer-html-content`.
54
+
55
+ `header_html` and `footer_html` still accept file paths. Supplying both a path
56
+ and content for the same side raises `Sghtmltopdf::UsageError`, including when
57
+ one comes from global configuration. `nil` or `false` disables a configured
58
+ option; an empty string is an explicitly empty header or footer. Either HTML
59
+ form takes precedence over simple text options for that side.
60
+
61
+ Content uses the same placeholder expansion and margin clipping as file input.
62
+ Embedded `data:` images are supported; external resources remain blocked.
63
+ With server delegation, markup travels in URL query parameters, so URL length
64
+ limits may apply and request logs may contain the markup.
65
+
41
66
  ## Rails
42
67
 
43
68
  Adding the gem is enough; the Railtie wires everything up, and nothing is loaded when Rails is absent.
Binary file
Binary file
Binary file
Binary file
@@ -1,24 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sghtmltopdf
4
- # グローバルな既定オプション。
4
+ # The global default options.
5
5
  #
6
6
  # Sghtmltopdf.configure do |c|
7
7
  # c.page_size = "A4"
8
8
  # c.gothic_font = "/path/to/NotoSansJP-Regular.ttf"
9
9
  # end
10
10
  #
11
- # ここで設定した値は`render`/`render_to_file`の引数で上書きできる
12
- # (マージ順はグローバル 呼び出し時)
11
+ # A value set here can be overridden by an argument to `render`/`render_to_file`
12
+ # (merged in the order global, then call-time).
13
13
  #
14
- # キー名の妥当性は検査しない。オプション定義はRust側(`cli/options.rs`)の
15
- # 1箇所に集約する方針のため、未知のキーはレンダリング時にclapが`UsageError`をraiseする。
14
+ # Key names are not validated. The option definitions live in one place on the Rust side
15
+ # (`cli/options.rs`), so an unknown key makes clap raise a `UsageError` at render time.
16
16
  class Configuration
17
17
  def initialize(options = {})
18
18
  @options = {}
19
- # 明示的に設定した値(@options)と、Railtieなどが流し込んだ既定値
20
- # (@defaults)は分けて持つ。読み出しは常に@optionsが勝つので、
21
- # イニシャライザの実行順に依存しない。
19
+ # Values set explicitly (@options) are kept separately from the defaults injected by
20
+ # the Railtie and others (@defaults). Reads always prefer @options, so nothing depends
21
+ # on the order the initialisers run in.
22
22
  @defaults = {}
23
23
  options.each { |key, value| self[key] = value }
24
24
  end
@@ -32,30 +32,30 @@ module Sghtmltopdf
32
32
  @options[Options.canonical_key(key)] = value
33
33
  end
34
34
 
35
- # @param with_defaults [Boolean] 流し込まれた既定値を含めるか。
36
- # HTTPサーバへ委譲するときは`false`にする。Rails向けの既定値
37
- # (`base_url`・`allow`)はローカルのファイル解決のためのもので、
38
- # サーバモードではリクエストから指定できないキーだから
35
+ # @param with_defaults [Boolean] whether to include the injected defaults.
36
+ # Set it to `false` when delegating to the HTTP server: the Rails-oriented defaults
37
+ # (`base_url` and `allow`) exist for local file resolution and are keys server mode
38
+ # cannot take from a request
39
39
  def to_h(with_defaults: true)
40
40
  with_defaults ? @defaults.merge(@options) : @options.dup
41
41
  end
42
42
 
43
- # 既定値を流し込む。Railtie Rails向けの既定値を入れるのに使う。
44
- # 明示的に設定された値より弱い(順序に関係なく`[]=`が勝つ)
43
+ # Inject the defaults. Used by the Railtie to set the Rails-oriented defaults.
44
+ # They are weaker than explicitly set values (`[]=` wins regardless of order).
45
45
  def apply_defaults(defaults)
46
46
  defaults.each { |key, value| @defaults[Options.canonical_key(key)] = value }
47
47
  self
48
48
  end
49
49
 
50
- # `c.page_size = "A4"`と`c.page_size`を受ける。
50
+ # Accepts both `c.page_size = "A4"` and `c.page_size`.
51
51
  def method_missing(name, *args)
52
52
  key = name.to_s
53
53
  if key.end_with?("=")
54
- raise ArgumentError, "#{name}は引数1つを取ります" unless args.size == 1
54
+ raise ArgumentError, "#{name} takes one argument" unless args.size == 1
55
55
 
56
56
  self[key.chomp("=")] = args.first
57
57
  else
58
- raise ArgumentError, "#{name}は引数を取りません" unless args.empty?
58
+ raise ArgumentError, "#{name} takes no arguments" unless args.empty?
59
59
 
60
60
  self[key]
61
61
  end
@@ -3,44 +3,42 @@
3
3
  require "uri"
4
4
 
5
5
  module Sghtmltopdf
6
- # オプションハッシュを変換する。
6
+ # Converts an options hash into:
7
7
  #
8
- # * ネイティブ拡張へ渡すCLIの引数列(argv) [.to_argv]
9
- # * HTTPサーバモードへ渡すクエリ文字列 … [.to_query]
8
+ # * the CLI argument list (argv) passed to the native extension ... [.to_argv]
9
+ # * the query string passed to HTTP server mode ... [.to_query]
10
10
  module Options
11
- # 入力は常に標準入力を表す`-`を置く(実際のバイト列はFFIで直接渡すため
12
- # 読まれない)。出力先はRust側のSinkが決めるので、ここもダミーの`-`。
13
- # `-`入力のときCLIは`--output`を必須にするため、省略はできない。
14
- ARGV_PREFIX = ["sghtmltopdf", "-", "--output", "-"].freeze
15
11
 
16
- # Ruby側だけで解釈するキー。変換オプションではないので、argvにも
17
- # クエリにも出さない。
12
+ # The keys interpreted on the Ruby side alone. They are not conversion options, so they
13
+ # appear in neither the argv nor the query.
18
14
  TRANSPORT_KEYS = %i[server_url server_open_timeout server_read_timeout chunk_size].freeze
19
15
 
20
- # 別名のキー(値は正規名)CLIは`--allow`を`--allow-path`の別名として
21
- # 受けるが、Ruby側は2つのキーのまま持ち回ってはいけない。既定が一方の
22
- # キー、呼び出し時の指定がもう一方のキーだと、ハッシュのマージでは
23
- # 上書きにならず両方がargvへ出てしまう(同じフラグの繰り返しは
24
- # 「置き換え」ではなく「合併」の意味になる)
16
+ # Alias keys (values are the canonical names). The CLI accepts `--allow` as an
17
+ # alias of `--allow-path`, but the Ruby side must not carry both keys around.
18
+ # If the defaults use one key and the call uses the other, a hash merge does
19
+ # not override: both end up in argv (repeating the same flag means "union",
20
+ # not "replace").
25
21
  ALIAS_KEYS = {allow: :allow_path}.freeze
26
22
 
27
23
  module_function
28
24
 
29
- # 別名のキーを正規名へ寄せる。
25
+ # Map an alias key to its canonical name.
30
26
  def canonical_key(key)
31
27
  key = key.to_sym
32
28
  ALIAS_KEYS.fetch(key, key)
33
29
  end
34
30
 
35
- # ハッシュのキーをまとめて正規化する。
31
+ # Normalize all keys of a hash.
36
32
  def canonicalize(options)
37
33
  options.to_h { |key, value| [canonical_key(key), value] }
38
34
  end
39
35
 
40
- # @param options [Hash] Rubyのオプションハッシュ
41
- # @return [Array<String>] clapへ渡す引数列
36
+ # @param options [Hash] the Ruby options hash
37
+ # @return [Array<String>] the conversion options passed to the core's `Converter`.
38
+ # The HTML and the destination travel over FFI, so there is no program name, input
39
+ # path or `--output` here.
42
40
  def to_argv(options)
43
- argv = ARGV_PREFIX.dup
41
+ argv = []
44
42
  each_pair(options) do |name, value|
45
43
  argv.push("--#{name}")
46
44
  argv.push(value) unless value.nil?
@@ -48,18 +46,18 @@ module Sghtmltopdf
48
46
  argv
49
47
  end
50
48
 
51
- # @param options [Hash] Rubyのオプションハッシュ
52
- # @return [String] `POST /pdf`のクエリ文字列(先頭に`?`は付けない)
49
+ # @param options [Hash] the Ruby options hash
50
+ # @return [String] the query string for `POST /pdf` (with no leading `?`)
53
51
  def to_query(options)
54
52
  parts = []
55
53
  each_pair(options) do |name, value|
56
- # 値なしのフラグはキーだけを置く(サーバは値なし=真として扱う)
54
+ # A valueless flag becomes just the key (the server treats no value as true).
57
55
  parts << (value.nil? ? escape(name) : "#{escape(name)}=#{escape(value)}")
58
56
  end
59
57
  parts.join("&")
60
58
  end
61
59
 
62
- # 1つのキーと値をargvの断片へ変換する。
60
+ # Convert one key and value into an argv fragment.
63
61
  #
64
62
  # page_size: "A4" → ["--page-size", "A4"]
65
63
  # grayscale: true → ["--grayscale"]
@@ -69,8 +67,8 @@ module Sghtmltopdf
69
67
  pairs_for(key, value).flat_map { |name, arg| arg.nil? ? ["--#{name}"] : ["--#{name}", arg] }
70
68
  end
71
69
 
72
- # 1つのキーと値を「フラグ名と値」のペアの列にする。値が`nil`のペアは
73
- # 値を取らないフラグ(`--toc`など)
70
+ # Turn one key and value into a list of "flag name and value" pairs. A pair whose value is
71
+ # `nil` is a flag taking no value (`--toc` and the like).
74
72
  def pairs_for(key, value)
75
73
  name = flag_name(key)
76
74
  return font_pairs(value) if name == "font"
@@ -78,26 +76,25 @@ module Sghtmltopdf
78
76
  case value
79
77
  when nil, false then []
80
78
  when true then [[name, nil]]
81
- # 配列は同じオプションの繰り返し。要素ごとに同じ規則を適用する。
79
+ # An array means the same option repeated. The same rule applies to each element.
82
80
  when Array then value.flat_map { |element| pairs_for(key, element) }
83
81
  when Hash
84
- # wicked_pdfの`margin: {top: 10}`のような入れ子は受けない。対応する
85
- # CLIフラグが無く、機械的に平坦化すると綴り違いのキーまで黙って
86
- # 通ってしまう。移行時は移行ガイドの対応表を見て書き換えてもらう。
87
- # なお単位を省いた数値の解釈はwicked_pdfと同じくmm(`cli/units.rs`)
82
+ # Nesting such as wicked_pdf's `margin: {top: 10}` is not accepted. There is no
83
+ # corresponding CLI flag, and flattening it mechanically would let even misspelled
84
+ # keys through silently. When migrating, use the correspondence table in the
85
+ # migration guide to rewrite them. A unitless number is read as mm, as in wicked_pdf (`cli/units.rs`).
88
86
  example = value.keys.first
89
87
  raise ArgumentError,
90
- "#{key}にHashは渡せません(pathindexを取るのは:fontだけです)" \
91
- "入れ子のオプションは平坦なキーで指定してください" \
92
- "#{": #{key}_#{example}: \"…\"" if example}"
88
+ "a Hash cannot be passed for #{key} (only :font takes a path and an index). " \
89
+ "Give nested options as flat keys" \
90
+ "#{": for example #{key}_#{example}: \"...\"" if example}"
93
91
  else [[name, value.to_s]]
94
92
  end
95
93
  end
96
94
 
97
- # `--font`と`--font-index`は出現順で対応付けられる(CLI
98
- # `ArgMatches#indices_of`で「`--font-index`より手前にある最後の`--font`」
99
- # へ結び付ける)。そのため、フェイス番号は
100
- # 必ず対応する`--font`の直後へ置く。
95
+ # `--font` and `--font-index` are paired by their order of appearance (the CLI ties each
96
+ # `--font-index` to "the last `--font` before it" via `ArgMatches#indices_of`).
97
+ # So a face index always goes immediately after its own `--font`.
101
98
  #
102
99
  # font: "a.ttf" → ["--font", "a.ttf"]
103
100
  # font: {path: "a.ttc", index: 1} → ["--font", "a.ttc", "--font-index", "1"]
@@ -113,7 +110,7 @@ module Sghtmltopdf
113
110
  when Array then value.flat_map { |element| font_pairs(element) }
114
111
  when Hash
115
112
  path = value[:path] || value["path"]
116
- raise ArgumentError, "fontHashにはpathが必要です: #{value.inspect}" if path.nil?
113
+ raise ArgumentError, "a font Hash needs a path: #{value.inspect}" if path.nil?
117
114
 
118
115
  index = value[:index] || value["index"]
119
116
  pairs = [["font", path.to_s]]
@@ -123,12 +120,12 @@ module Sghtmltopdf
123
120
  end
124
121
  end
125
122
 
126
- # `:page_size` `page-size`。
123
+ # `:page_size` becomes `page-size`.
127
124
  def flag_name(key)
128
125
  key.to_s.tr("_", "-")
129
126
  end
130
127
 
131
- # 変換オプションだけを、渡された順にペアとして列挙する。
128
+ # Enumerate only the conversion options, as pairs, in the order they were given.
132
129
  def each_pair(options, &block)
133
130
  options.each do |key, value|
134
131
  key = canonical_key(key)
@@ -28,12 +28,12 @@ module Sghtmltopdf
28
28
  defaults
29
29
  end
30
30
 
31
- # 読むのはinitializerの中ではなく`after_initialize`。パイプラインが
32
- # `config.assets.paths`を埋めるのは自分のinitializer(Propshaftなら
33
- # `propshaft.append_assets_path`)で、そちらの方が後に走るため。
31
+ # Read in `after_initialize`, not inside the initializer. The pipeline fills
32
+ # `config.assets.paths` in its own initializer (for Propshaft,
33
+ # `propshaft.append_assets_path`), and that one runs later.
34
34
  #
35
- # `config/initializers`より後になるが、`apply_defaults`は明示的に設定した
36
- # 値より常に弱いので、ユーザーの設定を踏むことはない。
35
+ # This runs after `config/initializers`, but `apply_defaults` is always
36
+ # weaker than explicitly set values, so it never overrides user settings.
37
37
  initializer "sghtmltopdf.defaults" do |app|
38
38
  app.config.after_initialize do
39
39
  Sghtmltopdf.config.apply_defaults(Sghtmltopdf::Railtie.default_options(app))
@@ -1,25 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sghtmltopdf
4
- # `render pdf: "invoice"`のオプションを、
4
+ # Sorts the options of `render pdf: "invoice"` into three groups:
5
5
  #
6
- # * Railsのビュー描画(`render_to_string`)へ渡すもの
7
- # * レスポンスの組み立て(`send_data`)へ渡すもの
8
- # * PDF変換(`Sghtmltopdf.render`)へ渡すもの
6
+ # * those passed to Rails view rendering (`render_to_string`)
7
+ # * those passed to building the response (`send_data`)
8
+ # * those passed to PDF conversion (`Sghtmltopdf.render`)
9
9
  #
10
- # の3つに振り分ける。
11
- # Railsに依存しないpure Rubyのクラスなので、Rails無しでも単体テストできる。
10
+ #
11
+ # It is a pure Ruby class with no dependency on Rails, so it can be unit tested without Rails.
12
12
  class Renderer
13
- # `render_to_string`へそのまま渡すキー。
13
+ # The keys passed straight to `render_to_string`.
14
14
  RAILS_RENDER_KEYS = %i[
15
15
  action assigns body collection file formats handlers html inline layout
16
16
  locals object partial plain prefixes template variants
17
17
  ].freeze
18
18
 
19
- # レスポンスの組み立てに使うキー(`send_data`へ渡す)
19
+ # The keys used to build the response (passed to `send_data`).
20
20
  RESPONSE_KEYS = %i[disposition filename status].freeze
21
21
 
22
- # レンダラ自身が解釈するキー(PDFにせずHTMLのまま返すデバッグ用)
22
+ # The keys the renderer itself interprets (for debugging: return the HTML rather than a PDF).
23
23
  RENDERER_KEYS = %i[show_as_html].freeze
24
24
 
25
25
  PDF_CONTENT_TYPE = "application/pdf"
@@ -27,17 +27,17 @@ module Sghtmltopdf
27
27
 
28
28
  attr_reader :name, :options
29
29
 
30
- # @param name [String, Symbol, nil] `pdf:`に渡された値(ファイル名の素)
31
- # @param options [Hash] `render`に渡されたその他のオプション
32
- # @param default_name [String, nil] `name`が空のときのファイル名
33
- # (コントローラの`action_name`を想定)
30
+ # @param name [String, Symbol, nil] the value given to `pdf:` (the basis of the file name)
31
+ # @param options [Hash] the other options given to `render`
32
+ # @param default_name [String, nil] the file name when `name` is empty
33
+ # (the controller's `action_name` is expected)
34
34
  def initialize(name, options = {}, default_name: nil)
35
35
  @name = blank?(name) ? (default_name || "document").to_s : name.to_s
36
36
  @options = options.to_h { |key, value| [key.to_sym, value] }
37
37
  end
38
38
 
39
- # `ActionController::Renderers.add(:pdf)`でレンダラを登録する。
40
- # RailtieAction Controller読み込みフック(`on_load`)から呼ぶ。
39
+ # Register the renderer with `ActionController::Renderers.add(:pdf)`.
40
+ # Called from the Railtie's Action Controller load hook (`on_load`).
41
41
  def self.register!
42
42
  ::ActionController::Renderers.add(:pdf) do |name, options|
43
43
  renderer = ::Sghtmltopdf::Renderer.new(name, options, default_name: action_name)
@@ -46,18 +46,18 @@ module Sghtmltopdf
46
46
  end
47
47
  end
48
48
 
49
- # ビューの描画に使うオプション。
49
+ # The options used to render the view.
50
50
  def render_options
51
51
  options.select { |key, _| RAILS_RENDER_KEYS.include?(key) }
52
52
  end
53
53
 
54
- # PDF変換に使うオプション。
54
+ # The options used for the PDF conversion.
55
55
  def convert_options
56
56
  known = RAILS_RENDER_KEYS + RESPONSE_KEYS + RENDERER_KEYS
57
57
  options.reject { |key, _| known.include?(key) }
58
58
  end
59
59
 
60
- # 描画したHTMLをレスポンスの本文へ変換する。
60
+ # Turn the rendered HTML into the response body.
61
61
  def body_for(html)
62
62
  show_as_html? ? html : Sghtmltopdf.render(html, **convert_options)
63
63
  end
@@ -73,19 +73,19 @@ module Sghtmltopdf
73
73
  show_as_html? ? HTML_CONTENT_TYPE : PDF_CONTENT_TYPE
74
74
  end
75
75
 
76
- # `filename: "x.pdf"` > `pdf: "x"` の順。拡張子は二重に付けない。
76
+ # `filename: "x.pdf"` wins over `pdf: "x"`. The extension is not doubled up.
77
77
  def filename
78
78
  base = blank?(options[:filename]) ? name : options[:filename].to_s
79
79
  base.downcase.end_with?(".pdf") ? base : "#{base}.pdf"
80
80
  end
81
81
 
82
- # wicked_pdfと同じく既定は`inline`(ブラウザ内で開く)
82
+ # The default is `inline` (opened in the browser), as in wicked_pdf.
83
83
  def disposition
84
84
  blank?(options[:disposition]) ? "inline" : options[:disposition].to_s
85
85
  end
86
86
 
87
- # wicked_pdfの`show_as_html`相当。PDFにせずHTMLをそのまま返すので、
88
- # ブラウザの開発者ツールでレイアウトを確認できる。
87
+ # The equivalent of wicked_pdf's `show_as_html`. It returns the HTML rather than a PDF, so
88
+ # the layout can be inspected in the browser's developer tools.
89
89
  def show_as_html?
90
90
  value = options[:show_as_html]
91
91
  !(value.nil? || value == false || value == "false")
@@ -6,7 +6,7 @@ require "uri"
6
6
  module Sghtmltopdf
7
7
  class ServerError < Error; end
8
8
 
9
- # HTTPサーバモード(`sghtmltopdf server`)へ変換を委譲するクライアント。
9
+ # The client delegating conversion to HTTP server mode (`sghtmltopdf server`).
10
10
  #
11
11
  # Sghtmltopdf.configure { |c| c.server_url = "http://pdf.internal:8080" }
12
12
  # pdf = Sghtmltopdf.render(html, page_size: "A4")
@@ -14,29 +14,28 @@ module Sghtmltopdf
14
14
  DEFAULT_OPEN_TIMEOUT = 5
15
15
  DEFAULT_READ_TIMEOUT = 120
16
16
 
17
- # 一度に読むチャンクの目安。`?stream=1`のときはこの単位でブロックへ渡る。
17
+ # The rough size of each read. With `?stream=1` this is the unit handed to the block.
18
18
  CHUNK_SIZE = 64 * 1024
19
19
 
20
20
  attr_reader :uri, :open_timeout, :read_timeout
21
21
 
22
- # @param url [String] サーバのベースURL(`http://host:port`)
22
+ # @param url [String] the server's base URL (`http://host:port`)
23
23
  def initialize(url, open_timeout: nil, read_timeout: nil)
24
24
  @uri = parse(url)
25
25
  @open_timeout = (open_timeout || DEFAULT_OPEN_TIMEOUT).to_f
26
26
  @read_timeout = (read_timeout || DEFAULT_READ_TIMEOUT).to_f
27
27
  end
28
28
 
29
- # HTMLPDFへ変換する。
29
+ # Convert HTML to PDF.
30
30
  #
31
- # ブロックを渡すと`?stream=1`(chunked transfer encoding)を使い、
32
- # サーバがページを確定したそばからチャンクを渡す。ブロックが無ければ
33
- # PDF全体をStringで返す。
31
+ # Given a block it uses `?stream=1` (chunked transfer encoding) and hands over chunks as
32
+ # the server settles each page. With no block it returns the whole PDF as a String.
34
33
  def render(html, options, &block)
35
34
  request = build_request(html, options, stream: !block.nil?)
36
35
  pdf = nil
37
36
  start do |http|
38
- # `request`はブロック付きだとレスポンスオブジェクトを返すので、
39
- # 結果は外の変数で受ける。
37
+ # With a block, `request` returns the response object, so the result is received in an
38
+ # outer variable.
40
39
  http.request(request) do |response|
41
40
  ensure_success!(response)
42
41
  if block
@@ -49,9 +48,9 @@ module Sghtmltopdf
49
48
  pdf
50
49
  end
51
50
 
52
- # 変換結果を`path`へ書き出す。途中で失敗しても壊れたPDFを残さないよう、
53
- # 一時ファイルへ書いてからrenameする(ネイティブ拡張の`FileSink`と同じ
54
- # 挙動に揃えている)
51
+ # Write the conversion result to `path`. To leave no broken PDF on a failure part-way
52
+ # through, it writes to a temporary file and renames (matching the behaviour of the
53
+ # native extension's `FileSink`).
55
54
  def render_to_file(html, options, path)
56
55
  tmp = "#{path}.#{Process.pid}.tmp"
57
56
  begin
@@ -60,7 +59,7 @@ module Sghtmltopdf
60
59
  end
61
60
  rescue SystemCallError => e
62
61
  File.unlink(tmp) if File.exist?(tmp)
63
- raise InputError, "#{path}への書き出しに失敗しました: #{e.message}"
62
+ raise InputError, "failed to write to #{path}: #{e.message}"
64
63
  rescue StandardError
65
64
  File.unlink(tmp) if File.exist?(tmp)
66
65
  raise
@@ -74,7 +73,7 @@ module Sghtmltopdf
74
73
  def parse(url)
75
74
  uri = URI.parse(url.to_s)
76
75
  unless uri.is_a?(URI::HTTP) && uri.host
77
- raise ArgumentError, "server_urlにはhttp(s)URLを指定してください: #{url.inspect}"
76
+ raise ArgumentError, "server_url must be an http(s) URL: #{url.inspect}"
78
77
  end
79
78
 
80
79
  uri
@@ -102,12 +101,12 @@ module Sghtmltopdf
102
101
  &block
103
102
  )
104
103
  rescue Net::OpenTimeout, Net::ReadTimeout => e
105
- raise ServerError, "#{base}への接続がタイムアウトしました: #{e.class}"
104
+ raise ServerError, "the connection to #{base} timed out: #{e.class}"
106
105
  rescue SocketError, SystemCallError, IOError, OpenSSL::SSL::SSLError => e
107
- raise ServerError, "#{base}への接続に失敗しました: #{e.message}"
106
+ raise ServerError, "the connection to #{base} failed: #{e.message}"
108
107
  end
109
108
 
110
- # エラー応答の本文は`text/plain`の日本語メッセージ(CLIと同じ文言)
109
+ # An error response's body is a `text/plain` message (the same wording as the CLI).
111
110
  def ensure_success!(response)
112
111
  return if response.is_a?(Net::HTTPOK)
113
112
 
@@ -120,8 +119,8 @@ module Sghtmltopdf
120
119
  when 400 then UsageError
121
120
  when 413 then InputError
122
121
  when 500 then RenderError
123
- # 404/405はパスやメソッドの間違い=相手がsghtmltopdfのサーバでない
124
- # 可能性が高い。503/504はキュー溢れ・キュー待ちのタイムアウト。
122
+ # A 404 or 405 means a wrong path or method, most likely because the other end is not
123
+ # an sghtmltopdf server. A 503 or 504 means the queue overflowed or the queue wait timed out.
125
124
  else ServerError
126
125
  end
127
126
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sghtmltopdf
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.1"
5
5
  end
data/lib/sghtmltopdf.rb CHANGED
@@ -5,9 +5,9 @@ require_relative "sghtmltopdf/options"
5
5
  require_relative "sghtmltopdf/configuration"
6
6
  require_relative "sghtmltopdf/renderer"
7
7
 
8
- # precompiled gemRubyのマイナーバージョンごとのディレクトリへ`.so`を置く
9
- # (rake-compilerのクロスビルドの慣習)。開発中の`rake compile`は
10
- # `lib/sghtmltopdf/sghtmltopdf.so`に置くので、両方を試す。
8
+ # A precompiled gem puts the `.so` in a directory per Ruby minor version
9
+ # (rake-compiler's cross-build convention). During development `rake compile` puts it in
10
+ # `lib/sghtmltopdf/sghtmltopdf.so`, so both are tried.
11
11
  begin
12
12
  RUBY_VERSION =~ /(\d+\.\d+)/
13
13
  require "sghtmltopdf/#{Regexp.last_match(1)}/sghtmltopdf"
@@ -15,37 +15,36 @@ rescue LoadError
15
15
  require "sghtmltopdf/sghtmltopdf"
16
16
  end
17
17
 
18
- # `Error`(ネイティブ拡張が定義)を継承するため、拡張の読み込みより後に書く。
18
+ # It inherits `Error` (defined by the native extension), so it comes after the extension is loaded.
19
19
  require_relative "sghtmltopdf/server_client"
20
20
 
21
21
  module Sghtmltopdf
22
- # ブロック付き`render`で1回に渡すバイト数の目安(ローカル変換のみ)
23
- # ページ確定ごとにブロックを呼ぶとGVLの取り直しが増えるため、ここまで
24
- # 溜めてから渡す。
22
+ # The rough number of bytes handed over per call to a block-taking `render` (local conversion only).
23
+ # Calling the block on every settled page would mean reacquiring the GVL too often, so this
24
+ # much is accumulated first.
25
25
  DEFAULT_CHUNK_SIZE = 64 * 1024
26
26
 
27
27
  class << self
28
- # HTMLを変換してPDFのバイト列(ASCII-8BITString)を返す。
28
+ # Convert HTML and return the PDF bytes (an ASCII-8BIT String).
29
29
  #
30
- # ブロックを渡すと、PDF全体を組み立ててから返す代わりにチャンクごとに
31
- # ブロックを呼ぶ(返り値はnil)Rackの`response.stream`へ流したり、S3の
32
- # マルチパートアップロードへ繋いだりするための口(エンジン側は出力先(sink)
33
- # を意識しない設計に対応する)。
30
+ # Given a block, it calls the block per chunk rather than assembling the whole PDF first
31
+ # (returning nil). It is the hook for streaming into Rack's `response.stream` or into an
32
+ # S3 multipart upload (matching the engine's design, which is unaware of the output sink).
34
33
  #
35
34
  # Sghtmltopdf.render(html) { |bytes| response.stream.write(bytes) }
36
35
  #
37
- # ローカル・サーバ委譲のどちらでも、PDF全体が組み上がるのを待たずに
38
- # 書き出せる(ローカルは確定したページから順に、サーバは`?stream=1`の
39
- # chunked transfer encodingをそのまま渡す)
36
+ # Both locally and when delegating to a server, it can be written out without waiting for
37
+ # the whole PDF to be assembled (locally page by page as they settle; from a server, the
38
+ # `?stream=1` chunked transfer encoding passed straight through).
40
39
  #
41
- # ただし逐次になるのはPDFの書き出しだけで、HTMLのパースとレイアウトは
42
- # 文書全体に対して先に行う。最初のチャンクが届くのは変換の終盤で、
43
- # ピークメモリもブロック無しの場合と変わらない。HTMLを読みながら
44
- # ページを確定させたい場合は`streaming: true`と併せて使う
45
- # (制約と引き換えにメモリが大きく減る)
40
+ # Only the PDF writing is incremental, though: HTML parsing and layout still happen for
41
+ # the whole document first. The first chunk arrives late in the conversion, and the peak
42
+ # memory is no different from the block-less case. To settle pages while the HTML is being
43
+ # read, use it together with `streaming: true`
44
+ # (which trades constraints for a large reduction in memory).
46
45
  #
47
- # 1回に渡すバイト数の目安は`chunk_size:`で変えられる(既定64KiB
48
- # ローカル変換のみ。小さくするとGVLの取り直しが増える)
46
+ # The rough bytes per call can be changed with `chunk_size:` (64KiB by default; local
47
+ # conversion only; a smaller value means reacquiring the GVL more often).
49
48
  def render(html, **options, &block)
50
49
  options = Options.canonicalize(options)
51
50
  client = server_client(options)
@@ -56,10 +55,10 @@ module Sghtmltopdf
56
55
  nil
57
56
  end
58
57
 
59
- # HTMLを変換して`path`へ書き出す。
58
+ # Convert HTML and write it to `path`.
60
59
  #
61
- # 一時ファイルへ書いて成功時だけrenameするため、途中で失敗しても
62
- # 壊れたPDFが出力先に残らない(サーバへ委譲する場合も同じ)
60
+ # It writes to a temporary file and renames only on success, so a failure part-way through
61
+ # leaves no broken PDF at the destination (the same when delegating to a server).
63
62
  def render_to_file(html, path, **options)
64
63
  options = Options.canonicalize(options)
65
64
  client = server_client(options)
@@ -69,7 +68,7 @@ module Sghtmltopdf
69
68
  nil
70
69
  end
71
70
 
72
- # グローバルな既定オプション。
71
+ # The global default options.
73
72
  def configure
74
73
  yield config
75
74
  config
@@ -79,19 +78,19 @@ module Sghtmltopdf
79
78
  @config ||= Configuration.new
80
79
  end
81
80
 
82
- # 主にテスト用。設定を空に戻す。
81
+ # Mainly for tests. Resets the configuration to empty.
83
82
  def reset_config!
84
83
  @config = Configuration.new
85
84
  end
86
85
 
87
86
  private
88
87
 
89
- # グローバル設定 呼び出し時オプションの順にマージしてargvにする。
88
+ # Merge in the order global settings, then call-time options, and turn that into argv.
90
89
  def argv_for(options)
91
90
  Options.to_argv(config.to_h.merge(options))
92
91
  end
93
92
 
94
- # `server_url`があればサーバへ委譲する。タイムアウトも同じ順でマージする。
93
+ # With a `server_url` it delegates to the server. The timeout merges in the same order.
95
94
  def server_client(options)
96
95
  merged = config.to_h.merge(options)
97
96
  url = merged[:server_url]
@@ -104,16 +103,16 @@ module Sghtmltopdf
104
103
  )
105
104
  end
106
105
 
107
- # ブロックへ1回に渡すバイト数の目安(ローカル変換のみ)
106
+ # The rough bytes handed to the block per call (local conversion only).
108
107
  def chunk_size(options)
109
108
  value = config.to_h.merge(options)[:chunk_size]
110
109
  value.nil? ? DEFAULT_CHUNK_SIZE : Integer(value)
111
110
  end
112
111
 
113
- # サーバへ渡すオプション。流し込まれた既定値は外す
114
- # (Rails向けの`base_url`・`allow`はローカルのファイル解決のための
115
- # 既定値で、サーバモードではリクエストから指定できず400になる。
116
- # 明示的に設定した値はそのまま送り、可否はサーバに判断させる)
112
+ # The options passed to the server. The injected defaults are removed
113
+ # (the Rails-oriented `base_url` and `allow` are defaults for local file resolution, and
114
+ # server mode cannot take them from a request, giving a 400.
115
+ # An explicitly set value is sent as-is and the server decides whether to accept it).
117
116
  def server_options(options)
118
117
  config.to_h(with_defaults: false).merge(options)
119
118
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sghtmltopdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.1
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - yo_waka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-05 00:00:00.000000000 Z
11
+ date: 2026-09-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Ruby binding for sghtmltopdf, a successor to wkhtmltopdf: an HTML-to-PDF