petit-felix 0.1.4 → 0.1.6

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.
@@ -0,0 +1,300 @@
1
+ require "prawn"
2
+ require 'fileutils'
3
+ require "prawndown-ext"
4
+ require "felix/metadata"
5
+ require "felix/error"
6
+ require "worker/pdf_writer"
7
+ require "worker/templater/methods"
8
+ require "worker/templater/error"
9
+ require "worker/templater/validation"
10
+ require "worker/templater/font"
11
+ require "eqn"
12
+
13
+ ## Prawn PDF writer that inputs template files
14
+
15
+ module PetitFelix
16
+ module Worker
17
+
18
+ class TemplatePDFWriter < PetitFelix::Worker::DefaultPDFWriter
19
+
20
+ # Highest a stack is allowed to be
21
+ MAX_STACK = 1024
22
+
23
+ ## Functions
24
+
25
+ def init_values options, pdf
26
+
27
+ @variables = {}
28
+
29
+ @options = Marshal.load(Marshal.dump(options))
30
+
31
+ # Options to use for method calls and stuff
32
+ # Updated every time a template is loaded
33
+ @metaoptions = {}
34
+ @pdf = pdf
35
+
36
+ # stack referencing current running commands
37
+ @command_stack = []
38
+
39
+ # stack referencing current program counter
40
+ @counter_stack = []
41
+
42
+ # stack referencing current running template
43
+ # currently unused, will use when stitching
44
+ # external templates together.
45
+ @template_stack = []
46
+
47
+ # Templates
48
+ @template = {}
49
+
50
+ # prints errors
51
+ @error_printer = PetitFelix::Error.new
52
+
53
+ # For variables of errors
54
+ @error_param = {}
55
+
56
+ set_variables
57
+ end
58
+
59
+ def set_variables
60
+
61
+ @metaoptions.keys.each do |key|
62
+
63
+ @variables[key] = @metaoptions[key]
64
+
65
+ end
66
+
67
+ if @variables.key? :markdown_metadata
68
+
69
+ @variables[:markdown_metadata].keys.each do |meta|
70
+
71
+ @variables[meta] = @variables[:markdown_metadata][meta]
72
+
73
+ end
74
+
75
+ end
76
+
77
+ ## add additional functional stuff
78
+ @variables["cursor"] = @pdf.cursor
79
+ @variables["bounds_height"] = @pdf.bounds.height
80
+ @variables["bounds_width"] = @pdf.bounds.width
81
+ @variables["pages"] = @pdf.page_count
82
+
83
+ # the currently loaded markdown file
84
+ @variables["loaded_markdown"] = {}
85
+
86
+ end
87
+
88
+ def replace_variables args
89
+
90
+ args.keys.each do |arg|
91
+
92
+ if args[arg].instance_of? String
93
+
94
+ args[arg] = replace_variable args[arg]
95
+
96
+ end
97
+ end
98
+
99
+ args
100
+
101
+ end
102
+
103
+ def replace_variable string
104
+
105
+ @variables.keys.each do |key|
106
+ string = string.gsub("${#{key}}", @variables[key].to_s)
107
+ end
108
+
109
+ string
110
+ end
111
+
112
+ ## Parsing template stuff
113
+
114
+ # Reads template from JSON
115
+ # Format: Array of objects where
116
+ # each object has command and set of args
117
+ def read_template
118
+
119
+ if @options.key? "template"
120
+
121
+ if File.file? @options["template"]
122
+
123
+ obj = JSON.parse(File.read(@options["template"]), symbolize_names: true)
124
+
125
+ default_options = obj[:default_variables].transform_keys!(&:to_s)
126
+
127
+ if default_options.nil?
128
+ default_options = {}
129
+ end
130
+
131
+ @fonts = {}
132
+
133
+ @metaoptions = default_options.merge @options
134
+
135
+ set_variables
136
+
137
+ if obj.key? :fonts
138
+
139
+ @fonts = obj[:fonts]
140
+
141
+ end
142
+
143
+ add_fonts
144
+
145
+ @template = {
146
+ "main" => obj[:definition]
147
+ }
148
+
149
+ # Runs the main function as entry point of the template
150
+ @template_stack.push "main"
151
+ result = execute_function "main", "main", self
152
+
153
+ if result[0] != 0
154
+
155
+ print_error result[0], result[1]
156
+ end
157
+
158
+ else
159
+
160
+ @error_param["arg"] = @options["template"].to_s
161
+ print_error 15, -1
162
+
163
+ end
164
+
165
+ else
166
+
167
+ print_error 16, -1
168
+
169
+ end
170
+ end
171
+
172
+ def execute_function template_id, function_id, obj
173
+
174
+ definition = nil
175
+
176
+ if !@template.key? template_id
177
+
178
+ @error_param["arg"] = template_id.to_s
179
+ # Fails because template ID not found.
180
+ return [5, -1]
181
+
182
+ else
183
+
184
+ if !@template[template_id].key? function_id.to_sym
185
+
186
+ @error_param["arg"] = function_id.to_s
187
+ # Fails because template function ID not found.
188
+ return [6, -1]
189
+
190
+ else
191
+
192
+ definition = Marshal.load(Marshal.dump(@template[template_id][function_id.to_sym]))
193
+
194
+ end
195
+
196
+ end
197
+
198
+ if definition.instance_of? Array
199
+
200
+ counter = 0
201
+
202
+ @counter_stack.push counter
203
+
204
+ for index in counter ... definition.size
205
+
206
+ # executes the command
207
+ line = definition[counter]
208
+
209
+ set_variables
210
+
211
+ command = ""
212
+
213
+ if line.key? :cmd
214
+
215
+ command = line[:cmd].to_sym
216
+
217
+ end
218
+
219
+ if line.key? :command
220
+
221
+ command = line[:command].to_sym
222
+
223
+ end
224
+
225
+ args = {
226
+ "LINE_NUMBER" => counter
227
+ }
228
+
229
+ if line.key? :args
230
+
231
+ args = line[:args]
232
+
233
+ end
234
+
235
+ begin
236
+
237
+ args = replace_variables(args)
238
+
239
+ rescue => error
240
+
241
+ print "\n"
242
+ print error
243
+ print "\n"
244
+ print "Error rendering variables!\n"
245
+
246
+ end
247
+
248
+ if !command.empty?
249
+
250
+ if COMMAND.keys.include? command
251
+
252
+ @command_stack.push definition
253
+
254
+ if @command_stack.count > 1024
255
+ # Failed because of stack overflow
256
+ return [4, counter]
257
+
258
+ end
259
+
260
+ comm = COMMAND[command].call obj, args
261
+
262
+ @counter_stack[-1] = counter
263
+ counter += 1
264
+
265
+ # something about command execution failed
266
+ if comm != 0
267
+
268
+ return [comm, counter]
269
+
270
+ end
271
+
272
+ @command_stack.pop
273
+ else
274
+ # failed because command not found
275
+ return [3, counter]
276
+
277
+ end
278
+
279
+ else
280
+ # failed because no command defined
281
+ return [2, -1]
282
+
283
+ end
284
+ end
285
+
286
+ @counter_stack.pop()
287
+
288
+ # Returns 0 if successful
289
+ return [0, counter]
290
+
291
+ end
292
+
293
+ # Failed because malformed command list
294
+ return [1, -1]
295
+
296
+ end
297
+
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,90 @@
1
+ ## Error handling stuff for TemplatePDFWriter
2
+
3
+ module PetitFelix
4
+ module Worker
5
+
6
+ class TemplatePDFWriter < PetitFelix::Worker::DefaultPDFWriter
7
+
8
+ # error count: 16
9
+
10
+ ERROR_CODES = [
11
+ "OK",
12
+ "Malformed command list.",
13
+ "No command defined. Use \"com\" or \"command\" to define commands.",
14
+ "Command not found.",
15
+ "Stack overflow.",
16
+ "Template ID \"{{arg}}\" not found.",
17
+ "Template method \"{{arg}}\" not found.",
18
+ "\"{{arg}}\" argument not defined.",
19
+ "Expression \"{{arg}}\" does not result in boolean result.",
20
+ "Expression \"{{arg}}\" cannot be evaluated.",
21
+ "File \"{{arg}}\" not found.",
22
+ "Not a valid position.",
23
+ "\"at\" (Array) argument not defined.",
24
+ "\"{{arg}}\" is not an array.",
25
+ "Image \"{{arg}}\" not found.",
26
+ "Template file \"{{arg}}\" not found.",
27
+ "\"template\" option not defined. No template file can be loaded."
28
+ ]
29
+
30
+ ## Error display
31
+
32
+ def error_replace_string error
33
+
34
+ @error_param.keys.each do |key|
35
+
36
+ error = error.gsub "{{#{key}}}", @error_param[key]
37
+
38
+ end
39
+
40
+ error
41
+ end
42
+
43
+ def print_error error_code, line
44
+
45
+ if error_code > -1 && error_code < ERROR_CODES.count
46
+
47
+ @error_printer.print_err "Error reading template. #{error_replace_string( ERROR_CODES[error_code])}"
48
+
49
+ else
50
+
51
+ @error_printer.print_err "Error reading template. General template processing error occured."
52
+
53
+ end
54
+
55
+ print "Error code: #{error_code}"
56
+
57
+ print "\n\n"
58
+ print "Processing markdown file: #{@metaoptions["filename"]}"
59
+ print "\n\n"
60
+
61
+ stack_rv = @command_stack.reverse
62
+
63
+ if line >= 0 && !stack_rv.empty?
64
+
65
+ print "\n\nCurrent line:\n"
66
+ print stack_rv[0][line]
67
+
68
+ print "\n\nCurrent Stack:"
69
+ test_arr = *(0..[19,@command_stack.count-1].min)
70
+ test_arr.each do | i |
71
+
72
+ command_obj = stack_rv[i]
73
+
74
+ line_edit = command_obj[0..@counter_stack[i]+1]
75
+
76
+ print "\n"
77
+ print "Line: #{line_edit.count}: "
78
+ print line_edit[-1]
79
+
80
+ end
81
+ end
82
+
83
+ print "\n"
84
+
85
+ return error_code
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,59 @@
1
+ ## font handling stuff for TemplatePDFWriter
2
+
3
+ module PetitFelix
4
+ module Worker
5
+
6
+ class TemplatePDFWriter < PetitFelix::Worker::DefaultPDFWriter
7
+
8
+ # Adds a font to the pdf document
9
+ def add_font font, font_name
10
+
11
+ if font.key?(:normal)
12
+
13
+ if font.key?(:italic)
14
+
15
+ font[:italic] = font[:normal]
16
+
17
+ end
18
+
19
+ if font.key?(:bold)
20
+
21
+ font[:bold] = font[:normal]
22
+
23
+ end
24
+
25
+ if font.key?(:bold_italic)
26
+
27
+ font[:bold_italic] = font[:normal]
28
+
29
+ end
30
+
31
+ font.keys.each do |key|
32
+
33
+ font[key] = replace_variable font[key]
34
+
35
+ end
36
+
37
+ font_families.update(font_name => font)
38
+
39
+ end
40
+
41
+ end
42
+
43
+ def add_fonts
44
+
45
+ font_families.clear
46
+
47
+ fonts = Marshal.load(Marshal.dump(@fonts))
48
+
49
+ fonts.keys.each do |font|
50
+
51
+ add_font fonts[font], font.to_s
52
+
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
59
+ end