rcodetools 0.4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/CHANGES +18 -0
  2. data/README +34 -0
  3. data/README.emacs +54 -0
  4. data/README.method_analysis +13 -0
  5. data/README.vim +84 -0
  6. data/README.xmpfilter +202 -0
  7. data/Rakefile +123 -0
  8. data/Rakefile.method_analysis +30 -0
  9. data/THANKS +6 -0
  10. data/bin/rct-complete +37 -0
  11. data/bin/rct-doc +50 -0
  12. data/bin/rct-meth-args +392 -0
  13. data/bin/xmpfilter +75 -0
  14. data/icicles-rcodetools.el +31 -0
  15. data/lib/method_analyzer.rb +107 -0
  16. data/lib/rcodetools/completion.rb +282 -0
  17. data/lib/rcodetools/doc.rb +176 -0
  18. data/lib/rcodetools/options.rb +83 -0
  19. data/lib/rcodetools/xmpfilter.rb +208 -0
  20. data/lib/rcodetools/xmptestunitfilter.rb +197 -0
  21. data/rcodetools.el +162 -0
  22. data/rcodetools.vim +118 -0
  23. data/setup.rb +1585 -0
  24. data/test/data/add_markers-input.rb +2 -0
  25. data/test/data/add_markers-output.rb +2 -0
  26. data/test/data/bindings-input.rb +26 -0
  27. data/test/data/bindings-output.rb +31 -0
  28. data/test/data/completion-input.rb +1 -0
  29. data/test/data/completion-output.rb +2 -0
  30. data/test/data/completion_emacs-input.rb +1 -0
  31. data/test/data/completion_emacs-output.rb +5 -0
  32. data/test/data/completion_emacs_icicles-input.rb +1 -0
  33. data/test/data/completion_emacs_icicles-output.rb +5 -0
  34. data/test/data/doc-input.rb +1 -0
  35. data/test/data/doc-output.rb +1 -0
  36. data/test/data/method_analyzer-data.rb +33 -0
  37. data/test/data/method_args.data.rb +106 -0
  38. data/test/data/no_warnings-input.rb +3 -0
  39. data/test/data/no_warnings-output.rb +4 -0
  40. data/test/data/refe-input.rb +1 -0
  41. data/test/data/refe-output.rb +1 -0
  42. data/test/data/ri-input.rb +1 -0
  43. data/test/data/ri-output.rb +1 -0
  44. data/test/data/ri_emacs-input.rb +1 -0
  45. data/test/data/ri_emacs-output.rb +1 -0
  46. data/test/data/ri_vim-input.rb +1 -0
  47. data/test/data/ri_vim-output.rb +1 -0
  48. data/test/data/rspec-input.rb +48 -0
  49. data/test/data/rspec-output.rb +52 -0
  50. data/test/data/rspec_poetry-input.rb +48 -0
  51. data/test/data/rspec_poetry-output.rb +52 -0
  52. data/test/data/simple_annotation-input.rb +8 -0
  53. data/test/data/simple_annotation-output.rb +8 -0
  54. data/test/data/unit_test-input.rb +50 -0
  55. data/test/data/unit_test-output.rb +52 -0
  56. data/test/data/unit_test_poetry-input.rb +50 -0
  57. data/test/data/unit_test_poetry-output.rb +52 -0
  58. data/test/test_completion.rb +467 -0
  59. data/test/test_doc.rb +403 -0
  60. data/test/test_functional.rb +18 -0
  61. data/test/test_method_analyzer.rb +99 -0
  62. data/test/test_method_args.rb +134 -0
  63. data/test/test_run.rb +41 -0
  64. data/test/test_xmpfilter.rb +36 -0
  65. data/test/test_xmptestunitfilter.rb +84 -0
  66. metadata +139 -0
@@ -0,0 +1,30 @@
1
+
2
+ # Rake tasks to generate TAGS and gather method analysis information.
3
+ # See README.method_analysis for more information.
4
+
5
+ ## my standard Rakefile
6
+ task :tags => "TAGS"
7
+
8
+ desc "Generate method_analysis by ruby -rmethod_analyzer."
9
+ task :analyze => [:_prepare_method_analyze, :tags] do
10
+ at_exit { sh "ls -l method_analysis" }
11
+ end
12
+
13
+ task :_prepare_method_analyze do
14
+ ENV['METHOD_ANALYZER_FORMAT']="marshal"
15
+ sh "rm -f method_analysis"
16
+ puts "generating method_analysis"
17
+ end
18
+
19
+ ## application-specific Rakefile (RTtool)
20
+ task :analyze do
21
+ sh "ruby -Ilib -rmethod_analyzer test/test.rb"
22
+ sh "ruby -Ilib -rmethod_analyzer test/test-rt2html-lib.rb"
23
+ sh "ruby -Ilib -rmethod_analyzer test/test-rtparser.rb"
24
+ end
25
+
26
+ file "TAGS" => FileList["lib/rt/*.rb"] do
27
+ sh "method_args.rb -t lib/rt/*.rb > TAGS"
28
+ end
29
+
30
+
data/THANKS ADDED
@@ -0,0 +1,6 @@
1
+ Some names forgotten, tell me if you care :) -- mfp
2
+
3
+ rubikitch
4
+ * expanded xmp3.rb (a previous version of xmpfilter.rb) to support RSpec expectations
5
+ * wrote the elisp magic to use xmpfilter.rb with emacs
6
+ * made the 100% accurate, editor-independent completion system
data/bin/rct-complete ADDED
@@ -0,0 +1,37 @@
1
+ #! /home/batsman/usr//bin/ruby
2
+ require 'rcodetools/xmpfilter'
3
+ require 'rcodetools/completion'
4
+ require 'rcodetools/options'
5
+
6
+ options = DEFAULT_OPTIONS
7
+ klass = XMPCompletionFilter
8
+
9
+ opts = OptionParser.new do |opts|
10
+ opts.extend OptionHandler
11
+ opts.set_banner
12
+
13
+ opts.separator ""
14
+ opts.separator "Modes:"
15
+ opts.on("-C", "--completion", "List completion candidates.(default)") do
16
+ klass = XMPCompletionFilter
17
+ end
18
+ opts.on("--completion-emacs", "Generate completion code for Emacs.") do
19
+ klass = XMPCompletionEmacsFilter
20
+ end
21
+ opts.on("--completion-emacs-icicles", "Generate completion code for Emacs/Icicles.") do
22
+ klass = XMPCompletionEmacsIciclesFilter
23
+ end
24
+
25
+ opts.handle_position options
26
+ opts.handle_interpreter options
27
+ opts.handle_misc options
28
+ end
29
+
30
+ set_extra_opts options
31
+ opts.parse!(ARGV)
32
+
33
+ targetcode = ARGF.read
34
+ Dir.chdir options[:wd] if options[:wd]
35
+
36
+ # Do the job. dispatched by klass.
37
+ puts klass.run(targetcode, options)
data/bin/rct-doc ADDED
@@ -0,0 +1,50 @@
1
+ #! /home/batsman/usr//bin/ruby
2
+ require 'rcodetools/xmpfilter'
3
+ require 'rcodetools/doc'
4
+ require 'rcodetools/options'
5
+
6
+ options = DEFAULT_OPTIONS
7
+ klass = XMPDocFilter
8
+
9
+ opts = OptionParser.new do |opts|
10
+ opts.extend OptionHandler
11
+ opts.set_banner
12
+
13
+ opts.separator ""
14
+ opts.separator "Modes:"
15
+ opts.on("-D", "--doc", "Print callee method with class.(default)") do
16
+ klass = XMPDocFilter
17
+ end
18
+ opts.on("--refe", "Refe callee method.") do
19
+ klass = XMPReFeFilter
20
+ end
21
+ opts.on("--ri", "Ri callee method.") do
22
+ klass = XMPRiFilter
23
+ end
24
+ opts.on("--ri-emacs", "Generate ri code for emacs.") do
25
+ klass = XMPRiEmacsFilter
26
+ end
27
+ opts.on("--ri-vim", "Generate ri code for vim.") do
28
+ klass = XMPRiVimFilter
29
+ end
30
+ opts.separator ""
31
+ opts.on("--use-method-analyzer", "") do |n|
32
+ options[:use_method_analyzer] = true
33
+ end
34
+ opts.on("--filename=FILENAME") do |n|
35
+ options[:filename] = File.expand_path n
36
+ end
37
+
38
+ opts.handle_position options
39
+ opts.handle_interpreter options
40
+ opts.handle_misc options
41
+ end
42
+
43
+ set_extra_opts options
44
+ opts.parse!(ARGV)
45
+
46
+ targetcode = ARGF.read
47
+ Dir.chdir options[:wd] if options[:wd]
48
+
49
+ # Do the job. dispatched by klass.
50
+ puts klass.run(targetcode, options)
data/bin/rct-meth-args ADDED
@@ -0,0 +1,392 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c)
3
+ # 2006 Mauricio Fernandez <mfp@acm.org> http://eigenclass.org
4
+ # 2006 rubikitch <rubikitch@ruby-lang.org> http://www.rubyist.net/~rubikitch/
5
+ #
6
+ # Use and distribution subject to the same conditions as Ruby.
7
+
8
+
9
+ $VERBOSE = nil
10
+ $__method_args_off = true
11
+
12
+ if ARGV.empty?
13
+ puts <<EOF
14
+ rct-meth-args [-i] [-m] [-c] [-n] <file> [<file> ...]
15
+
16
+ -i omit instance methods defined in classes
17
+ -m omit instance methods defined in modules
18
+ -c omit class methods
19
+
20
+ -n print the filename and line number with output lines
21
+ -t generate TAGS output
22
+
23
+ The given files will be #require()d in order.
24
+ Examples:
25
+ ruby method_args.rb complex
26
+ ruby method_args.rb thread
27
+ ruby method_args.rb -c rubygems
28
+ EOF
29
+ exit
30
+ end
31
+
32
+ def debugprint(*args)
33
+ $stderr.puts(*args) if $DEBUG
34
+ end
35
+
36
+ module MethodArgs
37
+ MAX_ARGS = 20
38
+
39
+ private
40
+ def needed_args(arity)
41
+ arity >= 0 ? arity : arity.abs - 1
42
+ end
43
+
44
+ def with_tracer
45
+ begin
46
+ set_trace_func @__trace_func
47
+ yield
48
+ ensure
49
+ set_trace_func nil
50
+ end
51
+ end
52
+
53
+ module LineContents
54
+ # usage: Contents[filename][lineno]
55
+ Contents = Hash.new{ |h,k|
56
+ sum = 0
57
+ # Unshift is needed because lineno starts with 1.
58
+ h[k] = File.readlines(k).map{ |line| [line.chomp, sum+=line.length] }.unshift nil
59
+ }
60
+ def content
61
+ Contents[filename][lineno.to_i][0] rescue ""
62
+ end
63
+
64
+ def byte
65
+ Contents[filename][lineno.to_i-1][1] rescue 0
66
+ end
67
+
68
+ def arg_desc
69
+ # TODO
70
+ desc = content[ /\((.+)\)/]
71
+ desc.gsub!(/(\S),(\S)/, '\1, \2')
72
+ desc.gsub!(/(\S)=(\S)/, '\1 = \2')
73
+ desc
74
+ end
75
+
76
+ FileNameCache = Hash.new{ |h,k| h[k] = File.expand_path(k) }
77
+ def full_filename
78
+ FileNameCache[filename]
79
+ end
80
+ end
81
+
82
+ class Location < Struct.new(:filename, :lineno)
83
+ include LineContents
84
+ end
85
+
86
+ class Printer
87
+ def method_info(io, x)
88
+ prefix = x[:location] ? "#{x[:location].filename}:#{x[:location].lineno}:" : ""
89
+ io.puts "#{prefix}#{x[:fullname]}#{x[:arg_desc]}" unless x[:klass].to_s == "<Struct>"
90
+ end
91
+
92
+ def included_location(io, x)
93
+ x[:callsite] and io.print "#{x[:callsite].filename}:#{x[:callsite].lineno}:"
94
+ io.puts([ x[:comment], x[:mod], x[:flag], x[:self] ].join(" "))
95
+ end
96
+ end
97
+
98
+ class TagsPrinter
99
+ def initialize
100
+ @previous_filename = ""
101
+ end
102
+
103
+ def output_filename(filename)
104
+ if @previous_filename != filename
105
+ @previous_filename = filename
106
+ puts "\cl"
107
+ puts "#{filename},0"
108
+ end
109
+ end
110
+
111
+ def method_info(io, x)
112
+ return unless x[:location]
113
+ output_filename x[:location].full_filename
114
+ io.puts "#{x[:location].content}::#{x[:fullname]}#{x[:location].lineno},#{x[:location].byte}"
115
+ end
116
+
117
+ def included_location(io, x)
118
+ return unless x[:callsite]
119
+ output_filename x[:callsite].full_filename
120
+ io.puts "#{x[:callsite].content}::#{x[:mod]}#{x[:callsite].lineno},#{x[:callsite].byte}"
121
+ end
122
+ end
123
+
124
+ def _print_method_info(klass, is_singleton, meth, arg_desc=nil, location=nil, with_location=$__with_location, printer=$__printer)
125
+ arg_desc ||= "(...)"
126
+ arg_desc = " " + arg_desc unless arg_desc.empty?
127
+ flag = is_singleton ? "." : "#"
128
+ x = { :arg_desc => arg_desc, :klass => klass,
129
+ :fullname => [klass, flag, meth].join,
130
+ :location => with_location && location,
131
+ }
132
+ printer.method_info $>, x
133
+ end
134
+
135
+ def output_attr_info(klass, object, meth, is_singleton, location)
136
+ arg_desc = meth.to_s =~ /=$/ ? "(value)" : ""
137
+ _print_method_info klass, is_singleton, meth, arg_desc, location
138
+ end
139
+
140
+ def output_method_info(klass, object, meth, is_singleton = false, by_attr = nil, by_define_method = nil)
141
+ return if $__method_args_off
142
+ file = line = params = values = nil
143
+ location = nil
144
+ begin
145
+ unless %w[initialize].include?(meth.to_s)
146
+ if is_singleton
147
+ return if class << klass; private_instance_methods(true) end.include?(meth.to_s)
148
+ else
149
+ return if class << object; private_instance_methods(true) end.include?(meth.to_s)
150
+ end
151
+ end
152
+ rescue TypeError # no virtual class
153
+ end
154
+
155
+ arity = is_singleton ? object.method(meth).arity : klass.instance_method(meth).arity
156
+ @__trace_func = lambda{|event, file, line, id, binding, classname|
157
+ begin
158
+ debugprint "!EVENT: #{event} #{classname}##{id}, #{file} #{line}"
159
+ debugprint "(#{self} #{meth})"
160
+ if event[/call/] && classname == self && id == meth
161
+ location = Location.new(file, line) if event == 'call'
162
+ debugprint "EVENT: #{event} #{classname}##{id}"
163
+ throw :done
164
+ end
165
+ rescue Exception
166
+ nil # rcov workaround
167
+ end
168
+ }
169
+ if by_define_method
170
+ _print_method_info klass, is_singleton, meth, nil, by_define_method
171
+ return
172
+ end
173
+
174
+ if by_attr
175
+ output_attr_info klass, object, meth, is_singleton, by_attr
176
+ return
177
+ end
178
+
179
+ catch(:done) do
180
+ begin
181
+ with_tracer { object.send(meth, *(0...needed_args(arity))) }
182
+ rescue Exception
183
+ nil # rcov workaround
184
+ end
185
+ end
186
+
187
+ arg_desc = location.arg_desc
188
+
189
+ _print_method_info klass, is_singleton, meth, arg_desc, location
190
+ rescue Exception
191
+ debugprint "GOT EXCEPTION while processing #{klass} #{meth}"
192
+ debugprint $!.class
193
+ debugprint $!.message
194
+ debugprint $!.backtrace
195
+ _print_method_info klass, is_singleton, meth, nil, location
196
+ ensure
197
+ set_trace_func(nil)
198
+ end
199
+ end
200
+
201
+ class Object
202
+ include MethodArgs
203
+ end
204
+
205
+ class Module
206
+ class CallSite # compatible with Location
207
+ include MethodArgs::LineContents
208
+ def initialize(caller_string)
209
+ @filename, @lineno, @in = caller_string.split(/:/)
210
+ end
211
+ attr_reader :filename, :lineno
212
+ end
213
+
214
+ def _method_defined_with(ivar, caller, &block)
215
+ begin
216
+ instance_variable_set(ivar, caller)
217
+ yield
218
+ ensure
219
+ instance_variable_set(ivar, false)
220
+ end
221
+ end
222
+
223
+ def with_attr(caller, &block)
224
+ _method_defined_with :@by_attr, caller, &block
225
+ end
226
+
227
+ def with_define_method(caller, &block)
228
+ _method_defined_with :@by_define_method, caller, &block
229
+ end
230
+
231
+ [ :attr, :attr_reader, :attr_writer, :attr_accessor ].each do |meth|
232
+ attr = instance_method(meth)
233
+ define_method(meth) do |*args|
234
+ with_attr(CallSite.new(caller(1)[0])){ attr.bind(self).call(*args) }
235
+ end
236
+ end
237
+
238
+ alias :__define_method_orig :define_method
239
+ def define_method(*args, &body)
240
+ with_define_method(CallSite.new(caller(1)[0])){ __define_method_orig(*args, &body) }
241
+ end
242
+
243
+ end
244
+
245
+ new_args = []
246
+ omissions = {}
247
+ $__with_location = false
248
+ $__printer = Printer.new
249
+
250
+ ARGV.each do |arg|
251
+ case arg
252
+ when "-n"; $__with_location = true
253
+ when "-t"; $__printer = TagsPrinter.new; $__with_location = true
254
+ when /-./; omissions[$&] = true
255
+ else new_args << arg
256
+ end
257
+ end
258
+
259
+ ARGV.replace new_args
260
+
261
+ class Object
262
+ ALLOCATOR = Hash.new{|h,k| h[k] = k.allocate }.merge(Fixnum=>1,
263
+ Bignum=>10000000000000000,
264
+ Float=>1.1,
265
+ Symbol=>:method_args_tmp,
266
+ Binding=>binding,
267
+ UnboundMethod=>instance_method(:object_id),
268
+ Method=>method(:object_id),
269
+ Proc=>lambda{},
270
+ Continuation=>callcc{|c|c},
271
+ Thread=>Thread.new{},
272
+ FalseClass=>false,
273
+ TrueClass=>true,
274
+ NilClass=>nil,
275
+ Struct=>Struct.new(:a).new(1))
276
+
277
+ # ABSTRACT_CLASSES = %w[Digest::Base ]
278
+ def self.method_added(meth)
279
+ # if ABSTRACT_CLASSES.include? self.to_s
280
+ # _print_method_info self, false, meth
281
+ # return
282
+ # end
283
+ begin
284
+ o = ALLOCATOR[self]
285
+ rescue Exception # for abstract classes
286
+ nil
287
+ end
288
+ output_method_info(self, o, meth, false, @by_attr, @by_define_method)
289
+ end
290
+ end unless omissions["-i"]
291
+
292
+ class Module
293
+ method_added = instance_method(:method_added)
294
+ define_method(:method_added) do |meth|
295
+ begin
296
+ if instance_of? Module
297
+ o = Object.new
298
+ o.extend(self)
299
+ output_method_info(self, o, meth, false, @by_attr, @by_define_method)
300
+ end
301
+ method_added.bind(self).call(meth)
302
+ rescue Exception
303
+ _print_method_info self, false, meth
304
+ end
305
+ end
306
+ end unless omissions["-m"]
307
+
308
+
309
+ class Class
310
+ def singleton_method_added(meth)
311
+ by_attr = class << self; @by_attr; end
312
+ by_define_method = class << self; @by_define_method; end
313
+ output_method_info(self, self, meth, true, by_attr, by_define_method)
314
+ rescue Exception
315
+ _print_method_info self, true, meth
316
+ end
317
+ end unless omissions["-c"]
318
+
319
+ #### include / extend
320
+ class Module
321
+ def _print_included_location(mod, caller_string, comment, flag, with_location=$__with_location, printer=$__printer)
322
+ if caller_string # nil when the class is defined by C
323
+ x = { :comment => comment, :mod => mod, :flag => flag, :self => self,
324
+ :callsite => with_location && CallSite.new(caller_string)
325
+ }
326
+ printer.included_location $>, x
327
+ end
328
+ end
329
+
330
+ undef_method :included
331
+ def included(mod)
332
+ _print_included_location mod, caller(0)[1], "include", "<="
333
+ end
334
+
335
+ undef_method :extended
336
+ def extended(mod)
337
+ _print_included_location mod, caller(0)[1], "extend", "<-" if Module === mod
338
+ end
339
+ end
340
+
341
+ #### inheritance
342
+ class Class
343
+ undef :inherited
344
+ def inherited(klass, caller_level=0)
345
+ _print_included_location klass, caller(caller_level)[1], "class", "<" unless self == Object
346
+ end
347
+ end
348
+
349
+ #### Struct inspection
350
+ class << Struct
351
+ def to_s
352
+ orig = super
353
+ if orig =~ /<Class/
354
+ mems = instance_methods(false).select{ |m| m.to_s !~ /=$/}.sort.join(",")
355
+ mems.empty? ? "<Struct>" : "<Struct: #{mems}>"
356
+ else
357
+ orig
358
+ end
359
+ end
360
+
361
+ def inherited(klass)
362
+ if self == Struct
363
+ @inherited_delay = lambda{ super(klass, 3) }
364
+ else
365
+ super(klass, 1)
366
+ end
367
+ end
368
+
369
+ @@struct_initializing = false
370
+ def method_added(meth)
371
+ super unless @@struct_initializing
372
+ end
373
+
374
+ orig_new = instance_method(:new)
375
+ define_method(:new) do |*args|
376
+ begin
377
+ @@struct_initializing = true
378
+ orig_new.bind(self).call(*args)
379
+ ensure
380
+ @@struct_initializing = false
381
+ @inherited_delay[]
382
+ end
383
+ end
384
+
385
+ end
386
+
387
+ $__method_args_off = false
388
+
389
+ ARGV.each{|x| require x}
390
+
391
+ $__method_args_off = true
392
+ # END { puts "zzzz OK" }