How to add classes in different files into one module in Ruby? - ruby

I currently creating a gem, so, I have a folder with different files, which contains different classes, this folder will be updated with more files and also current ones will be updated as well, in another file I have a module that should contain these classes.
Currently, I add manually to the module all the classes:
File1.rb:
module MyModule
class ClassA
# code here
end
end
File2.rb:
module MyModule
class ClassB
# code here
end
end
But, since I will add more classes and current classes will be updated this is not optimal and very dangerous to maintain clean, so is there any other way to add classes in different files in one module set in another file?
Thanks in advance

No there is no another way and I don't see any danger in doing it the way you did (correct way).

Related

How can I move all classes from a directory under a module?

I have a project with a lot of tests. One issue is that many classes under tests/integration and tests/functional have colliding class names. This produces errors when trying to run tests inside RubyMine.
To avoid the huge task to rename them one by one, I was thinking to move all classes inside integration inside a module, e.g. IntegrationTests, end result would be:
module IntegrationTests
class Whatever < Something
...
end
end
I see found way to refactor all classes under that directory like that. Any clues? I would also accept answers using another tool if this is impossible with RubyMine itself.

Add Ruby classes to a module when defined in separate files

I would like to namespace my Ruby classes by putting them in a module. Indeed, this is a good idea if I decide to publish my Ruby gem so that the class names do not clash with existing classes in another gem. I know I can do the following for a class A::B:
module A
class B
end
end
However, the above is quite cumbersome in that I need to put all my class definitions into a single Ruby source file in order to scope them under the module. I would rather keep my class definitions in separate source files, much like a Java project, so how can I add classes to a module when they are all defined in separate files?
The accepted practice in this case is to wrap every file in module block
# a/b.rb
module A
class B
end
end
# a/c.rb
module A
class C
end
end
Btw. because of the way constant are resolved, it is advisable to use the long form I quoted above instead class A::B
(http://blog.honeybadger.io/avoid-these-traps-when-nesting-ruby-modules/).

Location of a class in rails app

I want to extend the functionality of Array, add a method that checks if a key exists in array and that the array is not empty, where to write the class and how to make sure it's loaded?
You can either put it into lib/ and make sure that it is autoloaded as outlined in the answer by shioyama; or you could just put it into an initializer. I like the initializer approach a bit better, since it is easier (you get autoloading for free).
I usually create a core_ext subdirectory of the initializers directory and put my core class extensions in there. I always try to put the name of the class that is being extended and a description of what I add into the filename, so in you case I would create a file RAILS_ROOT/config/initializers/core_ext/array_my_function containing:
module MyFunctionForArray
def my_function(arg1, arg2)
# ...
end
end
Array.send :include, MyFunctionForArray
I always try to not reopen the class and extend it directly but to put my extensions into a module and then including this module into the class to extend.
Standard way to do it is to put the code in lib/ and make sure it's autoloaded by rails by adding a line to config/application.rb:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Then in your code, just make sure you require it wherever you use it. If you want to apply it everywhere, create an initializer in config/initializers with a line:
require 'my_array'
Where my_array.rb is the name of the file in lib where you have the file. That will make it available in your models, controllers, views, etc.
See also: Best way to load module/class from lib folder in Rails 3?
Also, beware of one pitfall of autoloading a directory structure in ruby (not just rails), explained in this answer: Best way to load module/class from lib folder in Rails 3?

Ruby modules that use some common method:where to put this method?

Given some Uploader Class, I have three modules included in it.
They have each their own distinctive uses and that's why I divided them into three modules. But, as it turns out, there is one method that all three modules need.
So, it is so far obvious to me that there must be a better way than defining this method in each of these three modules. Should I make a fourth module and put this method in it, and have these original three modules include this fourth module? Or is there a better way?
Yes, it sounds like you should have a fourth module. But it sounds like you might actually need a class hierarchy rather than independent, flat modules. Apply the 'is a' test - can you say an UploaderA instance is an Uploader? If so, you should have
class Uploader
include FourthModule # with shared functionality for all uploaders
# or just go ahead and put the shared functionality right in the Uploader class here.
end
class UploaderA < Uploader
end

getting contents (classes & modules) of required files in ruby

Is there any way, to track dynamically which classes or modules are included in required files.
a short example:
#my_module.rb
module MyCustomModule
def foo
end
end
#custom.rb
require 'my_module.rb'
#is here any way to track which modules are in the required 'my_module.rb'
#without parsing the file or having some naming conventions?
The aim is, to require dynamically a bunch of files and including the contained modules in a class, regardless of how they are named.
You can use ObjectSpace to determine newly defined Modules.
#custom.rb
existing_modules = ObjectSpace.each_object(Module).to_a
require 'my_module.rb'
new_modules = ObjectSpace.each_object(Module).to_a - existing_modules
# => [MyCustomModule]
class X
new_modules.each{|m| include m}
end
Note: You probably want to only include the top level ones, though, so check the names for ::

Resources