Note that there are some explanatory texts on larger screens.

plurals
  1. POConstants in classes created with Class.new
    primarykey
    data
    text
    <p>I'm writing a little piece of code in Ruby (1.9.3), and I use a pair of simple "enum-like" classes, that define some constants with <strong>const_set</strong> and some behavior of these constants (e.g. the class <strong>Days</strong> may have the constants <strong>MON</strong>, <strong>TUE</strong>... and <strong>Days::MON.succ</strong> should evaluate to <strong>TUE</strong>).</p> <p>I'm really comfortable with these classes. However, while growing my code, i sometimes need to add more of them, and I don't like the idea of having five or more classes that share 99% of source code, e.g.:</p> <pre><code>class Days NAMES = %w( MON TUE ... ) INSTANCES = [] def initialize(num) @num = num end # An example operation def +(n) INSTANCES[(@num + n) % INSTANCES.length] end # Another example operation def succ self + 1 end def to_s NAMES[@num] end NAMES.each_with_index do |name, idx| instance = new(idx) INSTANCES[idx] = instance const_set name, instance end end class Months NAMES = %w( JAN FEB ... ) ... end </code></pre> <p>I was wondering if Ruby's metaprogramming capabilities could be used to generate these classes. However, I'm having an hard time creating <strong>NAMES</strong>, <strong>INSTANCES</strong> and the "enum-named" constants (e.g. <strong>MON</strong>, <strong>TUE</strong>, ...). Being <strong>const_set</strong> a class method of <strong>Class</strong>, in this code it's context (the value of <strong>self</strong>) is respectively <strong>Days</strong> and <strong>Months</strong>.</p> <p>When creating a factory method, I'm compelled to do something like this:</p> <pre><code>def enum_new(names_array) Class.new do const_set "NAMES" [] names_array.each_with_index do |name, idx| NAMES[idx] = name end ... end end Days = enum_new(%w| MON TUE ... |) Months = enum_new(%w| JAN FEB ... |) </code></pre> <p>but this won't work (at least, not like i hoped it to), because <strong>const_set</strong> won't be called in the context of the class whose name is <em>magically</em> set (i.e. <strong>Days</strong> and <strong>Months</strong>), but apparently in the context of <strong>Class</strong>; therefore, not only it won't be accessible from the instance methods, but it will be overwrited every time <strong>enum_new</strong> is called with a new array of names as argument. A similar problem shows up when using class variables, because they'll be shared between any class generated with the method (because they'll become class variables of <strong>Class</strong>, i guess).</p> <p>Is there any way to create constants in a class generated with <strong>Class.new</strong>, obtaining this way classes identical in everything to the original <strong>Days</strong> and <strong>Months</strong> classes, without having to pollute my code with almost identical classes?</p> <p>Thanks for your attention and patience! :)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload