typst 0.13.2 → 0.13.3

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: 26c5aa0d53ccc72726e84813f15e44c7af5058644e303e7a717c6e434f3491f9
4
- data.tar.gz: e2a4c340aed40a83c85b2fbb369ecf6925b354d5bd01d794168933dfc3999a94
3
+ metadata.gz: efba2668a9abea7b8c3679ce34f67d35c29737f1c2c3afd88c8542b7609ec4e8
4
+ data.tar.gz: 285d1408b40eafc2237089c7b5bfcd32196f832ce4b1e05e5175a2cde5558ae8
5
5
  SHA512:
6
- metadata.gz: 064b3692ae5e033d33e6c2960ec53112a61abb76d1c69a66d07ea75f2ff284044fb85d9eefc9c7d510c3bc1f07f4447a2e2edf4983d864b696e36b418abdfab2
7
- data.tar.gz: 38409e19ae6faaea38db473515a24df16d0e1bb2cd42fad113557e8e8ca13bfda4e9564976e68bf53ea4ae7624c9433d8a8679b30438a4bb39f7803b73677e5f
6
+ metadata.gz: c15d656ce6673c9e1c8d67f5743c8c13a1ea3e8a960d93271f27ec8a4e41144f505593f37ec81bf97a7f608b123a7fa57fbac4aada94a5bdc2b06369eb09f607
7
+ data.tar.gz: 9c080fa1092d04481e1a78c99e871d53af7138025a0586d2993bb9d8f43167f7eee2c742d266478011172d4a62150e6589723c191080bdc2daedfec20be1dd70
data/README.md CHANGED
@@ -14,59 +14,75 @@ gem install typst
14
14
  ```ruby
15
15
  require "typst"
16
16
 
17
- # Compile `readme.typ` to PDF and save as `readme.pdf`
18
- Typst::Pdf.new("readme.typ").write("readme.pdf")
17
+ # Compile a typst file and write the output to a PDF file
18
+ Typst("readme.typ").compile(:pdf).write("readme.pdf")
19
19
 
20
- # Or return PDF content as an array of bytes
21
- pdf_bytes = Typst::Pdf.new("readme.typ").bytes
22
- # => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
20
+ # Use a typst file `readme.typ`
21
+ t = Typst("readme.typ")
23
22
 
24
- # Or return PDF content as a string of bytes
25
- document = Typst::Pdf.new("readme.typ").document
26
- # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
23
+ # Use a typst string
24
+ t = Typst(body: %{hello world})
27
25
 
28
- # Compile `readme.typ` to SVG and save as `readme_0.svg`, `readme_1.svg`
29
- Typst::Svg.new("readme.typ").write("readme.svg")
26
+ # Use a typst file in a zip file
27
+ t = Typst(zip: "test/main.typ.zip")
30
28
 
31
- # Or return SVG content as an array of pages
32
- pages = Typst::Svg.new("readme.typ").pages
33
- # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
29
+ # Compile to PDF
30
+ f = t.compile(:pdf)
34
31
 
35
- # Compile `readme.typ` to PNG and save as `readme_0.png`, `readme_1.png`
36
- Typst::Png.new("readme.typ").write("readme.png")
32
+ # Compile to SVG
33
+ f = t.compile(:svg)
37
34
 
38
- # Or return PNG content as an array of pages
39
- pages = Typst::Png.new("readme.typ").pages
40
- # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
35
+ # Compile to PNG
36
+ f = t.compile(:png)
41
37
 
42
- # Compile `readme.typ` to SVG and save as `readme.html`
43
- Typst::Html.new("readme.typ", title: "README").write("readme.html")
38
+ # Compile to SVGs enveloped in HTML
39
+ # Depracation warning: this feature will go away once Typst HTML moves out of experimental
40
+ f = t.compile(:html, title: "Typst+Ruby")
44
41
 
45
- # Or return HTML content
46
- markup = Typst::Html.new("readme.typ", title: "README").document
47
- # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>README</title>\n</head>\n<bo..."
42
+ # Compile to HTML (using Typst expirmental HTML)
43
+ f = t.compile(:html_experimental)
48
44
 
49
- # Use native Typst experimental HTML feature to write single frame HTML file
50
- Typst::HtmlExperimental.new("readme.typ").write("readme.html")
45
+ # Access PDF or HTML output as a string
46
+ # Note: For PDF and PNG this will give data, for SVG and HTML this will give markup
47
+ Typst("readme.typ").compile(:pdf).document
48
+ # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
49
+ Typst("readme.typ").compile(:html).document
50
+ # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>main</title>\n</head>\n<body>\n<svg class=\"typst-doc\" ...
51
+
52
+ # Or return content as an array of bytes
53
+ pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
54
+ # => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
51
55
 
52
- # Or return single frame HTML content (using native Typst experimental HTML feature)
53
- markup = Typst::HtmlExperimental.new("readme.typ").document
54
- # => "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n..."
56
+ # Write the output to a file
57
+ # Note: for multi-page documents using formats other than PDF, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
58
+ f.write("filename.pdf")
55
59
 
56
- # Compile from a string to PDF
57
- t = Typst::Pdf.from_s(%{hello world})
60
+ # Return SVG, HTML or PNG content as an array of pages
61
+ Typst("readme.typ").compile(:svg).pages
62
+ # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
63
+ Typst("readme.typ").compile(:html).pages
64
+ # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
65
+ Typst("readme.typ").compile(:png).pages
66
+ # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
58
67
 
59
- # Compile from a string to SVG
60
- t = Typst::Svg.from_s(%{hello world})
68
+ # Pass values into typst using sys_inputs
69
+ sys_inputs_example = %{
70
+ #let persons = json(bytes(sys.inputs.persons))
61
71
 
62
- # Compile from a string to PNG
63
- t = Typst::Png.from_s(%{hello world})
72
+ #for person in persons [
73
+ #person.name is #person.age years old.\\
74
+ ]
75
+ }
76
+ people = [{"name" => "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}]
77
+ data = { "persons" => people.to_json }
78
+ Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf")
64
79
 
65
- # Compile from a string to SVG multi-frame/pages wrapped in HTML (non-native Typst)
66
- t = Typst::Html.from_s(%{hello world})
80
+ # Apply inputs to typst to product multiple PDFs
67
81
 
68
- # Compile from a string to single frame HTML (native Typst experimental feature)
69
- t = Typst::HtmlExperimental.from_s(%{hello world})
82
+ t = Typst(body: sys_inputs_example)
83
+ people.each do |person|
84
+ t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf")
85
+ end
70
86
 
71
87
  # A more complex example of compiling from string
72
88
  main = %{
@@ -89,24 +105,10 @@ template = %{
89
105
  icon = File.read("icon.svg")
90
106
  font_bytes = File.read("Example.ttf")
91
107
 
92
- t = Typst::Pdf.from_s(main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes })
93
-
94
- # Pass values into a typst template using sys_inputs
95
- sys_inputs_example = %{
96
- #let persons = json(bytes(sys.inputs.persons))
97
-
98
- #for person in persons [
99
- #person.name is #person.age years old.\\
100
- ]
101
- }
102
- Typst::Pdf.from_s(sys_inputs_example, sys_inputs: { "persons" => [{"name": "John", "age": 35}, {"name": "Xoliswa", "age": 45}].to_json }).write("sys_inputs_example.pdf")
103
-
104
- # From a zip file that includes a main.typ
105
- # zip file include flat dependencies included and a fonts directory
106
- Typst::Pdf::from_zip("working_directory.zip")
107
-
108
+ Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf)
109
+
108
110
  # From a zip with a named main typst file
109
- Typst::Pdf::from_zip("working_directory.zip", "hello.typ")
111
+ Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
110
112
 
111
113
  Typst::Query.new("heading", "readme.typ").result
112
114
  # =>
data/README.typ CHANGED
@@ -17,59 +17,75 @@ gem install typst
17
17
  ```ruby
