yard 0.2.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.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- data/LICENSE.txt +22 -0
- data/README.pdf +0 -0
- data/bin/yardoc +73 -0
- data/bin/yri +4 -0
- data/lib/code_object.rb +340 -0
- data/lib/formatter.rb +78 -0
- data/lib/handlers/all_handlers.rb +2 -0
- data/lib/handlers/attribute_handler.rb +46 -0
- data/lib/handlers/class_handler.rb +29 -0
- data/lib/handlers/class_variable_handler.rb +9 -0
- data/lib/handlers/code_object_handler.rb +104 -0
- data/lib/handlers/constant_handler.rb +11 -0
- data/lib/handlers/exception_handler.rb +20 -0
- data/lib/handlers/method_handler.rb +27 -0
- data/lib/handlers/mixin_handler.rb +9 -0
- data/lib/handlers/module_handler.rb +9 -0
- data/lib/handlers/visibility_handler.rb +7 -0
- data/lib/handlers/yield_handler.rb +31 -0
- data/lib/namespace.rb +98 -0
- data/lib/quick_doc.rb +104 -0
- data/lib/ruby_lex.rb +1318 -0
- data/lib/source_parser.rb +246 -0
- data/lib/tag_library.rb +162 -0
- data/lib/tag_type.rb +155 -0
- data/lib/yard.rb +3 -0
- data/templates/html_formatter.erb +455 -0
- data/test/fixtures/docstring.txt +23 -0
- data/test/fixtures/docstring2.txt +4 -0
- data/test/test_code_object.rb +66 -0
- data/test/test_namespace.rb +10 -0
- metadata +78 -0
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            class YARD::AttributeHandler < YARD::CodeObjectHandler
         | 
| 2 | 
            +
              handles /\Aattr(_(reader|writer|accessor))?\b/
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def process
         | 
| 5 | 
            +
                attr_type   = statement.tokens.first.text.to_sym
         | 
| 6 | 
            +
                symbols     = eval("[" + statement.tokens[1..-1].to_s + "]")
         | 
| 7 | 
            +
                read, write = true, false
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                # Change read/write based on attr_reader/writer/accessor
         | 
| 10 | 
            +
                case attr_type
         | 
| 11 | 
            +
                when :attr
         | 
| 12 | 
            +
                  # In the case of 'attr', the second parameter (if given) isn't a symbol.
         | 
| 13 | 
            +
                  read = symbols.pop if symbols.size == 2
         | 
| 14 | 
            +
                when :attr_accessor
         | 
| 15 | 
            +
                  write = true
         | 
| 16 | 
            +
                when :attr_reader
         | 
| 17 | 
            +
                  # change nothing
         | 
| 18 | 
            +
                when :attr_writer
         | 
| 19 | 
            +
                  read, write = false, true
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # Add all attributes
         | 
| 23 | 
            +
                symbols.each do |name| 
         | 
| 24 | 
            +
                  name = name.to_s
         | 
| 25 | 
            +
                  object[:attributes].update(name.to_s => { :read => read, :write => write })
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  # Show their methods as well
         | 
| 28 | 
            +
                  [name, "#{name}="].each do |method|
         | 
| 29 | 
            +
                    YARD::MethodObject.new(method, current_visibility, current_scope, object, statement.comments) do |obj|
         | 
| 30 | 
            +
                      if method.to_s.include? "="
         | 
| 31 | 
            +
                        src = "def #{method}(value)"
         | 
| 32 | 
            +
                        full_src = "#{src}\n  @#{name} = value\nend"
         | 
| 33 | 
            +
                        doc = "Sets the attribute +#{name}+\n@param value the value to set the attribute +#{name}+ to."
         | 
| 34 | 
            +
                      else
         | 
| 35 | 
            +
                        src = "def #{method}"
         | 
| 36 | 
            +
                        full_src = "#{src}\n  @#{name}\nend"
         | 
| 37 | 
            +
                        doc = "Returns the value of attribute +#{name}+"
         | 
| 38 | 
            +
                      end
         | 
| 39 | 
            +
                      obj.attach_source(src)
         | 
| 40 | 
            +
                      obj.attach_full_source(full_src)
         | 
| 41 | 
            +
                      obj.attach_docstring(doc)
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            class YARD::ClassHandler < YARD::CodeObjectHandler
         | 
| 2 | 
            +
              handles RubyToken::TkCLASS
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def process
         | 
