In my Rails project I have a specific list of externally-supplied files I want to process using Rake. My goal is to be able to specify the source directory of these files as an argument like so:
rake foofiles:process[vendor/sources]
Currently I'm specifying the file names (and their relative paths within the source directory) using a FileList assigned to a constant:
REQUIRED_FILES = FileList[
'blah.csv',
'subdir/something.csv',
'subdir/monkeys/foo.bar',
...
]
How can I prepend each of these files with my source directory argument so that I can make a task that depends on those files existing in that directory? (ideally nothing would happen without all those files being present)
For example, if I used the rake command as typed above, I'd need my task to depend on vendor/sources/blah.csv, vendor/sources/subdir/something.csv, vendor/sources/subdir/monkeys/foo.bar etc.
Edit: Adding a prefix to each element in an array/list is relatively trivial, I'm more confused about how to structure my task(s) and their dependencies so I can actually access the source folder argument I've supplied, then use the new prepended file list as a dependency for the processing task that actually does the work.
The main invoked task is gonna have to look something like this if I want the syntax I used at the top:
namespace :foofiles do
task :process, [:source_directory] => [???, my_newly_prepended_file_list] do |t, args|
# Do stuff
end
end
But I don't know how to provide the :source_directory argument to a task that does the prepending, and then subsequently return the prepended file list to the :process task as a dependency.
Why not just keep an array of the suffixes, then append the argument to the start of each element in the array, then create the filelist?
suffixes = [
'blah.csv',
'subdir/something.csv',
'subdir/monkeys/foo.bar',
]
files = suffixes.map { |suffix| File.join(prefix, suffix) }
file_list = FileList[*files]
Where prefix is the argument passed in.
I ended up just using an environment variable, it's much easier to work with in my case than Rake's built-in argument implementation. This way I can work with the variable and build my FileList with the prepended path (in the way Cameron suggested in the other answer) outside a task block:
namespace :foofiles do
REQUIRED_FILES = [...]
source_directory = ENV['SOURCEDIR'] || 'vendor/sources'
source_files = FileList[REQUIRED_FILES.map { |relative_path| File.join source_directory, relative_path }]
# Note: FileList can take an array inside the square brackets without needing the splat (*) operator
task process: source_files do
...
end
end
So now I can call it from the terminal like this:
SOURCEDIR=some/folder rake foofiles:process
Related
I need to delete the directory after its creation but I am getting an error because the directory is still in use by ruby.exe or another ruby process is there any way that I can close the directory like closing the file so that it will delete after its creation. When i reload the page and then try to remove the directory then the directory successfully delete.
Here is the code which i am trying
if Dir.exists?("first/test")
FileUtils.rm_rf("first/test")
FileUtils.mkdir("first/test")
else
Dir.mkdir("first/test")
end
Test folder does contain sub directories and files.
The stream was not closing after writing files in rubyzip class
I have modified the code in rubyzip class like this
disk_file = File.open(diskFilePath, "rb")
io.get_output_stream(zipFilePath) { |f|
f.puts(disk_file.read())
}
disk_file.close
There are two main problems with your code, I think:
According to Ruby documentation, Dir.exists? is deprecated and should not be used. Use Dir.exist? (without the 's') instead;
You are trying to create a directory structure with FileUtils.mkdir or Dir.mkdir when, in fact, you need a 'stronger' method: FileUtils.mkdir_p.
Try this:
if Dir.exist?("first/test")
FileUtils.rm_rf("first/test")
FileUtils.mkdir_p("first/test")
else
FileUtils.mkdir_p("first/test")
end
And see the corresponding documentation.
I believe that doing
FileUtils.mkdir("first")
FileUtils.mkdir("first/test")
would work fine, although I haven't tested it, because the second dir ('test') would be create inside an existing one. But if you need to create a whole structure in a single command you'd need the -p flag using a bash command and the corresponding FileUtils.mkdir_p method.
Let me also point you that this if..else structure is not good this way. You want to create the directory structure in both if and else, and if the same command appears in both if and else, it must be taken out of the if..else, like this.
if Dir.exist?("first/test")
FileUtils.rm_rf("first/test")
end
FileUtils.mkdir_p("first/test")
I hope this helps.
I have already built several Rake tasks to import a series of CSV files into my PostgreSQL database, but I've always had those tasks directed to a path on my local computer.
I need to have the tasks set up to access a secure on directory so my client can simply copy files into this directory, and when the Rake task is executed it automatically pulls from the online source.
This seems like it would be a simple adjustment in my code but I'm not sure how to make it work. If anyone has any suggested reading or can quickly help edit my code it would be appreciated.
Below is a copy of one of my Rake tasks:
require 'csv'
namespace :import_command_vehicles_csv do
task :create_command_vehicles => :environment do
puts "Import Command Vehicles"
csv_text = File.read('/Users/Ben/Sites/ror/LFD/command_vehicles.csv', :encoding => 'windows-1251:utf-8')
csv = CSV.parse(csv_text, :headers => true)
csv.each_with_index do |row,index|
row = row.to_hash.with_indifferent_access
CommandVehicle.create!(row.to_hash.symbolize_keys)
command_vehicle = CommandVehicle.last
if #report_timesheet_hash.key?(command_vehicle.report_nr)
command_vehicle.timesheet_id = "#{#report_timesheet_hash[command_vehicle.report_nr]}"
end
#command_vehicle.timesheet_id = #timesheet_id_array[index]
command_vehicle.save
end
end
end
You can create rake tast that can accept parameters and then you can pass whatever path you like.
Check out this link Set Multiple Environmental Variables On Invocation of Rake Task to see how to pass parameters via enviroment variables and this link http://viget.com/extend/protip-passing-parameters-to-your-rake-tasks to see bracket notation.
'/Users/Ben/Sites/ror/LFD/command_vehicles.csv' will only work on your local machine, unless you have an identical path to your resources on the remote host, which is hardly likely. As a result, you need to change the absolute path, to one that is relative to your file.
I have a folder hierarchy on my Desktop, stuck several folders down, like:
- test
| lib
| - test.rb
| config
| - config.yaml
And test.rb contains:
File.realpath('../config/config.yaml', File.dirname(__FILE__))
__FILE__ is a special variable that returns the absolute path to the script currently being interpreted. That makes it easy to find where something else is if you know where it exists relative to the current __FILE__.
The value returned by realpath will be the absolute path to the "config.yaml" file, based on its relative path from the current file. In other words, that would return something like:
/Users/ttm/Desktop/tests/junk/test/config/config.yaml
The nice thing about Rake is it's really using Ruby scripts, so you can take advantage of things like File.realpath. Also, remember that Rake's idea of the current-working directory is based on the location of the script being run, so everything it wants to access has to be relative to the script's location, or an absolute path, or you have to change Rake's idea of the current-working directory by using a chdir or cd.
Doing the later makes my head hurt eventually so I prefer to define some constants pointing to the required resources, and figuring out the real absolute path becomes easy doing it this way.
See "How can I get the name of the command called for usage prompts in Ruby?"
for more information.
I have some data stored as an XML file. I put it into a directory I've created, app/data/myxml.xml.
Now I want to parse it using Nokogiri. To locate the file I am referencing an absolute path:
#doc = Nokogiri::XML(open("/home/me/webA/myrailsproject/app/data/myxml.xml"))
The absolute path definitely make the code ugly. Is there a shorter, cleaner way to reference the file? Such as:
#doc = Nokogiri::XML(open("myxml"))
The current directory in a Rails is the application root, so you could just do
#doc = Nokogiri::XML(open("data/myxml.xml"))
Or if you want to be sure, you can use the RAILS_ROOT constant -
#doc = Nokogiri::XML(open("#{RAILS_ROOT}/data/myxml.xml"))
My default environment.rb is overflowing, and i would like to have a separate file that works exactly the same way. How can I do so?
You're likely adding things to the environment file that should be in an initializer. Check the config/initializers directory for some examples of what to put in there. That should allow you to break things up and make everything more organized.
Rails actually uses eval to load the special environment files such as config/environments/development.rb. This is the code it uses:
eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
You could define a method such as load_more_environment like this:
def load_more_environment(path)
eval(IO.read(path), binding, path)
end
The first argument to eval is just the code you want to load and it will be executed within the current binding. The third argument will be used to report syntax errors in the file.
I need to move a folder from a plugin to the main app/views. I guess using rake to do this with the following command is the easiest way:
require 'fileutils'
FileUtils.mv('/vendor/plugins/easy_addresses/lib/app/views', '/app/views/')
I'm just not sure where to tell script where to look and where to place the folder.
The file I want to move is in the following location: `vender/plugins/easy_addresses/lib/app/views/easy_addresses
easy_ addresses is the name of the folder in views that I want to move to my_app/app/views/
FileUtils.mv('/source/', '/destination/')
There is a constant which has the rails root, just prepend it to your pathes:
File.join(RAILS_ROOT, "app", "views")
Here RAILS_ROOT holds the location "where to look", and using File.join on the path components takes care of concatenating the components using the right path separator suitable for the used system.
In the result the above method call gives you the complete absolute path to "app/views" in your application.
Edit:
In Rails >= 3 you can use Rails.root.join('app', 'views').