what is the right way to use CLEAN rake task? - ruby

This is what I'm trying to do in my Rakefile:
require 'rake/clean'
CLEAN = ['coverage']
This is what I see in the log:
$ rake
/code/foo/Rakefile:29: warning: already initialized constant CLEAN
/Users/foo/.rvm/gems/ruby-2.1.3/gems/rake-10.3.2/lib/rake/clean.rb:61: warning: previous definition of CLEAN was here
I don't like these warnings.. What is the right way?

CLEAN is a FileList that is used by the predefined clean task. To add your own files to be cleaned, add them to this list. You can use the include method:
require 'rake/clean'
CLEAN.include 'coverage'
Now running rake clean will remove your files, as well as the predefined set of temporary files if any have bean created.

'rake/clean' already defines the constant CLEAN like so: CLEAN = ::Rake::FileList["**/*~", "**/*.bak", "**/core"]. Constants aren't meant to be overridden (although ruby will let you). If you want to specify the files to be cleaned, you should create your own rake task similar the existing one.
The existing task runs:
Rake::Cleaner.cleanup_files(CLEAN)
So you could run:
Rake::Cleaner.cleanup_files(['coverage'])
to clean up your coverage files.

Related

Can a Ruby test get the location of the folder where Rake executed it from?

Can a Ruby test get the location of the folder where Rake executed it from? I want to run Test::Unit unit tests using Rake but my defined "test suites" in Rake need to be able to find locations of libraries relative to the root of my project.
With Maven, I can set a system property like so :
<properties>
<main.basedir>${project.basedir}</main.basedir>
</properties>
And then Java can reference it like so:
String baseDir = System.getProperty("main.basedir");
Can Ruby do something similar? If so, how? Do I need to use a Rake namespace-require + include ? Not brewing my own framework: just trying to do the most basic test setup. I do have some lib files I created that my tests want to use.
This doesn't work because it hard codes the base dir into the class file:
base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
You can probably do this by injecting it in a test helper and getting the base location relative to the location of the file the test helper is is, but I would like to ask you what are you actually trying to achive?
normally the tests have access to the lib path and you should be able to just require what you want to use in the tests directly. are you using something like rspec or test::unit? are you brewing your own test framework?
so overall the answer is yes you can do it, but you should not have to do it. can show you how once you clarify what test framework you're using.
Edit
For test unit, this describes almost what you want to do:
https://github.com/test-unit/test-unit/blob/master/doc/text/how-to.md
The run_test.rb helper is placed in test. You see how the base dir is built by using the path of file (as mentioned above) and how the lib dir is placed on the load path.

Rake `directory` does not recursively create folders

I'm trying out Rake today to build my project, coding along with Jim Weirich's presentation. I have a task create_directories:
task :create_directories do
directory('build/subfolder')
end
Now when I execute rake create_directories, it outputs mkdir -p build and the build folder is created, but not the subfolder. Why is the subfolder not created as well?
directory:
private instance method directory(*args, &block) in Rake::DSL in rake\dsl_definition.rb
Documentation:
Declare a set of files tasks to create the given directories on demand.
Example: directory "testdata/doc"
You can use mkdir_p in FileUtils
task :create_directories do
FileUtils.mkdir_p 'build/subfolder'
end
documentation
HTH

How do I Declare a Rake::PackageTask with Prerequisites?