18
18
  require "typst"
19
19
 
20
- # Compile `readme.typ` to PDF and save as `readme.pdf`
21
- Typst::Pdf.new("readme.typ").write("readme.pdf")
20
+ # Compile a typst file and write the output to a PDF file
21
+ Typst("readme.typ").compile(:pdf).write("readme.pdf")
22
22
 
23
- # Or return PDF content as an array of bytes
24
- pdf_bytes = Typst::Pdf.new("readme.typ").bytes
25
- # => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
23
+ # Use a typst file `readme.typ`
24
+ t = Typst("readme.typ")
26
25
 
27
- # Or return PDF content as a string of bytes
28
- document = Typst::Pdf.new("readme.typ").document
29
- # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
26
+ # Use a typst string
27
+ t = Typst(body: %{hello world})
30
28
 
31
- # Compile `readme.typ` to SVG and save as `readme_0.svg`, `readme_1.svg`
32
- Typst::Svg.new("readme.typ").write("readme.svg")
29
+ # Use a typst file in a zip file
30
+ t = Typst(zip: "test/main.typ.zip")
33
31
 
34
- # Or return SVG content as an array of pages
35
- pages = Typst::Svg.new("readme.typ").pages
36
- # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
32
+ # Compile to PDF
33
+ f = t.compile(:pdf)
37
34
 