| 5 | 
            +
                words = statement.tokens.to_s.strip.split(/\s+/)
         | 
| 6 | 
            +
                class_name, superclass = words[1], (words[3] || "Object")
         | 
| 7 | 
            +
                if class_name == "<<"
         | 
| 8 | 
            +
                  if words[2] == "self"
         | 
| 9 | 
            +
                    class_name = nil
         | 
| 10 | 
            +
                  else
         | 
| 11 | 
            +
                    class_name = "Anonymous$#{class_name}"
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                if class_name.nil?
         | 
| 16 | 
            +
                  # This is a class << self block. We change the scope to class level methods
         | 
| 17 | 
            +
                  # and reset the visibility to public, but we don't enter a new namespace.
         | 
| 18 | 
            +
                  scope, vis = current_namespace.attributes[:scope], current_visibility
         | 
| 19 | 
            +
                  current_visibility = :public
         | 
| 20 | 
            +
                  current_namespace.attributes[:scope] = :class
         | 
| 21 | 
            +
                  parse_block
         | 
| 22 | 
            +
                  current_namespace.attributes[:scope], current_visibility = scope, vis
         | 
| 23 | 
            +
                else
         | 
| 24 | 
            +
                  class_name = move_to_namespace(class_name)
         | 
| 25 | 
            +
                  class_obj = YARD::ClassObject.new(class_name, superclass, object, statement.comments)
         | 
| 26 | 
            +
                  enter_namespace(class_obj) { parse_block }
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,104 @@ | |
| 1 | 
            +
            class YARD::CodeObjectHandler
         | 
| 2 | 
            +
              class << self
         | 
| 3 | 
            +
                def subclasses
         | 
| 4 | 
            +
                  @@subclasses || []
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
                def inherited(subclass)
         | 
| 8 | 
            +
                  @@subclasses ||= []
         | 
| 9 | 
            +
                  @@subclasses << subclass
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
                def handles(token)
         | 
| 13 | 
            +
                  @handler = token
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
                def handles?(tokens)
         | 
| 17 | 
            +
                  case @handler
         | 
| 18 | 
            +
                  when String
         | 
| 19 | 
            +
                    tokens.first.text == @handler
         | 
| 20 | 
            +
                  when Regexp
         | 
| 21 | 
            +
                    tokens.to_s =~ @handler
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    @handler <= tokens.first.class
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
              
         | 
| 28 | 
            +
              attr_reader :parser, :statement
         | 
| 29 | 
            +
              
         | 
| 30 | 
            +
              def initialize(source_parser, stmt)
         | 
| 31 | 
            +
                @parser = source_parser
         | 
| 32 | 
            +
                @statement = stmt
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              def process
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
              
         | 
| 38 | 
            +
              protected
         | 
| 39 | 
            +
                def current_visibility
         | 
| 40 | 
            +
                  current_namespace.attributes[:visibility]
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def current_visibility=(value)
         | 
| 44 | 
            +
                  current_namespace.attributes[:visibility] = value
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                
         | 
| 47 | 
            +
                def current_scope
         | 
| 48 | 
            +
                  current_namespace.attributes[:scope]
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
                def current_scope=(value)
         | 
| 52 | 
            +
                  current_namespace.attributes[:scope] = value
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
                
         | 
| 55 | 
            +
                def object
         | 
| 56 | 
            +
                  current_namespace.object
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
                def attributes
         | 
| 60 | 
            +
                  current_namespace.attributes
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
              
         | 
| 63 | 
            +
                def current_namespace
         | 
| 64 | 
            +
                  parser.current_namespace
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
              
         | 
| 67 | 
            +
                def current_namespace=(value)
         | 
| 68 | 
            +
                  parser.current_namespace = value
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
              
         | 
| 71 | 
            +
                def enter_namespace(name, *args, &block)
         | 
| 72 | 
            +
                  namespace = parser.current_namespace
         | 
| 73 | 
            +
                  if name.is_a? YARD::CodeObject
         | 
| 74 | 
            +
                    self.current_namespace = YARD::NameStruct.new(name)
         | 
| 75 | 
            +
                    #object.add_child(name)
         | 
| 76 | 
            +
                    yield(name)
         | 
| 77 | 
            +
                  else
         | 
| 78 | 
            +
                    object.add_child(name, *args) do |obj| 
         | 
