Skip to content

Commit

Permalink
Add support for private_constant class method calls to recognize pr…
Browse files Browse the repository at this point in the history
…ivate

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

Closes lsegalgh-219
  • Loading branch information
lsegal committed Dec 25, 2010
2 parents 8b16023 + 2810eb5 commit 13edebf
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 49 deletions.
70 changes: 36 additions & 34 deletions lib/yard/autoload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 5 additions & 6 deletions lib/yard/code_objects/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 0 additions & 9 deletions lib/yard/code_objects/method_object.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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?
Expand Down
21 changes: 21 additions & 0 deletions lib/yard/handlers/ruby/legacy/private_constant_handler.rb
Original file line number Diff line number Diff line change
@@ -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
36 changes: 36 additions & 0 deletions lib/yard/handlers/ruby/private_constant_handler.rb
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions spec/handlers/examples/private_constant_handler_001.rb.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module A
Foo = 1
class B; end
module C; end
module D; end

private_constant :Foo, 'B', C
end
24 changes: 24 additions & 0 deletions spec/handlers/private_constant_handler_spec.rb
Original file line number Diff line number Diff line change
@@ -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 13edebf

Please sign in to comment.