38
- # Compile `readme.typ` to PNG and save as `readme_0.png`, `readme_1.png`
39
- Typst::Png.new("readme.typ").write("readme.png")
35
+ # Compile to SVG
36
+ f = t.compile(:svg)
40
37
 
41
- # Or return PNG content as an array of pages
42
- pages = Typst::Png.new("readme.typ").pages
43
- # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
38
+ # Compile to PNG
39
+ f = t.compile(:png)
44
40
 
45
- # Compile `readme.typ` to SVG and save as `readme.html`
46
- Typst::Html.new("readme.typ", title: "README").write("readme.html")
41
+ # Compile to SVGs enveloped in HTML
42
+ # Depracation warning: this feature will go away once Typst HTML moves out of experimental
43
+ f = t.compile(:html, title: "Typst+Ruby")
47
44
 
48
- # Or return HTML content
49
- markup = Typst::Html.new("readme.typ", title: "README").document
50
- # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>README</title>\n</head>\n<bo..."
45
+ # Compile to HTML (using Typst expirmental HTML)
46
+ f = t.compile(:html_experimental)
51
47
 
52
- # Use native Typst experimental HTML feature to write single frame HTML file
53
- Typst::HtmlExperimental.new("readme.typ").write("readme.html")
48
+ # Access PDF or HTML output as a string
49
+ # Note: For PDF and PNG this will give data, for SVG and HTML this will give markup
50
+ Typst("readme.typ").compile(:pdf).document
51
+ # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
52
+ Typst("readme.typ").compile(:html).document
53
+ # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>main</title>\n</head>\n<body>\n<svg class=\"typst-doc\" ...
54
54
 
55
- # Or return single frame HTML content (using native Typst experimental HTML feature)
56
- markup = Typst::HtmlExperimental.new("readme.typ").document
57
- # => "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n..."
55
+ # Or return content as an array of bytes
56
+ pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
57
+ # => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
58
58
 
59
- # Compile from a string to PDF
60
- t = Typst::Pdf.from_s(%{hello world})
59
+ # Write the output to a file
60
+ # Note: for multi-page documents using formats other than PDF, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
61
+ f.write("filename.pdf")
61
62
 
62
- # Compile from a string to SVG
63
- t = Typst::Svg.from_s(%{hello world})
63
+ # Return SVG, HTML or PNG content as an array of pages
64
+ Typst("readme.typ").compile(:svg).pages
65
+ # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
66
+ Typst("readme.typ").compile(:html).pages
67
+ # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
68
+ Typst("readme.typ").compile(:png).pages
69
+ # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
70
+
71
+ # Pass values into typst using sys_inputs
72
+ sys_inputs_example = %{
73
+ #let persons = json(bytes(sys.inputs.persons))
64
74
 
65
- # Compile from a string to PNG
66
- t = Typst::Png.from_s(%{hello world})
75
+ #for person in persons [
76
+ #person.name is #person.age years old.\\
77
+ ]
78
+ }
79
+ people = [{"name" => "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}]
80
+ data = { "persons" => people.to_json }
81
+ Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf")
67
82
 
68
- # Compile from a string to SVG multi-frame/pages wrapped in HTML (non-native Typst)
69
- t = Typst::Html.from_s(%{hello world})
83
+ # Apply inputs to typst to product multiple PDFs
70
84
 
71
- # Compile from a string to single frame HTML (native Typst experimental feature)
72
- t = Typst::HtmlExperimental.from_s(%{hello world})
85
+ t = Typst(body: sys_inputs_example)
86
+ people.each do |person|
87
+ t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf")
88
+ end
73
89
 
74
90
  # A more complex example of compiling from string
75
91
  main = %{
@@ -92,14 +108,10 @@ template = %{
92
108
  icon = File.read("icon.svg")
93
109
  font_bytes = File.read("Example.ttf")
94
110
 
95
- t = Typst::Pdf.from_s(main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes })
96
-
97
- # From a zip file that includes a main.typ
98
- # zip file include flat dependencies included and a fonts directory
99
- Typst::Pdf::from_zip("working_directory.zip")
100
-
111
+ Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf)
112
+
101
113
  # From a zip with a named main typst file
102
- Typst::Pdf::from_zip("working_directory.zip", "hello.typ")
114
+ Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
103
115
 
104
116
  Typst::Query.new("heading", "readme.typ").result
105
117
  # =>
data/lib/base.rb ADDED
@@ -0,0 +1,169 @@
1
+ module Typst
2
+ class Base
3
+ attr_accessor :options
4
+ attr_accessor :compiled
5
+
6
+ def initialize(*options)
7
+ if options.size.zero?
8
+ raise "No options given"
9
+ elsif options.first.is_a?(String)
10
+ file, options = options
11
+ options ||= {}
12
+ options[:file] = file
13
+ elsif options.first.is_a?(Hash)
14
+ options = options.first
15
+ end
16
+
17
+ if options.has_key?(:file)
18
+ raise "Can't find file" unless File.exist?(options[:file])
19
+ elsif options.has_key?(:body)
20
+ raise "Empty body" if options[:body].to_s.empty?
21
+ elsif options.has_key?(:zip)
22
+ raise "Can't find zip" unless File.exist?(options[:zip])
23
+ else
24
+ raise "No input given"
25
+ end
26
+
27
+ root = Pathname.new(options[:root] || ".").expand_path
28
+ raise "Invalid path for root" unless root.exist?
29
+ options[:root] = root.to_s
30
+
31
+ font_paths = (options[:font_paths] || []).collect{ |fp| Pathname.new(fp).expand_path }
32
+ options[:font_paths] = font_paths.collect(&:to_s)
33
+
34
+ options[:dependencies] ||= {}
35
+ options[:fonts] ||= {}
36
+ options[:sys_inputs] ||= {}
37
+
38
+ self.options = options
39
+ end
40
+
41
+ def typst_args
42
+ [options[:file], options[:root], options[:font_paths], File.dirname(__FILE__), false, options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h]
43
+ end
44
+
45
+ def self.from_s(main_source, **options)
46
+ dependencies = options[:dependencies] ||= {}
47
+ fonts = options[:fonts] ||= {}
48
+
49
+ Dir.mktmpdir do |tmp_dir|
50
+ tmp_main_file = Pathname.new(tmp_dir).join("main.typ")
51
+ File.write(tmp_main_file, main_source)
52
+
53
+ dependencies.each do |dep_name, dep_source|
54
+ tmp_dep_file = Pathname.new(tmp_dir).join(dep_name)
55
+ File.write(tmp_dep_file, dep_source)
56
+ end
57
+
58
+ relative_font_path = Pathname.new(tmp_dir).join("fonts")
59
+ fonts.each do |font_name, font_bytes|
60
+ Pathname.new(relative_font_path).mkpath
61
+ tmp_font_file = relative_font_path.join(font_name)
62
+ File.write(tmp_font_file, font_bytes)
63
+ end
64
+
65
+ options[:file] = tmp_main_file
66
+ options[:root] = tmp_dir
67
+ options[:font_paths] = [relative_font_path]
68
+
69
+ if options[:format]
70
+ Typst::formats[options[:format]].new(**options)
71
+ else
72
+ new(**options)
73
+ end
74
+ end
75
+ end
76
+
77
+ def self.from_zip(zip_file_path, main_file = nil, **options)
78
+ options[:dependencies] ||= {}
79
+ options[:fonts] ||= {}
80
+
81
+ Zip::File.open(zip_file_path) do |zipfile|
82
+ file_names = zipfile.dir.glob("*").collect{ |f| f.name }
83
+ case
84
+ when file_names.include?(main_file) then tmp_main_file = main_file
85
+ when file_names.include?("main.typ") then tmp_main_file = "main.typ"
86
+ when file_names.size == 1 then tmp_main_file = file_names.first
87
+ else raise "no main file found"
88
+ end
89
+ main_source = zipfile.file.read(tmp_main_file)
90
+ file_names.delete(tmp_main_file)
91
+ file_names.delete("fonts/")
92
+
93
+ file_names.each do |dep_name|
94
+ options[:dependencies][dep_name] = zipfile.file.read(dep_name)
95
+ end
96
+
97
+ font_file_names = zipfile.dir.glob("fonts/*").collect{ |f| f.name }
98
+ font_file_names.each do |font_name|
99
+ options[:fonts][Pathname.new(font_name).basename.to_s] = zipfile.file.read(font_name)
100
+ end
101
+
102
+ options[:main_file] = tmp_main_file
103
+
104
+ from_s(main_source, **options)
105
+ end
106
+ end
107
+
108
+ def with_dependencies(dependencies)
109
+ self.options[:dependencies] = self.options[:dependencies].merge(dependencies)
110
+ self
111
+ end
112
+
113
+ def with_fonts(fonts)
114
+ self.options[:fonts] = self.options[:fonts].merge(fonts)
115
+ self
116
+ end
117
+
118
+ def with_inputs(inputs)
119
+ self.options[:sys_inputs] = self.options[:sys_inputs].merge(inputs)
120
+ self
121
+ end
122
+
123
+ def with_font_paths(font_paths)
124
+ self.options[:font_paths] = self.options[:font_paths] + font_paths
125
+ self
126
+ end
127
+
128
+ def with_root(root)
129
+ self.options[:root] = root
130
+ self
131
+ end
132
+
133
+ def compile(format, **options)
134
+ raise "Invalid format" if Typst::formats[format].nil?
135
+
136
+ options = self.options.merge(options)
137
+
138
+ if options.has_key?(:file)
139
+ Typst::formats[format].new(**options).compiled
140
+ elsif options.has_key?(:body)
141
+ Typst::formats[format].from_s(options[:body], **options).compiled
142
+ elsif options.has_key?(:zip)
143
+ Typst::formats[format].from_zip(options[:zip], options[:main_file], **options).compiled
144
+ else
145
+ raise "No input given"
146
+ end
147
+ end
148
+
149
+ def write(output)
150
+ STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
151
+ compiled.write(output)
152
+ end
153
+
154
+ def document
155
+ STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
156
+ compiled.document
157
+ end
158
+
159
+ def bytes
160
+ STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
161
+ compiled.bytes
162
+ end
163
+
164
+ def pages
165
+ STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
166
+ compiled.pages
167
+ end
168
+ end
169
+ end
data/lib/document.rb ADDED
@@ -0,0 +1,29 @@
1
+ module Typst
2
+ class Document
3
+ attr_accessor :bytes
4
+
5
+ def initialize(bytes)
6
+ @bytes = bytes
7
+ end
8
+
9
+ def write(out)
10
+ if pages.size == 1
11
+ File.write(out, pages.first, mode: "wb")
12
+ else
13
+ pages.each_with_index do |page, i|
14
+ fn = File.basename(out, ".*") + "_{{n}}" + File.extname(out) unless out.include?("{{n}}")
15
+ fn = fn.gsub("{{n}}", (i+1).to_s)
16
+ File.write(fn, page, mode: "wb")
17
+ end
18
+ end
19
+ end
20
+
21
+ def pages
22
+ bytes.collect{ |page| page.pack("C*").to_s }
23
+ end
24
+
25
+ def document
26
+ pages.size == 1 ? pages.first : pages
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ module Typst
2
+ class Html < Base
3
+ def initialize(*options)
4
+ super(*options)
5
+ title = CGI::escapeHTML(@options[:title] || File.basename(@options[:file], ".*"))
6
+ @compiled = HtmlDocument.new(Typst::_to_svg(*self.typst_args), title)
7
+ end
8
+ end
9
+
10
+ class HtmlDocument < Document
11
+ attr_accessor :title
12
+
13
+ def initialize(bytes, title)
14
+ super(bytes)
15
+ self.title = title
16
+ end
17
+
18
+ def markup
19
+ %{
20
+ <!DOCTYPE html>
21
+ <html>
22
+ <head>
23
+ <title>#{title}</title>
24
+ </head>
25
+ <body>
26
+ #{pages.join("<br />")}
27
+ </body>
28
+ </html>
29
+ }
30
+ end
31
+ alias_method :document, :markup
32
+ end
33
+
34
+ register_format(html: Html)
35
+ end
@@ -0,0 +1,11 @@
1
+ module Typst
2
+ class HtmlExperimental < Base
3
+ def initialize(*options)
4
+ super(*options)
5
+ @compiled = HtmlExperimentalDocument.new(Typst::_to_html(*self.typst_args))
6
+ end
7
+ end
8
+ class HtmlExperimentalDocument < Document; end
9
+
10
+ register_format(html_experimental: HtmlExperimental)
11
+ end
@@ -0,0 +1,11 @@
1
+ module Typst
2
+ class Pdf < Base
3
+ def initialize(*options)
4
+ super(*options)
5
+ @compiled = PdfDocument.new(Typst::_to_pdf(*self.typst_args))
6
+ end
7
+ end
8
+ class PdfDocument < Document; end
9
+
10
+ register_format(pdf: Pdf)
11
+ end
@@ -0,0 +1,11 @@
1
+ module Typst
2
+ class Png < Base
3
+ def initialize(*options)
4
+ super(*options)
5
+ @compiled = PngDocument.new(Typst::_to_png(*self.typst_args))
6
+ end
7
+ end
8
+ class PngDocument < Document; end
9
+
10
+ register_format(png: Png)
11
+ end
@@ -0,0 +1,11 @@
1
+ module Typst
2
+ class Svg < Base
3
+ def initialize(*options)
4
+ super(*options)
5
+ @compiled = SvgDocument.new(Typst::_to_svg(*self.typst_args))
6
+ end
7
+ end
8
+ class SvgDocument < Document; end
9
+
10
+ register_format(svg: Svg)
11
+ end
data/lib/query.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Typst
2
+ class Query < Base
3
+ attr_accessor :format
4
+
5
+ def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], sys_inputs: {})
6
+ super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
7
+ self.format = format
8
+ @result = Typst::_query(selector, field, one, format, input, root, font_paths, File.dirname(__FILE__), false, sys_inputs)
9
+ end
10
+
11
+ def result(raw: false)
12
+ case raw || format
13
+ when "json" then JSON(@result)
14
+ when "yaml" then YAML::safe_load(@result)
15
+ else @result
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/typst.rb CHANGED
@@ -1,203 +1,31 @@
1
- require_relative "typst/typst"
2
- require "cgi"
3
- require "pathname"
4
- require "tmpdir"
5
- require "zip/filesystem"
1
+ def Typst(*options)
2
+ Typst::Base.new(*options)
3
+ end
6
4
 
