Use Accessors
While I haven't found a really elegant solution for initializing a singleton the way you want, it's fairly trivial to implement this with an accessor. For example, in Ruby 3.1.2:
require 'singleton'
class Example
include Singleton
attr_accessor :file_name
end
#=> [:file_name, :file_name=]
You can then use the accessor to populate @file_name if it doesn't already contain a truthy value since instance variables auto-vivify as nil
:
Example.instance.file_name ||= "/tmp/foo"
#=> "/tmp/foo"
Example.instance.file_name
#=> "/tmp/foo"
Example.instance
#=> #<Example:0x0000000108da72b8 @file_name="/tmp/foo">
Removing Writable Accessors After Setting a Value
Obviously, you can also re-assign the variable since you have a writable accessor. If you don't want to allow that on your singleton class after you've set your instance variable for the first time, just undefine the attr_writer method once it's truthy:
# @return [Class<Example>, nil] class if method removed; otherwise nil
Example.instance.singleton_class.undef_method(:file_name=) if
Example.instance.file_name && Example.instance.respond_to?(:file_name=)
A Simplification with Caveats
You could do this all at once like so:
require 'singleton'
class Example
include Singleton
attr_accessor :file_name
end
Example.instance.file_name ||= "/tmp/foo"
Example.instance.singleton_class.undef_method(:file_name=)
Example.instance
#=> #<Example:0x0000000108da72b8 @file_name="/tmp/foo">
but if you don't know ahead of time whether your instance variable has been set you may prefer the more verbose approach. Your use cases may certainly vary.