Skip to content

Module function without argument - #1825

Open
thyresias wants to merge 3 commits into
ruby:masterfrom
thyresias:module-function-no-arg
Open

thyresias wants to merge 3 commits into
ruby:masterfrom
thyresias:module-function-no-arg

Conversation

@thyresias

Copy link
Copy Markdown

This supports module_function without argument (#1823).
I had initially the intention to use a special value for @visibibility, but I think it is better that it has actual visibility values, so I introduced @module_function_mode.

Comment thread lib/rdoc/parser/ruby.rb

def _visit_call_module_function(call_node)
if !call_node.arguments || call_node.arguments.arguments.empty?
@scanner.visibility = :private

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition doesn't check @scanner.in_proc_block and it means in cases like

module M
  Module.new do
    module_function
  end

  def outer; end
end

The private visibility leaks outside of the anonymous module.

assert_equal ['m1', 'm2'], singleton_methods.map(&:name)
assert_equal [:public, :public], singleton_methods.map(&:visibility)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add this test:

def test_module_function_no_arg_does_not_leak_from_block
  util_parser <<~RUBY
    module M
      Module.new do
        module_function
      end
      def outer; end
    end
  RUBY

  mod = @store.find_module_named 'M'
  methods = mod.method_list.map { |method| [method.name, method.singleton, method.visibility] }
  assert_equal [['outer', false, :public]], methods
end

Comment thread lib/rdoc/parser/ruby.rb
RBS_SIG_LINE = /\A#:\s/ # :nodoc:

attr_accessor :visibility
attr_accessor :visibility, :module_function_mode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Visibility and module_function_mode are exclusive.
We don't want to introduce instance values with complex dependencies. Simple internal representation is better.
How about changing attr_accessor :visibility to attr_accessor :visibility_mode
and define def visibility that computes actual visibility from exclusive state like this?

attr_accessor :visibility_mode   # :public, :private, :protected, :module_function

def visibility
  @visibility_mode == :module_function ? :private : @visibility_mode
end

Comment thread lib/rdoc/parser/ruby.rb
return unless receiver_name
when nil
visibility = @scanner.visibility
mod_function = @scanner.module_function_mode && !singleton

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

singleton is always nil because the local variable is not assigned yet.
I think it's a mistake of @scanner.singleton, but module_function_mode is only set on non-singleton module scope. Simply removing && (singleton_check_expression) is enough.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to check singleton in _visit_call_module_function.

module A
  class << A
    module_function rescue p($!) # NameError, RDoc should just ignore it
    def f; end # public method
  end
end

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants