3

For example:

ABC = 'abc'
DEF = 'def'
XYZ = 'anything'
LIST_ALL = [ABC, DEF, XYZ]

If I do

LIST_ALL.reject(&:blank?).join(', ') # => "abc, def, anything"

What I am looking for is to get the constant names, not their values Expected output:

LIST_ALL.something() #=> "ABC, DEF, XYZ"

Approach #1:

class X
  ABC = "abc"
  DEF = "def"
  GHI = ""
  XYZ = "anything"
  LIST_ALL = %w(ABC DEF GHI XYZ)

  def self.something()
     puts LIST_ALL.reject{|c| c.constantize.blank?}.join(', ')
     # puts LIST_ALL[0].constantize
  end
end

Error:

(NameError)  uninitialized constant ABC;
timekeeper
  • 698
  • 15
  • 37
  • 1
    How about `LIST_ALL.map(&:upcase)` and after that apply join if you want string. like this `LIST_ALL.map(&:upcase).join(", ")` – Ajay Barot Feb 13 '18 at 20:31
  • 1
    @AjayBarot Sorry. upcase wont always work. This is just an example. Will update the question for better understandability that upcase won't always work. Thanks for pointing it out. – timekeeper Feb 13 '18 at 20:44

3 Answers3

4

Ruby has no explicit hook for instance naming, as I can see. However, classes does.

CONSTANT = 'my constant value'
instance = Class.new
CONSTANT = instance
instance.name.to_s
=> "CONSTANT"

Unfortunately, this will mess with your constant value, and that's not what you want.

In any case, a solution I see is to stop using constants directly and use a hash. Just like:

MY_HASH  = { 'ABC' => 'abc', 'DEF' => 'def' }
puts "constant names are #{MY_HASH.keys.join(', ')}"
=> "constant names are ABC, DEF"

puts "constant values are #{MY_HASH.values.join(', ')}"
=> "constant values are abc, def"

If you still wanna mess with metaprogramming, check this answer.

vinibrsl
  • 6,563
  • 4
  • 31
  • 44
  • vnbrs@ Map seems overkill for my purpose. I am building up LIST_ALL just to use it to validate that it is a valid input. And the valid inputs are ABC, DEF, XYZ – timekeeper Feb 13 '18 at 20:53
  • You don't need `map` if you build the hash using the old syntax. `{ 'ABC' => 'abc', 'DEF' => 'def' }` – vinibrsl Feb 13 '18 at 20:55
  • LIST_ALL should be the list of constants i.e ABC, DEF and XYZ. Not in string. Later, I want to concatenate like `"constant names are: " + LIST_ALL.something()` which should then give output as `constant names are: ABC, DEF, XYZ` – timekeeper Feb 13 '18 at 21:01
  • I made a change @AayushKumarSingha – vinibrsl Feb 13 '18 at 21:11
  • Thanks for your help. In my implementation part, I have less inclination to use a map. Since, every other place its done this way. Making it consistent. I am looking more ways if possible. – timekeeper Feb 14 '18 at 12:59
  • I removed the map @AayushKumarSingha – vinibrsl Feb 14 '18 at 13:01
2

Store the constant names as strings, when you want to check the constant value use `#constantize'...

ABC = 'abc'
DEF = 'def'
GHI = ''
XYZ = 'anything'
LIST_ALL = %w(ABC DEF GHI XYZ)

Then you can do...

LIST_ALL.reject{|c| c.constantize.blank?}.join(', ') # => "ABC, DEF, XYZ"
SteveTurczyn
  • 36,057
  • 6
  • 41
  • 53
  • Can you also include how to use #constantize to get constants value when required? – timekeeper Feb 14 '18 at 21:40
  • Just use "#constantize" by itself. `ABC = "text"; my_constant = "ABC"` then `my_constant.constantize` will return "text" – SteveTurczyn Feb 15 '18 at 09:24
  • `undefined method 'constantize' for "ABC":String (repl):6:in 'block in
    ' (repl):6:in 'reject' (repl):6:in '
    '` getting this error
    – timekeeper Feb 16 '18 at 16:58
  • I realized constantize is rails specific. On running using RoR, I am getting this error: `(NameError) uninitialized constant ABC;` I have updated the question using your approach. – timekeeper Feb 16 '18 at 17:19
  • I have edited the answer. With more detailed implementation details. Thanks a ton for your answer. Also, my very first step to meta-programming. – timekeeper Feb 16 '18 at 19:26
  • Uninitialized constant? You've defined the constant ABC before you attempted the `constantize`? – SteveTurczyn Feb 16 '18 at 19:33
  • I have added my implementation details as another answer. It is working for me now. The constants needed to be as :: otherwise, was getting uninitialized constants. – timekeeper Feb 16 '18 at 22:43
0

Implementation details inside a class.
Add <classname>::<constant_name> otherwise throws (NameError) uninitialized Constant ABC:

class X
  ABC = "123"
  DEF = "456"
  LIST_ALL = %w(X::ABC X::DEF)

  def something()
    puts LIST_ALL.reject{|c| c.constantize.blank?}.join(', ') # output: X::ABC, X::DEF
    puts LIST_ALL[0].constantize # output: 123
  end
end

Note: to use constantize, Ruby on Rails is pre-requisite.

timekeeper
  • 698
  • 15
  • 37