postscript 0.1.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/.rspec +2 -0
- data/Gemfile +12 -0
- data/README.adoc +72 -0
- data/Rakefile +10 -0
- data/lib/postscript/color.rb +132 -0
- data/lib/postscript/errors.rb +56 -0
- data/lib/postscript/format_number.rb +22 -0
- data/lib/postscript/matrix.rb +109 -0
- data/lib/postscript/model/literals/array.rb +41 -0
- data/lib/postscript/model/literals/dictionary.rb +34 -0
- data/lib/postscript/model/literals/hex.rb +37 -0
- data/lib/postscript/model/literals/name.rb +40 -0
- data/lib/postscript/model/literals/number.rb +36 -0
- data/lib/postscript/model/literals/procedure.rb +41 -0
- data/lib/postscript/model/literals/string.rb +30 -0
- data/lib/postscript/model/literals.rb +19 -0
- data/lib/postscript/model/operator.rb +58 -0
- data/lib/postscript/model/operators/arithmetic.rb +264 -0
- data/lib/postscript/model/operators/boolean.rb +182 -0
- data/lib/postscript/model/operators/color.rb +74 -0
- data/lib/postscript/model/operators/container.rb +186 -0
- data/lib/postscript/model/operators/control_flow.rb +119 -0
- data/lib/postscript/model/operators/device.rb +21 -0
- data/lib/postscript/model/operators/dictionary.rb +118 -0
- data/lib/postscript/model/operators/font.rb +121 -0
- data/lib/postscript/model/operators/graphics_state.rb +84 -0
- data/lib/postscript/model/operators/painting.rb +29 -0
- data/lib/postscript/model/operators/path.rb +169 -0
- data/lib/postscript/model/operators/stack.rb +72 -0
- data/lib/postscript/model/operators/transformations.rb +103 -0
- data/lib/postscript/model/operators.rb +89 -0
- data/lib/postscript/model/program.rb +68 -0
- data/lib/postscript/model/token.rb +43 -0
- data/lib/postscript/model.rb +17 -0
- data/lib/postscript/serializer.rb +325 -0
- data/lib/postscript/source/ast_builder.rb +308 -0
- data/lib/postscript/source/lexer.rb +322 -0
- data/lib/postscript/source/operand_stack.rb +55 -0
- data/lib/postscript/source.rb +21 -0
- data/lib/postscript/version.rb +5 -0
- data/lib/postscript.rb +33 -0
- data/postscript.gemspec +37 -0
- metadata +91 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscript
|
|
4
|
+
module Source
|
|
5
|
+
# Comment-aware PS lexer.
|
|
6
|
+
#
|
|
7
|
+
# Distinguishes +#+ line comments from +%+ inside string literals,
|
|
8
|
+
# captures DSC comments (lines beginning with +%%+), and tags every
|
|
9
|
+
# token with its source position (line, column).
|
|
10
|
+
#
|
|
11
|
+
# The legacy Tokenizer stripped comments with a global
|
|
12
|
+
# +gsub(/%[^\n\r]*/, " ")+ before lexing, which corrupted +%+ chars
|
|
13
|
+
# inside string literals. This implementation walks the source as a
|
|
14
|
+
# state machine so +%+ inside (...) or <...> survives.
|
|
15
|
+
class Lexer
|
|
16
|
+
attr_reader :source, :position, :line, :column
|
|
17
|
+
|
|
18
|
+
def initialize(source)
|
|
19
|
+
@source = source.to_s
|
|
20
|
+
@position = 0
|
|
21
|
+
@line = 1
|
|
22
|
+
@column = 1
|
|
23
|
+
@tokens = []
|
|
24
|
+
@state = :top
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def tokenize
|
|
28
|
+
until eos?
|
|
29
|
+
case @state
|
|
30
|
+
when :top then scan_top
|
|
31
|
+
when :string then scan_string_body
|
|
32
|
+
when :hexstring then scan_hexstring_body
|
|
33
|
+
when :comment then scan_comment_body
|
|
34
|
+
when :dsc then scan_dsc_body
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
@tokens.freeze
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.tokenize(source)
|
|
41
|
+
new(source).tokenize
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def eos? = @position >= @source.bytesize
|
|
47
|
+
|
|
48
|
+
def peek(offset = 0)
|
|
49
|
+
@source.getbyte(@position + offset)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def advance
|
|
53
|
+
byte = @source.getbyte(@position)
|
|
54
|
+
@position += 1
|
|
55
|
+
if byte == 10 # \n
|
|
56
|
+
@line += 1
|
|
57
|
+
@column = 1
|
|
58
|
+
else
|
|
59
|
+
@column += 1
|
|
60
|
+
end
|
|
61
|
+
byte
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def scan_top
|
|
65
|
+
skip_whitespace and return
|
|
66
|
+
byte = peek
|
|
67
|
+
return if byte.nil?
|
|
68
|
+
|
|
69
|
+
char = byte.chr
|
|
70
|
+
|
|
71
|
+
case char
|
|
72
|
+
when "%" then start_dsc_or_comment
|
|
73
|
+
when "(" then start_string
|
|
74
|
+
when "<"
|
|
75
|
+
if peek(1) == 60 # <<
|
|
76
|
+
advance
|
|
77
|
+
advance
|
|
78
|
+
emit(:dict_open, "<<")
|
|
79
|
+
else
|
|
80
|
+
start_hexstring
|
|
81
|
+
end
|
|
82
|
+
when ">" then maybe_close_dict
|
|
83
|
+
when "{" then advance and emit(:proc_open, "{")
|
|
84
|
+
when "}" then advance and emit(:proc_close, "}")
|
|
85
|
+
when "[" then advance and emit(:array_open, "[")
|
|
86
|
+
when "]" then advance and emit(:array_close, "]")
|
|
87
|
+
when "/", "\\"
|
|
88
|
+
start_name_with_slash(char)
|
|
89
|
+
else
|
|
90
|
+
scan_word_or_number
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def skip_whitespace
|
|
95
|
+
consumed = false
|
|
96
|
+
until eos?
|
|
97
|
+
byte = peek
|
|
98
|
+
break unless whitespace_byte?(byte)
|
|
99
|
+
|
|
100
|
+
advance
|
|
101
|
+
consumed = true
|
|
102
|
+
end
|
|
103
|
+
consumed
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def whitespace_byte?(byte)
|
|
107
|
+
byte && [32, 9, 10, 13, 12, 11, 0].include?(byte)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def start_dsc_or_comment
|
|
111
|
+
advance # consume first %
|
|
112
|
+
if peek == 37 # second %
|
|
113
|
+
advance # consume second %
|
|
114
|
+
@state = :dsc
|
|
115
|
+
else
|
|
116
|
+
@state = :comment
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def scan_dsc_body
|
|
121
|
+
start_pos = @position
|
|
122
|
+
start_line = @line
|
|
123
|
+
start_col = @column
|
|
124
|
+
until eos? || @source.getbyte(@position) == 10
|
|
125
|
+
advance
|
|
126
|
+
end
|
|
127
|
+
text = @source.byteslice(start_pos, @position - start_pos)
|
|
128
|
+
@tokens << Model::Token.new(:dsc, text.chomp, line: start_line, column: start_col)
|
|
129
|
+
@state = :top
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def scan_comment_body
|
|
133
|
+
until eos? || @source.getbyte(@position) == 10
|
|
134
|
+
advance
|
|
135
|
+
end
|
|
136
|
+
@state = :top
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def start_string
|
|
140
|
+
start_line = @line
|
|
141
|
+
start_col = @column
|
|
142
|
+
advance # consume (
|
|
143
|
+
@string_start = { line: start_line, column: start_col, bytes: +"" }
|
|
144
|
+
@string_depth = 1
|
|
145
|
+
@state = :string
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def scan_string_body
|
|
149
|
+
until eos?
|
|
150
|
+
byte = @source.getbyte(@position)
|
|
151
|
+
case byte
|
|
152
|
+
when 92 # backslash
|
|
153
|
+
advance
|
|
154
|
+
handle_escape
|
|
155
|
+
when 40 # (
|
|
156
|
+
advance
|
|
157
|
+
@string_depth += 1
|
|
158
|
+
@string_start[:bytes] << "("
|
|
159
|
+
when 41 # )
|
|
160
|
+
advance
|
|
161
|
+
@string_depth -= 1
|
|
162
|
+
if @string_depth.zero?
|
|
163
|
+
emit_string
|
|
164
|
+
return
|
|
165
|
+
end
|
|
166
|
+
@string_start[:bytes] << ")"
|
|
167
|
+
else
|
|
168
|
+
advance
|
|
169
|
+
@string_start[:bytes] << byte.chr
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
raise LexError.new("unterminated string literal",
|
|
173
|
+
source_position: [@string_start[:line], @string_start[:column]])
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def handle_escape
|
|
177
|
+
byte = peek
|
|
178
|
+
return if byte.nil?
|
|
179
|
+
|
|
180
|
+
char = byte.chr
|
|
181
|
+
replacement =
|
|
182
|
+
case char
|
|
183
|
+
when "n" then "\n"
|
|
184
|
+
when "r" then "\r"
|
|
185
|
+
when "t" then "\t"
|
|
186
|
+
when "b" then "\b"
|
|
187
|
+
when "f" then "\f"
|
|
188
|
+
when "\\" then "\\"
|
|
189
|
+
when "(" then "("
|
|
190
|
+
when ")" then ")"
|
|
191
|
+
when "0".."7"
|
|
192
|
+
consume_octal_escape
|
|
193
|
+
else
|
|
194
|
+
char
|
|
195
|
+
end
|
|
196
|
+
if replacement.is_a?(String)
|
|
197
|
+
advance
|
|
198
|
+
@string_start[:bytes] << replacement
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def consume_octal_escape
|
|
203
|
+
digits = +""
|
|
204
|
+
3.times do
|
|
205
|
+
byte = peek
|
|
206
|
+
break unless byte && (byte >= 48 && byte <= 55) # 0..7
|
|
207
|
+
|
|
208
|
+
digits << byte.chr
|
|
209
|
+
advance
|
|
210
|
+
end
|
|
211
|
+
code = digits.to_i(8) & 0xFF
|
|
212
|
+
@string_start[:bytes] << code.chr
|
|
213
|
+
nil
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def emit_string
|
|
217
|
+
@tokens << Model::Token.new(:string, @string_start[:bytes],
|
|
218
|
+
line: @string_start[:line], column: @string_start[:column])
|
|
219
|
+
@string_start = nil
|
|
220
|
+
@state = :top
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def start_hexstring
|
|
224
|
+
start_line = @line
|
|
225
|
+
start_col = @column
|
|
226
|
+
advance # consume <
|
|
227
|
+
@hex_start = { line: start_line, column: start_col, bytes: +"" }
|
|
228
|
+
@state = :hexstring
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def scan_hexstring_body
|
|
232
|
+
until eos?
|
|
233
|
+
byte = @source.getbyte(@position)
|
|
234
|
+
case byte
|
|
235
|
+
when 62 # >
|
|
236
|
+
advance
|
|
237
|
+
emit_hexstring
|
|
238
|
+
return
|
|
239
|
+
when 32, 9, 10, 13, 12
|
|
240
|
+
advance
|
|
241
|
+
else
|
|
242
|
+
advance
|
|
243
|
+
@hex_start[:bytes] << byte.chr
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
raise LexError.new("unterminated hex string literal",
|
|
247
|
+
source_position: [@hex_start[:line], @hex_start[:column]])
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def emit_hexstring
|
|
251
|
+
hex = @hex_start[:bytes].delete("^0-9a-fA-F")
|
|
252
|
+
@tokens << Model::Token.new(:hexstring, hex,
|
|
253
|
+
line: @hex_start[:line], column: @hex_start[:column])
|
|
254
|
+
@hex_start = nil
|
|
255
|
+
@state = :top
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def maybe_close_dict
|
|
259
|
+
if peek(1) == 62 # >>
|
|
260
|
+
advance
|
|
261
|
+
advance
|
|
262
|
+
emit(:dict_close, ">>")
|
|
263
|
+
else
|
|
264
|
+
# Lone '>' is not a valid token in PS; skip and warn via token.
|
|
265
|
+
advance
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def start_name_with_slash(prefix)
|
|
270
|
+
start_line = @line
|
|
271
|
+
start_col = @column
|
|
272
|
+
advance
|
|
273
|
+
bytes = +""
|
|
274
|
+
until eos?
|
|
275
|
+
byte = peek
|
|
276
|
+
break if byte.nil? || whitespace_byte?(byte) || delimiter_byte?(byte)
|
|
277
|
+
|
|
278
|
+
bytes << byte.chr
|
|
279
|
+
advance
|
|
280
|
+
end
|
|
281
|
+
@tokens << Model::Token.new(:name, bytes, line: start_line, column: start_col, literal: true)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def delimiter_byte?(byte)
|
|
285
|
+
return false unless byte
|
|
286
|
+
|
|
287
|
+
char = byte.chr
|
|
288
|
+
"%()<>{}/[]".include?(char)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def scan_word_or_number
|
|
292
|
+
start_line = @line
|
|
293
|
+
start_col = @column
|
|
294
|
+
bytes = +""
|
|
295
|
+
until eos?
|
|
296
|
+
byte = peek
|
|
297
|
+
break if byte.nil? || whitespace_byte?(byte) || delimiter_byte?(byte)
|
|
298
|
+
|
|
299
|
+
bytes << byte.chr
|
|
300
|
+
advance
|
|
301
|
+
end
|
|
302
|
+
emit_word(bytes, start_line, start_col)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def emit_word(bytes, line, col)
|
|
306
|
+
type =
|
|
307
|
+
if NUMBER_RE.match?(bytes)
|
|
308
|
+
:number
|
|
309
|
+
else
|
|
310
|
+
:operator
|
|
311
|
+
end
|
|
312
|
+
@tokens << Model::Token.new(type, bytes, line: line, column: col)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
NUMBER_RE = /\A[-+]?(?:\d+\.\d*|\.\d+|\d+)(?:[eE][-+]?\d+)?\z/.freeze
|
|
316
|
+
|
|
317
|
+
def emit(type, value)
|
|
318
|
+
@tokens << Model::Token.new(type, value, line: @line, column: @column)
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscript
|
|
4
|
+
module Source
|
|
5
|
+
# Parse-time operand stack. Wraps an Array with type-aware pops.
|
|
6
|
+
class OperandStack
|
|
7
|
+
def initialize
|
|
8
|
+
@items = []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def push(value)
|
|
12
|
+
@items.push(value)
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
alias << push
|
|
16
|
+
|
|
17
|
+
def pop
|
|
18
|
+
return Model::Computed.new(operator_keyword: "(missing)") if @items.empty?
|
|
19
|
+
|
|
20
|
+
@items.pop
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def pop_number(default_on_empty: nil)
|
|
24
|
+
return default_on_empty if @items.empty? && !default_on_empty.nil?
|
|
25
|
+
|
|
26
|
+
value = pop
|
|
27
|
+
return value.to_f if value.is_a?(Model::Literals::Number)
|
|
28
|
+
return value.to_f if value.is_a?(Numeric)
|
|
29
|
+
|
|
30
|
+
# Parse-time fallback: a Name (e.g. /x defined via def) or a
|
|
31
|
+
# Computed sentinel (e.g. result of an arithmetic op) cannot
|
|
32
|
+
# be evaluated to a number yet. Return 0 so the operator
|
|
33
|
+
# instance can be built; the visitor will re-resolve at
|
|
34
|
+
# runtime if the program is executed.
|
|
35
|
+
0.0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def peek(offset = 0)
|
|
39
|
+
@items[-1 - offset]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def length
|
|
43
|
+
@items.length
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def empty?
|
|
47
|
+
@items.empty?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_a
|
|
51
|
+
@items.dup
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscript
|
|
4
|
+
# Source-reading layer: PS source text -> Model::Program.
|
|
5
|
+
#
|
|
6
|
+
# Lexer produces an array of Model::Token; AstBuilder walks tokens and
|
|
7
|
+
# emits a typed Model::Program. Errors are raised as Postscript::LexError
|
|
8
|
+
# and Postscript::SyntaxError respectively.
|
|
9
|
+
module Source
|
|
10
|
+
autoload :Lexer, "postscript/source/lexer"
|
|
11
|
+
autoload :AstBuilder, "postscript/source/ast_builder"
|
|
12
|
+
autoload :OperandStack, "postscript/source/operand_stack"
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# One-shot convenience: PS source -> Model::Program.
|
|
17
|
+
def parse(source)
|
|
18
|
+
AstBuilder.build(Lexer.tokenize(source))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/postscript.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscript
|
|
4
|
+
autoload :VERSION, "postscript/version"
|
|
5
|
+
|
|
6
|
+
# Errors
|
|
7
|
+
autoload :Error, "postscript/errors"
|
|
8
|
+
autoload :ParseError, "postscript/errors"
|
|
9
|
+
autoload :LexError, "postscript/errors"
|
|
10
|
+
autoload :SyntaxError, "postscript/errors"
|
|
11
|
+
autoload :RenderError, "postscript/errors"
|
|
12
|
+
autoload :StackUnderflowError, "postscript/errors"
|
|
13
|
+
autoload :UndefinedOperatorError, "postscript/errors"
|
|
14
|
+
autoload :RecursionLimitError, "postscript/errors"
|
|
15
|
+
autoload :SizeLimitError, "postscript/errors"
|
|
16
|
+
autoload :SerializeError, "postscript/errors"
|
|
17
|
+
autoload :ExitSignal, "postscript/errors"
|
|
18
|
+
autoload :QuitSignal, "postscript/errors"
|
|
19
|
+
|
|
20
|
+
# General-purpose value types
|
|
21
|
+
autoload :FormatNumber, "postscript/format_number"
|
|
22
|
+
autoload :Matrix, "postscript/matrix"
|
|
23
|
+
autoload :Color, "postscript/color"
|
|
24
|
+
|
|
25
|
+
# PS source-reading layer
|
|
26
|
+
autoload :Source, "postscript/source"
|
|
27
|
+
|
|
28
|
+
# Typed PS domain model
|
|
29
|
+
autoload :Model, "postscript/model"
|
|
30
|
+
|
|
31
|
+
# PS source serializer
|
|
32
|
+
autoload :Serializer, "postscript/serializer"
|
|
33
|
+
end
|
data/postscript.gemspec
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/postscript/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "postscript"
|
|
7
|
+
spec.version = Postscript::VERSION
|
|
8
|
+
spec.authors = ["Ribose Inc."]
|
|
9
|
+
spec.email = ["open.source@ribose.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Pure Ruby PostScript (PS) / EPS parser, domain model, and serializer"
|
|
12
|
+
spec.description = <<~HEREDOC
|
|
13
|
+
Postscript is a pure-Ruby PostScript (PS) / EPS parser, typed
|
|
14
|
+
domain model, and serializer. It is the lower layer of the
|
|
15
|
+
postsvg converter and is independently reusable for any tool
|
|
16
|
+
that needs to read, write, or transform PostScript source.
|
|
17
|
+
HEREDOC
|
|
18
|
+
|
|
19
|
+
spec.homepage = "https://github.com/claricle/postscript"
|
|
20
|
+
spec.license = "BSD-2-Clause"
|
|
21
|
+
spec.required_ruby_version = ">= 3.0.0"
|
|
22
|
+
|
|
23
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
24
|
+
spec.metadata["source_code_uri"] = "https://github.com/claricle/postscript"
|
|
25
|
+
spec.metadata["changelog_uri"] = "https://github.com/claricle/postscript/blob/main/CHANGELOG.md"
|
|
26
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/claricle/postscript/issues"
|
|
27
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
28
|
+
|
|
29
|
+
spec.files = Dir.chdir(__dir__) do
|
|
30
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
31
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
spec.bindir = "exe"
|
|
35
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
36
|
+
spec.require_paths = ["lib"]
|
|
37
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: postscript
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ribose Inc.
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: |
|
|
13
|
+
Postscript is a pure-Ruby PostScript (PS) / EPS parser, typed
|
|
14
|
+
domain model, and serializer. It is the lower layer of the
|
|
15
|
+
postsvg converter and is independently reusable for any tool
|
|
16
|
+
that needs to read, write, or transform PostScript source.
|
|
17
|
+
email:
|
|
18
|
+
- open.source@ribose.com
|
|
19
|
+
executables: []
|
|
20
|
+
extensions: []
|
|
21
|
+
extra_rdoc_files: []
|
|
22
|
+
files:
|
|
23
|
+
- ".rspec"
|
|
24
|
+
- Gemfile
|
|
25
|
+
- README.adoc
|
|
26
|
+
- Rakefile
|
|
27
|
+
- lib/postscript.rb
|
|
28
|
+
- lib/postscript/color.rb
|
|
29
|
+
- lib/postscript/errors.rb
|
|
30
|
+
- lib/postscript/format_number.rb
|
|
31
|
+
- lib/postscript/matrix.rb
|
|
32
|
+
- lib/postscript/model.rb
|
|
33
|
+
- lib/postscript/model/literals.rb
|
|
34
|
+
- lib/postscript/model/literals/array.rb
|
|
35
|
+
- lib/postscript/model/literals/dictionary.rb
|
|
36
|
+
- lib/postscript/model/literals/hex.rb
|
|
37
|
+
- lib/postscript/model/literals/name.rb
|
|
38
|
+
- lib/postscript/model/literals/number.rb
|
|
39
|
+
- lib/postscript/model/literals/procedure.rb
|
|
40
|
+
- lib/postscript/model/literals/string.rb
|
|
41
|
+
- lib/postscript/model/operator.rb
|
|
42
|
+
- lib/postscript/model/operators.rb
|
|
43
|
+
- lib/postscript/model/operators/arithmetic.rb
|
|
44
|
+
- lib/postscript/model/operators/boolean.rb
|
|
45
|
+
- lib/postscript/model/operators/color.rb
|
|
46
|
+
- lib/postscript/model/operators/container.rb
|
|
47
|
+
- lib/postscript/model/operators/control_flow.rb
|
|
48
|
+
- lib/postscript/model/operators/device.rb
|
|
49
|
+
- lib/postscript/model/operators/dictionary.rb
|
|
50
|
+
- lib/postscript/model/operators/font.rb
|
|
51
|
+
- lib/postscript/model/operators/graphics_state.rb
|
|
52
|
+
- lib/postscript/model/operators/painting.rb
|
|
53
|
+
- lib/postscript/model/operators/path.rb
|
|
54
|
+
- lib/postscript/model/operators/stack.rb
|
|
55
|
+
- lib/postscript/model/operators/transformations.rb
|
|
56
|
+
- lib/postscript/model/program.rb
|
|
57
|
+
- lib/postscript/model/token.rb
|
|
58
|
+
- lib/postscript/serializer.rb
|
|
59
|
+
- lib/postscript/source.rb
|
|
60
|
+
- lib/postscript/source/ast_builder.rb
|
|
61
|
+
- lib/postscript/source/lexer.rb
|
|
62
|
+
- lib/postscript/source/operand_stack.rb
|
|
63
|
+
- lib/postscript/version.rb
|
|
64
|
+
- postscript.gemspec
|
|
65
|
+
homepage: https://github.com/claricle/postscript
|
|
66
|
+
licenses:
|
|
67
|
+
- BSD-2-Clause
|
|
68
|
+
metadata:
|
|
69
|
+
homepage_uri: https://github.com/claricle/postscript
|
|
70
|
+
source_code_uri: https://github.com/claricle/postscript
|
|
71
|
+
changelog_uri: https://github.com/claricle/postscript/blob/main/CHANGELOG.md
|
|
72
|
+
bug_tracker_uri: https://github.com/claricle/postscript/issues
|
|
73
|
+
rubygems_mfa_required: 'true'
|
|
74
|
+
rdoc_options: []
|
|
75
|
+
require_paths:
|
|
76
|
+
- lib
|
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: 3.0.0
|
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - ">="
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '0'
|
|
87
|
+
requirements: []
|
|
88
|
+
rubygems_version: 4.0.16
|
|
89
|
+
specification_version: 4
|
|
90
|
+
summary: Pure Ruby PostScript (PS) / EPS parser, domain model, and serializer
|
|
91
|
+
test_files: []
|