sourcify 0.5.0 → 0.6.0.rc1

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.
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