7
5
  module Typst
8
- class Base
9
- attr_accessor :input
10
- attr_accessor :root
11
- attr_accessor :font_paths
12
- attr_accessor :sys_inputs
13
-
14
- def initialize(input, root: ".", font_paths: [], sys_inputs: {})
15
- self.input = input
16
- self.root = Pathname.new(root).expand_path.to_s
17
- self.font_paths = font_paths.collect{ |fp| Pathname.new(fp).expand_path.to_s }
18
- self.sys_inputs = sys_inputs
19
- end
20
-
21
- def write(output)
22
- File.open(output, "wb"){ |f| f.write(document) }
23
- end
24
-
25
- def self.from_s(main_source, dependencies: {}, fonts: {}, sys_inputs: {})
26
- dependencies = {} if dependencies.nil?
27
- fonts = {} if fonts.nil?
28
- Dir.mktmpdir do |tmp_dir|
29
- tmp_main_file = Pathname.new(tmp_dir).join("main.typ")
30
- File.write(tmp_main_file, main_source)
31
-
32
- dependencies.each do |dep_name, dep_source|
33
- tmp_dep_file = Pathname.new(tmp_dir).join(dep_name)
34
- File.write(tmp_dep_file, dep_source)
35
- end
36
-
37
- relative_font_path = Pathname.new(tmp_dir).join("fonts")
38
- fonts.each do |font_name, font_bytes|
39
- Pathname.new(relative_font_path).mkpath
40
- tmp_font_file = relative_font_path.join(font_name)
41
- File.write(tmp_font_file, font_bytes)
42
- end
43
-
44
- new(tmp_main_file, root: tmp_dir, font_paths: [relative_font_path], sys_inputs: sys_inputs)
45
- end
46
- end
47
-
48
- def self.from_zip(zip_file_path, main_file = nil, sys_inputs: {})
49
- dependencies = {}
50
- fonts = {}
51
-
52
- Zip::File.open(zip_file_path) do |zipfile|
53
- file_names = zipfile.dir.glob("*").collect{ |f| f.name }
54
- case
55
- when file_names.include?(main_file) then tmp_main_file = main_file
56
- when file_names.include?("main.typ") then tmp_main_file = "main.typ"
57
- when file_names.size == 1 then tmp_main_file = file_names.first
58
- else raise "no main file found"
59
- end
60
- main_source = zipfile.file.read(tmp_main_file)
61
- file_names.delete(tmp_main_file)
62
- file_names.delete("fonts/")
63
-
64
- file_names.each do |dep_name|
65
- dependencies[dep_name] = zipfile.file.read(dep_name)
66
- end
67
-
68
- font_file_names = zipfile.dir.glob("fonts/*").collect{ |f| f.name }
69
- font_file_names.each do |font_name|
70
- fonts[Pathname.new(font_name).basename.to_s] = zipfile.file.read(font_name)
71
- end
72
-
73
- from_s(main_source, dependencies: dependencies, fonts: fonts, sys_inputs: sys_inputs)
74
- end
75
- end
76
- end
77
-
78
- class Pdf < Base
79
- attr_accessor :bytes
80
-
81
- def initialize(input, root: ".", font_paths: [], sys_inputs: {})
82
- super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
83
- @bytes = Typst::_to_pdf(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs)[0]
84
- end
85
-
86
- def document
87
- bytes.pack("C*").to_s
88
- end
89
- end
90
-
91
- class Svg < Base
92
- attr_accessor :pages
93
-
94
- def initialize(input, root: ".", font_paths: [], sys_inputs: {})
95
- super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
96
- @pages = Typst::_to_svg(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs).collect{ |page| page.pack("C*").to_s }
97
- end
98
-
99
- def write(output)
100
- if pages.size > 1
101
- pages.each_with_index do |page, i|
102
- if output.include?("{{n}}")
103
- file_name = output.gsub("{{n}}", (i+1).to_s)
104
- else
105
- file_name = File.basename(output, File.extname(output)) + "_" + i.to_s
106
- file_name = file_name + File.extname(output)
107
- end
108
- File.open(file_name, "w"){ |f| f.write(page) }
109
- end
110
- elsif pages.size == 1
111
- File.open(output, "w"){ |f| f.write(pages[0]) }
112
- else
113
- end
114
- end
115
- end
116
-
117
- class Png < Base
118
- attr_accessor :pages
6
+ @@formats = {}
119
7
 
