Module: SourceLocationDesc

Included in:
Method, UnboundMethod
Defined in:
lib/method_describer/method_desc.rb

Instance Method Summary collapse

Instance Method Details

#desc(want_just_summary = false, want_the_description_returned = false) ⇒ Object

add a Method#desc which spits out all it knows about that method ri, location, local ri, etc. TODO does this work with class methods?



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/method_describer/method_desc.rb', line 19

def desc want_just_summary = false, want_the_description_returned = false
  doc = []

  # to_s is something like "#<Method: String#strip>"
  # or #<Method: GiftCertsControllerTest(Test::Unit::TestCase)#get>
  # or "#<Method: A.go>"
  # or "#<Method: Order(id: integer, order_number: integer, created_on: datetime, shipped_on: datetime, order_user_id: integer, order_status_code_id: integer, notes: text, referer: string, order_shipping_type_id: integer, product_cost: float, shipping_cost: float, tax: float, auth_transaction_id: string, promotion_id: integer, shipping_address_id: integer, billing_address_id: integer, order_account_id: integer).get_cc_processor>"

  string = to_s

  if string.include? ')#'
    # case #<Method: GiftCertsControllerTest(Test::Unit::TestCase)#get>
    string =~ /\((.*)\)/ # extract out what is between parentheses for the classname
    class_name = $1
  elsif string.include?( '(' ) && string.include?( ').' )
    # case "Method: Order(id:...).class_method"
    string =~ /Method: (.*)\(/
    class_name = $1
  elsif string =~ /Method: (.*)\..*>/
    # case "#<Method: A.go>"
    class_name = $1
  else
    # case "#<Method: String#strip>"
    string =~ /Method: (.*)#.*/
    class_name = $1
  end

  # now get method name, type
  string =~ /Method: .*([#\.])(.*)>/ # include the # or .
  joiner = $1
  method_name = $2
  full_name = "#{class_name}#{joiner}#{method_name}"
  puts "#{to_s}      arity: #{arity}" # TODO add to doc, I want it before ri for now though :)

  # now run default RI for it
  begin
    puts 'ri for ' + full_name
    RDoc::RI::Driver.run [full_name, '--no-pager'] unless want_just_summary
  rescue *[StandardError, SystemExit]
    # not found
  end
  puts '(end ri)'

  # now gather up any other information we now about it, in case there are no rdocs

  if !(respond_to? :source_location)
    # pull out names for 1.8
    begin
      klass = eval(class_name)
      # we don't call to_ruby to overcome ruby2ruby bug http://rubyforge.org/tracker/index.php?func=detail&aid=26891&group_id=1513&atid=5921
      if joiner == '#'
        doc << RubyToRuby.new.process(ParseTree.translate(klass, method_name))
      else
        doc << RubyToRuby.new.process(ParseTree.translate(klass.singleton_class, method_name))
      end
      args = Arguments.names( klass, method_name) rescue Arguments.names(klass.singleton_class, method_name)
      out = []
      args.each{|arg_pair|
        out << arg_pair.join(' = ')
      }
      out = out.join(', ')
      return out if want_just_summary

      doc << "Parameters: #{method_name}(" + out + ")"
    rescue Exception => e
      puts "fail to parse tree: #{class_name} #{e} #{e.backtrace}" if $VERBOSE
    end
  else
    # 1.9.x
    file, line = source_location
    if file
      # then it's a pure ruby method
      doc << "at #{file}:#{line}"
      all_lines = File.readlines(file)
      head_and_sig = all_lines[0...line]
      sig = head_and_sig[-1]
      head = head_and_sig[0..-2]

      doc << sig
      head.reverse_each do |line|
        break unless line =~ /^\s*#(.*)/
        doc.unshift "     " + $1.strip
      end

      # now the real code will end with 'end' same whitespace as the first
      sig_white_space = sig.scan(/\W+/)[0]
      body = all_lines[line..-1]
      body.each{|line|
        doc << line
        if line.start_with?(sig_white_space + "end")
          break
        end
      }
      # how do I get the rest now?
      return sig + "\n" + head[0] if want_just_summary
    else
      doc << 'appears to be a c method'
    end
    if respond_to? :parameters
      doc << "Original code signature: %s" % sig.to_s.strip if sig
      doc << "#parameters signature: %s( %p )" % [name, parameters]
    end
  end

  puts doc # always output it since RI does currently [todo make optional I suppose, and non out-putty]

  if want_the_description_returned # give them something they can examine
     doc
  else
     self
  end
end