reports_web 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 +7 -0
- data/LICENSE.md +22 -0
- data/README.md +93 -0
- data/lib/pao_reports_web/engine.rb +80 -0
- data/lib/pao_reports_web/print_data.rb +131 -0
- data/lib/pao_reports_web/version.rb +4 -0
- data/lib/pao_reports_web.rb +2 -0
- data/lib/reports_web.rb +6 -0
- metadata +59 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: cce3c314a64cb98332c0bd5f20ee01090efcb661fec493cd956200fec8ca554e
|
|
4
|
+
data.tar.gz: 56a79b610b2312d3b830276daca73404ccec9b6c776f40c9db953fe9dd6cc875
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 17ca2e2979d7c46b2ae716a4fd048113bbf5d307098fd7304120b1c892a408052b9d7f636c96015d5b9a784090d28c29ff6434611cb79a64e7ec14fb92ad7d63
|
|
7
|
+
data.tar.gz: a7c0cf4f546619cdb3f19c2e2a56c82fc93ba197e3e3c19fce540965cef75576eb45363db74fa2a1e92ddd86c797a815ae33e7f10a3de436c4651a9fd4690b63
|
data/LICENSE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Reports.Web License / 使用許諾
|
|
2
|
+
|
|
3
|
+
Copyright (c) Pao@Office. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This package is part of **Reports.Web**, a commercial product of Pao@Office.
|
|
6
|
+
Use of this package is governed by the Reports.Web End User License Agreement:
|
|
7
|
+
|
|
8
|
+
- 使用許諾(正式な条件): https://www.pao.ac/reports.web/manual/index.html#16
|
|
9
|
+
- 製品サイト: https://www.pao.ac/reports.web/
|
|
10
|
+
- ご購入・お見積もり: https://www.pao.ac/reports.web/buy.html
|
|
11
|
+
|
|
12
|
+
## 要点 / Summary
|
|
13
|
+
|
|
14
|
+
- **体験版 / Trial** — 出力される帳票には赤い「SAMPLE」の印が付きます。購入前の評価に、無償でお使いいただけます。
|
|
15
|
+
Output carries a red "SAMPLE" mark. You may evaluate it free of charge before purchase.
|
|
16
|
+
- **製品版 / Product** — ご購入時に納品するライセンスファイルを Reports.Web エンジンに設定すると、「SAMPLE」の印が消えます。
|
|
17
|
+
Configure the license file delivered on purchase in the Reports.Web engine to remove the mark.
|
|
18
|
+
- **ライセンスの数え方 / Licensing** — 開発用パソコン 1 台につき 1 開発ライセンスです。運用専用のサーバーやエンドユーザーのパソコンには不要です(ランタイムライセンスフリー)。
|
|
19
|
+
One development license per development PC. Production servers and end-user PCs need no license (royalty-free runtime).
|
|
20
|
+
|
|
21
|
+
上記の要点と使用許諾が異なる場合は、使用許諾が優先します。
|
|
22
|
+
If this summary and the license agreement differ, the license agreement prevails.
|
data/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# reports_web
|
|
2
|
+
|
|
3
|
+
**Reports.Web for Ruby** — 帳票定義(`.prepdj`)に値を入れて印刷データ(PREPEJ)を作り、Reports.Web エンジン(C++ WebAssembly)で PDF にします。請求書・見積書・納品書・宛名ラベル・名刺など、日本の業務帳票向けです。
|
|
4
|
+
|
|
5
|
+
Build print data (PREPEJ) from a report definition (`.prepdj`) and render it to PDF with the Reports.Web engine (C++ WebAssembly). Designed for Japanese business forms: invoices, estimates, delivery slips, address labels, business cards.
|
|
6
|
+
|
|
7
|
+
- 製品サイト / Product: https://www.pao.ac/reports.web/
|
|
8
|
+
- サンプル / Samples: https://github.com/ReportsWeb/wasm-ruby
|
|
9
|
+
- オンラインデモ / Live demo: https://www.pao.ac/demo/reports.web/samples/ruby/
|
|
10
|
+
|
|
11
|
+
## しくみ / How it works
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
your Ruby app ──(PREPEJ JSON)──▶ Reports.Web engine (Docker: ghcr.io/reportsweb/engine) ──▶ PDF
|
|
15
|
+
▲
|
|
16
|
+
report definition (.prepdj) designed in the browser designer
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
帳票のデザインは、ブラウザで動くデザイナーで作ります。アプリは値を入れて印刷データを作り、エンジンに送るだけです。描画はすべてエンジンが行います。
|
|
20
|
+
|
|
21
|
+
## インストール / Install
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
gem install reports_web # or: gem 'reports_web', '~> 1.0' in your Gemfile
|
|
25
|
+
docker run -d -p 3107:3107 ghcr.io/reportsweb/engine:1.0.0
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Ruby 3.1 以降。エンジンは Docker イメージで動きます。追加の gem は不要です(json・net/http を使います)。
|
|
29
|
+
Requires Ruby 3.1+. The engine runs as a Docker image. No extra gem dependencies.
|
|
30
|
+
|
|
31
|
+
## 使い方 / Quick start
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require 'json'
|
|
35
|
+
require 'reports_web'
|
|
36
|
+
|
|
37
|
+
definition = JSON.parse(File.read('report.prepdj', encoding: 'UTF-8'))
|
|
38
|
+
|
|
39
|
+
print_data = PaoReportsWeb::PrintData.new
|
|
40
|
+
.set_definition(definition)
|
|
41
|
+
.page_start
|
|
42
|
+
.set_value('Title', 'あっという間に帳票出力')
|
|
43
|
+
.set_value('CustomerName', '株式会社パオ')
|
|
44
|
+
.page_end
|
|
45
|
+
|
|
46
|
+
engine = PaoReportsWeb::ReportsWebEngine.new(url: 'http://127.0.0.1:3107')
|
|
47
|
+
File.binwrite('report.pdf', engine.render_pdf(print_data))
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### `PaoReportsWeb::PrintData`
|
|
53
|
+
|
|
54
|
+
| メソッド / Method | 内容 / Description |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `set_definition(definition)` | 帳票定義(`.prepdj` の内容)を設定 / Set the report definition |
|
|
57
|
+
| `page_start(definition = nil)` / `page_end` | ページの開始と終了。ページごとに別の定義も使えます / Begin and end a page |
|
|
58
|
+
| `set_value(name, value, index = 0, drawing = true)` | 文字などの値を入れる / Set a value |
|
|
59
|
+
| `set_repeated_value(name, value, x, y)` | 繰り返し(明細行など)の値 / Value for a repeated object |
|
|
60
|
+
| `set_image(name, source)` / `set_barcode(name, code)` | 画像・バーコード / Image and barcode |
|
|
61
|
+
| `change_attributes(name, values)` | 色・位置などの属性を変える / Change attributes |
|
|
62
|
+
| `to_h` / `to_json` / `save(path)` | 印刷データ(PREPEJ)として取り出す・保存する / Get or save the PREPEJ |
|
|
63
|
+
|
|
64
|
+
### `PaoReportsWeb::ReportsWebEngine`
|
|
65
|
+
|
|
66
|
+
| メソッド / Method | 内容 / Description |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `new(url:, timeout: 90, max_bytes:)` | 既定の URL は `REPORTS_ENGINE_URL`、なければ `http://127.0.0.1:3107` |
|
|
69
|
+
| `render_pdf(print_data)` | PDF のバイト列(String)を返します / Returns the PDF bytes |
|
|
70
|
+
| `health` | エンジンの状態 / Engine status |
|
|
71
|
+
|
|
72
|
+
エラーは `PaoReportsWeb::ReportsWebEngineError`(`status` に HTTP ステータス)で返ります。
|
|
73
|
+
Errors are raised as `PaoReportsWeb::ReportsWebEngineError` with the HTTP `status`.
|
|
74
|
+
|
|
75
|
+
## 体験版と製品版 / Trial and product
|
|
76
|
+
|
|
77
|
+
この gem とエンジンのイメージは体験版です。出力には赤い「SAMPLE」の印が付きます。ご購入後に納品するライセンスファイルをエンジンに設定すると、印が消えます。
|
|
78
|
+
|
|
79
|
+
The gem and the engine image are trial builds: output carries a red "SAMPLE" mark. Mount the license file delivered on purchase to remove it:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
docker run -d -p 3107:3107 -v /path/to/reports-web.license:/app/reports-web.license:ro ghcr.io/reportsweb/engine:1.0.0
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
開発用パソコン 1 台につき 1 ライセンス、運用環境はランタイムライセンスフリーです。詳しくは [LICENSE.md](LICENSE.md) と [使用許諾](https://www.pao.ac/reports.web/manual/index.html#16) をご覧ください。
|
|
86
|
+
|
|
87
|
+
## 他の言語 / Other languages
|
|
88
|
+
|
|
89
|
+
Reports.Web は同じ帳票定義と印刷データを、PHP・Java・.NET・Go・Ruby・Rust・Node.js から使えます。Pure Java・Pure Python・WPF 版もあります。
|
|
90
|
+
https://github.com/ReportsWeb
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
Pao@Office — https://www.pao.ac/ — info@pao.ac
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
6
|
+
module PaoReportsWeb
|
|
7
|
+
# Error returned by the Reports.Web engine. +status+ is the HTTP status, or nil for transport errors.
|
|
8
|
+
class ReportsWebEngineError < StandardError
|
|
9
|
+
attr_reader :status
|
|
10
|
+
|
|
11
|
+
def initialize(message, status = nil)
|
|
12
|
+
super(message)
|
|
13
|
+
@status = status
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Client for the Reports.Web engine (ghcr.io/reportsweb/engine).
|
|
18
|
+
# Sends PREPEJ print data to POST /render/pdf and returns the PDF bytes.
|
|
19
|
+
class ReportsWebEngine
|
|
20
|
+
DEFAULT_MAX = 32 * 1024 * 1024
|
|
21
|
+
|
|
22
|
+
attr_reader :url
|
|
23
|
+
|
|
24
|
+
# url: engine base URL (default: REPORTS_ENGINE_URL or http://127.0.0.1:3107)
|
|
25
|
+
# timeout: seconds; max_bytes: largest PDF accepted from the engine
|
|
26
|
+
def initialize(url: nil, timeout: 90, max_bytes: DEFAULT_MAX)
|
|
27
|
+
@url = (url || ENV['REPORTS_ENGINE_URL'] || 'http://127.0.0.1:3107').sub(%r{/+\z}, '')
|
|
28
|
+
@timeout = timeout
|
|
29
|
+
@max_bytes = max_bytes
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# GET /health. Returns the engine status, e.g. {"status"=>"ok", "engine"=>"C++ WebAssembly"}.
|
|
33
|
+
def health
|
|
34
|
+
response = request(Net::HTTP::Get.new(uri('/health')))
|
|
35
|
+
raise ReportsWebEngineError.new("Engine health check failed (HTTP #{response.code}).", response.code.to_i) unless response.is_a?(Net::HTTPSuccess)
|
|
36
|
+
JSON.parse(response.body)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Render PREPEJ print data (PrintData, its Hash form, or JSON text) to a PDF (binary String).
|
|
40
|
+
def render_pdf(data, swap_pdf_image: nil)
|
|
41
|
+
payload = case data
|
|
42
|
+
when String then data
|
|
43
|
+
when PrintData then data.to_json
|
|
44
|
+
else JSON.generate(data)
|
|
45
|
+
end
|
|
46
|
+
raise ReportsWebEngineError, 'Print data exceeds 32 MiB.' if payload.bytesize > DEFAULT_MAX
|
|
47
|
+
req = Net::HTTP::Post.new(uri('/render/pdf'))
|
|
48
|
+
req['Content-Type'] = 'application/json'
|
|
49
|
+
req['X-Reports-Swap-Pdf-Image'] = swap_pdf_image.to_s unless swap_pdf_image.nil?
|
|
50
|
+
req.body = payload
|
|
51
|
+
response = request(req)
|
|
52
|
+
unless response.is_a?(Net::HTTPSuccess)
|
|
53
|
+
detail = begin
|
|
54
|
+
JSON.parse(response.body.to_s)['error']
|
|
55
|
+
rescue JSON::ParserError, TypeError
|
|
56
|
+
response.body.to_s
|
|
57
|
+
end
|
|
58
|
+
message = "Engine could not create the PDF (HTTP #{response.code})"
|
|
59
|
+
message += detail.to_s.empty? ? '.' : ": #{detail}"
|
|
60
|
+
raise ReportsWebEngineError.new(message, response.code.to_i)
|
|
61
|
+
end
|
|
62
|
+
pdf = response.body.to_s.b
|
|
63
|
+
raise ReportsWebEngineError, "PDF exceeds #{@max_bytes} bytes." if pdf.bytesize > @max_bytes
|
|
64
|
+
raise ReportsWebEngineError, 'Engine response is not a PDF.' unless pdf.start_with?('%PDF-')
|
|
65
|
+
pdf
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def uri(path) = URI(@url + path)
|
|
71
|
+
|
|
72
|
+
def request(req)
|
|
73
|
+
target = req.uri
|
|
74
|
+
Net::HTTP.start(target.host, target.port, use_ssl: target.scheme == 'https',
|
|
75
|
+
open_timeout: [@timeout, 10].min, read_timeout: @timeout) { |http| http.request(req) }
|
|
76
|
+
rescue StandardError => e
|
|
77
|
+
raise ReportsWebEngineError, "Cannot reach the Reports.Web engine at #{@url}: #{e.message}"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
|
|
5
|
+
module PaoReportsWeb
|
|
6
|
+
# Framework-independent builder for the shared PREPEJ print-document format.
|
|
7
|
+
class PrintData
|
|
8
|
+
FORMAT = 'Reports.net PrintData'
|
|
9
|
+
VERSION = '1.0'
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@definition = nil
|
|
13
|
+
@pages = []
|
|
14
|
+
@page = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def set_definition(definition)
|
|
18
|
+
raise ArgumentError, 'Cannot change the definition inside a page' if @page
|
|
19
|
+
self.class.validate_definition!(definition)
|
|
20
|
+
@pages.each { |page| page['Definition'] = deep_copy(@definition) if page['Definition'].nil? } if @definition
|
|
21
|
+
@definition = deep_copy(definition)
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def page_start(definition = nil)
|
|
26
|
+
raise ArgumentError, 'Call page_end before starting another page' if @page
|
|
27
|
+
self.class.validate_definition!(definition) if definition
|
|
28
|
+
raise ArgumentError, 'Set a definition first' unless definition || @definition
|
|
29
|
+
@page = {'Index' => @pages.length + 1, 'Definition' => definition && deep_copy(definition), 'Values' => [], 'DynamicAttributes' => []}
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def set_value(name, value, index = 0, drawing = true)
|
|
34
|
+
add_value(name, nil, value, index, drawing)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def set_repeated_value(name, value, x, y, drawing = true)
|
|
38
|
+
add_value(name, nil, value, 0, drawing, x, y)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def set_typed_value(name, kind, value, index = 0, drawing = true)
|
|
42
|
+
add_value(name, kind, value, index, drawing)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def set_image(name, source) = set_typed_value(name, 'DynamicImage', source)
|
|
46
|
+
def set_barcode(name, code) = set_typed_value(name, 'DynamicBarcode', code)
|
|
47
|
+
|
|
48
|
+
def change_attributes(name, values, index = 0)
|
|
49
|
+
change_repeated_attributes(name, values, index)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def change_repeated_attributes(name, values, index = 0, x: nil, y: nil, kind: nil)
|
|
53
|
+
page = current_page
|
|
54
|
+
validate_indices!(index, x, y)
|
|
55
|
+
raise ArgumentError, 'Attributes must be an object' unless values.is_a?(Hash)
|
|
56
|
+
normalized = values.to_h { |key, value| raise(ArgumentError, 'Attribute values cannot be null') if value.nil?; [key.to_s, scalar(value)] }
|
|
57
|
+
item = {'Name' => required(name), 'Type' => resolve_type(name, kind), 'Index' => index, 'Values' => normalized}
|
|
58
|
+
item.merge!('IndexX' => x, 'IndexY' => y) unless x.nil?
|
|
59
|
+
page['DynamicAttributes'] << item
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def page_end
|
|
64
|
+
@pages << current_page
|
|
65
|
+
@page = nil
|
|
66
|
+
self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def to_h
|
|
70
|
+
raise ArgumentError, 'An unfinished page exists' if @page
|
|
71
|
+
raise ArgumentError, 'A definition is required' unless @definition
|
|
72
|
+
raise ArgumentError, 'At least one completed page is required' if @pages.empty?
|
|
73
|
+
deep_copy({'Format' => FORMAT, 'Version' => VERSION, 'Definition' => @definition, 'Pages' => @pages})
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def to_json(pretty: false)
|
|
77
|
+
(pretty ? JSON.pretty_generate(to_h) : JSON.generate(to_h)) + "\n"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def save(path)
|
|
81
|
+
Tempfile.create(['.print-', '.tmp'], File.dirname(path)) do |file|
|
|
82
|
+
file.write(to_json(pretty: true)); file.flush; file.close
|
|
83
|
+
File.rename(file.path, path)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.validate_definition!(definition)
|
|
88
|
+
portable = definition.is_a?(Hash) && definition.key?('Version') && definition['Objects'].is_a?(Array) && %w[mm px].include?((definition['CoordinateUnit'] || 'mm').downcase)
|
|
89
|
+
web = definition.is_a?(Hash) && definition['format'] == 'pao-reports-web' && definition['version'] == 1 && definition['pages'].is_a?(Array) && !definition['pages'].empty?
|
|
90
|
+
raise ArgumentError, 'Invalid report definition' unless portable || web
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
def add_value(name, kind, value, index, drawing, x = nil, y = nil)
|
|
95
|
+
validate_indices!(index, x, y)
|
|
96
|
+
item = {'Name' => required(name), 'Type' => resolve_type(name, kind), 'Index' => index, 'Drawing' => drawing, 'Value' => scalar(value)}
|
|
97
|
+
item.merge!('IndexX' => x, 'IndexY' => y) unless x.nil?
|
|
98
|
+
current_page['Values'] << item
|
|
99
|
+
self
|
|
100
|
+
end
|
|
101
|
+
# 型省略時だけ、当該ページの定義を参照する。明示指定は保持する。
|
|
102
|
+
def resolve_type(name, explicit)
|
|
103
|
+
return required(explicit) unless explicit.nil?
|
|
104
|
+
d = current_page['Definition'] || @definition
|
|
105
|
+
objects = (d['Objects'] || []) + (d['pages'] || []).flat_map { |p| p['objects'] || [] }
|
|
106
|
+
kinds = %w[Text Line Square Circle Image Barcode]
|
|
107
|
+
web = {'text'=>'Text', 'line'=>'Line', 'rectangle'=>'Square', 'ellipse'=>'Circle', 'image'=>'Image', 'barcode'=>'Barcode'}
|
|
108
|
+
objects.each do |o|
|
|
109
|
+
next unless (o['Name'] || o['name']) == required(name)
|
|
110
|
+
return 'Dynamic' + kinds[o['Kind'].to_i] if /\A[0-5]\z/.match?(o['Kind'].to_s)
|
|
111
|
+
return 'Dynamic' + web[o['kind']] if web.key?(o['kind'])
|
|
112
|
+
end
|
|
113
|
+
'DynamicText'
|
|
114
|
+
end
|
|
115
|
+
def current_page = @page || raise(ArgumentError, 'Call page_start first')
|
|
116
|
+
def required(value) = value.to_s.strip.then { |v| v.empty? ? raise(ArgumentError, 'A name is required') : v }
|
|
117
|
+
def scalar(value)
|
|
118
|
+
return nil if value.nil?
|
|
119
|
+
raise ArgumentError, 'A finite scalar is required' if value.is_a?(Float) && !value.finite?
|
|
120
|
+
return value.dup if value.is_a?(String)
|
|
121
|
+
return value.to_s if value.is_a?(Numeric) || value == true || value == false
|
|
122
|
+
raise ArgumentError, 'Values must be scalar'
|
|
123
|
+
end
|
|
124
|
+
def deep_copy(value) = Marshal.load(Marshal.dump(value))
|
|
125
|
+
def validate_indices!(index, x, y)
|
|
126
|
+
valid = index.is_a?(Integer) && index >= 0 && x.nil? == y.nil?
|
|
127
|
+
valid &&= x.is_a?(Integer) && x >= 0 && y.is_a?(Integer) && y >= 0 unless x.nil?
|
|
128
|
+
raise ArgumentError, 'Indices must be non-negative integers; supply both x and y, or neither' unless valid
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
data/lib/reports_web.rb
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Reports.Web for Ruby: PaoReportsWeb::PrintData builds PREPEJ print data,
|
|
3
|
+
# PaoReportsWeb::ReportsWebEngine renders it to PDF with the Reports.Web engine.
|
|
4
|
+
require_relative 'pao_reports_web/version'
|
|
5
|
+
require_relative 'pao_reports_web/print_data'
|
|
6
|
+
require_relative 'pao_reports_web/engine'
|
metadata
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: reports_web
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Pao@Office
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-10-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: 'Reports.Web is a report designer and PDF engine for Japanese business
|
|
14
|
+
forms (invoices, estimates, delivery slips, labels, business cards). This gem builds
|
|
15
|
+
print data (PREPEJ JSON) and renders it to PDF with the Reports.Web engine (C++
|
|
16
|
+
WebAssembly, Docker image ghcr.io/reportsweb/engine). Trial build: output carries
|
|
17
|
+
a red SAMPLE mark until a purchased license file is configured in the engine.'
|
|
18
|
+
email:
|
|
19
|
+
- info@pao.ac
|
|
20
|
+
executables: []
|
|
21
|
+
extensions: []
|
|
22
|
+
extra_rdoc_files: []
|
|
23
|
+
files:
|
|
24
|
+
- LICENSE.md
|
|
25
|
+
- README.md
|
|
26
|
+
- lib/pao_reports_web.rb
|
|
27
|
+
- lib/pao_reports_web/engine.rb
|
|
28
|
+
- lib/pao_reports_web/print_data.rb
|
|
29
|
+
- lib/pao_reports_web/version.rb
|
|
30
|
+
- lib/reports_web.rb
|
|
31
|
+
homepage: https://www.pao.ac/reports.web/
|
|
32
|
+
licenses:
|
|
33
|
+
- Nonstandard
|
|
34
|
+
metadata:
|
|
35
|
+
homepage_uri: https://www.pao.ac/reports.web/
|
|
36
|
+
source_code_uri: https://github.com/ReportsWeb/wasm-ruby
|
|
37
|
+
documentation_uri: https://github.com/ReportsWeb/wasm-ruby#readme
|
|
38
|
+
bug_tracker_uri: https://www.pao.ac/reports.web/
|
|
39
|
+
post_install_message:
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.1'
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
requirements: []
|
|
54
|
+
rubygems_version: 3.5.22
|
|
55
|
+
signing_key:
|
|
56
|
+
specification_version: 4
|
|
57
|
+
summary: 'Reports.Web for Ruby: build PREPEJ print data from .prepdj report definitions
|
|
58
|
+
and render PDF with the Reports.Web engine.'
|
|
59
|
+
test_files: []
|