120
- def initialize(input, root: ".", font_paths: [], sys_inputs: {})
121
- super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
122
- @pages = Typst::_to_png(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs).collect{ |page| page.pack("C*").to_s }
123
- end
124
-
125
- def write(output)
126
- if pages.size > 1
127
- pages.each_with_index do |page, i|
128
- if output.include?("{{n}}")
129
- file_name = output.gsub("{{n}}", (i+1).to_s)
130
- else
131
- file_name = File.basename(output, File.extname(output)) + "_" + i.to_s
132
- file_name = file_name + File.extname(output)
133
- end
134
- File.open(file_name, "w"){ |f| f.write(page) }
135
- end
136
- elsif pages.size == 1
137
- File.open(output, "w"){ |f| f.write(pages[0]) }
138
- else
139
- end
140
- end
8
+ def self.register_format(**format)
9
+ @@formats.merge!(format)
141
10
  end
142
-
143
- class Html < Base
144
- attr_accessor :title
145
- attr_accessor :svg
146
- attr_accessor :html
147
-
148
- def initialize(input, title: nil, root: ".", font_paths: [], sys_inputs: {})
149
- super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
150
- title = title || File.basename(input, File.extname(input))
151
- self.title = CGI::escapeHTML(title)
152
- self.svg = Svg.new(self.input, root: self.root, font_paths: self.font_paths, sys_inputs: sys_inputs)
153
- end
154
11
 
