ppr 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ppr/keyword_searcher.rb +15 -14
- data/lib/ppr/ppr_core.rb +96 -86
- data/lib/ppr/safer_generator.rb +14 -14
- data/lib/ppr/version.rb +1 -1
- data/lib/ppr.rb +3 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c406b99cf38bd9244827b268c16a331b41f752d
|
4
|
+
data.tar.gz: 213074c919132f292e4edff0e0389c537f3b5349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e908bea3122b499442c72844fa5675a0cf58626dc15d2b2437d574f7536e2f6c0861c89d242de5242a97076e4c0d37bf86b2f21a8f2573820b8ea48a1c0479a
|
7
|
+
data.tar.gz: 412ca44eee6324788cd342ff83b75502bb133bb10f933814e403e3933137bb12fd0939a9fe9cbfb340b02811ccb61f9b3a7c6b2c8ab5c99e4eca4de1e15aacd7
|
data/lib/ppr/keyword_searcher.rb
CHANGED
@@ -2,11 +2,12 @@
|
|
2
2
|
## Map class for searching keywords in a text. ##
|
3
3
|
######################################################################
|
4
4
|
|
5
|
-
|
5
|
+
##
|
6
|
+
# Tool for looking for keywords within a string.
|
6
7
|
class KeywordSearcher
|
7
8
|
|
8
|
-
|
9
|
-
#
|
9
|
+
# Creates a new keyword searcher, where words are between +seperators+
|
10
|
+
# regular expressions.
|
10
11
|
def initialize(separator = "")
|
11
12
|
# Checks and set the separator.
|
12
13
|
@separator = Regexp.new(separator).to_s
|
@@ -25,7 +26,7 @@ class KeywordSearcher
|
|
25
26
|
return self
|
26
27
|
end
|
27
28
|
|
28
|
-
|
29
|
+
# Adds a +keyword+ to the searcher associated with an +object+.
|
29
30
|
def []=(keyword,object)
|
30
31
|
# Ensure the keyword is a valid string.
|
31
32
|
keyword = keyword.to_str
|
@@ -41,17 +42,17 @@ class KeywordSearcher
|
|
41
42
|
@keyword_extract = Regexp.new(@keywords.join("|"))
|
42
43
|
end
|
43
44
|
|
44
|
-
|
45
|
+
# Get the object corresponding to +keyword+.
|
45
46
|
def [](keyword)
|
46
47
|
return @map[keyword.to_s]
|
47
48
|
end
|
48
49
|
|
49
|
-
|
50
|
-
#
|
50
|
+
# Search a keyword inside a +text+ and return the corresponding object
|
51
|
+
# if found with the range in the string where it has been found.
|
51
52
|
#
|
52
|
-
#
|
53
|
+
# If a keyword is in +skip+ it s ignored.
|
53
54
|
#
|
54
|
-
#
|
55
|
+
# NOTE: the first found object is returned.
|
55
56
|
def find(text,skip = [])
|
56
57
|
# print "skip=#{skip} @keywords=#{@keywords}\n"
|
57
58
|
# Compute the regular expression for finding the keywords.
|
@@ -78,13 +79,13 @@ class KeywordSearcher
|
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
|
-
#
|
83
|
-
#
|
82
|
+
# Search each keyword inside a +text+ and apply the block on the
|
83
|
+
# corresponding objects if found with the range in the string where it
|
84
|
+
# has been found.
|
84
85
|
#
|
85
|
-
#
|
86
|
+
# Returns an enumerator if no block is given.
|
86
87
|
#
|
87
|
-
#
|
88
|
+
# NOTE: keywords included into a longer one are ignored.
|
88
89
|
def each_in(text)
|
89
90
|
return to_enum(:each_in,text) unless block_given?
|
90
91
|
# Check and clone the text to avoid side effects.
|
data/lib/ppr/ppr_core.rb
CHANGED
@@ -8,38 +8,42 @@ require "ppr/keyword_searcher.rb"
|
|
8
8
|
module Ppr
|
9
9
|
|
10
10
|
|
11
|
-
##
|
11
|
+
##
|
12
|
+
# Converts a +name+ to an attribute symbol.
|
12
13
|
def Ppr.to_attribute(name)
|
13
14
|
name = name.to_s
|
14
15
|
(name.start_with?("@") ? name : "@" + name).to_sym
|
15
16
|
end
|
16
17
|
|
17
|
-
##
|
18
|
+
##
|
19
|
+
# Describes a storage for line number
|
18
20
|
class LineNumber < SimpleDelegator
|
19
|
-
|
21
|
+
# Creates a new storage for line number +num+.
|
20
22
|
def initialize(num)
|
21
23
|
super(num.to_i)
|
22
24
|
end
|
23
25
|
|
24
|
-
|
26
|
+
# Sets the line number to +num+.
|
25
27
|
def set(num)
|
26
28
|
__setobj__(num.to_i)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
32
|
|
31
|
-
##
|
33
|
+
##
|
34
|
+
# Describes a macro of the ruby preprocessor.
|
32
35
|
class Macro
|
33
36
|
|
34
|
-
|
37
|
+
# The name of the macro.
|
35
38
|
attr_reader :name
|
36
39
|
|
37
|
-
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
40
|
+
# Creates a new macro named +name+, starting at line number +num+,
|
41
|
+
# generated from preprocessor +ppr+ and with possible +variables+.
|
42
|
+
#
|
43
|
+
# Other parameters:
|
44
|
+
# +expand+:: used to redefine the expand operator
|
45
|
+
# +final+:: indicates that the result of the macro expansion
|
46
|
+
# shall not be preprocessed again.
|
43
47
|
def initialize(name, num, ppr, *variables, expand: ":<", final: true)
|
44
48
|
# Check and set the name.
|
45
49
|
@name = name.to_str
|
@@ -82,13 +86,13 @@ class Macro
|
|
82
86
|
#}}} This comment is just to avoid confusing the text editor.
|
83
87
|
end
|
84
88
|
|
85
|
-
|
86
|
-
#
|
89
|
+
# Tells if the maco expansion result is final (i.e., it is not preprocessed
|
90
|
+
# again) or not.
|
87
91
|
def final?
|
88
92
|
return @final
|
89
93
|
end
|
90
94
|
|
91
|
-
|
95
|
+
# Adds a +line+ to the macro.
|
92
96
|
def add(line)
|
93
97
|
# Process the line.
|
94
98
|
# Remove the ending newline if any.
|
@@ -96,13 +100,13 @@ class Macro
|
|
96
100
|
end
|
97
101
|
alias << add
|
98
102
|
|
99
|
-
|
103
|
+
# Checks if the macro is empty (no code line yet).
|
100
104
|
def empty?
|
101
105
|
return @lines.empty?
|
102
106
|
end
|
103
107
|
|
104
|
-
|
105
|
-
#
|
108
|
+
# Generates the code of the macro invoked at line number +i_number+
|
109
|
+
# using +values+ for the variables.
|
106
110
|
def generate(i_number,*values)
|
107
111
|
# First generate a variable for the resulting text.
|
108
112
|
result = "result_"
|
@@ -140,13 +144,13 @@ class Macro
|
|
140
144
|
|
141
145
|
# Methods used by apply for handling exception messages.
|
142
146
|
|
143
|
-
|
144
|
-
#
|
147
|
+
# Regular expression for identifying a line number inside an exception
|
148
|
+
# message.
|
145
149
|
E_NUMBER = /:[1-9][0-9]*:/
|
146
|
-
|
150
|
+
# Type of exception which correspond to a macro execution.
|
147
151
|
E_TYPE = /\(eval\)\s*/
|
148
152
|
|
149
|
-
|
153
|
+
# Tells if an exception +message+ includes a line number.
|
150
154
|
def e_number(message)
|
151
155
|
found = E_NUMBER.match(message)
|
152
156
|
if found then
|
@@ -158,12 +162,12 @@ class Macro
|
|
158
162
|
end
|
159
163
|
end
|
160
164
|
|
161
|
-
|
165
|
+
# Tells if an exception message is of a given +type+.
|
162
166
|
def e_type?(message,type)
|
163
167
|
return message =~ Regexp.new(type)
|
164
168
|
end
|
165
169
|
|
166
|
-
|
170
|
+
# Shifts the line number inside an exception +message+ by +sh+.
|
167
171
|
def e_shift_number(message,sh)
|
168
172
|
# Edit the message to fix the line number and raise then.
|
169
173
|
return message.gsub(E_NUMBER) { |str|
|
@@ -181,8 +185,8 @@ class Macro
|
|
181
185
|
}
|
182
186
|
end
|
183
187
|
|
184
|
-
|
185
|
-
#
|
188
|
+
# Update an exception +message+ to refer macro +name+ invoked at line
|
189
|
+
# number +i_number+ and adds a possible macro line +number+.
|
186
190
|
def Macro.e_message(name, message, i_number, number = nil)
|
187
191
|
result = "Ppr error (#{name}:#{i_number})"
|
188
192
|
result << ":#{number}: " if number
|
@@ -190,13 +194,13 @@ class Macro
|
|
190
194
|
return result
|
191
195
|
end
|
192
196
|
|
193
|
-
|
194
|
-
#
|
197
|
+
# Update an exception +message+ to refer the macro invoked at line number
|
198
|
+
# +i_number+ and adds a possible macro line +number+.
|
195
199
|
def e_message(message, i_number, number = nil)
|
196
200
|
Macro.e_message(@name,message,i_number,number)
|
197
201
|
end
|
198
202
|
|
199
|
-
|
203
|
+
# Applies the macro invoked at line number +i_number+ with +arguments+.
|
200
204
|
def apply(i_number,*arguments)
|
201
205
|
# Generate the code of the macro.
|
202
206
|
code = self.generate(i_number,*arguments)
|
@@ -261,20 +265,22 @@ class Macro
|
|
261
265
|
end
|
262
266
|
|
263
267
|
|
264
|
-
##
|
268
|
+
##
|
269
|
+
# Describes an assignment macro of the ruby preprocessor.
|
265
270
|
class Assign < Macro
|
266
|
-
|
267
|
-
#
|
268
|
-
#
|
269
|
-
#
|
271
|
+
# Creates a new assignment macro whose assigned variable is +var+,
|
272
|
+
# starting at line number +num+ generated from preprocessor +ppr+.
|
273
|
+
#
|
274
|
+
# Other parameters:
|
275
|
+
# +expand+:: redefines the expand operator string.
|
270
276
|
def initialize(name, num, ppr, expand: ":<")
|
271
277
|
super(name,num,ppr,expand: expand)
|
272
278
|
# Creates the attribute which will be assigned.
|
273
279
|
@var_sym = Ppr.to_attribute(name)
|
274
280
|
end
|
275
281
|
|
276
|
-
|
277
|
-
#
|
282
|
+
# Applies the macro invoked at line number +i_number+,
|
283
|
+
# its result in assigned to the class variable.
|
278
284
|
def apply(i_number)
|
279
285
|
# Expands the macro.
|
280
286
|
line = super(i_number)
|
@@ -285,17 +291,18 @@ class Assign < Macro
|
|
285
291
|
end
|
286
292
|
end
|
287
293
|
|
288
|
-
##
|
294
|
+
##
|
295
|
+
# Descibes an abstract class for loading or requiring files.
|
289
296
|
class LoadRequire < Macro
|
290
|
-
|
291
|
-
#
|
292
|
-
#
|
293
|
-
#
|
297
|
+
# Creates a new load or require macro starting at line number +num+
|
298
|
+
# generated from preprocessor +ppr+.
|
299
|
+
#
|
300
|
+
# The +expand+ strings be redefined through keyword arguments.
|
294
301
|
def initialize(num, ppr, expand: ":<")
|
295
302
|
super("",num,ppr,expand: expand)
|
296
303
|
end
|
297
304
|
|
298
|
-
|
305
|
+
# Loads and preprocess file +name+.
|
299
306
|
def loadm(name)
|
300
307
|
output = StringIO.new("")
|
301
308
|
# print "name=#{name}\n"
|
@@ -306,10 +313,11 @@ class LoadRequire < Macro
|
|
306
313
|
end
|
307
314
|
end
|
308
315
|
|
309
|
-
##
|
316
|
+
##
|
317
|
+
# Describes a macro loading and pasting a file into the current one.
|
310
318
|
class Load < LoadRequire
|
311
|
-
|
312
|
-
#
|
319
|
+
# Applies the macro invoked at line number +i_number+,
|
320
|
+
# its result is the name of the file to be loaded.
|
313
321
|
def apply(i_number)
|
314
322
|
# Expand the macro, its result is the name of the file to load.
|
315
323
|
name = super(i_number)
|
@@ -320,13 +328,13 @@ class Load < LoadRequire
|
|
320
328
|
end
|
321
329
|
end
|
322
330
|
|
323
|
-
|
324
|
-
#
|
331
|
+
# Describes a macro loading and pasting a file into the current one
|
332
|
+
# only if it has not already been loaded before.
|
325
333
|
class Require < LoadRequire
|
326
334
|
@@required = [] # The already required files.
|
327
335
|
|
328
|
-
|
329
|
-
#
|
336
|
+
# Applies the macro invoked at line number +i_number+,
|
337
|
+
# its result is the name of the file to be loaded if not already loaded.
|
330
338
|
def apply(i_number)
|
331
339
|
# Expand the macro, its result is the name of the file to load.
|
332
340
|
name = super(i_number)
|
@@ -343,36 +351,38 @@ class Require < LoadRequire
|
|
343
351
|
end
|
344
352
|
end
|
345
353
|
|
346
|
-
##
|
354
|
+
##
|
355
|
+
# Describes a conditional macro.
|
347
356
|
class If < Macro
|
348
|
-
|
349
|
-
#
|
350
|
-
#
|
351
|
-
#
|
357
|
+
# Creates a new load or require macro starting at line number +num+
|
358
|
+
# generated from preprocessor +ppr+.
|
359
|
+
#
|
360
|
+
# The +expand+ strings be redefined through keyword arguments.
|
352
361
|
def initialize(num, ppr, expand: ":<")
|
353
362
|
super("",num,ppr,expand: expand)
|
354
363
|
end
|
355
364
|
end
|
356
365
|
|
357
366
|
|
358
|
-
##
|
367
|
+
##
|
368
|
+
# Describes the ruby preprocessor.
|
359
369
|
#
|
360
|
-
#
|
370
|
+
# Usage:
|
361
371
|
# ppr = Ppr::Preprocessor.new(<some options>)
|
362
372
|
# ppr.preprocess(<some input stream>, <some output stream>)
|
363
373
|
class Preprocessor
|
364
374
|
|
365
|
-
|
366
|
-
#
|
367
|
-
#
|
368
|
-
#
|
369
|
-
#
|
370
|
-
#
|
371
|
-
#
|
372
|
-
#
|
375
|
+
# Creates a new preprocessor, where +apply+, +applyR+, +define+, +defineR+,
|
376
|
+
# +assign+, +loadm+, +requirem+, +ifm+, +elsem+ and +endm+ are the
|
377
|
+
# keywords defining the beginings and end of a macro definitions,
|
378
|
+
# and where +separator+ is the regular expression used for
|
379
|
+
# separating macro references to the remaining of the code, +expand+ is
|
380
|
+
# the string representing the expansion operator of the macro, +glue+ is
|
381
|
+
# string used for glueing a macro expension to the text,
|
382
|
+
# +escape+ is the escape character.
|
373
383
|
#
|
374
|
-
#
|
375
|
-
#
|
384
|
+
# Assigned parameters can be added through +param+ to be used within
|
385
|
+
# the macros of the preprocessed text.
|
376
386
|
def initialize(params = {},
|
377
387
|
apply: ".do", applyR: ".doR",
|
378
388
|
define: ".def", defineR: ".defR",
|
@@ -447,27 +457,27 @@ class Preprocessor
|
|
447
457
|
|
448
458
|
# Methods for handling the execution context of the macros.
|
449
459
|
|
450
|
-
|
460
|
+
# Executes a macro in a safe context.
|
451
461
|
def run(&proc)
|
452
462
|
@generator.run do |__stream__|
|
453
463
|
@context.instance_exec(__stream__,&proc)
|
454
464
|
end
|
455
465
|
end
|
456
466
|
|
457
|
-
|
467
|
+
# Sets parameter +param+ to +value+.
|
458
468
|
def parameter_set(param,value)
|
459
469
|
# print "Setting #{Ppr.to_attribute(param)} with #{value.to_s}\n"
|
460
470
|
@context.instance_variable_set(Ppr.to_attribute(param),value.to_s)
|
461
471
|
end
|
462
472
|
|
463
|
-
|
473
|
+
# Gets the value of parameter +param.
|
464
474
|
def parameter_get(param)
|
465
475
|
return @context.instance_variable_get(Ppr.to_attribute(param))
|
466
476
|
end
|
467
477
|
|
468
478
|
# Methods for parsing the lines.
|
469
479
|
|
470
|
-
|
480
|
+
# Restores a +string+ whose begining may have been glued.
|
471
481
|
def unglue_front(string)
|
472
482
|
if string.start_with?(@glue) then
|
473
483
|
# There is a glue, so remove it.
|
@@ -479,7 +489,7 @@ class Preprocessor
|
|
479
489
|
return string
|
480
490
|
end
|
481
491
|
|
482
|
-
|
492
|
+
# Restores a +string+ whose ending may have been glued.
|
483
493
|
def unglue_back(string)
|
484
494
|
if string.end_with?(@glue) then
|
485
495
|
# There is a glue, so remove it.
|
@@ -491,8 +501,7 @@ class Preprocessor
|
|
491
501
|
return string
|
492
502
|
end
|
493
503
|
|
494
|
-
|
495
|
-
# from offset +start+ of +line+.
|
504
|
+
# Gets the range of an argument starting at offset +start+ in +line+.
|
496
505
|
def get_argument_range(line, start)
|
497
506
|
if start >= line.size then
|
498
507
|
raise "incomplete arguments in macro call."
|
@@ -501,8 +510,9 @@ class Preprocessor
|
|
501
510
|
return (range[0]+start)..(range[1]+start-1)
|
502
511
|
end
|
503
512
|
|
504
|
-
|
505
|
-
#
|
513
|
+
# Iterates over the range each argument of a +line+ from offset +start+.
|
514
|
+
#
|
515
|
+
# NOTE: keywords included into a longer one are ignored.
|
506
516
|
def each_argument_range(line,start)
|
507
517
|
return to_enum(:each_argument_range,line,start) unless block_given?
|
508
518
|
begin
|
@@ -519,22 +529,22 @@ class Preprocessor
|
|
519
529
|
end
|
520
530
|
|
521
531
|
|
522
|
-
|
532
|
+
# Tells if a line corresponds to an end keyword.
|
523
533
|
def is_endm?(line)
|
524
534
|
@endm.match(line)
|
525
535
|
end
|
526
536
|
|
527
|
-
|
537
|
+
# Tells if a line corresponds to an else keyword.
|
528
538
|
def is_elsem?(line)
|
529
539
|
@elsem.match(line)
|
530
540
|
end
|
531
541
|
|
532
|
-
|
542
|
+
# Tells if a line corresponds to an endif keyword.
|
533
543
|
def is_endifm?(line)
|
534
544
|
@endifm.match(line)
|
535
545
|
end
|
536
546
|
|
537
|
-
|
547
|
+
# Extract a macro definition from a +line+ if there is one.
|
538
548
|
def get_macro_def(line)
|
539
549
|
line = line.strip
|
540
550
|
# Locate and identify the macro keyword.
|
@@ -613,9 +623,9 @@ class Preprocessor
|
|
613
623
|
end
|
614
624
|
|
615
625
|
|
616
|
-
|
626
|
+
# Applies recursively each element of +macros+ to +line+.
|
617
627
|
#
|
618
|
-
#
|
628
|
+
# NOTE: a same macro is apply only once in a portion of the line.
|
619
629
|
def apply_macros(line)
|
620
630
|
# print "apply_macros on line=#{line}\n"
|
621
631
|
|
@@ -677,10 +687,10 @@ class Preprocessor
|
|
677
687
|
return expanded
|
678
688
|
end
|
679
689
|
|
680
|
-
|
681
|
-
#
|
690
|
+
# Close a +macro+ being input registering it if named or applying it
|
691
|
+
# otherwise.
|
682
692
|
#
|
683
|
-
#
|
693
|
+
# NOTE: for internal use only.
|
684
694
|
def close_macro(macro)
|
685
695
|
# Is the macro named?
|
686
696
|
unless macro.name.empty? or macro.is_a?(Assign) then
|
@@ -717,8 +727,8 @@ class Preprocessor
|
|
717
727
|
end
|
718
728
|
private :close_macro
|
719
729
|
|
720
|
-
|
721
|
-
#
|
730
|
+
# Preprocess an +input+ stream and write the result to an +output+
|
731
|
+
# stream.
|
722
732
|
def preprocess(input, output)
|
723
733
|
# # The current list of macros.
|
724
734
|
# @macros = KeywordSearcher.new(@separator)
|
data/lib/ppr/safer_generator.rb
CHANGED
@@ -5,24 +5,24 @@
|
|
5
5
|
######################################################################
|
6
6
|
|
7
7
|
|
8
|
-
|
9
|
-
#
|
8
|
+
# Tool for executing in a safer sandbox a proc that generates a string into a
|
9
|
+
# stream.
|
10
10
|
class SaferGenerator
|
11
11
|
|
12
|
-
|
12
|
+
# The exception raised when the safer processed failed.
|
13
13
|
class SaferException < RuntimeError
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
# The list of dangerous constants of Object.
|
17
17
|
DANGER_CONSTANTS = [ :File, :IO, :Dir ]
|
18
18
|
|
19
|
-
|
19
|
+
# The list of dangerous methods of Kernel
|
20
20
|
DANGER_METHODS = [ :system, :`, :open ]
|
21
21
|
|
22
22
|
|
23
|
-
|
24
|
-
#
|
25
|
-
#
|
23
|
+
# Creates a new safe context with while removing Kernel methods and
|
24
|
+
# constants from +black_list+ in addition to the default dangerous
|
25
|
+
# ones.
|
26
26
|
def initialize(*black_list)
|
27
27
|
# Set the black list of methods.
|
28
28
|
@black_methods = black_list.select do |symbol|
|
@@ -34,10 +34,10 @@ class SaferGenerator
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
37
|
+
# Strips all the Kernel methods and constants appart from the
|
38
|
+
# elements of the white list.
|
39
|
+
# Also strip Object from dangerous methods and constants apart
|
40
|
+
# from the elements of the white list.
|
41
41
|
def secure
|
42
42
|
# Gather the methods to strip.
|
43
43
|
methods = DANGER_METHODS + @black_methods
|
@@ -54,9 +54,9 @@ class SaferGenerator
|
|
54
54
|
end
|
55
55
|
|
56
56
|
|
57
|
-
|
57
|
+
# Executes +block+ in a safe context for generating text into a +stream+.
|
58
58
|
#
|
59
|
-
#
|
59
|
+
# If no stream is given, returns the result as a string instead.
|
60
60
|
def run(stream = nil, &block)
|
61
61
|
unless stream
|
62
62
|
# No stream given
|
data/lib/ppr/version.rb
CHANGED
data/lib/ppr.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require "ppr/version"
|
2
2
|
require "ppr/ppr_core"
|
3
3
|
|
4
|
-
##
|
4
|
+
##
|
5
|
+
# Module including the classes implementing the preprocessor in Ruby.
|
5
6
|
#
|
6
|
-
#
|
7
|
+
# Usage:
|
7
8
|
# ppr = Ppr::Preprocessor.new(<some options>)
|
8
9
|
# ppr.preprocess(<input stream to preprocess>,
|
9
10
|
# <output stream where to write the preprocessing result>)}
|