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)
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!
In the controller my Rails project, I would like to create a new file /public/my_files/welcome.txt with content
Welcome to my website!
(The folder my_files does not exist yet.)
How can I do that?
(Edit: I know that to make a static page, I don't need to do it via a controller. I'm actually making a dynamic page, but I'm just simplifying the example.)
File.open(Rails.root + '/public/my_files/welcome.txt', 'w') {|f|
f.write("your dynamic data") }
This is the simplest way you can create a file. Ruby will automatically create the file if not present. Let me know if this fits within your requirment.
I am not really sure what you asking about, but if you just want a static page you can do so without using the controllers
Just make a folder in the public dir (right click >> new >> folder) and make a html file in it.
Then start the rails server and point your browser to
localhost:3000/my_files/welcome.html
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.
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
I'm trying to render .odf files from a controller action in a rails application. I'd like to be able to put templates inside my view folders called show.odp.erb, show.odf.erb, etc.. and have that represent the content.xml file that is inside the zip. I'd also like to be able to render these actions in the controller like so:
respond_to do |format|
format.odf {
#odf code here
}
format.odp {
#probably about the same as the odf code, but renders a different template with a different file extension.
}
I would also like to have a template content.xml file in my layouts directory that has the necessary headers and footers. The main questions I have are these:
should I put all .odf files in one folder in the layouts directory? or should i put the static ones in the public directory?
how can i insert the dynamic content.xml file into the directory before I zip it up and serve it? I hope this is an easy enough question for a render guru out there ;)
this was not easy. I wound up writing a module, that essentially pulls templates from a directory, applies a layout, zips up the whole package and serves it up. details are included with the module, as it's a bit too complicated to explain here, but it can be found at this pastebin link
hope this helps someone else
-C