As mentioned in this answer, in Ruby 2.1 or later, this code:
class SimpleTest
private
define_method :foo do
42
end
end
will define foo
as a private method of SimpleTest
instances. (In Ruby 2.0 and earlier it won't be private.) However, I'm looking to do something a little less trivial. I would like to define a DSL that classes can extend, and would like the methods that the DSL defines internally to respect the private/protected visibility of the calling context. That may not be clear, so here's an example:
module Dsl
def has_a(name)
define_method name do
42
end
end
end
class Test
extend Dsl
private
has_a :thing
end
As written, that code will define a public thing
method on Test
instances. Instead, I would like has_a
to be able to reflect on the method visibility where it was called (private
in this case), and define thing
under that same method visibility.
I'm not familiar with Ruby's C source code, but I took a quick look and found this function which seems like it might do what I want, but I don't think it's accessible from Ruby. (It seems to only be used here.) I also looked up the documentation for define_method
(since the first example works as desired) here and it seems like the noex
variable declared and set here:
int noex = NOEX_PUBLIC;
const NODE *cref = rb_vm_cref_in_context(mod, mod);
if (cref) {
noex = (int)cref->nd_visi;
}
could be the value I want, but again I don't know how I would get that in Ruby, or even if it would be able to reflect back on the calling scope (in Test
). Assuming I had the visibility, then I could simply call private name
(or protected name
) after the define_method
call inside has_a
if it wasn't called in a public
context.
Thoughts? Is there any way to do this, or am I out of luck?
I think this question has a similar answer to what you are looking for: https://stackoverflow.com/a/28075865/5129208
It looks like the author of that made a custom module to get the behavior you're after.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With