I've always liked Ruby's open class feature but have also wondered how do you keep track of all the changes made to the class definition during runtime? ...There isn't an easy way (that I know of) out of the box to know what files made what changes to your objects. But, are a few things that you can do that may give you hints as to where behavior is coming from.
Use modules instead of adding behavior directly.
On my current project we needed to add a % method to symbol. You can accomplish this with the following code.
class SymbolThe above code does what you need, but leaves no hint that you've made a change to Symbol. An alternative solution is to define a module and include that module in Symbol.
module SymbolExtensionGranted, this isn't a huge hint, but if you check
Symbol.send :include, SymbolExtension
Symbol.ancestorsyou'll find the following list.
SymbolMany people believe this is better than nothing, but the choice is yours.
Use the stack trace.
Another option is to use the stack trace to try to track down a specific method. If you are working with some code where a method is being modified somewhere, but it isn't in a module the following code could help you out.
class SymbolThe above code uses the method_added hook method and raises and exception when the method you are looking for is defined. At this point the stack trace should show you where the method was defined.
raise caller.to_s if method == :%
In practice I've had very little trouble with finding where behavior is defined. In all the projects I've been involved with we have a few conventions that we follow that help ensure we can find behavior definitions easily.
- Define behavior for the class PhoneNumber (for example) in the phone_number.rb file
- If you need to open a class that you have not created, create a [Class]Extension module and include it as shown above.
- Avoid dynamically adding behavior in unexpected places when possible. For example we don't define behavior in associations, such as:
# not recommended
has_many :people do