Project

General

Profile

Actions

Feature #12655

closed

Accessing the method visibility

Added by mathieujobin (Mathieu Jobin) over 7 years ago. Updated almost 2 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:76732]

Description

I took on the task to make the looksee gem work with ruby 2.3 and 2.4. Unfortunately, some features were not directly accessible in ruby, so a C extension was made, which includes some ruby internals.

For ruby 2.2 support, internal.h and method.h were included. For ruby 2.3, I found I need id_table.h at least, but I did not fully succeed making it work.

In a short email thread, koichi san suggested it would be better to request to add the necessary public interface to ruby so that looksee would not need internals.

looksee creates these new methods from ruby internals:

rb_define_method(mMRI, "internal_superclass", Looksee_internal_superclass, 1);
rb_define_method(mMRI, "internal_class", Looksee_internal_class, 1);
rb_define_method(mMRI, "internal_public_instance_methods", Looksee_internal_public_instance_methods, 1);
rb_define_method(mMRI, "internal_protected_instance_methods", Looksee_internal_protected_instance_methods, 1);
rb_define_method(mMRI, "internal_private_instance_methods", Looksee_internal_private_instance_methods, 1);
rb_define_method(mMRI, "internal_undefined_instance_methods", Looksee_internal_undefined_instance_methods, 1);
rb_define_method(mMRI, "included_class?", Looksee_included_class_p, 1);
rb_define_method(mMRI, "singleton_class?", Looksee_singleton_class_p, 1);
rb_define_method(mMRI, "singleton_instance", Looksee_singleton_instance, 1);
rb_define_method(mMRI, "real_module", Looksee_real_module, 1);
rb_define_method(mMRI, "module_name", Looksee_module_name, 1);

It uses the following macros to find the method visibility and whether it has been redefined:

UNDEFINED_METHOD_ENTRY_P(me)
METHOD_ENTRY_VISI(me)

Ideally, a ruby method that returns visibility should return one of the following values:

[:public, :protected, :private, :undefined, :overridden]

We are using other ruby macros to find where and within which module or class the method is defined.

RCLASS_SUPER(internal_class)
CLASS_OF(object)
RCLASS_M_TBL(klass)
SPECIAL_CONST_P(object)
BUILTIN_TYPE(object)
FL_TEST(singleton_class, FL_SINGLETON)
RCLASS_IV_TBL(singleton_class)
RBASIC(module_or_included_class)->klass

You can see what I have tried for ruby 2.3: https://github.com/oggy/looksee/pull/36/files#diff-d5ef4b0cfbd5a6712f37dfa7ffbe2130

I cannot use rb_id_table_foreach, which suggests that I need to import much ruby code into the extension. I prefer not to include more C into this gem.

So I am trying to extract st_table from struct rb_id_table*, but I am getting a deferencing incomplete type error.

Please help.


Related issues 1 (0 open1 closed)

Related to Ruby master - Feature #12084: `Class#instance`ClosedActions

Updated by shyouhei (Shyouhei Urabe) over 7 years ago

I think it should be possible to implement locksee in pure-ruby. To me it seems OK to have a way to access visibility of a method.

It is not clear if locksee cannot be implemented without exposing IClass, though.

Updated by nobu (Nobuyoshi Nakada) over 7 years ago

  • Description updated (diff)
  • Status changed from Open to Feedback

Mathieu Jobin wrote:

it uses the following macros to find the method visibility and if it has been redefined

UNDEFINED_METHOD_ENTRY_P(me)
METHOD_ENTRY_VISI(me)

I'd love to add the functions, but are they really needed?

Ideally, a ruby method that would return its visibility, should return one of the following value

[:public, :protected, :private, :undefined, :overridden]

I think :overridden doesn't make sense in ruby.
What do you expect by it?

we are using other ruby macros to find where the method is define, which module or class.

RCLASS_SUPER(internal_class)
CLASS_OF(object)
SPECIAL_CONST_P(object)
BUILTIN_TYPE(object)
FL_TEST(singleton_class, FL_SINGLETON)

