7

Since Ruby 2.0 or so, it's been possible to make a constant private using private_constant, resulting in an error if the constant is used directly outside the declaring module.

However, constants and const_defined? still return private constants, and const_get allows access to them. Is there a way to programmatically identify private constants and filter them out at run time?

(Note: What does Module.private_constant do? Is there a way to list only private constants? and its answer don't specifically address this case, but rather the reverse (how to list only private constants).)


Update: It looks as though in Ruby 1.9 and 2.0, constants did include only public constants. As of 2.1, the no-arg constants still includes only public constants, but setting inherit to false with constants(false) (i.e., list only constants defined in this module, not in its ancestor modules) has the side effect of exposing the private constants.

Community
  • 1
  • 1
David Moles
  • 48,006
  • 27
  • 136
  • 235
  • Possible duplicate of http://stackoverflow.com/questions/12944616/what-does-module-private-constant-do-is-there-a-way-to-list-only-private-consta – Dave Schweisguth May 03 '16 at 19:07
  • They are still defined. Do you want Ruby to lie? – tadman May 03 '16 at 19:10
  • 1
    I'm not replicating your problem in Ruby 2.1.4: `2.1.4 :001 > module Foo; X = 1; Y = 2; private_constant :Y; end; Foo.constants` returns `[:X]` – Neil Slater May 03 '16 at 19:18
  • @tadman No, I'm just noting what I've tried. – David Moles May 03 '16 at 19:19
  • @NeilSlater That's interesting. When I try to reduce it to a minimal test case, I'm not seeing it either. – David Moles May 03 '16 at 19:30
  • @DavidMoles: If you have some code that manipulates constants, maybe as part of framework, it may delete and re-add them. I guess that may remove the private flag if the code wasn't aware it needed to preserve them. I read the source for `private_constant` and the flag appears to be added directly to the constant (it is not a separate lookup), so if you delete a constant, you implicitly delete its private flag status. – Neil Slater May 03 '16 at 19:32
  • @NeilSlater It looks like it's related to the `inherit` flag -- see edits. – David Moles May 03 '16 at 19:38
  • @DaveSchweisguth That question is related but is actually the opposite of what I'm trying to do, and its current answer isn't entirely correct. – David Moles May 03 '16 at 19:41

1 Answers1

4

You can identify constants by next way:

class A
  C = "value"
  private_constant :C
  C2 = "value2"
end

A.constants #public constants
#=> [:C2]
A.constants(false) #public & private constants
#=> [:C, :C2]
A.constants(false) - A.constants #private constants
#=> [:C]
Ilya
  • 13,337
  • 5
  • 37
  • 53
  • OP appears to want array of non-private constants, and is saying that `constants` method returns *all* constants (they want to filter out privite constants). I agree however, that this works, and also `A.constants` returns `[:C2]` as expected - and what OP appears to want - so not entirely sure what the OP's actual problem is. – Neil Slater May 03 '16 at 19:23
  • @NeilSlater, I answered on answer `Is there a way to programmatically identify private constants?` – Ilya May 03 '16 at 19:25
  • New edit shows all possible ways. Cannot argue with that :-) I wonder why question says that this doesn't work for OP? – Neil Slater May 03 '16 at 19:29
  • @NeilSlater I was passing `(false)` in the code where I thought I had the problem. It wasn't obvious that `inherit=` had anything to do with public/private, so I didn't see that might be an issue. – David Moles May 03 '16 at 19:49