rdx 0.9.0.pre
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/.rdx +20 -0
- data/README +19 -0
- data/bin/rdx +7 -0
- data/examples/minimal/.rdx +8 -0
- data/examples/minimal/README +10 -0
- data/examples/minimal/lib/other_conventions.rb +64 -0
- data/examples/minimal/lib/the_basics.rb +94 -0
- data/examples/minimal/lib/using_directives.rb +66 -0
- data/examples/minimal/rakefile +27 -0
- data/examples/ruby-2.0.0-p0/README +7 -0
- data/examples/ruby-2.0.0-p0/install/core/.rdx +6 -0
- data/examples/ruby-2.0.0-p0/install/core/README +19 -0
- data/examples/ruby-2.0.0-p0/install/core/Rakefile +61 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/array.c.diff +166 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/bignum.c.diff +11 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/class.c.diff +36 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/compar.c.diff +11 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/complex.c.diff +301 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/cont.c.diff +65 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/dir.c.diff +147 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/re.rdoc.diff +328 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/security.rdoc.diff +8 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/standard_library.rdoc.diff +0 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax.rdoc.diff +0 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/assignment.rdoc.diff +160 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/calling_methods.rdoc.diff +130 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/control_expressions.rdoc.diff +254 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/exceptions.rdoc.diff +0 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/literals.rdoc.diff +54 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/methods.rdoc.diff +157 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/miscellaneous.rdoc.diff +91 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/modules_and_classes.rdoc.diff +161 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/precedence.rdoc.diff +8 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/doc/syntax/refinements.rdoc.diff +146 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/encoding.c.diff +276 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/enum.c.diff +281 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/enumerator.c.diff +479 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/error.c.diff +143 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/eval.c.diff +47 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/eval_jump.c.diff +23 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/file.c.diff +752 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/gc.c.diff +195 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/hash.c.diff +84 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/iseq.c.diff +354 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/load.c.diff +53 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/marshal.c.diff +98 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/math.c.diff +110 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/numeric.c.diff +103 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/object.c.diff +295 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/pack.c.diff +18 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/parse.y.diff +23 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/proc.c.diff +155 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/random.c.diff +126 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/range.c.diff +49 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/rational.c.diff +312 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/re.c.diff +207 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/ruby.c.diff +21 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/signal.c.diff +67 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/sprintf.c.diff +29 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/string.c.diff +73 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/struct.c.diff +20 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/time.c.diff +691 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/transcode.c.diff +435 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/variable.c.diff +62 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_backtrace.c.diff +164 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_eval.c.diff +99 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_method.c.diff +17 -0
- data/examples/ruby-2.0.0-p0/install/core/diffs/vm_trace.c.diff +393 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/.rdx +6 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/README +19 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/Rakefile +53 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/abbrev.rb.diff +77 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/base64.rb.diff +42 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/benchmark.rb.diff +144 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/cmath.rb.diff +52 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/forwardable.rb.diff +150 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/mathn.rb.diff +58 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/matrix.rb.diff +657 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/observer.rb.diff +31 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/optparse.rb.diff +147 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/ostruct.rb.diff +78 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/prime.rb.diff +52 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/pstore.rb.diff +110 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/scanf.rb.diff +100 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/securerandom.rb.diff +144 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/set.rb.diff +637 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/shellwords.rb.diff +66 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/singleton.rb.diff +37 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/tempfile.rb.diff +104 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/thread.rb.diff +38 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/time.rb.diff +140 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/tmpdir.rb.diff +52 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri.rb.diff +39 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/uri/common.rb.diff +237 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/weakref.rb.diff +36 -0
- data/examples/ruby-2.0.0-p0/install/stdlib/diffs/lib/yaml/store.rb.diff +27 -0
- data/examples/ruby-2.0.0-p0/rakefile +165 -0
- data/lib/rdx.rb +331 -0
- data/lib/rdx/assertions.rb +484 -0
- data/lib/rdx/binding.rb +151 -0
- data/lib/rdx/code_object.rb +598 -0
- data/lib/rdx/comment.rb +338 -0
- data/lib/rdx/convention.rb +1174 -0
- data/lib/rdx/directive.rb +1432 -0
- data/lib/rdx/example.rb +679 -0
- data/lib/rdx/generator.rb +112 -0
- data/lib/rdx/generator/rdoc.rb +1006 -0
- data/lib/rdx/options.rb +359 -0
- data/lib/rdx/plain_text.rb +65 -0
- data/lib/rdx/reporter.rb +421 -0
- data/lib/rdx/ruby_lex.rb +324 -0
- data/lib/rdx/runner.rb +309 -0
- data/lib/rdx/source_file.rb +94 -0
- data/lib/rdx/specification.rb +194 -0
- data/lib/rdx/statement.rb +248 -0
- data/lib/rdx/store.rb +119 -0
- data/lib/rdx/task.rb +361 -0
- data/lib/rdx/text.rb +688 -0
- data/lib/rdx/version.rb +15 -0
- data/rakefile +64 -0
- metadata +203 -0
data/lib/rdx/text.rb
ADDED
@@ -0,0 +1,688 @@
|
|
1
|
+
|
2
|
+
module RDX
|
3
|
+
|
4
|
+
#
|
5
|
+
# Various utilities for text processing.
|
6
|
+
#
|
7
|
+
module Text
|
8
|
+
|
9
|
+
#
|
10
|
+
# Contains some useful +Regexp+ patterns.
|
11
|
+
#
|
12
|
+
module REGEXP
|
13
|
+
|
14
|
+
# Matches a number token.
|
15
|
+
TK_NUMBER = /(?>
|
16
|
+
\d+
|
17
|
+
(?: _\d+ )*
|
18
|
+
)/x
|
19
|
+
|
20
|
+
# Matches a literal Integer (without tag <tt>0[bodx]?</tt>).
|
21
|
+
INT = INT_P = /(?>
|
22
|
+
[-+]? #{TK_NUMBER}
|
23
|
+
)/ox
|
24
|
+
|
25
|
+
# Matches the result of Rational#to_s.
|
26
|
+
RTNL = %r%(?>
|
27
|
+
[-+]? #{TK_NUMBER} / #{TK_NUMBER}
|
28
|
+
)%ox
|
29
|
+
|
30
|
+
# Matches the result of Rational#inspect.
|
31
|
+
RTNL_P = %r%(?> \(
|
32
|
+
#{RTNL}
|
33
|
+
\) )%ox
|
34
|
+
|
35
|
+
# Matches a literal Float.
|
36
|
+
FLT = FLT_P = /(?>
|
37
|
+
[-+]? #{TK_NUMBER} \. #{TK_NUMBER}
|
38
|
+
(?: [Ee] [-+]? #{TK_NUMBER} )?
|
39
|
+
)/ox
|
40
|
+
|
41
|
+
# Matches a literal Integer or Float.
|
42
|
+
INT_FLT = FLT_INT = INT_FLT_P = FLT_INT_P = /(?>
|
43
|
+
#{FLT} | #{INT}
|
44
|
+
)/ox
|
45
|
+
|
46
|
+
# Matches a literal Integer, Float and the result of Rational#to_s.
|
47
|
+
REAL = /(?>
|
48
|
+
#{RTNL} | #{INT_FLT}
|
49
|
+
)/ox
|
50
|
+
|
51
|
+
# Matches a literal Integer, Float and the result of Rational#inspect.
|
52
|
+
REAL_P = /(?>
|
53
|
+
#{RTNL_P} | #{INT_FLT_P}
|
54
|
+
)/ox
|
55
|
+
|
56
|
+
# Matches the text <tt>[+-]?Infinity</tt> and +NaN+ other than real numbers.
|
57
|
+
IPERREAL_P = /(?>
|
58
|
+
[-+]? Infinity | NaN | #{REAL_P}
|
59
|
+
)/ox
|
60
|
+
|
61
|
+
# Matches the result of Complex#to_s.
|
62
|
+
CMPLX = /(?>
|
63
|
+
#{REAL} [-+] #{REAL} i
|
64
|
+
)/ox
|
65
|
+
|
66
|
+
# Matches the result of Complex#inspect.
|
67
|
+
CMPLX_P = /(?> \(
|
68
|
+
#{IPERREAL_P} [-+] #{IPERREAL_P} \*? i
|
69
|
+
\) )/ox
|
70
|
+
|
71
|
+
# Matches the result of Numeric#to_s.
|
72
|
+
NUMERIC = %r%(?>
|
73
|
+
#{CMPLX} | #{REAL}
|
74
|
+
)%ox
|
75
|
+
|
76
|
+
# Matches the result of Numeric#inspect
|
77
|
+
NUMERIC_P = %r%(?>
|
78
|
+
#{CMPLX_P} | #{REAL_P}
|
79
|
+
)%ox
|
80
|
+
|
81
|
+
# Matches an identifier token.
|
82
|
+
TK_ID = /(?>
|
83
|
+
(?! true | false | nil | self | __FILE__ | __LINE__ | __ENCODING__ )
|
84
|
+
[A-Za-z_[^[:ascii:]]]\w*
|
85
|
+
)/x
|
86
|
+
|
87
|
+
# Matches a literal class (constant) name.
|
88
|
+
CLASS = CONSTANT = TK_CONST = /(?> (?:
|
89
|
+
(?: :: )?+ [A-Z] \w*+
|
90
|
+
)++ )/x
|
91
|
+
|
92
|
+
# Matches an instance variable token.
|
93
|
+
TK_IVAR = /(?>
|
94
|
+
@ \w+
|
95
|
+
)/x
|
96
|
+
|
97
|
+
# Matches a class variable token.
|
98
|
+
TK_CVAR = /(?>
|
99
|
+
@@ \w+
|
100
|
+
)/x
|
101
|
+
|
102
|
+
# Matches a global variable token.
|
103
|
+
TK_GVAR = /(?>
|
104
|
+
$ \w+
|
105
|
+
)/x
|
106
|
+
|
107
|
+
# Matches a fetching token.
|
108
|
+
FETCH = Regexp.union TK_CONST, TK_ID, TK_IVAR, TK_CVAR, TK_GVAR
|
109
|
+
|
110
|
+
# Matches a literal double-quoted string (without interpolation).
|
111
|
+
DQ_STRING = /(?> "
|
112
|
+
(?:
|
113
|
+
[^"#\\]*+
|
114
|
+
(?: \\. )?+
|
115
|
+
(?: \#(?![{@$]) )?+
|
116
|
+
)*+
|
117
|
+
" )/x
|
118
|
+
|
119
|
+
# Matches a literal single-quoted string.
|
120
|
+
SQ_STRING = /(?> '
|
121
|
+
(?:
|
122
|
+
[^'\\]*+
|
123
|
+
(?: \\. )?+
|
124
|
+
)*+
|
125
|
+
' )/x
|
126
|
+
|
127
|
+
# Matches the rest of line if it has no more code (spaces and comment).
|
128
|
+
END_CODE_IN_LINE = /[^\S\n]*(?:#.*)?$/
|
129
|
+
|
130
|
+
# Matches the magic comment of the string (eventual shebang line) and captures it.
|
131
|
+
MAGIC_COMMENT = %r%\A(?>
|
132
|
+
(?: \#! .* \n )? # Optional shebang line
|
133
|
+
[^\S\n]* ( \# .*? coding[:=] .* ) # Magic comment
|
134
|
+
)%x
|
135
|
+
|
136
|
+
# Matches the result of Time#to_s (but also invalid ones).
|
137
|
+
TIME = %r%(?>
|
138
|
+
\d{4,}-\d\d-\d\d \ \d\d:\d\d:\d\d \ [-+]\d{4}
|
139
|
+
)%x
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
extend self
|
144
|
+
|
145
|
+
#
|
146
|
+
# Converts _numeric_str_ to a +Numeric+ using +to_c+, +to_r+, +to_f+
|
147
|
+
# or +to_i+ according to the given +String+.
|
148
|
+
#
|
149
|
+
# RDX::Text.numeric_from_str "12" #=> 12 # Integer
|
150
|
+
# RDX::Text.numeric_from_str "1.2" #=> 1.2 # Float
|
151
|
+
# RDX::Text.numeric_from_str "1/2" #=> 1/2 # Rational
|
152
|
+
# RDX::Text.numeric_from_str "1+2i" #=> 1+2i # Complex
|
153
|
+
#
|
154
|
+
# If the string isn't valid can return unexpected results.
|
155
|
+
#
|
156
|
+
def numeric_from_str(numeric_str)
|
157
|
+
case numeric_str = numeric_str.to_str
|
158
|
+
when /i/
|
159
|
+
numeric_str.to_c
|
160
|
+
when /\//
|
161
|
+
numeric_str.to_r
|
162
|
+
when /[.eE]/
|
163
|
+
numeric_str.to_f
|
164
|
+
else
|
165
|
+
numeric_str.to_i
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
#
|
170
|
+
# Replaces every potential object id (hexadecimal number) in the given _string_ with
|
171
|
+
# _replacement_.
|
172
|
+
#
|
173
|
+
# RDX::Text.generalize_object_ids "#<Class:0x0007a89f>" #=> "#<Class:0xXXXXXX>"
|
174
|
+
# RDX::Text.generalize_object_ids "#<Class:0x00012b40af>" #=> "#<Class:0xXXXXXX>"
|
175
|
+
# RDX::Text.generalize_object_ids "An hexadecimal number: 0X14a58ef"
|
176
|
+
# #=> "An hexadecimal number: 0xXXXXXX"
|
177
|
+
#
|
178
|
+
def generalize_object_ids string, replacement='0xXXXXXX'
|
179
|
+
return string unless string.respond_to?(:to_str)
|
180
|
+
return string if Object.const_defined?(:Encoding) and
|
181
|
+
!string.encoding.ascii_compatible? || !string.valid_encoding?
|
182
|
+
string = string.to_str.dup
|
183
|
+
string.gsub!(/0[Xx]\h+/, replacement)
|
184
|
+
string
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
# Replace all occurrences of Numeric#to_s in the given _string_
|
189
|
+
# with _replacement_.
|
190
|
+
#
|
191
|
+
# RDX::Text.generalize_numerics "1.2e+7" #=> "0"
|
192
|
+
# RDX::Text.generalize_numerics "12and-7" #=> "0and0"
|
193
|
+
# RDX::Text.generalize_numerics "12/7" #=> "0"
|
194
|
+
# RDX::Text.generalize_numerics "12 / 7" #=> "0 / 0"
|
195
|
+
#
|
196
|
+
def generalize_numerics string, replacement='0'
|
197
|
+
return string unless string.respond_to?(:to_str)
|
198
|
+
return string if Object.const_defined?(:Encoding) and
|
199
|
+
!string.encoding.ascii_compatible? || !string.valid_encoding?
|
200
|
+
string.to_str.gsub REGEXP::NUMERIC, replacement
|
201
|
+
end
|
202
|
+
|
203
|
+
#
|
204
|
+
# Replace all occurrences of Time#to_s in the given _string_
|
205
|
+
# with _replacement_.
|
206
|
+
#
|
207
|
+
# txt = "Now it's: #{Time.now}"
|
208
|
+
# RDX::Text.generalize_times txt #=> "Now it's: 0000-01-01 00:00:00 +0000"
|
209
|
+
#
|
210
|
+
def generalize_times string, replacement=Time.utc(0).getlocal("+00:00").to_s
|
211
|
+
return string unless string.respond_to?(:to_str)
|
212
|
+
return string if Object.const_defined?(:Encoding) and
|
213
|
+
!string.encoding.ascii_compatible? || !string.valid_encoding?
|
214
|
+
string.to_str.gsub REGEXP::TIME, replacement
|
215
|
+
end
|
216
|
+
|
217
|
+
#
|
218
|
+
# Normalizes all floats in the given _string_ and replace them rounding with
|
219
|
+
# at most _digits_ significant digits. If _zero_threshold_ isn't +nil+ determines
|
220
|
+
# the threshold under which floats are considered <tt>0.0</tt>.
|
221
|
+
#
|
222
|
+
# RDX::Text.normalize_floats "12.345678" #=> "+12.3457"
|
223
|
+
# RDX::Text.normalize_floats "+12.345678" #=> "+12.3457"
|
224
|
+
# RDX::Text.normalize_floats "-123456.0", 3 #=> "-1.23e+05"
|
225
|
+
# RDX::Text.normalize_floats "-1.23E5" #=> "-123000.0"
|
226
|
+
# RDX::Text.normalize_floats "-1.23E5", 3 #=> "-1.23e+05"
|
227
|
+
# RDX::Text.normalize_floats "0.0000001" #=> "+0.0"
|
228
|
+
# RDX::Text.normalize_floats "0.0000001", 2, nil
|
229
|
+
# #=> "+1.0e-07"
|
230
|
+
# RDX::Text.normalize_floats "1_2.0000001" #=> "+12.0"
|
231
|
+
# RDX::Text.normalize_floats "1.2345678+1.2_345678i", 3
|
232
|
+
# #=> "+1.23+1.23i"
|
233
|
+
# RDX::Text.normalize_floats "6.0221412927e23", 4
|
234
|
+
# #=> "+6.022e+23"
|
235
|
+
#
|
236
|
+
def normalize_floats string, digits=6, zero_threshold=10.0**-digits
|
237
|
+
return string unless string.respond_to?(:to_str)
|
238
|
+
return string if Object.const_defined?(:Encoding) and
|
239
|
+
!string.encoding.ascii_compatible? || !string.valid_encoding?
|
240
|
+
string.to_str.gsub REGEXP::FLT do |float_str|
|
241
|
+
float = float_str.to_f
|
242
|
+
float = 0.0 if zero_threshold and float.abs < zero_threshold
|
243
|
+
str = "%+.#{digits}g" % float
|
244
|
+
str.sub! /(?:e[-+]?\d+)?$/, '.0\&' unless str.include? '.'
|
245
|
+
str
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
#
|
250
|
+
# Normalizes all occurrences of Time#to_s in the given _string_ to the result
|
251
|
+
# of the corresponding +UTC+ time.
|
252
|
+
#
|
253
|
+
# t0_cst = "1969-12-31 18:00:00 -0600"
|
254
|
+
# RDX::Text.normalize_times t0_cst
|
255
|
+
# #=> "1970-01-01 00:00:00 UTC"
|
256
|
+
#
|
257
|
+
def normalize_times string
|
258
|
+
return string unless string.respond_to?(:to_str)
|
259
|
+
return string if Object.const_defined?(:Encoding) and
|
260
|
+
!string.encoding.ascii_compatible? || !string.valid_encoding?
|
261
|
+
string.to_str.gsub REGEXP::TIME do |time_str|
|
262
|
+
*nums,offset = time_str.split /(?<=\d)[- :]/
|
263
|
+
time = Time.new *nums.map(&:to_i), offset.insert(3,':')
|
264
|
+
time.getutc.to_s
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
#
|
269
|
+
# Normalizes the spaces in the given _output_ string, removing invisible or
|
270
|
+
# redundant differences according to the given parameters.
|
271
|
+
#
|
272
|
+
# RDX::Text.normalize_output_spacing <<EOS
|
273
|
+
# This output is indented,
|
274
|
+
# contains spaces at the end of this line,\s\s\s
|
275
|
+
# four spaces separate these \s\s words,
|
276
|
+
# contains tab \t characters
|
277
|
+
# and ends with three line terminator\n\n
|
278
|
+
# EOS
|
279
|
+
# # =>
|
280
|
+
# # <<EOS.chomp("\n")
|
281
|
+
# # This output is indented,
|
282
|
+
# # contains spaces at the end of this line,
|
283
|
+
# # four spaces separate these words,
|
284
|
+
# # contains tab characters
|
285
|
+
# # and ends with three line terminator
|
286
|
+
# # EOS
|
287
|
+
#
|
288
|
+
def normalize_output_spacing output, flush_left=true, squeeze_spaces=true, strip_newlines=true
|
289
|
+
return output unless output.respond_to?(:to_str)
|
290
|
+
output = remove_trailing_inline_spaces expand_tabs output.to_str
|
291
|
+
output = flush_left output if flush_left
|
292
|
+
if squeeze_spaces
|
293
|
+
output.squeeze! ' '
|
294
|
+
output.gsub! /\n{3,}/, "\n\n"
|
295
|
+
end
|
296
|
+
output = strip_newlines(output) if strip_newlines
|
297
|
+
output
|
298
|
+
end
|
299
|
+
|
300
|
+
#
|
301
|
+
# Replaces in the given _string_ all the occurrences of _root_ with the _replacement_.
|
302
|
+
#
|
303
|
+
# dir = path = nil
|
304
|
+
# Dir.mktmpdir do |tmpdir|
|
305
|
+
# dir = tmpdir
|
306
|
+
# fname = 'a_file'
|
307
|
+
# path = File.join tmpdir, fname
|
308
|
+
# end
|
309
|
+
# RDX::Text.normalize_path path, dir, '<tmpdir>' #=> "<tmpdir>/a_file"
|
310
|
+
#
|
311
|
+
def normalize_path string, root=Dir.pwd, replacement='<relative_path>'
|
312
|
+
return string unless string.respond_to?(:to_str)
|
313
|
+
string.to_str.gsub root.to_str, replacement.to_str
|
314
|
+
end
|
315
|
+
|
316
|
+
#
|
317
|
+
# Normalizes the _output_ string through #normalize_output_spacing, #normalize_floats
|
318
|
+
# and #generalize_object_ids in cascade (the details removed are considered negligible
|
319
|
+
# for an output).
|
320
|
+
#
|
321
|
+
def normalize_output output
|
322
|
+
normalize_floats generalize_object_ids normalize_output_spacing output
|
323
|
+
end
|
324
|
+
|
325
|
+
#
|
326
|
+
# Removes minor details from an exception message _msg_ (the most important is that
|
327
|
+
# newlines are converted to regular spaces, so that the message can be written in
|
328
|
+
# multiple lines).
|
329
|
+
#
|
330
|
+
# RDX::Text.normalize_exception_message <<EOS
|
331
|
+
# undefined method `a_method'
|
332
|
+
# for "a quite long string":String
|
333
|
+
# EOS
|
334
|
+
# # => %Q{undefined method `a_method' for "a quite long string":string}
|
335
|
+
#
|
336
|
+
def normalize_exception_message msg
|
337
|
+
return msg unless msg.respond_to?(:to_str)
|
338
|
+
msg.to_str.strip.chomp('.').gsub(/\s+/,' ').downcase
|
339
|
+
end
|
340
|
+
|
341
|
+
#
|
342
|
+
# Splits the given _string_ to an exception class and message according to _mode_,
|
343
|
+
# which specifies the format of the string:
|
344
|
+
# * +:class+ : _class_
|
345
|
+
# * +:message+ : _message_
|
346
|
+
# * +:class_message+ : _class_ <tt>:</tt> _message_
|
347
|
+
# * +:message_class+ : _message_ <tt>(</tt> _class_ <tt>)</tt>
|
348
|
+
# If a field is not detected it's replaced with +nil+.
|
349
|
+
#
|
350
|
+
# # IRB style (rescued exception):
|
351
|
+
# str = "ArgumentError: wrong number of arguments (1 for 0)"
|
352
|
+
# RDX::Text.split_exception_string str, :class_message
|
353
|
+
# #=> ["ArgumentError", "wrong number of arguments (1 for 0)"]
|
354
|
+
# RDX::Text.split_exception_string str, :message_class
|
355
|
+
# #=> [nil, "ArgumentError: wrong number of arguments (1 for 0)"]
|
356
|
+
#
|
357
|
+
# # Command line style (unhandled exception):
|
358
|
+
# str = "no implicit conversion of Fixnum into String (TypeError)"
|
359
|
+
# RDX::Text.split_exception_string str, :message_class
|
360
|
+
# #=> ["TypeError", "no implicit conversion of Fixnum into String"]
|
361
|
+
# RDX::Text.split_exception_string str, :class_message
|
362
|
+
# #=> [nil, "no implicit conversion of Fixnum into String (TypeError)"]
|
363
|
+
#
|
364
|
+
def split_exception_string string, mode=:class_message
|
365
|
+
string = string.to_str
|
366
|
+
case mode
|
367
|
+
when :class
|
368
|
+
message = nil
|
369
|
+
klass = string.match(/\A\s*(#{REGEXP::CLASS})\s*\z/) && $1
|
370
|
+
when :message
|
371
|
+
message = string
|
372
|
+
klass = nil
|
373
|
+
when :class_message
|
374
|
+
message = string.strip
|
375
|
+
klass = message.slice!(/\A(#{REGEXP::CLASS})\s*:\s*/) && $1
|
376
|
+
when :message_class
|
377
|
+
message = string.strip
|
378
|
+
klass = message.slice!(/\s*\((#{REGEXP::CLASS})\)\z/) && $1
|
379
|
+
end
|
380
|
+
message = nil if message && message.empty?
|
381
|
+
[klass,message]
|
382
|
+
end
|
383
|
+
|
384
|
+
#
|
385
|
+
# Removes in _string_ the enclosing module (or class) _mod_ from the namespace.
|
386
|
+
#
|
387
|
+
# mod = Module.new
|
388
|
+
# wrapper = class << mod # creates a new lexical scope
|
389
|
+
# module Wrapped
|
390
|
+
# end
|
391
|
+
# self
|
392
|
+
# end
|
393
|
+
# str = "The wrapped module is: #{wrapper::Wrapped}"
|
394
|
+
# #-> "The wrapped module is: #<Class:0x36e7108>::Wrapped"
|
395
|
+
# RDX::Text.remove_enclosing_module str, wrapper
|
396
|
+
# #=> "The wrapped module is: Wrapped"
|
397
|
+
#
|
398
|
+
def remove_enclosing_module string, mod
|
399
|
+
return string unless string.respond_to?(:to_str)
|
400
|
+
return string if Object.const_defined?(:Encoding) and
|
401
|
+
!string.encoding.ascii_compatible? || !string.valid_encoding?
|
402
|
+
raise unless mod.is_a?(Module)
|
403
|
+
string = string.to_str
|
404
|
+
mod_str1 = mod.to_s
|
405
|
+
# For some reason, in nested constants' names is used Object#to_s and not Module#to_s
|
406
|
+
# The result is that for singleton classes we don't get the information about the attached object.
|
407
|
+
# So we have to bypass the inheritance chain:
|
408
|
+
mod_str2 = Object.instance_method(:to_s).bind(mod).call
|
409
|
+
mod_str = Regexp.escape(mod_str1) + '|' + Regexp.escape(mod_str2)
|
410
|
+
mod_rgxp = /(?:#{mod_str})::/
|
411
|
+
string.gsub(mod_rgxp,'')
|
412
|
+
end
|
413
|
+
alias remove_enclosing_class remove_enclosing_module
|
414
|
+
|
415
|
+
#
|
416
|
+
# Returns a +Regexp+ that matches _content_ (may be a +String+ or +Regexp+)
|
417
|
+
# wrapped into any of the one HTML _tags_ given (does not handle HTML escaping).
|
418
|
+
# If one tag is +nil+ the unwrapped _content_ is also allowed.
|
419
|
+
#
|
420
|
+
# RDX::Text.add_html_tags 'text', 'b' #=> %r%<b>text</b>%
|
421
|
+
# RDX::Text.add_html_tags 'dot.', 'u', nil #=> %r%dot\.|<u>dot\.</u>%
|
422
|
+
# RDX::Text.add_html_tags 'Fixnum', 'tt', 'code'
|
423
|
+
# #=> %r%<tt>Fixnum</tt>|<code>Fixnum</code>%
|
424
|
+
# # One very used by RDX:
|
425
|
+
# RDX::Text.add_html_tags /[Pp]roduces:?/, 'em', 'i'
|
426
|
+
# #=> %r%<em>(?-mix:[Pp]roduces:?)</em>|<i>(?-mix:[Pp]roduces:?)</i>%
|
427
|
+
#
|
428
|
+
def add_html_tags content, *tags
|
429
|
+
content = Regexp.escape(content.to_str) unless content.is_a?(Regexp)
|
430
|
+
pattern = []
|
431
|
+
pattern << content if tags.compact!
|
432
|
+
tags.each do |tag|
|
433
|
+
re_tag = Regexp.escape(tag.to_str)
|
434
|
+
wrapped = "<#{re_tag}>#{content}</#{re_tag}>"
|
435
|
+
pattern << wrapped
|
436
|
+
end
|
437
|
+
Regexp.compile pattern.join('|')
|
438
|
+
end
|
439
|
+
alias add_html_tag add_html_tags
|
440
|
+
|
441
|
+
#
|
442
|
+
# Returns a +Regexp+ pattern that matches any of the given _prompts_ at the beginning
|
443
|
+
# of a string (for definition). Leading spaces are allowed, one trailing is required to avoid
|
444
|
+
# the matching of another prompt.
|
445
|
+
#
|
446
|
+
# # Perhaps the most important for RDX:
|
447
|
+
# re = RDX::Text.build_prompt '=>' # => /\A\s*(?>=>)\s/
|
448
|
+
# str = " => 15"
|
449
|
+
# str.slice! re; str #=> "15"
|
450
|
+
# str = "=>> 24" # another prompt
|
451
|
+
# str.slice! re #=> nil
|
452
|
+
#
|
453
|
+
def build_prompt *prompts
|
454
|
+
prompts.flatten!
|
455
|
+
prompts.map! do |prompt|
|
456
|
+
prompt.is_a?(Regexp) ? prompt.to_s : Regexp.escape(prompt.to_str)
|
457
|
+
end
|
458
|
+
pat = prompts.uniq.join '|'
|
459
|
+
return /\A\s*(?>#{pat})\s/
|
460
|
+
end
|
461
|
+
|
462
|
+
#
|
463
|
+
# Assembles a +Regexp+ pattern that matches the given _parts_ in sequence,
|
464
|
+
# allowing inline spaces between them.
|
465
|
+
# Each part can be:
|
466
|
+
# * a +Regexp+
|
467
|
+
# * a +String+, which is interpreted literally
|
468
|
+
# * a +Symbol+, which represent a REGEXP constant
|
469
|
+
# (if begins with <tt>CAPTURE_</tt> the pattern is surrounded capturing parhentesis)
|
470
|
+
#
|
471
|
+
# str = "=> Float::MIN"
|
472
|
+
# re = RDX::Text.build_pattern '=>', :CLASS
|
473
|
+
# str.match re # > #<MatchData "=> Float::MIN">
|
474
|
+
# re = RDX::Text.build_pattern '=>', :CAPTURE_CLASS
|
475
|
+
# str[re,1] #=> "Float::MIN"
|
476
|
+
#
|
477
|
+
def build_pattern *parts
|
478
|
+
parts.map! do |part|
|
479
|
+
if part.is_a?(Regexp)
|
480
|
+
part
|
481
|
+
elsif part.is_a?(Symbol)
|
482
|
+
name = part.to_s
|
483
|
+
capturing = name.slice! /^CAPTURE_/
|
484
|
+
re = REGEXP.const_get(name,false)
|
485
|
+
capturing ? /(#{re})/ : re
|
486
|
+
else
|
487
|
+
Regexp.escape part.to_str
|
488
|
+
end
|
489
|
+
end
|
490
|
+
return Regexp.compile parts.join('[^\S\n]*')
|
491
|
+
end
|
492
|
+
|
493
|
+
#
|
494
|
+
# Substitutes the content of each line in _string_ (but not newlines themselves) with _replacement_
|
495
|
+
# (which is the empty string by default).
|
496
|
+
#
|
497
|
+
# RDX::Text.collect_newlines <<EOS
|
498
|
+
# useless data
|
499
|
+
# where line count matters
|
500
|
+
# EOS
|
501
|
+
# # => "\n\n"
|
502
|
+
# RDX::Text.collect_newlines <<EOS, '#'
|
503
|
+
# # This is a useless
|
504
|
+
# # ruby comment
|
505
|
+
# EOS
|
506
|
+
# # => "#\n#\n"
|
507
|
+
#
|
508
|
+
def collect_newlines string, replacement=nil
|
509
|
+
replacement ||= ''
|
510
|
+
string.to_str.gsub /^.*$/, replacement
|
511
|
+
end
|
512
|
+
|
513
|
+
#
|
514
|
+
# If _string_ is formatted like a C-style comments strips the stars without
|
515
|
+
# consuming newlines characters.
|
516
|
+
#
|
517
|
+
# RDX::Text.strip_stars <<EOS
|
518
|
+
# /*
|
519
|
+
# * C comment
|
520
|
+
# */
|
521
|
+
# EOS
|
522
|
+
# # => " \n C comment\n \n"
|
523
|
+
#--
|
524
|
+
# This method is adapted from RDoc::Text#strip_stars
|
525
|
+
# rb_cmt = <<EOS
|
526
|
+
# ##
|
527
|
+
# # Strips /* */ style comments
|
528
|
+
# EOS
|
529
|
+
# RDX::Text.strip_stars rb_cmt #=> rb_cmt
|
530
|
+
#
|
531
|
+
def strip_stars string
|
532
|
+
string = string.to_str
|
533
|
+
return string unless string =~ %r%\A\s*/\*.*\*/\s*\z%m
|
534
|
+
|
535
|
+
encoding = string.encoding if Object.const_defined? :Encoding
|
536
|
+
|
537
|
+
# text = text.gsub %r%Document-method:\s+[\w:.#=!?]+%, '' # handled in RDoc::Parser::C
|
538
|
+
|
539
|
+
space = ' '
|
540
|
+
space.force_encoding encoding if encoding
|
541
|
+
|
542
|
+
string.sub! %r%/\*+% do space*$&.length end
|
543
|
+
string.sub! %r%(\*+/)(\s*)\z% do space*$1.length + $2 end
|
544
|
+
string.gsub! %r%^[^\S\n]*\*?% do space * $&.length end
|
545
|
+
|
546
|
+
# empty = ''
|
547
|
+
# empty.force_encoding encoding if encoding
|
548
|
+
# text.gsub(/^\s+$/, empty)
|
549
|
+
|
550
|
+
string
|
551
|
+
end
|
552
|
+
|
553
|
+
#
|
554
|
+
# If _string_ is formatted like a Ruby-style comment strips hashes
|
555
|
+
# (and leading inline spaces before them), without consuming newlines characters.
|
556
|
+
# If _multihash_ is +true+ removes consecutive hashes.
|
557
|
+
#
|
558
|
+
# RDX::Text.strip_hashes <<EOS
|
559
|
+
# # A
|
560
|
+
# # Ruby
|
561
|
+
# # comment
|
562
|
+
# EOS
|
563
|
+
# # => " A\n Ruby\n comment\n"
|
564
|
+
# RDX::Text.strip_hashes "## meta-comment" #=> "# meta-comment"
|
565
|
+
# RDX::Text.strip_hashes "## meta-comment", true #=> " meta-comment"
|
566
|
+
#--
|
567
|
+
# This method is adapted from RDoc::Text#strip_hashes
|
568
|
+
#
|
569
|
+
def strip_hashes string, multihash=false
|
570
|
+
string = string.to_str
|
571
|
+
return string if string =~ /^[^\S\n]*+[^#]/
|
572
|
+
|
573
|
+
empty = ''
|
574
|
+
empty.force_encoding string.encoding if Object.const_defined? :Encoding
|
575
|
+
|
576
|
+
replacement = multihash ? empty : '\1'
|
577
|
+
string.gsub /^[^\S\n]*+#(#*)/, replacement
|
578
|
+
end
|
579
|
+
|
580
|
+
#
|
581
|
+
# Expands tab characters in _string_ to eight spaces.
|
582
|
+
#--
|
583
|
+
# Adapted from RDoc::Text#expand_tabs
|
584
|
+
#
|
585
|
+
def expand_tabs string
|
586
|
+
string = string.to_str
|
587
|
+
expanded = []
|
588
|
+
|
589
|
+
string.each_line do |line|
|
590
|
+
line.gsub!(/^((?:.{8})*?)([^\t\r\n]{0,7})\t/) do
|
591
|
+
r = "#{$1}#{$2}#{' ' * (8 - $2.size)}"
|
592
|
+
r.force_encoding string.encoding if Object.const_defined? :Encoding
|
593
|
+
r
|
594
|
+
end until line !~ /\t/
|
595
|
+
|
596
|
+
expanded << line
|
597
|
+
end
|
598
|
+
|
599
|
+
expanded.join ''
|
600
|
+
end
|
601
|
+
|
602
|
+
#
|
603
|
+
# Flush _string_ left based on the shortest line.
|
604
|
+
#
|
605
|
+
# RDX::Text.flush_left <<EOS
|
606
|
+
# this is
|
607
|
+
# indented
|
608
|
+
# EOS
|
609
|
+
# # =>
|
610
|
+
# # <<EOS
|
611
|
+
# # this is
|
612
|
+
# # indented
|
613
|
+
# # EOS
|
614
|
+
#--
|
615
|
+
# Taken as is from RDoc::Text#flush_left
|
616
|
+
#
|
617
|
+
def flush_left string
|
618
|
+
string = string.to_str
|
619
|
+
indent = string.each_line.map{ |ln| ln=~/\S/ }.compact.min
|
620
|
+
empty = ''
|
621
|
+
empty.force_encoding string.encoding if Object.const_defined? :Encoding
|
622
|
+
string.gsub /^ {0,#{indent}}/, empty # unlimited if indent == nil
|
623
|
+
end
|
624
|
+
|
625
|
+
#
|
626
|
+
# Removes trailing spaces (invisible) from each line of _string_.
|
627
|
+
#
|
628
|
+
# RDX::Text.remove_trailing_inline_spaces <<EOS
|
629
|
+
# lines ending\t\s
|
630
|
+
# with spaces\s\s\s
|
631
|
+
# EOS
|
632
|
+
# # => <<EOS
|
633
|
+
# # lines ending
|
634
|
+
# # with spaces
|
635
|
+
# # EOS
|
636
|
+
#
|
637
|
+
def remove_trailing_inline_spaces string
|
638
|
+
string.to_str.gsub %r%[^\S\n]+$%, ''
|
639
|
+
end
|
640
|
+
|
641
|
+
#
|
642
|
+
# Removes leading and trailing newlines from _string_.
|
643
|
+
#
|
644
|
+
# RDX::Text.strip_newlines "\nthe text\n\n" #=> "the text"
|
645
|
+
#
|
646
|
+
def strip_newlines string, leading=true, trailing=true
|
647
|
+
string = string.to_str.dup
|
648
|
+
string.slice! /\A\n+/ if leading
|
649
|
+
string.slice! /\n+\z/ if trailing
|
650
|
+
string
|
651
|
+
end
|
652
|
+
|
653
|
+
#
|
654
|
+
# Strips stars, hashes, expands tabs, flushes _text_ to the left.
|
655
|
+
#
|
656
|
+
# RDX::Text.normalize_comment <<EOS
|
657
|
+
# #
|
658
|
+
# # This is a
|
659
|
+
# # typical Ruby comment
|
660
|
+
# #
|
661
|
+
# EOS
|
662
|
+
# # => "\nThis is a\ntypical Ruby comment\n\n"
|
663
|
+
#
|
664
|
+
# RDX::Text.normalize_comment <<EOS
|
665
|
+
# /*
|
666
|
+
# * This is a
|
667
|
+
# * typical C comment
|
668
|
+
# */
|
669
|
+
# EOS
|
670
|
+
# # => "\nThis is a\ntypical C comment\n\n"
|
671
|
+
#
|
672
|
+
#--
|
673
|
+
# Method adapted from RDoc::Text#normalize_comment
|
674
|
+
#
|
675
|
+
def normalize_comment string, multihash=false
|
676
|
+
string = string.to_str
|
677
|
+
return string if string.empty?
|
678
|
+
string = strip_stars string
|
679
|
+
string = strip_hashes string, multihash
|
680
|
+
string = expand_tabs string
|
681
|
+
string = flush_left string
|
682
|
+
# string = strip_newlines string
|
683
|
+
string
|
684
|
+
end
|
685
|
+
|
686
|
+
end
|
687
|
+
|
688
|
+
end
|