In Rake, I can use the following syntax to declare that task charlie requires tasks alpha and bravo to have been completed first.
task :charlie => [:alpha, :bravo]
This seems to work fine if charlie is a typical Rake task or a file task but I cannot figure out how to do this for a Rake::PackageTask. Here are the relevant parts of the rakefile so far:
require 'rake/packagetask'
file :package_jar => [:compile] do
puts("Packaging library.jar...")
# code omitted for brevity, but this bit works fine
end
Rake::PackageTask.new("library", "1.0") do |pt|
puts("Packaging library distribution artefact...")
pt.need_tar = true
pt.package_files = ["target/library.jar"]
end
task :package => :package_jar
What's happening here is that, for a clean build, it complains that it doesn't "know how to build task 'target/library.jar'". I have to run rake package_jar from the command line manually to get it to work, which is a bit of a nuisance. Is there any way I can make package depend on package_jar?
For what it's worth, I am using Rake version 0.9.2.2 with Ruby 1.8.7 on Linux.
When you run rake package (without previously running anything else to create any needed files) Rake sees that the package task needs the file target/library.jar. Since this file doesn’t yet exist Rake checks to see if it knows how to create it. It doesn’t know of any rules that will create this file, so it fails with the error you see.
Rake does have a task that it thinks will create a file named package_jar, and that task in fact creates the file target/library.jar, but it doesn’t realise this.
The fix is to tell Rake exactly what file is created in the file task. Rake will then automatically find the dependency.
Change
file :package_jar => [:compile] do
to
file 'target/library.jar' => [:compile] do
and then remove the line
task :package => :package_jar
since package_jar no longer exists and Rake will find the dependency on the file by itself.
In general in rake, if you want to add a dependency to a task, you need that task's name. So you need to figure out the name of the actual rake task that Rake::PackageTask is registering.
The easiest way to do this is by running with --trace — it lists each task's name as it is executing.
(I believe the name of a buildr package task is the filename of the package it produces, but I don't remember for certain. Use --trace to find out.)
You can add a dependency to any task by writing,
someTask.enhance [other, tasks]
where other and tasks can be either task names or task objects.
So in your case, you could write:
library = Rake::PackageTask.new(...) do
...
end
task(:package).enhance([library])

Rake delete files task

In msbuild I can delete part of files in certain directory like this
<ItemGroup>
<FilesToDelete Include="$(DeploymentDir)\**\*" exclude="$(DeploymentDir)\**\*.log"/>
</ItemGroup>
<Delete Files="#(FilesToDelete)" />
It will delete all files except *.txt
Is there some rake task I can similar thing?
Ruby has built in classes to make this easy:
Dir['deployment_dir/**/*'].delete_if { |f| f.end_with?('.txt') }
However, for some built in tasks, rake has helpers for this. Adapted from the API docs you can select files like so:
files_to_delete = FileList.new('deployment_dir/**/*') do |fl|
fl.exclude('*.txt')
end
Then you can feed this into your delete task.
Better yet, you can use the built in CLEAN/CLOBBER tasks:
# Your rake file:
require 'rake/clean'
# [] is alias for .new(), and we can chain .exclude
CLEAN = FileList['deployment_dir/**/*'].exclude('*.txt')
Then you can say on the cmd line:
rake clean
Read up the tutorial.
#adzdavies's answer is good, but assigning to CLEAN will produce the following warning since CLEAN is a constant:
warning: already initialized constant CLEAN
You should instead use CLEAN's instance methods. It is a Rake::FileList, so you can add something like this to your Rakefile:
require 'rake/clean'
# this is untested, but you get the idea
CLEAN.include('deployment_dir/**/*').exclude('*.txt')
Then run:
rake clean

Directory layout for pure Ruby project

I'm starting to learn ruby. I'm also a day-to-day C++ dev.
For C++ projects I usually go with following dir structure
/
-/bin <- built binaries
-/build <- build time temporary object (eg. .obj, cmake intermediates)
-/doc <- manuals and/or Doxygen docs
-/src
--/module-1
--/module-2
-- non module specific sources, like main.cpp
- IDE project files (.sln), etc.
What dir layout for Ruby (non-Rails, non-Merb) would you suggest to keep it clean, simple and maintainable?
As of 2011, it is common to use jeweler instead of newgem as the latter is effectively abandoned.
Bundler includes the necessary infrastructure to generate a gem:
$ bundle gem --coc --mit --test=minitest --exe spider
Creating gem 'spider'...
MIT License enabled in config
Code of conduct enabled in config
create spider/Gemfile
create spider/lib/spider.rb
create spider/lib/spider/version.rb
create spider/spider.gemspec
create spider/Rakefile
create spider/README.md
create spider/bin/console
create spider/bin/setup
create spider/.gitignore
create spider/.travis.yml
create spider/test/test_helper.rb
create spider/test/spider_test.rb
create spider/LICENSE.txt
create spider/CODE_OF_CONDUCT.md
create spider/exe/spider
Initializing git repo in /Users/francois/Projects/spider
Gem 'spider' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html
Then, in lib/, you create modules as needed:
lib/
spider/
base.rb
crawler/
base.rb
spider.rb
require "spider/base"
require "crawler/base"
Read the manual page for bundle gem for details on the --coc, --exe and --mit options.
The core structure of a standard Ruby project is basically:
lib/
foo.rb
foo/
share/
foo/
test/
helper.rb
test_foo.rb
HISTORY.md (or CHANGELOG.md)
LICENSE.txt
README.md
foo.gemspec
The share/ is rare and is sometimes called data/ instead. It is for general purpose non-ruby files. Most projects don't need it, but even when they do many times everything is just kept in lib/, though that is probably not best practice.
The test/ directory might be called spec/ if BDD is being used instead of TDD, though you might also see features/ if Cucumber is used, or demo/ if QED is used.
These days foo.gemspec can just be .gemspec --especially if it is not manually maintained.
If your project has command line executables, then add:
bin/
foo
man/
foo.1
foo.1.md or foo.1.ronn
In addition, most Ruby project's have:
Gemfile
Rakefile
The Gemfile is for using Bundler, and the Rakefile is for Rake build tool. But there are other options if you would like to use different tools.
A few other not-so-uncommon files:
VERSION
MANIFEST
The VERSION file just contains the current version number. And the MANIFEST (or Manifest.txt) contains a list of files to be included in the project's package file(s) (e.g. gem package).
What else you might see, but usage is sporadic:
config/
doc/ (or docs/)
script/
log/
pkg/
task/ (or tasks/)
vendor/
web/ (or site/)
Where config/ contains various configuration files; doc/ contains either generated documentation, e.g. RDoc, or sometimes manually maintained documentation; script/ contains shell scripts for use by the project; log/ contains generated project logs, e.g. test coverage reports; pkg/ holds generated package files, e.g. foo-1.0.0.gem; task/ could hold various task files such as foo.rake or foo.watchr; vendor/ contains copies of the other projects, e.g. git submodules; and finally web/ contains the project's website files.
Then some tool specific files that are also relatively common:
.document
.gitignore
.yardopts
.travis.yml
They are fairly self-explanatory.
Finally, I will add that I personally add a .index file and a var/ directory to build that file (search for "Rubyworks Indexer" for more about that) and often have a work directory, something like:
work/
NOTES.md
consider/
reference/
sandbox/
Just sort of a scrapyard for development purposes.
#Dentharg: your "include one to include all sub-parts" is a common pattern. Like anything, it has its advantages (easy to get the things you want) and its disadvantages (the many includes can pollute namespaces and you have no control over them). Your pattern looks like this:
- src/
some_ruby_file.rb:
require 'spider'
Spider.do_something
+ doc/
- lib/
- spider/
spider.rb:
$: << File.expand_path(File.dirname(__FILE__))
module Spider
# anything that needs to be done before including submodules
end
require 'spider/some_helper'
require 'spider/some/other_helper'
...
I might recommend this to allow a little more control:
- src/
some_ruby_file.rb:
require 'spider'
Spider.include_all
Spider.do_something
+ doc/
- lib
- spider/
spider.rb:
$: << File.expand_path(File.dirname(__FILE__))
module Spider
def self.include_all
require 'spider/some_helper'
require 'spider/some/other_helper'
...
end
end
Why not use just the same layout? Normally you won't need build because there's no compilation step, but the rest seems OK to me.
I'm not sure what you mean by a module but if it's just a single class a separate folder wouldn't be necessary and if there's more than one file you normally write a module-1.rb file (at the name level as the module-1 folder) that does nothing more than require everything in module-1/.
Oh, and I would suggest using Rake for the management tasks (instead of make).
I would stick to something similar to what you are familiar with: there's no point being a stranger in your own project directory. :-)
Typical things I always have are lib|src, bin, test.
(I dislike these monster generators: the first thing I want to do with a new project is get some code down, not write a README, docs, etc.!)
So I went with newgem.
I removed all unnecessary RubyForge/gem stuff (hoe, setup, etc.), created git repo, imported project into NetBeans. All took 20 minutes and everything's on green.
That even gave me a basic rake task for spec files.
Thank you all.

Resources