When should I use the "class Object", "class Module", "Module Kernel" and nothing?

I am new to ruby ​​metaprogramming and I see that people metaprogramme code in different places, for example class Object , class Module , module Kernel and nothing (i.e. from the class / module definition block).

For example: I am creating the c_attr_accessor method to access class variables, and I'm not sure where I should put the code, since it works in any of these cases.

How to decide which place is more suitable for hosting the new global code?

+3
source share
2 answers

Each of these examples relates to different cases.

If you write methods that apply to all objects, you open the Object class so that all objects can access it. If you write methods that apply to all modules, then you open Module . Whenever you open a class to add methods, the methods should be applied to all instances of the class and nothing else.

The Kernel extension is different: people do this by adding methods that should be available for each scope, but not so that the methods are explicitly called for the object, making them private.

If you are outside of any class or Module operator, you fall into the scope of the main object and the methods that you define by default as private methods of Object . This is good for small or simple programs, but ultimately you will want to use the appropriate modules as namespaces to organize your methods.

As a final note on this subject, you should always be sure that you really want the methods that you add to the built-in classes and modules to be accessible to everything in your application, including external inclusions, since they all share the built-in classes and modules , other.

Now apply this to answer your question. Since you are defining a method that creates accessors for class variables, you must put it in the class class , as it applies to all classes and nothing more. Finally, you are most likely to use it only in class definitions (in the class statement), so we must make it private:

 class Class private def c_attr_accessor(name) # ... end end class User c_attr_accessor :class_variable_name # ... end 

If you really do not need this in every class (maybe several), then create a “mixin module” to extend each class that needs this function:

 module ClassVariableAccessor private def c_attr_accessor(name) # ... end end class User extend ClassVariableAccessor c_attr_accessor :class_variable_name # ... end 

Note that you use Object#extend to add c_attr_accessor only to the User object (remember that classes are objects, you will hear this a lot if you are new to Ruby metaprogramming).

There is another way to implement the last example, which works by explicitly extending its base class using the "" Module#included(base_class) , called whenever the module is turned on, and the base class is passed to base_class :

 module ClassVariableAccessor def included(base_class) base_class.extend ClassMethods end module ClassMethods def c_attr_accessor(name) # ... end end end class User include ClassVariableAccessor c_attr_accessor :class_variable_name # ... end 

I recommend this last solution because it is the most general and uses a simple interface that does not need to be updated. Hope this is not too much!

+3
source

Have you tried to find where the usual attribute attributes are defined? I would either define it in the same class / module, or create my own module into which all my new methods go.

+1
source

All Articles