2

I'm trying to create a module that will be included in many different classes. It needs to record the caller's path to the class file so I can reference the path in later code. This code tries to add a method to the calling class, but fails because it just returns the current value of @@x.

# /home/eric/FindMe.rb class FindMe include GladeGUI end # /home/eric/GladeGUI.rb module GladeGUI def self.included(obj) @@x, = caller[0].partition(":") # this works @@x = "/home/eric/FindMe.rb" obj.class_eval do def my_class_file_path return ????? # I want to return "/home/eric/FindMe.rb" end end end end 

The GladeGUI module will be "included" in many different classes, so I can't just add code to the calling class. I need a way to make @@x compile into a constant value, so the method stored in the class looks like this:

 def my_class_file_path return "/home/eric/FindMe.rb" end 

How do I convert a variable to a constant in code?

Thanks.

1 Answer 1

2

It seems like you don't actually need it to be a "constant" - you just need some way to make the method return the correct value all the time and not allow other code to come along and change the value (with the current @@x solution, someone can just modify @@x and it will break)

The solution is to store the data in a local variable instead of a class or instance variable, and then access that local variable via a closure.
No other code will have scope to 'see' the local variable and thus it cannot be changed.

But then the problem becomes that when you use def inside a class_eval, the scope of the caller isn't captured, so the code can't see your local variable. You can use define_method instead

Here's an example

# /home/eric/GladeGUI.rb module GladeGUI def self.included(obj) caller_file_path = caller[0].split(":").first obj.class_eval do define_method :my_class_file_path do return caller_file_path end end end end # /home/eric/FindMe.rb class FindMe include GladeGUI end puts FindMe.new.my_class_file_path # prints the correct path 

But - what if you want my_class_file_path to be a class method rather than an instance method - use define_singleton_method instead:

module GladeGUI def self.included(obj) caller_file_path = caller[0].split(":").first obj.class_eval do define_singleton_method :my_class_file_path do return caller_file_path end end end end ... puts FindMe.my_class_file_path 

Interesting side note: This is how you can fake "private variables" in javascript :-)

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.