| 79 | 
            +
                      self.current_namespace = YARD::NameStruct.new(obj)
         | 
| 80 | 
            +
                      obj.attach_source(statement.tokens.to_s, parser.file, statement.tokens.first.line_no)
         | 
| 81 | 
            +
                      obj.attach_docstring(statement.comments) 
         | 
| 82 | 
            +
                      yield(obj)
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
                  self.current_namespace = namespace
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
                
         | 
| 88 | 
            +
                def move_to_namespace(namespace)
         | 
| 89 | 
            +
                  # If the class extends over a namespace, go to the proper object
         | 
| 90 | 
            +
                  if namespace.include? "::"
         | 
| 91 | 
            +
                    path = namespace.split("::") 
         | 
| 92 | 
            +
                    name = path.pop
         | 
| 93 | 
            +
                    path = path.join("::")
         | 
| 94 | 
            +
                    full_namespace = [object.path, path].compact.join("::").gsub(/^::/, '')
         | 
| 95 | 
            +
                    current_namespace.object = YARD::Namespace.find_or_create_namespace(full_namespace)
         | 
| 96 | 
            +
                    namespace = name
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                  namespace
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
                
         | 
| 101 | 
            +
                def parse_block
         | 
| 102 | 
            +
                  parser.parse(statement.block) if statement.block
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
            end
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            class YARD::ConstantHandler < YARD::CodeObjectHandler
         | 
| 2 | 
            +
              HANDLER_MATCH = /\A[^@\$]\S*\s*=\s*/m
         | 
| 3 | 
            +
              handles HANDLER_MATCH
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              def process
         | 
| 6 | 
            +
                return unless object.is_a? YARD::CodeObjectWithMethods
         | 
| 7 | 
            +
                const, expr = *statement.tokens.to_s.split(/\s*=\s*/, 2)
         | 
| 8 | 
            +
                #expr.gsub!(/\/s+/,' ')
         | 
| 9 | 
            +
                obj = YARD::ConstantObject.new(const, object, statement)
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            class YARD::ExceptionHandler < YARD::CodeObjectHandler
         | 
| 2 | 
            +
              handles 'raise'
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def process
         | 
| 5 | 
            +
                tokens = statement.tokens.reject {|tk| [RubyToken::TkSPACE, RubyToken::TkLPAREN].include? tk }
         | 
| 6 | 
            +
                from = tokens.each_with_index do |token, index|
         | 
| 7 | 
            +
                  break index if token.class == RubyToken::TkIDENTIFIER && token.text == 'raise'
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
                if from.is_a? Fixnum
         | 
| 10 | 
            +
                  exception_class = tokens[(from+1)..-1].to_s[/^\s*(\S+?),?/, 1]
         | 
| 11 | 
            +
                  # RuntimeError for Strings or no parameter
         | 
| 12 | 
            +
                  exception_class = "RuntimeError" if exception_class =~ /^\"/ || exception_class.nil?
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  # Only add the tag if it hasn't already been added (by exception class).
         | 
| 15 | 
            +
                  unless object.tags("raise").any? {|tag| tag.name == exception_class }
         | 
| 16 | 
            +
                    object.tags << YARD::TagLibrary.raise_tag(exception_class)
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            class YARD::MethodHandler < YARD::CodeObjectHandler
         | 
| 2 | 
            +
              handles RubyToken::TkDEF
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def process
         | 
| 5 | 
            +
                stmt_nospace = statement.tokens.reject {|t| t.is_a? RubyToken::TkSPACE }
         | 
| 6 | 
            +
                method_name, method_scope = stmt_nospace[1].text, current_scope
         | 
| 7 | 
            +
                holding_object = object
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                # Use the third token (after the period) if statement begins with a "Constant." or "self."
         | 
| 10 | 
            +
                if [RubyToken::TkCOLON2,RubyToken::TkDOT].include?(stmt_nospace[2].class)
         | 
| 11 | 
            +
                  method_class = stmt_nospace[1].text
         | 
| 12 | 
            +
                  holding_object = YARD::Namespace.find_from_path(object.path, method_class)
         | 
| 13 | 
            +
                  holding_object = YARD::Namespace.find_or_create_namespace(method_class) if holding_object.nil?
         | 
