Browse files

Add support for `private_constant` class method calls to recognize pr…

…ivate

class, module and constant definitions (proposed for Ruby 1.9.3).

Closes gh-219
  • Loading branch information...
1 parent 8b16023 commit 2810eb5c488b4741d3911103cc0870a862db6128 @lsegal committed Dec 25, 2010
View
70 lib/yard/autoload.rb
@@ -56,46 +56,48 @@ module CodeObjects
module Handlers
module Ruby # All Ruby handlers
module Legacy # Handlers for old Ruby 1.8 parser
- autoload :Base, __p('handlers/ruby/legacy/base')
+ autoload :Base, __p('handlers/ruby/legacy/base')
- autoload :AliasHandler, __p('handlers/ruby/legacy/alias_handler')
- autoload :AttributeHandler, __p('handlers/ruby/legacy/attribute_handler')
- autoload :ClassHandler, __p('handlers/ruby/legacy/class_handler')
- autoload :ClassConditionHandler, __p('handlers/ruby/legacy/class_condition_handler')
- autoload :ClassVariableHandler, __p('handlers/ruby/legacy/class_variable_handler')
- autoload :ConstantHandler, __p('handlers/ruby/legacy/constant_handler')
- autoload :ExceptionHandler, __p('handlers/ruby/legacy/exception_handler')
- autoload :ExtendHandler, __p('handlers/ruby/legacy/extend_handler')
- autoload :MethodHandler, __p('handlers/ruby/legacy/method_handler')
- autoload :MixinHandler, __p('handlers/ruby/legacy/mixin_handler')
- autoload :ModuleHandler, __p('handlers/ruby/legacy/module_handler')
- autoload :ProcessHandler, __p('handlers/ruby/legacy/process_handler')
- autoload :VisibilityHandler, __p('handlers/ruby/legacy/visibility_handler')
- autoload :YieldHandler, __p('handlers/ruby/legacy/yield_handler')
+ autoload :AliasHandler, __p('handlers/ruby/legacy/alias_handler')
+ autoload :AttributeHandler, __p('handlers/ruby/legacy/attribute_handler')
+ autoload :ClassHandler, __p('handlers/ruby/legacy/class_handler')
+ autoload :ClassConditionHandler, __p('handlers/ruby/legacy/class_condition_handler')
+ autoload :ClassVariableHandler, __p('handlers/ruby/legacy/class_variable_handler')
+ autoload :ConstantHandler, __p('handlers/ruby/legacy/constant_handler')
+ autoload :ExceptionHandler, __p('handlers/ruby/legacy/exception_handler')
+ autoload :ExtendHandler, __p('handlers/ruby/legacy/extend_handler')
+ autoload :MethodHandler, __p('handlers/ruby/legacy/method_handler')
+ autoload :MixinHandler, __p('handlers/ruby/legacy/mixin_handler')
+ autoload :ModuleHandler, __p('handlers/ruby/legacy/module_handler')
+ autoload :PrivateConstantHandler, __p('handlers/ruby/legacy/private_constant_handler')
+ autoload :ProcessHandler, __p('handlers/ruby/legacy/process_handler')
+ autoload :VisibilityHandler, __p('handlers/ruby/legacy/visibility_handler')
+ autoload :YieldHandler, __p('handlers/ruby/legacy/yield_handler')
end
- autoload :Base, __p('handlers/ruby/base')
+ autoload :Base, __p('handlers/ruby/base')
- autoload :AliasHandler, __p('handlers/ruby/alias_handler')
- autoload :AttributeHandler, __p('handlers/ruby/attribute_handler')
- autoload :ClassHandler, __p('handlers/ruby/class_handler')
- autoload :ClassConditionHandler, __p('handlers/ruby/class_condition_handler')
- autoload :ClassVariableHandler, __p('handlers/ruby/class_variable_handler')
- autoload :ConstantHandler, __p('handlers/ruby/constant_handler')
- autoload :ExceptionHandler, __p('handlers/ruby/exception_handler')
- autoload :ExtendHandler, __p('handlers/ruby/extend_handler')
- autoload :MethodHandler, __p('handlers/ruby/method_handler')
- autoload :MethodConditionHandler, __p('handlers/ruby/method_condition_handler')
- autoload :MixinHandler, __p('handlers/ruby/mixin_handler')
- autoload :ModuleHandler, __p('handlers/ruby/module_handler')
- autoload :ProcessHandler, __p('handlers/ruby/process_handler')
- autoload :StructHandlerMethods, __p('handlers/ruby/struct_handler_methods')
- autoload :VisibilityHandler, __p('handlers/ruby/visibility_handler')
- autoload :YieldHandler, __p('handlers/ruby/yield_handler')
+ autoload :AliasHandler, __p('handlers/ruby/alias_handler')
+ autoload :AttributeHandler, __p('handlers/ruby/attribute_handler')
+ autoload :ClassHandler, __p('handlers/ruby/class_handler')
+ autoload :ClassConditionHandler, __p('handlers/ruby/class_condition_handler')
+ autoload :ClassVariableHandler, __p('handlers/ruby/class_variable_handler')
+ autoload :ConstantHandler, __p('handlers/ruby/constant_handler')
+ autoload :ExceptionHandler, __p('handlers/ruby/exception_handler')
+ autoload :ExtendHandler, __p('handlers/ruby/extend_handler')
+ autoload :MethodHandler, __p('handlers/ruby/method_handler')
+ autoload :MethodConditionHandler, __p('handlers/ruby/method_condition_handler')
+ autoload :MixinHandler, __p('handlers/ruby/mixin_handler')
+ autoload :ModuleHandler, __p('handlers/ruby/module_handler')
+ autoload :PrivateConstantHandler, __p('handlers/ruby/private_constant_handler')
+ autoload :ProcessHandler, __p('handlers/ruby/process_handler')
+ autoload :StructHandlerMethods, __p('handlers/ruby/struct_handler_methods')
+ autoload :VisibilityHandler, __p('handlers/ruby/visibility_handler')
+ autoload :YieldHandler, __p('handlers/ruby/yield_handler')
end
- autoload :Base, __p('handlers/base')
- autoload :Processor, __p('handlers/processor')
+ autoload :Base, __p('handlers/base')
+ autoload :Processor, __p('handlers/processor')
end
# The parser namespace holds all parsing engines used by YARD.
View
11 lib/yard/code_objects/base.rb
@@ -152,12 +152,10 @@ class Base
# @see #dynamic
def dynamic?; @dynamic end
- # This attribute exists in order to maintain a consistent interface
- # with the {MethodObject} class, so that a {Verifier} expression need
- # not check the object type before accessing visibility.
- #
- # @return [Symbol] always returns public for a base object.
- def visibility; :public end
+ # @return [Symbol] the visibility of an object (:public, :private, :protected)
+ attr_accessor :visibility
+ undef visibility=
+ def visibility=(v) @visibility = v.to_sym end
class << self
# Allocates a new code object
@@ -212,6 +210,7 @@ def initialize(namespace, name, *args, &block)
@current_file_has_comments = false
@name = name.to_sym
@source_type = :ruby
+ @visibility = :public
@tags = []
@docstring = Docstring.new('', self)
@namespace = nil
View
9 lib/yard/code_objects/method_object.rb
@@ -1,11 +1,6 @@
module YARD::CodeObjects
# Represents a Ruby method in source
class MethodObject < Base
- # The visibility of the method (+:public:+, +:protected+, +:private+)
- #
- # @return [Symbol] the method visibility
- attr_reader :visibility
-
# The scope of the method (+:class+ or +:instance+)
#
# @return [Symbol] the scope
@@ -49,10 +44,6 @@ def scope=(v)
@scope = v.to_sym
YARD::Registry.register(self) if reregister
end
-
- # Sets the visibility
- # @param [Symbol] v the new visibility (:public, :private, or :protected)
- def visibility=(v) @visibility = v.to_sym end
# @return whether or not the method is the #initialize constructor method
def constructor?
View
21 lib/yard/handlers/ruby/legacy/private_constant_handler.rb
@@ -0,0 +1,21 @@
+# (see Ruby::PrivateConstantHandler)
+class YARD::Handlers::Ruby::Legacy::PrivateConstantHandler < YARD::Handlers::Ruby::Legacy::Base
+ namespace_only
+ handles /\Aprivate_constant(\s|\(|$)/
+
+ process do
+ tokval_list(statement.tokens[2..-1], :attr, TkCONSTANT).each do |name|
+ privatize_constant name
+ end
+ end
+
+ private
+
+ def privatize_constant(name)
+ const = Proxy.new(namespace, name)
+ ensure_loaded!(const)
+ const.visibility = :private
+ rescue NamespaceMissingError
+ raise UndocumentableError, "private visibility set on unrecognized constant: #{name}"
+ end
+end
View
36 lib/yard/handlers/ruby/private_constant_handler.rb
@@ -0,0 +1,36 @@
+# Sets visibility of a constant (class, module, const)
+class YARD::Handlers::Ruby::PrivateConstantHandler < YARD::Handlers::Ruby::Base
+ namespace_only
+ handles method_call(:private_constant)
+
+ process do
+ errors = []
+ statement.parameters.each do |param|
+ next unless param.respond_to?(:type)
+ begin
+ privatize_constant(param)
+ rescue UndocumentableError => err
+ errors << err.message
+ end
+ end
+ if errors.size > 0
+ msg = errors.size == 1 ? ": #{errors[0]}" : "s: #{errors.join(", ")}"
+ raise UndocumentableError, "private constant#{msg} for #{namespace.path}"
+ end
+ end
+
+ private
+
+ def privatize_constant(node)
+ if node.literal? || (node.type == :var_ref && node[0].type == :const)
+ node = node.jump(:tstring_content, :const)
+ const = Proxy.new(namespace, node[0])
+ ensure_loaded!(const)
+ const.visibility = :private
+ else
+ raise UndocumentableError, "invalid argument to private_constant: #{node.source}"
+ end
+ rescue NamespaceMissingError
+ raise UndocumentableError, "private visibility set on unrecognized constant: #{node[0]}"
+ end
+end
View
8 spec/handlers/examples/private_constant_handler_001.rb.txt
@@ -0,0 +1,8 @@
+module A
+ Foo = 1
+ class B; end
+ module C; end
+ module D; end
+
+ private_constant :Foo, 'B', C
+end
View
24 spec/handlers/private_constant_handler_spec.rb
@@ -0,0 +1,24 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}PrivateConstantHandler" do
+ before(:all) { parse_file :private_constant_handler_001, __FILE__ }
+
+ it "should handle private_constant statement" do
+ Registry.at('A::Foo').visibility.should == :private
+ Registry.at('A::B').visibility.should == :private
+ Registry.at('A::C').visibility.should == :private
+ end
+
+ it "should make all other constants public" do
+ Registry.at('A::D').visibility.should == :public
+ end
+
+ it "should fail if parameter is not String, Symbol or Constant" do
+ undoc_error 'class Foo; private_constant x; end'
+ undoc_error 'class Foo; X = 1; private_constant X.new("hi"); end'
+ end if RUBY19
+
+ it "should fail if constant can't be recognized" do
+ undoc_error 'class Foo2; private_constant :X end'
+ end
+end

0 comments on commit 2810eb5

Please sign in to comment.