155
- def markup
156
- %{
157
- <!DOCTYPE html>
158
- <html>
159
- <head>
160
- <title>#{title}</title>
161
- </head>
162
- <body>
163
- #{svg.pages.join("<br />")}
164
- </body>
165
- </html>
166
- }
167
- end
168
- alias_method :document, :markup
169
- end
170
-
171
- class HtmlExperimental < Base
172
- attr_accessor :bytes
173
-
174
- def initialize(input, root: ".", font_paths: [], sys_inputs: {})
175
- super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
176
- @bytes = Typst::_to_html(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs)[0]
177
- end
178
-
179
- def document
180
- bytes.pack("C*").to_s
181
- end
182
- alias_method :markup, :document
12
+ def self.formats
13
+ @@formats
183
14
  end
15
+ end
184
16
 
185
- class Query < Base
186
- attr_accessor :format
187
- attr_accessor :result
188
17
 
189
- def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], sys_inputs: {})
190
- super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
191
- self.format = format
192
- self.result = Typst::_query(selector, field, one, format, self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs)
193
- end
18
+ require "cgi"
19
+ require "pathname"
20
+ require "tmpdir"
21
+ require "zip/filesystem"
194
22
 
195
- def result(raw: false)
196
- case raw || format
197
- when "json" then JSON(@result)
198
- when "yaml" then YAML::safe_load(@result)
199
- else @result
200
- end
201
- end
202
- end
203
- end
23
+ require_relative "typst/typst"
24
+ require_relative "base"
25
+ require_relative "query"
26
+ require_relative "document"
27
+ require_relative "formats/pdf"
28
+ require_relative "formats/svg"
29
+ require_relative "formats/png"
30
+ require_relative "formats/html"
31
+ require_relative "formats/html_experimental"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typst
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.2
4
+ version: 0.13.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flinn
@@ -71,6 +71,8 @@ files:
71
71
  - ext/typst/src/package.rs
72
72
  - ext/typst/src/query.rs
73
73
  - ext/typst/src/world.rs
74
+ - lib/base.rb
75
+ - lib/document.rb
74
76
  - lib/fonts/DejaVuSansMono-Bold.ttf
75
77
  - lib/fonts/DejaVuSansMono-BoldOblique.ttf
76
78
  - lib/fonts/DejaVuSansMono-Oblique.ttf
@@ -85,6 +87,12 @@ files:
85
87
  - lib/fonts/NewCM10-Regular.otf
86
88
  - lib/fonts/NewCMMath-Book.otf
87
89
  - lib/fonts/NewCMMath-Regular.otf
90
+ - lib/formats/html.rb
91
+ - lib/formats/html_experimental.rb
92
+ - lib/formats/pdf.rb
93
+ - lib/formats/png.rb
94
+ - lib/formats/svg.rb
95
+ - lib/query.rb
88
96
  - lib/typst.rb
89
97
  homepage: https://github.com/actsasflinn/typst-rb
90
98
  licenses: