rcodetools 0.4.0.0

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 (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" }