sourcify 0.5.0 → 0.6.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/HISTORY.txt +5 -0
- data/README.rdoc +86 -3
- data/Rakefile +47 -15
- data/lib/sourcify.rb +13 -0
- data/lib/sourcify/common/parser/converter.rb +29 -0
- data/lib/sourcify/common/parser/raw_scanner/comment.rb +23 -0
- data/lib/sourcify/common/parser/raw_scanner/counter.rb +43 -0
- data/lib/sourcify/common/parser/raw_scanner/dstring.rb +60 -0
- data/lib/sourcify/common/parser/raw_scanner/extensions.rb +121 -0
- data/lib/sourcify/common/parser/raw_scanner/heredoc.rb +26 -0
- data/lib/sourcify/common/parser/source_code.rb +33 -0
- data/lib/sourcify/common/ragel/common.rl +5 -0
- data/lib/sourcify/common/ragel/expressions.rl +38 -0
- data/lib/sourcify/{proc/scanner.rl → common/ragel/machines.rl} +10 -178
- data/lib/sourcify/errors.rb +4 -0
- data/lib/sourcify/method.rb +134 -0
- data/lib/sourcify/method/methods.rb +3 -0
- data/lib/sourcify/method/methods/to_raw_source.rb +30 -0
- data/lib/sourcify/method/methods/to_sexp.rb +30 -0
- data/lib/sourcify/method/methods/to_source.rb +30 -0
- data/lib/sourcify/method/parser.rb +104 -0
- data/lib/sourcify/method/parser/converter.rb +8 -0
- data/lib/sourcify/method/parser/raw_scanner.rb +2494 -0
- data/lib/sourcify/method/parser/raw_scanner.rl +144 -0
- data/lib/sourcify/method/parser/raw_scanner_extensions.rb +64 -0
- data/lib/sourcify/method/parser/scanner.rb +48 -0
- data/lib/sourcify/method/parser/source_code.rb +8 -0
- data/lib/sourcify/proc.rb +0 -2
- data/lib/sourcify/proc/parser.rb +2 -5
- data/lib/sourcify/proc/parser/converter.rb +2 -23
- data/lib/sourcify/proc/{scanner.rb → parser/raw_scanner.rb} +808 -806
- data/lib/sourcify/proc/parser/raw_scanner.rl +149 -0
- data/lib/sourcify/proc/parser/raw_scanner_extensions.rb +72 -0
- data/lib/sourcify/proc/parser/{code_scanner.rb → scanner.rb} +9 -5
- data/lib/sourcify/proc/parser/source_code.rb +2 -27
- data/lib/sourcify/version.rb +1 -1
- data/spec/method/others_from_def_end_block_spec.rb +49 -0
- data/spec/method/others_from_define_method_spec.rb +62 -0
- data/spec/method/raw_scanner/block_comment_spec.rb +8 -0
- data/spec/method/raw_scanner/double_colons_spec.rb +8 -0
- data/spec/method/raw_scanner/double_quote_str_w_interpolation_spec.rb +8 -0
- data/spec/method/raw_scanner/double_quote_str_wo_interpolation_spec.rb +8 -0
- data/spec/method/raw_scanner/heredoc_w_indent_spec.rb +8 -0
- data/spec/method/raw_scanner/heredoc_wo_indent_spec.rb +8 -0
- data/spec/method/raw_scanner/kw_block_start_alias1_spec.rb +20 -0
- data/spec/method/raw_scanner/kw_block_start_alias2_spec.rb +20 -0
- data/spec/method/raw_scanner/per_line_comment_spec.rb +8 -0
- data/spec/method/raw_scanner/single_quote_str_spec.rb +8 -0
- data/spec/method/raw_scanner/slash_operator_spec.rb +8 -0
- data/spec/method/raw_scanner/spec_helper.rb +80 -0
- data/spec/method/spec_helper.rb +1 -0
- data/spec/method/to_raw_source_spec.rb +31 -0
- data/spec/method/to_raw_source_w_specified_strip_enclosure_spec.rb +148 -0
- data/spec/method/to_sexp_from_def_end_block_w_variables_spec.rb +46 -0
- data/spec/method/to_sexp_from_def_end_block_within_irb_spec.rb +38 -0
- data/spec/method/to_sexp_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb +56 -0
- data/spec/method/to_sexp_from_define_method_w_variables_spec.rb +52 -0
- data/spec/method/to_sexp_from_define_method_within_irb_spec.rb +42 -0
- data/spec/method/to_sexp_w_specified_strip_enclosure_spec.rb +74 -0
- data/spec/method/to_source_from_def_end_block_w_19_extras_spec.rb +23 -0
- data/spec/method/to_source_from_def_end_block_w_nested_begin_spec.rb +35 -0
- data/spec/method/to_source_from_def_end_block_w_nested_case_spec.rb +35 -0
- data/spec/method/to_source_from_def_end_block_w_nested_class_spec.rb +51 -0
- data/spec/method/to_source_from_def_end_block_w_nested_do_end_block_spec.rb +33 -0
- data/spec/method/to_source_from_def_end_block_w_nested_for_spec.rb +126 -0
- data/spec/method/to_source_from_def_end_block_w_nested_if_spec.rb +82 -0
- data/spec/method/to_source_from_def_end_block_w_nested_literal_keyword_spec.rb +141 -0
- data/spec/method/to_source_from_def_end_block_w_nested_method_spec.rb +33 -0
- data/spec/method/to_source_from_def_end_block_w_nested_module_spec.rb +59 -0
- data/spec/method/to_source_from_def_end_block_w_nested_unless_spec.rb +82 -0
- data/spec/method/to_source_from_def_end_block_w_nested_until_spec.rb +179 -0
- data/spec/method/to_source_from_def_end_block_w_nested_while_spec.rb +179 -0
- data/spec/method/to_source_from_def_end_block_w_singleton_method_spec.rb +19 -0
- data/spec/method/to_source_from_def_end_block_within_irb_spec.rb +30 -0
- data/spec/method/to_source_from_def_end_w_multi_blocks_and_many_matches_spec.rb +30 -0
- data/spec/method/to_source_from_def_end_w_multi_blocks_and_single_match_spec.rb +36 -0
- data/spec/method/to_source_from_define_method_w_braced_block_spec.rb +113 -0
- data/spec/method/to_source_from_define_method_w_do_end_block_spec.rb +145 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_many_matches_spec.rb +56 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_single_match_spec.rb +73 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_many_matches_spec.rb +36 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_no_match_spec.rb +36 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_single_match_spec.rb +28 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb +103 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_many_matches_spec.rb +36 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_no_match_spec.rb +36 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_single_match_spec.rb +28 -0
- data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_ignore_nested_spec.rb +36 -0
- data/spec/method/to_source_from_define_method_within_irb_spec.rb +32 -0
- data/spec/method/to_source_magic_file_var_spec.rb +176 -0
- data/spec/method/to_source_magic_line_var_spec.rb +298 -0
- data/spec/method/to_source_w_specified_strip_enclosure_spec.rb +39 -0
- data/spec/no_method/unsupported_platform_spec.rb +26 -0
- data/spec/proc/raw_scanner/block_comment_spec.rb +8 -0
- data/spec/proc/raw_scanner/double_colons_spec.rb +8 -0
- data/spec/proc/raw_scanner/double_quote_str_w_interpolation_spec.rb +8 -0
- data/spec/proc/raw_scanner/double_quote_str_wo_interpolation_spec.rb +8 -0
- data/spec/proc/raw_scanner/heredoc_w_indent_spec.rb +8 -0
- data/spec/proc/raw_scanner/heredoc_wo_indent_spec.rb +8 -0
- data/spec/proc/raw_scanner/kw_block_start_alias1_spec.rb +20 -0
- data/spec/proc/raw_scanner/kw_block_start_alias2_spec.rb +20 -0
- data/spec/proc/raw_scanner/per_line_comment_spec.rb +8 -0
- data/spec/proc/raw_scanner/single_quote_str_spec.rb +8 -0
- data/spec/proc/raw_scanner/slash_operator_spec.rb +8 -0
- data/spec/proc/raw_scanner/spec_helper.rb +63 -0
- data/spec/{proc_scanner/block_comment_spec.rb → raw_scanner/block_comment_shared_spec.rb} +1 -5
- data/spec/{proc_scanner/double_colons_spec.rb → raw_scanner/double_colons_shared_spec.rb} +1 -5
- data/spec/{proc_scanner/double_quote_str_w_interpolation_spec.rb → raw_scanner/double_quote_str_w_interpolation_shared_spec.rb} +1 -5
- data/spec/{proc_scanner/double_quote_str_wo_interpolation_spec.rb → raw_scanner/double_quote_str_wo_interpolation_shared_spec.rb} +1 -5
- data/spec/raw_scanner/heredoc_w_indent_shared_spec.rb +69 -0
- data/spec/raw_scanner/heredoc_wo_indent_shared_spec.rb +70 -0
- data/spec/{proc_scanner/kw_do_alias1_spec.rb → raw_scanner/kw_block_start_alias1_shared_spec.rb} +10 -26
- data/spec/{proc_scanner/kw_do_alias2_spec.rb → raw_scanner/kw_block_start_alias2_shared_spec.rb} +10 -25
- data/spec/{proc_scanner/per_line_comment_spec.rb → raw_scanner/per_line_comment_shared_spec.rb} +1 -5
- data/spec/raw_scanner/shared_specs.rb +3 -0
- data/spec/{proc_scanner/single_quote_str_spec.rb → raw_scanner/single_quote_str_shared_spec.rb} +1 -5
- data/spec/{proc_scanner/slash_operator_spec.rb → raw_scanner/slash_operator_shared_spec.rb} +1 -5
- data/spec/run_spec.sh +7 -1
- data/spec/spec_helper.rb +8 -25
- metadata +204 -47
- data/.rvmrc +0 -1
- data/VERSION +0 -1
- data/lib/sourcify/proc/scanner/comment.rb +0 -21
- data/lib/sourcify/proc/scanner/counter.rb +0 -44
- data/lib/sourcify/proc/scanner/dstring.rb +0 -59
- data/lib/sourcify/proc/scanner/extensions.rb +0 -171
- data/lib/sourcify/proc/scanner/heredoc.rb +0 -24
- data/spec/proc_scanner/heredoc_spec.rb +0 -144
- data/spec/proc_scanner/spec_helper.rb +0 -33
data/.gitignore
CHANGED
data/HISTORY.txt
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== Current (pre 0.6.0)
|
2
|
+
|
3
|
+
* adds Method#to_source, Method#to_sexp & Method#to_raw_source to MRI-1.9.2 (issue#3)
|
4
|
+
* extensive refactoring to existing proc support to support the above
|
5
|
+
|
1
6
|
=== 0.5.0 (May 2, 2011)
|
2
7
|
|
3
8
|
* adds Proc#to_raw_source that supports extracting of raw code, as it is written in
|
data/README.rdoc
CHANGED
@@ -20,6 +20,7 @@ uses a home-baked ragel-generated scanner to extract the proc code. Further proc
|
|
20
20
|
with RubyParser & Ruby2Ruby to ensure 100% with ParseTree (yup, there is no denying that
|
21
21
|
i really like ParseTree).
|
22
22
|
|
23
|
+
|
23
24
|
== Installing It
|
24
25
|
|
25
26
|
The religiously standard way:
|
@@ -30,9 +31,8 @@ Or on 1.9.* or JRuby:
|
|
30
31
|
|
31
32
|
$ gem install ruby_parser file-tail sourcify
|
32
33
|
|
33
|
-
== Using It
|
34
34
|
|
35
|
-
Sourcify adds 4 methods to Proc
|
35
|
+
== Sourcify adds 4 methods to Proc
|
36
36
|
|
37
37
|
=== 1. Proc#to_source
|
38
38
|
|
@@ -101,6 +101,83 @@ consistency under 1.8.*:
|
|
101
101
|
lambda { x + y }.source_location
|
102
102
|
# >> ["/tmp/test.rb", 5]
|
103
103
|
|
104
|
+
|
105
|
+
== Sourcify adds 3 methods to Method
|
106
|
+
|
107
|
+
*IMPORTANT*: These only work for MRI-1.9.2, as currently, only it supports
|
108
|
+
(1) discovering of the original source location with Method#source_location,
|
109
|
+
and (2) reliably determinig a method's parameters with Method#parameters.
|
110
|
+
Attempting to use these methods on other rubies will raise
|
111
|
+
Sourcify::PlatformNotSupportedError.
|
112
|
+
|
113
|
+
*NOTE*: The following works for methods defined using both def .. end &
|
114
|
+
Module#define_method. However, when a method is defined using the later
|
115
|
+
approach, sourcify uses Proc#to_source to handle the processing, thus, the
|
116
|
+
usual gotchas related to proc source extraction apply.
|
117
|
+
|
118
|
+
=== 1. Method#to_source
|
119
|
+
|
120
|
+
Returns the code representation of the method:
|
121
|
+
|
122
|
+
require 'sourcify'
|
123
|
+
|
124
|
+
class MyMath
|
125
|
+
def self.sum(x, y)
|
126
|
+
x + y # (blah)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
MyMath.method(:sum).to_source
|
131
|
+
# >> "def sum(x, y)
|
132
|
+
# >> (x + y)
|
133
|
+
# >> end"
|
134
|
+
|
135
|
+
Just like the Proc#to_source equivalent, u can set :strip_enclosure => true
|
136
|
+
to extract only the body within.
|
137
|
+
|
138
|
+
=== 2. Method#to_sexp
|
139
|
+
|
140
|
+
Returns the S-expression of the method:
|
141
|
+
|
142
|
+
require 'sourcify'
|
143
|
+
|
144
|
+
class MyMath
|
145
|
+
def self.sum(x, y)
|
146
|
+
x + y # (blah)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
MyMath.method(:sum).to_sexp
|
151
|
+
>> s(:defn,
|
152
|
+
>> :sum,
|
153
|
+
>> s(:args, :x, :y),
|
154
|
+
>> s(:scope, s(:block, s(:call, s(:lvar, :x), :+, s(:arglist, s(:lvar, :y))))))
|
155
|
+
|
156
|
+
Just like the Proc#to_sexp equivalent, u can set :strip_enclosure => true
|
157
|
+
to extract only the body within.
|
158
|
+
|
159
|
+
=== 3. Method#to_raw_source
|
160
|
+
|
161
|
+
Unlike Method#to_source, which returns code that retains only functional aspects,
|
162
|
+
fetching of raw source returns the method's raw code, including fluff like comments:
|
163
|
+
|
164
|
+
require 'sourcify'
|
165
|
+
|
166
|
+
class MyMath
|
167
|
+
def self.sum(x, y)
|
168
|
+
x + y # (blah)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
MyMath.method(:sum).to_source
|
173
|
+
# >> "def sum(x, y)
|
174
|
+
# >> x + y # (blah)
|
175
|
+
# >> end"
|
176
|
+
|
177
|
+
Just like the Proc#to_raw_source equivalent, u can set :strip_enclosure => true
|
178
|
+
to extract only the body within.
|
179
|
+
|
180
|
+
|
104
181
|
== Performance
|
105
182
|
|
106
183
|
Performance is embarassing for now, benchmarking results for processing 500 procs
|
@@ -117,6 +194,7 @@ probably become better & faster as my knowlegde & skills with ragel improve. Als
|
|
117
194
|
instead of generating a pure ruby scanner, we can generate native code (eg. C or java, or
|
118
195
|
whatever) instead. As i'm a C & java noob, this will probably take some time to realize.
|
119
196
|
|
197
|
+
|
120
198
|
== Gotchas
|
121
199
|
|
122
200
|
Nothing beats ParseTree's ability to access the runtime AST, it is a very powerful feature.
|
@@ -210,6 +288,7 @@ Under the hood, sourcify relies on RubyParser to yield s-expression, and since R
|
|
210
288
|
does not yet fully handle 1.8.7 & 1.9.* syntax, you will get a nasty Racc::ParseError when
|
211
289
|
you have any code that is not compatible with 1.8.6.
|
212
290
|
|
291
|
+
|
213
292
|
== Is it really working ??
|
214
293
|
|
215
294
|
Sourcify spec suite currently passes in the following rubies:
|
@@ -226,6 +305,7 @@ For projects:
|
|
226
305
|
|
227
306
|
(TODO: the more the merrier)
|
228
307
|
|
308
|
+
|
229
309
|
== Projects using it
|
230
310
|
|
231
311
|
Projects using sourcify include:
|
@@ -233,6 +313,7 @@ Projects using sourcify include:
|
|
233
313
|
* ruote[http://ruote.rubyforge.org/]
|
234
314
|
* dm-ambition[https://github.com/dkubb/dm-ambition]
|
235
315
|
|
316
|
+
|
236
317
|
== Additional Resources
|
237
318
|
|
238
319
|
Sourcify is heavily inspired by many ideas gathered from the ruby community:
|
@@ -243,8 +324,9 @@ Sourcify is heavily inspired by many ideas gathered from the ruby community:
|
|
243
324
|
The sad fact that Proc#to_source wouldn't be available in the near future:
|
244
325
|
* http://redmine.ruby-lang.org/issues/show/2080
|
245
326
|
|
327
|
+
|
246
328
|
== Note on Patches/Pull Requests
|
247
|
-
|
329
|
+
|
248
330
|
* Fork the project.
|
249
331
|
* Make your feature addition or bug fix.
|
250
332
|
* Add tests for it. This is important so I don't break it in a
|
@@ -253,6 +335,7 @@ The sad fact that Proc#to_source wouldn't be available in the near future:
|
|
253
335
|
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
254
336
|
* Send me a pull request. Bonus points for topic branches.
|
255
337
|
|
338
|
+
|
256
339
|
== Copyright
|
257
340
|
|
258
341
|
Copyright (c) 2010 NgTzeYang. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -8,20 +8,38 @@ task :default => :spec
|
|
8
8
|
|
9
9
|
RUBIES = {
|
10
10
|
:parsetree => [
|
11
|
-
'ruby-1.8.6-p420@sourcify-parsetree',
|
12
|
-
'ruby-1.8.7-p334@sourcify-parsetree',
|
13
|
-
'ree-1.8.7-2011.03@sourcify-parsetree'
|
11
|
+
[nil, 'ruby-1.8.6-p420@sourcify-parsetree'],
|
12
|
+
[nil, 'ruby-1.8.7-p334@sourcify-parsetree'],
|
13
|
+
[nil, 'ree-1.8.7-2011.03@sourcify-parsetree']
|
14
14
|
],
|
15
15
|
:static => [
|
16
|
-
'ruby-1.8.6-p420@sourcify',
|
17
|
-
'ruby-1.8.7-p334@sourcify',
|
18
|
-
'ree-1.8.7-2011.03@sourcify',
|
19
|
-
'jruby-1.6.
|
20
|
-
'ruby-1.9.1-p378@sourcify',
|
21
|
-
'ruby-1.9.2-
|
16
|
+
[nil, 'ruby-1.8.6-p420@sourcify'],
|
17
|
+
[nil, 'ruby-1.8.7-p334@sourcify'],
|
18
|
+
[nil, 'ree-1.8.7-2011.03@sourcify'],
|
19
|
+
[nil, 'jruby-1.6.3@sourcify'],
|
20
|
+
[nil, 'ruby-1.9.1-p378@sourcify'],
|
21
|
+
['METHOD_TO_SOURCE=true', 'ruby-1.9.2-p290@sourcify'],
|
22
|
+
|
23
|
+
# NOTE: This doesn't support Method#to_source (& friends) yet yet due to
|
24
|
+
# jruby's Method#parameters bug, see http://jira.codehaus.org/browse/JRUBY-5954
|
25
|
+
['JRUBY_OPTS="--1.9"', 'jruby-1.6.3@sourcify'],
|
26
|
+
|
22
27
|
]
|
23
28
|
}
|
24
29
|
|
30
|
+
def run_spec_script_for(envs_and_rubies)
|
31
|
+
envs_and_rubies.group_by{|arry| arry[0..-2] }.each do |envs, arry|
|
32
|
+
rubies = arry.map(&:last)
|
33
|
+
declared_envs = ['export MUTE_BACON=true']
|
34
|
+
declared_envs << envs.map{|env| env ? "export #{env}" : nil }.compact
|
35
|
+
|
36
|
+
system [
|
37
|
+
declared_envs.flatten.join('; '),
|
38
|
+
"rvm #{rubies.join(',')} exec #{SPEC_SCRIPT}"
|
39
|
+
].join('; ')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
25
43
|
# ///////////////////////////////////////////////////////////
|
26
44
|
# Running Specs
|
27
45
|
# ///////////////////////////////////////////////////////////
|
@@ -32,20 +50,34 @@ end
|
|
32
50
|
|
33
51
|
desc "Run specs in all rubies (both ParseTree & static scanner modes)"
|
34
52
|
task :'spec:all' do
|
35
|
-
|
36
|
-
RUBIES.values.flatten.join(',') + ' exec ' + SPEC_SCRIPT
|
53
|
+
run_spec_script_for RUBIES.values.flatten(1)
|
37
54
|
end
|
38
55
|
|
39
56
|
desc "Run specs in rubies supporting ParseTree mode"
|
40
57
|
task :'spec:parsetree' do
|
41
|
-
|
42
|
-
RUBIES[:parsetree].join(',') + ' exec ' + SPEC_SCRIPT
|
58
|
+
run_spec_script_for RUBIES[:parsetree]
|
43
59
|
end
|
44
60
|
|
45
61
|
desc "Run specs in rubies supporting static scanner mode"
|
46
62
|
task :'spec:static' do
|
47
|
-
|
48
|
-
|
63
|
+
run_spec_script_for RUBIES[:static]
|
64
|
+
end
|
65
|
+
|
66
|
+
# ///////////////////////////////////////////////////////////
|
67
|
+
# Build ruby files from ragel definitions
|
68
|
+
# ///////////////////////////////////////////////////////////
|
69
|
+
desc "Run ragel to generate ruby scanner files from ragel definitions"
|
70
|
+
task :ragel do
|
71
|
+
%w{method proc}.each do |m|
|
72
|
+
common_dir = File.expand_path('../lib/sourcify/common/ragel', __FILE__)
|
73
|
+
ragel_dir = File.expand_path("../lib/sourcify/#{m}/parser", __FILE__)
|
74
|
+
ragel_file = File.join(ragel_dir, 'raw_scanner.rl')
|
75
|
+
ruby_file = File.join(ragel_dir, 'raw_scanner.rb')
|
76
|
+
File.delete(ruby_file) rescue nil
|
77
|
+
puts 'Processing %s -> %s' %
|
78
|
+
[ragel_file, ruby_file].map{|f| f.sub(File.expand_path('../', __FILE__) + '/', '')}
|
79
|
+
system("ragel -I #{common_dir} -R #{ragel_file}")
|
80
|
+
end
|
49
81
|
end
|
50
82
|
|
51
83
|
# ///////////////////////////////////////////////////////////
|
data/lib/sourcify.rb
CHANGED
@@ -12,6 +12,17 @@ rescue LoadError
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module Sourcify #:nodoc:
|
15
|
+
|
16
|
+
IS_19x = RUBY_VERSION.include?('1.9.')
|
17
|
+
|
18
|
+
HAS_RIPPER =
|
19
|
+
begin
|
20
|
+
require 'ripper'
|
21
|
+
true
|
22
|
+
rescue LoadError
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
15
26
|
class << self
|
16
27
|
|
17
28
|
def require_rb(*args)
|
@@ -27,5 +38,7 @@ module Sourcify #:nodoc:
|
|
27
38
|
end
|
28
39
|
|
29
40
|
Sourcify.require_rb('facets')
|
41
|
+
Sourcify.require_rb('errors')
|
30
42
|
Sourcify.require_rb('version')
|
31
43
|
Sourcify.require_rb('proc')
|
44
|
+
Sourcify.require_rb('method')
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sourcify
|
2
|
+
module Common
|
3
|
+
class Parser #:nodoc:all
|
4
|
+
class Converter
|
5
|
+
class << self
|
6
|
+
|
7
|
+
RUBY_PARSER = RubyParser.new
|
8
|
+
RUBY_2_RUBY = Ruby2Ruby.new
|
9
|
+
|
10
|
+
def to_sexp(code, file = nil)
|
11
|
+
retried = false
|
12
|
+
begin
|
13
|
+
RUBY_PARSER.reset
|
14
|
+
(retried ? RubyParser.new : RUBY_PARSER).parse(*[code, file].compact)
|
15
|
+
rescue Racc::ParseError, SyntaxError
|
16
|
+
return nil if retried
|
17
|
+
retried = true; retry
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_code(sexp)
|
22
|
+
RUBY_2_RUBY.process(Sexp.from_array(sexp.to_a))
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Sourcify
|
2
|
+
module Common
|
3
|
+
class Parser
|
4
|
+
module RawScanner #:nodoc:all
|
5
|
+
class Comment
|
6
|
+
|
7
|
+
def <<(content)
|
8
|
+
(@contents ||= []) << content
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
@contents.join
|
13
|
+
end
|
14
|
+
|
15
|
+
def closed?
|
16
|
+
@contents[-1].split("\n")[-1].strip == '=end'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Sourcify
|
2
|
+
module Common
|
3
|
+
class Parser
|
4
|
+
module RawScanner #:nodoc:all
|
5
|
+
class Counter
|
6
|
+
|
7
|
+
attr_reader :counts
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@counts = [0,0]
|
11
|
+
end
|
12
|
+
|
13
|
+
def started?
|
14
|
+
@counts.any?(&:nonzero?)
|
15
|
+
end
|
16
|
+
|
17
|
+
def just_started?
|
18
|
+
@counts.any?{|count| count == 1 }
|
19
|
+
end
|
20
|
+
|
21
|
+
def balanced?
|
22
|
+
@counts.any?(&:zero?)
|
23
|
+
end
|
24
|
+
|
25
|
+
def decrement
|
26
|
+
(0..1).each{|i| @counts[i] -= 1 unless @counts[i].zero? }
|
27
|
+
end
|
28
|
+
|
29
|
+
def increment(val = 1)
|
30
|
+
if val.is_a?(Range)
|
31
|
+
@counts[0] += val.first
|
32
|
+
@counts[1] += val.last
|
33
|
+
else
|
34
|
+
(0..1).each{|i| @counts[i] += 1 }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Sourcify
|
2
|
+
module Common
|
3
|
+
class Parser
|
4
|
+
module RawScanner #:nodoc:all
|
5
|
+
class DString < Struct.new(:tag)
|
6
|
+
|
7
|
+
# To suppress 'warning: Object#type is deprecated; use Object#class' when
|
8
|
+
# evaluating string
|
9
|
+
attr_reader :type
|
10
|
+
|
11
|
+
def <<(content)
|
12
|
+
(@contents ||= []) << content
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
@contents.join
|
17
|
+
end
|
18
|
+
|
19
|
+
def closed?
|
20
|
+
evaluable? && parsable?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
CLOSING_TAGS = {'(' => ')', '[' => ']', '<' => '>', '{' => '}'}
|
26
|
+
|
27
|
+
def evaluable?
|
28
|
+
@contents[-1][-1].chr == end_tag
|
29
|
+
end
|
30
|
+
|
31
|
+
def parsable?
|
32
|
+
begin
|
33
|
+
RubyParser.new.parse(safe_contents)
|
34
|
+
true
|
35
|
+
rescue Exception
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def safe_contents
|
41
|
+
# NOTE: %x & ` strings are dangerous to eval cos they execute shell commands,
|
42
|
+
# thus we convert them to normal strings 1st
|
43
|
+
to_s.gsub(/(%x)(\W|\_)/, '%Q\2').gsub(/.{0,2}(`)/) do |s|
|
44
|
+
s =~ /^(%Q|%W|%r|%x|.?%|.?\\)/ ? s : s.sub(/`$/,'%Q`')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def start_tag
|
49
|
+
@start_tag ||= tag[-1].chr
|
50
|
+
end
|
51
|
+
|
52
|
+
def end_tag
|
53
|
+
@end_tag ||= (CLOSING_TAGS[start_tag] || start_tag)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
%w{heredoc comment dstring counter}.each do |f|
|
2
|
+
Sourcify.require_rb('common', 'parser', 'raw_scanner', f)
|
3
|
+
end
|
4
|
+
|
5
|
+
module Sourcify
|
6
|
+
module Common
|
7
|
+
class Parser
|
8
|
+
module RawScanner #:nodoc:all
|
9
|
+
module Extensions
|
10
|
+
|
11
|
+
class Escape < Exception; end
|
12
|
+
|
13
|
+
def process(data, opts={})
|
14
|
+
begin
|
15
|
+
@start_pattern = opts[:start_pattern] || /.*/
|
16
|
+
@body_matcher = opts[:body_matcher] || lambda{|_| true }
|
17
|
+
@stop_on_newline = opts[:stop_on_newline]
|
18
|
+
@results, @data = [], data.unpack("c*")
|
19
|
+
reset_attributes
|
20
|
+
execute!
|
21
|
+
rescue Escape
|
22
|
+
@results
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def data_frag(range)
|
27
|
+
@data[range].pack('c*')
|
28
|
+
end
|
29
|
+
|
30
|
+
def push(key, ts, te)
|
31
|
+
@tokens << [key, data_frag(ts .. te.pred)]
|
32
|
+
end
|
33
|
+
|
34
|
+
def push_dstring(ts, te)
|
35
|
+
data = data_frag(ts .. te.pred)
|
36
|
+
@dstring ||= DString.new(data[%r{^("|`|/|%(?:Q|W|r|x|)(?:\W|_))},1])
|
37
|
+
@dstring << data
|
38
|
+
return true unless @dstring.closed?
|
39
|
+
@tokens << [:dstring, @dstring.to_s]
|
40
|
+
@dstring = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def push_comment(ts, te)
|
44
|
+
data = data_frag(ts .. te.pred)
|
45
|
+
@comment ||= Comment.new
|
46
|
+
@comment << data
|
47
|
+
return true unless @comment.closed?
|
48
|
+
@tokens << [:comment, @comment.to_s]
|
49
|
+
@comment = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def push_heredoc(ts, te)
|
53
|
+
data = data_frag(ts .. te.pred)
|
54
|
+
unless @heredoc
|
55
|
+
indented, tag = data.match(/\<\<(\-?)['"]?(\w+)['"]?$/)[1..3]
|
56
|
+
@heredoc = Heredoc.new(tag, !indented.empty?)
|
57
|
+
end
|
58
|
+
@heredoc << data
|
59
|
+
return true unless @heredoc.closed?(data_frag(te .. te))
|
60
|
+
@tokens << [:heredoc, @heredoc.to_s]
|
61
|
+
@heredoc = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def push_label(ts, te)
|
65
|
+
# NOTE: 1.9.* supports label key, which RubyParser cannot handle, thus
|
66
|
+
# conversion is needed.
|
67
|
+
@tokens << [:symbol, ':' + data_frag(ts .. te - 2)]
|
68
|
+
@tokens << [:space, ' ']
|
69
|
+
@tokens << [:assoc, '=>']
|
70
|
+
end
|
71
|
+
|
72
|
+
def preceded_with?(*args)
|
73
|
+
prev_token = @tokens[-1][0] == :space ? @tokens[-2] : @tokens[-1]
|
74
|
+
!([args].flatten & prev_token).empty? rescue nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def increment_lineno
|
78
|
+
@lineno += 1
|
79
|
+
raise Escape \
|
80
|
+
if @stop_on_newline || !@results.empty? || (@results.empty? && @rejecting_block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def codified_tokens
|
84
|
+
@tokens.map(&:last).join
|
85
|
+
end
|
86
|
+
|
87
|
+
def reset_attributes
|
88
|
+
@tokens, @lineno = [], 1
|
89
|
+
@heredoc, @dstring, @comment, @rejecting_block = nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def offset_attributes
|
93
|
+
@lineno = 1 # Fixing JRuby's lineno bug (see http://jira.codehaus.org/browse/JRUBY-5014)
|
94
|
+
@tokens = [@tokens[-1]] unless @tokens.empty?
|
95
|
+
end
|
96
|
+
|
97
|
+
if HAS_RIPPER
|
98
|
+
|
99
|
+
def valid?(snippet, validate_as = nil)
|
100
|
+
sexp = Ripper.sexp(snippet)
|
101
|
+
|
102
|
+
case validate_as
|
103
|
+
when :hash then sexp[-1][0][0] == :hash
|
104
|
+
when nil then sexp && true
|
105
|
+
else raise ArgumentError
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
else
|
110
|
+
|
111
|
+
def valid?(snippet, _ = nil)
|
112
|
+
RubyParser.new.parse("#{snippet}") rescue false
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|