| 14 | 
            +
                  method_name = stmt_nospace[3..-1].to_s[/\A(.+?)(?:\(|;|$)/,1]
         | 
| 15 | 
            +
                  method_scope = :class
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              
         | 
| 18 | 
            +
                method_object = YARD::MethodObject.new(method_name, current_visibility, 
         | 
| 19 | 
            +
                                                       method_scope, holding_object, statement.comments)
         | 
| 20 | 
            +
                enter_namespace(method_object) do |obj|
         | 
| 21 | 
            +
                  #puts "->\tMethod #{obj.path} (visibility: #{obj.visibility})"
         | 
| 22 | 
            +
                  # Attach better source code
         | 
| 23 | 
            +
                  obj.attach_source(statement, parser.file)
         | 
| 24 | 
            +
                  parse_block
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            class YARD::ModuleHandler < YARD::CodeObjectHandler
         | 
| 2 | 
            +
              handles RubyToken::TkMODULE
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def process
         | 
| 5 | 
            +
                module_name = move_to_namespace(statement.tokens[2].text)
         | 
| 6 | 
            +
                child = YARD::ModuleObject.new(module_name, object, statement.comments)
         | 
| 7 | 
            +
                enter_namespace(child) { parse_block }
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            class YARD::YieldHandler < YARD::CodeObjectHandler
         | 
| 2 | 
            +
              handles 'yield'
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              def process
         | 
| 5 | 
            +
                tokens = statement.tokens.reject {|tk| [RubyToken::TkSPACE, RubyToken::TkLPAREN].include? tk.class }
         | 
| 6 | 
            +
                from = tokens.each_with_index do |token, index|
         | 
| 7 | 
            +
                  break index if token.class == RubyToken::TkYIELD
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
                if from.is_a? Fixnum
         | 
| 10 | 
            +
                  params = []
         | 
| 11 | 
            +
                  (from+1).step(tokens.size-1, 2) do |index|
         | 
| 12 | 
            +
                    # FIXME: This won't work if the yield has a method call or complex constant name (A::B) 
         | 
| 13 | 
            +
                    params << tokens[index].text
         | 
| 14 | 
            +
                    break unless tokens[index+1].is_a? RubyToken::TkCOMMA
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                  
         | 
| 17 | 
            +
                  # Only add the tags if none were added at all
         | 
| 18 | 
            +
                  if object.tags("yieldparam").empty? && object.tags("yield").empty?
         | 
| 19 | 
            +
                    params.each do |param|
         | 
| 20 | 
            +
                      # TODO: We can technically introspect any constant to find out parameter types,
         | 
| 21 | 
            +
                      #       not just self.
         | 
| 22 | 
            +
                      # If parameter is self, we have a chance to get some extra information
         | 
| 23 | 
            +
                      if param == "self"
         | 
| 24 | 
            +
                        param = "[#{object.parent.path}] _self the object that yields the value (self)"
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                      object.tags << YARD::TagLibrary.yieldparam_tag(param)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
    
        data/lib/namespace.rb
    ADDED
    
    | @@ -0,0 +1,98 @@ | |
| 1 | 
            +
            require 'singleton'
         | 
| 2 | 
            +
            require 'find'
         | 
| 3 | 
            +
            require 'yaml'
         | 
| 4 | 
            +
            require File.dirname(__FILE__) + '/code_object'
         | 
| 5 | 
            +
            require File.dirname(__FILE__) + '/source_parser'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module YARD
         | 
| 8 | 
            +
              class Namespace
         | 
| 9 | 
            +
                DEFAULT_YARDOC_FILE = "_Yardoc"
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                include Singleton
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                class << self
         | 
| 14 | 
            +
                  ##
         | 
| 15 | 
            +
                  # Attempt to find a namespace and return it if it exists. Similar
         | 
| 16 | 
            +
                  # to the {YARD::Namsepace::at} method but creates the namespace
         | 
| 17 | 
            +
                  # as a module if it does not exist, and return it.
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @param [String] namespace the namespace to search for.
         | 
| 20 | 
            +
                  # @return [CodeObject] the namespace that was found or created.
         | 
| 21 | 
            +
                  def find_or_create_namespace(namespace)
         | 
| 22 | 
            +
                    return at(namespace) if at(namespace)
         | 
| 23 | 
            +
                    name = namespace.split("::").last
         | 
| 24 | 
            +
                    object = ModuleObject.new(name)
         | 
| 25 | 
            +
                    instance.namespace.update(namespace => object)
         | 
| 26 | 
            +
                    object
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                  
         | 
| 29 | 
            +
                  def add_object(object)
         | 
| 30 | 
            +
                    instance.add_object(object)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                  
         | 
| 33 | 
            +
                  def at(name)
         | 
| 34 | 
            +
                    instance.at(name)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  alias_method :[], :at
         | 
| 37 | 
            +
                  
         | 
| 38 | 
            +
                  def root
         | 
| 39 | 
            +
                    at('')
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                  
         | 
| 42 | 
            +
                  def all
         | 
| 43 | 
            +
                    instance.namespace.keys
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                  
         | 
| 46 | 
            +
                  def each_object
         | 
| 47 | 
            +
                    instance.namespace.each do |name, object|
         | 
| 48 | 
            +
                      yield(name, object)
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                  
         | 
| 52 | 
            +
                  def load(file = DEFAULT_YARDOC_FILE, reload = false)
         | 
| 53 | 
            +
                    if File.exists?(file) && !reload
         | 
| 54 | 
            +
                      instance.namespace.replace(Marshal.load(IO.read(file)))
         | 
| 55 | 
            +
                    else
         | 
| 56 | 
            +
                      Find.find(".") do |path|
         | 
| 57 | 
            +
                        SourceParser.parse(path) if path =~ /\.rb$/
         | 
| 58 | 
            +
                      end
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
                    save
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                  
         | 
| 63 | 
            +
                  def save(file = DEFAULT_YARDOC_FILE)
         | 
| 64 | 
            +
                    File.open(file, "w") {|f| Marshal.dump(instance.namespace, f) }
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                  
         | 
| 67 | 
            +
                  def find_from_path(object, name)
         | 
| 68 | 
            +
                    object = at(object) unless object.is_a? CodeObject
         | 
| 69 | 
            +
                    return object if name == 'self'
         | 
| 70 | 
            +
                    
         | 
| 71 | 
            +
                    while object
         | 
| 72 | 
            +
                      ["::", ""].each do |type|
         | 
| 73 | 
            +
                        obj = at(object.path + type + name)
         | 
| 74 | 
            +
                        return obj if obj
         | 
| 75 | 
            +
                      end
         | 
| 76 | 
            +
                      object = object.parent
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                    nil
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
                
         | 
| 82 | 
            +
                attr_reader :namespace
         | 
| 83 | 
            +
                
         | 
| 84 | 
            +
                def initialize
         | 
| 85 | 
            +
                  @namespace = { '' => CodeObjectWithMethods.new('', :root) }
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
                
         | 
| 88 | 
            +
                def add_object(object)
         | 
| 89 | 
            +
                  return object if namespace[object.path] && object.docstring.nil?
         | 
| 90 | 
            +
                  namespace.update(object.path => object)
         | 
| 91 | 
            +
                  object
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
                def at(name)
         | 
| 95 | 
            +
                  namespace[name]
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
            end
         | 
    
        data/lib/quick_doc.rb
    ADDED
    
    | @@ -0,0 +1,104 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/namespace'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module YARD
         | 
| 4 | 
            +
              class QuickDoc
         | 
| 5 | 
            +
                def initialize(name)
         | 
| 6 | 
            +
                  Namespace.load
         | 
| 7 | 
            +
                  if name.nil?
         | 
| 8 | 
            +
                    puts "Method Listing:"
         | 
| 9 | 
            +
                    puts "---------------"
         | 
| 10 | 
            +
                    puts Namespace.all.select {|n| Namespace.at(n).is_a? MethodObject }.sort.join("\n") 
         | 
| 11 | 
            +
                    return 
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  meth = Namespace.at(name)
         | 
| 15 | 
            +
                  if meth.nil? 
         | 
| 16 | 
            +
                    puts "No entry for #{name}"
         | 
| 17 | 
            +
                    return
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                  
         | 
| 20 | 
            +
                  ns = meth.path
         | 
| 21 | 
            +
                  rvalue = meth.tag('return')
         | 
| 22 | 
            +
                  return_type = rvalue && rvalue.type ? rvalue.type : "undefined"
         | 
| 23 | 
            +
                  block = nil
         | 
| 24 | 
            +
                  unless meth.tags("yieldparam").empty?
         | 
| 25 | 
            +
                    block = " {|" + meth.tags("yieldparam").collect {|tag| tag.name }.join(", ") + "| ... }"
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  
         | 
| 28 | 
            +
                  puts "Documentation for #{ns}"
         | 
| 29 | 
            +
                  puts "==================#{'=' * ns.length}"
         | 
| 30 | 
            +
                  if meth.file
         | 
| 31 | 
            +
                    puts "File: '#{meth.file}' (on line #{meth.line})"
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                  puts "Type: #{return_type}\t\tVisibility: #{meth.visibility}"
         | 
| 34 | 
            +
                  puts
         | 
| 35 | 
            +
                  if meth.tag('deprecated')
         | 
| 36 | 
            +
                    desc = meth.tag('deprecrated').text
         | 
| 37 | 
            +
                    puts
         | 
| 38 | 
            +
                    puts "!! This method is deprecated" + (desc ? ": #{desc}" : ".")
         | 
| 39 | 
            +
                    puts
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                  if meth.docstring
         | 
| 42 | 
            +
                    puts word_wrap(meth.docstring, ns.length + 18)
         | 
| 43 | 
            +
                    puts 
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                  unless meth.tags("param").empty? && meth.tags("raise").empty? && meth.tags("return").empty?
         | 
| 46 | 
            +
                    puts "Meta Tags:"
         | 
| 47 | 
            +
                    puts "----------"
         | 
| 48 | 
            +
                    meth.tags("param").each do |tag|
         | 
| 49 | 
            +
                      types = tag.types.empty? ? "" : "[#{tag.types.join(", ")}] "
         | 
| 50 | 
            +
                      puts "> Parameter: #{types}#{tag.name} => #{tag.text}"
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                    meth.tags("raise").each do |tag|
         | 
| 53 | 
            +
                      puts "> Raises #{tag.name} exception#{tag.text ? ': ' + tag.text : ''}"
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                    meth.tags("return").each do |tag|
         | 
| 56 | 
            +
                      puts "> Returns #{tag.types.empty? ? "" : "(as " + tag.types.join(", ") + ')'} #{tag.text}"
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                    puts
         | 
| 59 | 
            +
                    unless meth.tags("yieldparam").empty?
         | 
| 60 | 
            +
                      puts "Yields:"
         | 
| 61 | 
            +
                      puts "-------"
         | 
| 62 | 
            +
                      meth.tags("yieldparam").each do |tag|
         | 
| 63 | 
            +
                        types = tag.types.empty? ? "" : "[#{tag.types.join(", ")}] "
         | 
| 64 | 
            +
                        puts "> Block parameter: #{types}#{tag.name} => #{tag.text}"
         | 
| 65 | 
            +
                        puts
         | 
| 66 | 
            +
                      end
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                  if meth.source
         | 
| 70 | 
            +
                    puts "Definition:"
         | 
| 71 | 
            +
                    puts "-----------"
         | 
| 72 | 
            +
                    puts format_code(meth.source.sub("\n", "#{block}" + (return_type ? " # -> " + return_type : "") + "\n"))
         | 
| 73 | 
            +
                    puts    
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                  unless meth.tags("see").empty?
         | 
| 76 | 
            +
                    puts "See Also:"
         | 
| 77 | 
            +
                    puts "---------"
         | 
| 78 | 
            +
                    meth.tags("see").each do |tag|
         | 
| 79 | 
            +
                      puts "\t- #{tag.text}"
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                    puts
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
                
         | 
| 85 | 
            +
                protected
         | 
| 86 | 
            +
                  def word_wrap(text, length = 80)
         | 
| 87 | 
            +
                    text.gsub(/(.{0,#{length - 3}}\s)/, "\n" + '\1')
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  def format_code(text, indent_size = 2)
         | 
| 91 | 
            +
                    last_indent, tab = nil, 0
         | 
| 92 | 
            +
                    text.split(/\r?\n/).collect do |line|
         | 
| 93 | 
            +
                      indent = line[/^(\s*)/, 1].length
         | 
| 94 | 
            +
                      if last_indent && indent > last_indent
         | 
| 95 | 
            +
                        tab += indent_size
         | 
| 96 | 
            +
                      elsif last_indent && indent < last_indent
         | 
| 97 | 
            +
                        tab -= indent_size
         | 
| 98 | 
            +
                      end
         | 
| 99 | 
            +
                      last_indent = indent
         | 
| 100 | 
            +
                      (" " * tab) + line.sub(/^\s*/, '')
         | 
| 101 | 
            +
                    end.join("\n")
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
            end
         |