These would be safe.

RCLASS_M_TBL(klass)
RCLASS_IV_TBL(singleton_class)

It's not recommended to directly access internal members, m_tbl, iv_tbl, etc.

RBASIC(module_or_included_class)->klass

It is preferable to use RBASIC_CLASS() instead of RBASIC()->klass.

that is mostly it

you can see what I have tried for ruby 2.3
https://github.com/oggy/looksee/pull/36/files#diff-d5ef4b0cfbd5a6712f37dfa7ffbe2130

I'm unable to use rb_id_table_foreach which seems like I would need to import too much of ruby code inside the extension... which I would prefer not including more C into this gem

The reason to use id_table seems to collect methods for each visibilities.
What differs from rb_class_public_instance_methods etc?

What you need are rb_class_undefined_instance_methods and
rb_class_singleton_object (provisional names)?

Updated by oggy (George Ogata) over 7 years ago

Hi,

I'm the original author of looksee.

I agree that we don't need everything in the Looksee extension in ruby. Looksee was written back in 2009 when I think the situation was a little different, but now I believe Module#ancestors should suffice to get the chain of modules.

Nobuyoshi Nakada wrote:

What you need are rb_class_undefined_instance_methods and
rb_class_singleton_object (provisonal names)?

I think this is exactly right. Would you consider exposing these at the ruby level?

Updated by shyouhei (Shyouhei Urabe) over 7 years ago

We briefly looked at this issue at yesterday's developer meeting and roughly agreed that locksee should be able to be done in pure-ruby.

Sad news is we had no time to have a deeper look at it so what is actually needed was not made clear at the meeting.

Updated by oggy (George Ogata) over 7 years ago

Thanks Shyouhei! I believe I need the 2 methods Nobu has implemented in this patch here to implement Looksee entirely in ruby, which I would love to do. In the latest version of looksee I have reduced the MRI extension down to just these 2 methods, so if this were in trunk I could swap those in & try it.

(Or if you are reluctant to expose these at the ruby level, is there any chance they could be made available to extensions?)

Updated by mathieujobin (Mathieu Jobin) almost 5 years ago

I know its been two years already.
but do you think we could get those new methods merged into trunk?

Updated by mathieujobin (Mathieu Jobin) about 4 years ago

mri/2.x.0/internal.h:1363:11: error: conflicting types for ‘rb_st_copy’
1363 | st_table *rb_st_copy(VALUE obj, struct st_table *orig_tbl);

looks like this has changed in ruby 2.7

we would have appreciated the public methods from nobu to be merged in...

Actions #9

Updated by nobu (Nobuyoshi Nakada) about 4 years ago

Sorry, I've forgotten completely.
Updated the patch, but it is sorry to be too late for 2.7.

Actions #10

Updated by sawa (Tsuyoshi Sawada) about 4 years ago

  • Subject changed from accessing a method visibility to Accessing the method visibility
  • Description updated (diff)
Actions #11

Updated by jeremyevans0 (Jeremy Evans) over 2 years ago

Updated by matz (Yukihiro Matsumoto) about 2 years ago

OK, I accept introducing undefined_instance_methods. It returns a list of undefined methods of the receiver class.
Unlike instance_methods etc. it should not traverse the inheritance chain.

Matz.

Updated by jeremyevans0 (Jeremy Evans) almost 2 years ago

I modified @nobu's patch for undefined methods to remove Object#undefined_methods and remove the optional argument from Module#undefined_instance_methods, and submitted a pull request for that: https://github.com/ruby/ruby/pull/5733

Actions #14

Updated by jeremyevans (Jeremy Evans) almost 2 years ago

  • Status changed from Feedback to Closed

Applied in changeset git|7cda7fbbdc14f4262afaa94cdeb5a5987f1eb01a.


Add Module#undefined_instance_methods

Implements [Feature #12655]

Co-authored-by: Nobuyoshi Nakada

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0