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.
Files changed (130) hide show
  1. data/.gitignore +1 -0
  2. data/HISTORY.txt +5 -0
  3. data/README.rdoc +86 -3
  4. data/Rakefile +47 -15
  5. data/lib/sourcify.rb +13 -0
  6. data/lib/sourcify/common/parser/converter.rb +29 -0
  7. data/lib/sourcify/common/parser/raw_scanner/comment.rb +23 -0
  8. data/lib/sourcify/common/parser/raw_scanner/counter.rb +43 -0
  9. data/lib/sourcify/common/parser/raw_scanner/dstring.rb +60 -0
  10. data/lib/sourcify/common/parser/raw_scanner/extensions.rb +121 -0
  11. data/lib/sourcify/common/parser/raw_scanner/heredoc.rb +26 -0
  12. data/lib/sourcify/common/parser/source_code.rb +33 -0
  13. data/lib/sourcify/common/ragel/common.rl +5 -0
  14. data/lib/sourcify/common/ragel/expressions.rl +38 -0
  15. data/lib/sourcify/{proc/scanner.rl → common/ragel/machines.rl} +10 -178
  16. data/lib/sourcify/errors.rb +4 -0
  17. data/lib/sourcify/method.rb +134 -0
  18. data/lib/sourcify/method/methods.rb +3 -0
  19. data/lib/sourcify/method/methods/to_raw_source.rb +30 -0
  20. data/lib/sourcify/method/methods/to_sexp.rb +30 -0
  21. data/lib/sourcify/method/methods/to_source.rb +30 -0
  22. data/lib/sourcify/method/parser.rb +104 -0
  23. data/lib/sourcify/method/parser/converter.rb +8 -0
  24. data/lib/sourcify/method/parser/raw_scanner.rb +2494 -0
  25. data/lib/sourcify/method/parser/raw_scanner.rl +144 -0
  26. data/lib/sourcify/method/parser/raw_scanner_extensions.rb +64 -0
  27. data/lib/sourcify/method/parser/scanner.rb +48 -0
  28. data/lib/sourcify/method/parser/source_code.rb +8 -0
  29. data/lib/sourcify/proc.rb +0 -2
  30. data/lib/sourcify/proc/parser.rb +2 -5
  31. data/lib/sourcify/proc/parser/converter.rb +2 -23
  32. data/lib/sourcify/proc/{scanner.rb → parser/raw_scanner.rb} +808 -806
  33. data/lib/sourcify/proc/parser/raw_scanner.rl +149 -0
  34. data/lib/sourcify/proc/parser/raw_scanner_extensions.rb +72 -0
  35. data/lib/sourcify/proc/parser/{code_scanner.rb → scanner.rb} +9 -5
  36. data/lib/sourcify/proc/parser/source_code.rb +2 -27
  37. data/lib/sourcify/version.rb +1 -1
  38. data/spec/method/others_from_def_end_block_spec.rb +49 -0
  39. data/spec/method/others_from_define_method_spec.rb +62 -0
  40. data/spec/method/raw_scanner/block_comment_spec.rb +8 -0
  41. data/spec/method/raw_scanner/double_colons_spec.rb +8 -0
  42. data/spec/method/raw_scanner/double_quote_str_w_interpolation_spec.rb +8 -0
  43. data/spec/method/raw_scanner/double_quote_str_wo_interpolation_spec.rb +8 -0
  44. data/spec/method/raw_scanner/heredoc_w_indent_spec.rb +8 -0
  45. data/spec/method/raw_scanner/heredoc_wo_indent_spec.rb +8 -0
  46. data/spec/method/raw_scanner/kw_block_start_alias1_spec.rb +20 -0
  47. data/spec/method/raw_scanner/kw_block_start_alias2_spec.rb +20 -0
  48. data/spec/method/raw_scanner/per_line_comment_spec.rb +8 -0
  49. data/spec/method/raw_scanner/single_quote_str_spec.rb +8 -0
  50. data/spec/method/raw_scanner/slash_operator_spec.rb +8 -0
  51. data/spec/method/raw_scanner/spec_helper.rb +80 -0
  52. data/spec/method/spec_helper.rb +1 -0
  53. data/spec/method/to_raw_source_spec.rb +31 -0
  54. data/spec/method/to_raw_source_w_specified_strip_enclosure_spec.rb +148 -0
  55. data/spec/method/to_sexp_from_def_end_block_w_variables_spec.rb +46 -0
  56. data/spec/method/to_sexp_from_def_end_block_within_irb_spec.rb +38 -0
  57. data/spec/method/to_sexp_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb +56 -0
  58. data/spec/method/to_sexp_from_define_method_w_variables_spec.rb +52 -0
  59. data/spec/method/to_sexp_from_define_method_within_irb_spec.rb +42 -0
  60. data/spec/method/to_sexp_w_specified_strip_enclosure_spec.rb +74 -0
  61. data/spec/method/to_source_from_def_end_block_w_19_extras_spec.rb +23 -0
  62. data/spec/method/to_source_from_def_end_block_w_nested_begin_spec.rb +35 -0
  63. data/spec/method/to_source_from_def_end_block_w_nested_case_spec.rb +35 -0
  64. data/spec/method/to_source_from_def_end_block_w_nested_class_spec.rb +51 -0
  65. data/spec/method/to_source_from_def_end_block_w_nested_do_end_block_spec.rb +33 -0
  66. data/spec/method/to_source_from_def_end_block_w_nested_for_spec.rb +126 -0
  67. data/spec/method/to_source_from_def_end_block_w_nested_if_spec.rb +82 -0
  68. data/spec/method/to_source_from_def_end_block_w_nested_literal_keyword_spec.rb +141 -0
  69. data/spec/method/to_source_from_def_end_block_w_nested_method_spec.rb +33 -0
  70. data/spec/method/to_source_from_def_end_block_w_nested_module_spec.rb +59 -0
  71. data/spec/method/to_source_from_def_end_block_w_nested_unless_spec.rb +82 -0
  72. data/spec/method/to_source_from_def_end_block_w_nested_until_spec.rb +179 -0
  73. data/spec/method/to_source_from_def_end_block_w_nested_while_spec.rb +179 -0
  74. data/spec/method/to_source_from_def_end_block_w_singleton_method_spec.rb +19 -0
  75. data/spec/method/to_source_from_def_end_block_within_irb_spec.rb +30 -0
  76. data/spec/method/to_source_from_def_end_w_multi_blocks_and_many_matches_spec.rb +30 -0
  77. data/spec/method/to_source_from_def_end_w_multi_blocks_and_single_match_spec.rb +36 -0
  78. data/spec/method/to_source_from_define_method_w_braced_block_spec.rb +113 -0
  79. data/spec/method/to_source_from_define_method_w_do_end_block_spec.rb +145 -0
  80. data/spec/method/to_source_from_define_method_w_multi_blocks_and_many_matches_spec.rb +56 -0
  81. data/spec/method/to_source_from_define_method_w_multi_blocks_and_single_match_spec.rb +73 -0
  82. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_many_matches_spec.rb +36 -0
  83. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_no_match_spec.rb +36 -0
  84. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_and_single_match_spec.rb +28 -0
  85. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_attached_to_spec.rb +103 -0
  86. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_many_matches_spec.rb +36 -0
  87. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_no_match_spec.rb +36 -0
  88. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_body_matcher_and_single_match_spec.rb +28 -0
  89. data/spec/method/to_source_from_define_method_w_multi_blocks_and_specified_ignore_nested_spec.rb +36 -0
  90. data/spec/method/to_source_from_define_method_within_irb_spec.rb +32 -0
  91. data/spec/method/to_source_magic_file_var_spec.rb +176 -0
  92. data/spec/method/to_source_magic_line_var_spec.rb +298 -0
  93. data/spec/method/to_source_w_specified_strip_enclosure_spec.rb +39 -0
  94. data/spec/no_method/unsupported_platform_spec.rb +26 -0
  95. data/spec/proc/raw_scanner/block_comment_spec.rb +8 -0
  96. data/spec/proc/raw_scanner/double_colons_spec.rb +8 -0
  97. data/spec/proc/raw_scanner/double_quote_str_w_interpolation_spec.rb +8 -0
  98. data/spec/proc/raw_scanner/double_quote_str_wo_interpolation_spec.rb +8 -0
  99. data/spec/proc/raw_scanner/heredoc_w_indent_spec.rb +8 -0
  100. data/spec/proc/raw_scanner/heredoc_wo_indent_spec.rb +8 -0
  101. data/spec/proc/raw_scanner/kw_block_start_alias1_spec.rb +20 -0
  102. data/spec/proc/raw_scanner/kw_block_start_alias2_spec.rb +20 -0
  103. data/spec/proc/raw_scanner/per_line_comment_spec.rb +8 -0
  104. data/spec/proc/raw_scanner/single_quote_str_spec.rb +8 -0
  105. data/spec/proc/raw_scanner/slash_operator_spec.rb +8 -0
  106. data/spec/proc/raw_scanner/spec_helper.rb +63 -0
  107. data/spec/{proc_scanner/block_comment_spec.rb → raw_scanner/block_comment_shared_spec.rb} +1 -5
  108. data/spec/{proc_scanner/double_colons_spec.rb → raw_scanner/double_colons_shared_spec.rb} +1 -5
  109. data/spec/{proc_scanner/double_quote_str_w_interpolation_spec.rb → raw_scanner/double_quote_str_w_interpolation_shared_spec.rb} +1 -5
  110. data/spec/{proc_scanner/double_quote_str_wo_interpolation_spec.rb → raw_scanner/double_quote_str_wo_interpolation_shared_spec.rb} +1 -5
  111. data/spec/raw_scanner/heredoc_w_indent_shared_spec.rb +69 -0
  112. data/spec/raw_scanner/heredoc_wo_indent_shared_spec.rb +70 -0
  113. data/spec/{proc_scanner/kw_do_alias1_spec.rb → raw_scanner/kw_block_start_alias1_shared_spec.rb} +10 -26
  114. data/spec/{proc_scanner/kw_do_alias2_spec.rb → raw_scanner/kw_block_start_alias2_shared_spec.rb} +10 -25
  115. data/spec/{proc_scanner/per_line_comment_spec.rb → raw_scanner/per_line_comment_shared_spec.rb} +1 -5
  116. data/spec/raw_scanner/shared_specs.rb +3 -0
  117. data/spec/{proc_scanner/single_quote_str_spec.rb → raw_scanner/single_quote_str_shared_spec.rb} +1 -5
  118. data/spec/{proc_scanner/slash_operator_spec.rb → raw_scanner/slash_operator_shared_spec.rb} +1 -5
  119. data/spec/run_spec.sh +7 -1
  120. data/spec/spec_helper.rb +8 -25
  121. metadata +204 -47
  122. data/.rvmrc +0 -1
  123. data/VERSION +0 -1
  124. data/lib/sourcify/proc/scanner/comment.rb +0 -21
  125. data/lib/sourcify/proc/scanner/counter.rb +0 -44
  126. data/lib/sourcify/proc/scanner/dstring.rb +0 -59
  127. data/lib/sourcify/proc/scanner/extensions.rb +0 -171
  128. data/lib/sourcify/proc/scanner/heredoc.rb +0 -24
  129. data/spec/proc_scanner/heredoc_spec.rb +0 -144
  130. data/spec/proc_scanner/spec_helper.rb +0 -33
data/.gitignore CHANGED
@@ -20,4 +20,5 @@ pkg
20
20
  Gemfile.lock
21
21
 
22
22
  ## PROJECT::SPECIFIC
23
+ .rvmrc
23
24
  tmp
@@ -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
@@ -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.1@sourcify',
20
- 'ruby-1.9.1-p378@sourcify',
21
- 'ruby-1.9.2-p180@sourcify',
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
- system 'export MUTE_BACON=true; rvm ' +
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
- system 'export MUTE_BACON=true; rvm ' +
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
- system 'export MUTE_BACON=true; rvm ' +
48
- RUBIES[:static].join(',') + ' exec ' + SPEC_SCRIPT
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
  # ///////////////////////////////////////////////////////////
@@ -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