If i want to move /lib/foo_bar.rb to /lib/tidy/foo_bar.rb or even /lib/tidy/somestuff/foo_bar.rb
must i declare FooBar to be module Tidy or module Tidy::Somestuff
in other words must the modules match the directory structure?
Yes, if you don't want to specify the load path. You can add lib/tidy to the LOAD_PATH and then Rails will find it, but it's easier to just stick with the conventions
Related
Upon running rails g graphql:install, a set of useful base type files are created in /app/graphql/types for us to extend when defining our own types. When running any of the generators, it creates these files in the same folder also. I set about creating sub directories thinking I could add some sense to this giant catch-all directory, but couldn't get things to load properly.
Since there is a base file for each type (base_enum.rb, base_object.rb, etc.), I created a folder for extensions of each of these types (enum_types, object_types, etc.). This broke auto loading though and I had to explicitly import these files to be able to use these custom types. So, at the top of query_type.rb, mutation_type.rb and app/graphql/mutations/base_mutation.rb I added the following:
['enum_typs', 'input_object_types', 'interface_types', 'object_types', 'scalar_types', 'union_types'].each do |dir|
Dir[File.dirname(__FILE__) + "/#{dir}/*.rb"].each {|file| require file }
end
This allowed things to run, but any change would break auto loading so I would have to restart the server on each change. I started reading through this article about auto loading on the rails site, but it was quite honestly a little over my head. Though it led me to believe I had to either find the correct names for my folders or namespace the objects defined in my type definition files properly to be able to do this.
Is there a sane way to organize these files in sub-directories which doesn't break auto loading? Do most projects just have a flat folder structure for these files?
Thank you!
Is it possible to merge multiple module definitions in a single file and avoid possible clashes with Rails autoloading ?
Thanks !
I am not sure I understood how this would help “to avoid possible clashes with Rails autoloading”, but the answer is “yes”: one might define as many modules, classes, constants and whatever is defineable in the single file.
Ruby has no restriction on the relation between file names and modules/classes names. One might define modules A1 and A2 in file b.rb. Standard lib/namespace/class_name.rb convetion is the convention only, as soon as file is required, it’s content is being loaded.
File.rename(blog_path + '/' + project_path, File.expand_path(topic_name, blog_path))
I use these code to rename ruby file name, but I think there is a better way to write this functionality with less code since it includes blog_path two times.
The code is OK, but I think there is no need to expand_path here - this method creates an absolute path from the the relative one.
Also, it is good to use File.join to create a path instead just concatenate it with slash - it will be completely OS independent. So I would write your code like this:
File.rename(File.join(blog_path, project_path), File.join(blog_path, topic_name))
Or if you want to get rid of doubled blog_path, change working directory before doing a rename:
Dir.chdir(blog_path)
File.rename(project_path, topic_name)
More info on working with files and directories in Ruby you can find in the article: Ruby for Admins: Files and Directories.
I want to dynamically load code by traversing a directory structure and dynamically load whatever modules I find there.
The purpose for doing so is to run a series of validations. If a top-level validation fails, any child validations will not be run.
My thinking was that a controller object could scan the directories, build up a hierarchy of modules and then make the decisions on whether or not to traverse a particular part of the tree based on the success/failure of higher-level validations.
For example, I might have a series of validations I want to run against a regex, however, none of the validations should be run if the regex doesn't exist or is empty. In this case, the top level directory would contain just the exists validation, and a child directory would contain all the other validations to be run if the regex exists.
Being able to define these validations in separate files and create the needed hierarchy would be extremely useful for ease of adding additional validations later, rather than having to crack open an existing class and add methods.
Is there a way an application can dynamically scan a directory, save the filenames in a collection and then use the elements of that collection in a require? I don't think so. What about a load?
Is there any way to achieve such a design? Or am I thinking about it all wrong and should think of some other methodology instead?
Your request is very doable, but no language will do it for you automatically. You have to write the code to dive into the directories, determine the existence of the tests and then decide whether you should drill down further.
Ruby will help you though. There is the Find module, which is included in the standard library. This is from its docs:
The Find module supports the top-down traversal of a set of file paths.
For example, to total the size of all files under your home directory,
ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
require 'find'
total_size = 0
Find.find(ENV["HOME"]) do |path|
if FileTest.directory?(path)
if File.basename(path)[0] == ?.
Find.prune # Don't look any further into this directory.
else
next
end
else
total_size += FileTest.size(path)
end
end
From that code you would look for the signatures of the files and embedded folders, to decide if you should drill down further. For each file found that is one you want, use require to load it.
You can find other examples out on the "internets" showing how people use Find. Also the Dir module has similar functionality using glob, only you have to tell it where to descend, and then can iterate over the returned results.
I wanted to make a generator that created files (and directories, etc...) based on already existing files in the app (for instance, the views or controllers). So if we had views set up like this
-app
-views
- layouts
- application.html.erb
- users
- index.html.erb
- show.html.erb
- etc ...
and I wanted to create files based on them I can do (with just ruby)
directories = Dir.entries("#{Rails.root}/app/views")
directories.each do |directory|
unless directory == "." or directory == ".."
files = Dir.entries("#{Rails.root}/app/views/#{directory}")
files.each do |file|
unless file == "." or file == ".."
text = File.read("#{Rails.root}/app/views/#{directory}/#{file}")
something #=> whatever else needs to go here to edit the file
something else #=> output_file.puts whatever
end
end
end
end
so this is basically what I would like to do with a generator so I can roll my code into a plugin and use it for other apps.
First question, how can I generate arbitrary files (with filenames based on existing filenames using the generator. Is it appropriate to cycle through the directories like I did above, grab the directory/file and generate files? Is there a way to do what I did using a simpler method (mine seems easily breakable).
Also, should I put all that read/format/write code inside the generator itself and just pass a string into the "initialize content" section of create_file or should I put it somewhere else. Or should I use the generator to create the bare files and populate it with an init script?
Is there a more rails type of way of populating generated files, or should I just shove all my formatting code inside the generator. If so, what is the appropriate way to approach this.
I am not sure if you want to know how generators are built in rails3 or not. The code you are showing is not very generator-like. In generators you can use all commands from Thor, which offers you a very powerful toolset of manipulating files, and injecting code (strings) into classes or files.
So I would most definitely fill your files inside a generator, because then it happens on user request, and the user can choose whether or not certain files need or can be overwritten or not.
Inside your gem, you will have a lib/generators folder, containing a templates folder, containing all files you might want to place inside the rails application.
From the Thor documentation, here is a nice example to construct files in a generator.
Hope this helps.
there's a simple API to use generators in Rails. here you can find a good guide:
http://guides.rubyonrails.org/generators.html
if you want to check some code:
https://github.com/coderloop/tamed_beast (I'm the author of its generators)
https://github.com/pilu/web-app-theme (another clean example)