I have a problem creating a Rails plugin, lets call it Mplug. The plugin is pretty much only a rake task, but with a library that the rake task uses.
The problem is to require files. Lets say that this is the rake task:
namespace :mplug do
task :create do
Mplug::Indexer.new
end
end
This will not recognize the constant Mplug. So I thought I needed to require it.
require 'mplug'
namespace :mplug do
task :create do
Mplug::Indexer.new
end
end
But then I get this message.
no such file to load -- mplug
So, ok. Lets try to give the path to the plugin then.
require 'vendor/plugins/mplug/lib/mplug'
namespace :mplug do
task :create do
Mplug::Indexer.new
end
end
This actually works. However, except that I guess that this is a bad way to do it, I now have to require the files in my plugin as if I was in the rails root. For example:
module Mplug
end
require 'mplug/indexer'
Now has to be:
module Mplug
end
require 'vendor/plugins/mplug/lib/mplug/indexer'
Which I do not want to do of course.
Is there any neat way to solve this?
Thanks!
The easiest solution to this problem would be to register the rake task using the Rails::Railtie API. In lib/mplug.rb, define your Railtie:
module Mplug
class Railtie < ::Rails::Railtie
rake_tasks do
load "mplug/rails.rake"
end
end
end
Then, in lib/mplug/rails.rake:
namespace :mplug do
task :create do
Mplug::Indexer.new
end
end
Then, make sure your plugin is defined in your Gemfile. If your plugin is in vendor/plugins, add this line to your Gemfile:
gem "mplug", :path => "vendor/plugins/mplug"
If you push the plugin to a git repo, use :git.
Now, rake mplug:create will be available! If you want it to show up in rake -T, make sure you add a description:
namespace :mplug do
desc "creating an mplug"
task :create do
Mplug::Indexer.new
end
end
One option is to use the FILE constant, and then provide the rest of the path relative to the current file:
require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib', 'mplug')
(if your rake task file is in your plugin_root/tasks...)
Related
I want to add original rake task to my rails app by making gem. But, I couldn't.
Please tell me my mistake.
In my gem file
>lib/gem_test.rb
require "gem_test/version"
require 'gem_test/railtie' if defined?(Rails) && Rails.version >= "3"
module GemTest
#this is dummy method for loading check
def self.hogehoge
"hogehoge"
end
end
>lib/gem_test/railtie.rb
module GemTest
class Railtie < Rails::Railtie
rake_tasks do
load "tasks/gem_test.rake"
end
end
end
>lib/tasks/gem_test.rake
namespace :fugafuga do
desc "fugafuga"
task :piyopiyo do
puts "piyopoyo"
end
end
and, Gemfile in my rails app,gem gem_test, git:mygitrepository. But I don't find fugafuga:piyopiyotask in result of rake -T.
If need more infomation, see my repository
I think you must require rake in your rakefile:
namespace :fugafuga do
require 'rake' <----
desc "fugafuga"
task :piyopiyo do
puts "piyopoyo"
end
end
I tried putting my script in a class that inherited from my model, like so:
class ScriptName < MyModel
But when I ran rake my_script at the command-line, I got this error:
rake aborted!
uninitialized constant MyModel
What am I doing wrong?
Also, should I name my file my_script.rb or my_script.rake?
Just require the file. I do this in one of my rake tasks (which I name my_script.rake)
require "#{Rails.root.to_s}/app/models/my_model.rb"
Here's a full example
# lib/tasks/my_script.rake
require "#{Rails.root.to_s}/app/models/video.rb"
class Vid2 < Video
def self.say_hello
"Hello I am vid2"
end
end
namespace :stuff do
desc "hello"
task :hello => :environment do
puts "saying hello..."
puts Vid2.say_hello
puts "Finished!"
end
end
But a better design is to have the rake task simply call a helper method. The benefits are that it's easier to scan the available rake tasks, easier to debug, and the code the rake task runs becomes very testable. You could add a rake_helper_spec.rb file for example.
# /lib/rake_helper.rb
class Vid2 < Video
def self.say_hello
"Hello I am vid2"
end
end
# lib/tasks/myscript.rake
namespace :stuff do
desc "hello"
task :hello => :environment do
Vid2.say_hello
end
end
All I had to do to get this to work was put my requires above the task specification, and then just declare the :environment flag like so:
task :my_script => :environment do
#some code here
end
Just by doing that, gave me access to all my models. I didn't need to require 'active_record' or even require my model.
Just specified environment and all my models were accessible.
I was also having a problem with Nokogiri, all I did was removed it from the top of my file as a require and added it to my Gemfile.
I want to test a method defined in a rake task.
rake file
#lib/tasks/simple_task.rake
namespace :xyz do
task :simple_task => :environment do
begin
if task_needs_to_run?
puts "Lets run this..."
#some code which I don't wish to test
...
end
end
end
def task_needs_to_run?
# code that needs testing
return 2 > 1
end
end
Now, I want to test this method, task_needs_to_run? in a test file
How do I do this ?
Additional note: I would ideally want test another private method in the rake task as well... But I can worry about that later.
The usual way to do this is to move all actual code into a module and leave the task implementation to be only:
require 'that_new_module'
namespace :xyz do
task :simple_task => :environment do
ThatNewModule.doit!
end
end
If you use environmental variables or command argument, just pass them in:
ThatNewModule.doit!(ENV['SOMETHING'], ARGV[1])
This way you can test and refactor the implementation without touching the rake task at all.
You can just do this:
require 'rake'
load 'simple_task.rake'
task_needs_to_run?
=> true
I tried this myself... defining a method inside a Rake namespace is the same as defining it at the top level.
loading a Rakefile doesn't run any of the tasks... it just defines them. So there is no harm in loading your Rakefile inside a test script, so you can test associated methods.
When working within a project with a rake context (something like this) already defined:
describe 'my_method(my_method_argument)' do
include_context 'rake'
it 'calls my method' do
expect(described_class.send(:my_method, my_method_argument)).to eq(expected_results)
end
end
I have a module and a child class. Where i have all the functionality inside the module. and inside the child class I just call the methods from the module. I want this module to be linked with a rake task under a namespace, and these two files are in the same directory. RAILS_ROOT/lib. How do I do this? I am running Rails 3.0.3.
create a file under lib/tasks/your_namespace.rake , and write the task:
namespace :your_namespace do
desc "An optional description of your task"
task :your_task_name => [:environment] do
# your code stuff
end
end
you should be able to use code from modules. In case, just add this line in rake task:
require 'yourfile'
You need to both require and then include:
require 'your_module'
namespace :your_task do
include YourModule
...
I have a gem that requires a 'Cms' namespace to be present when running.
However, when running rake tasks, nothing works as this Cms namespace isn't present. How do I get my rake tasks to work?
You can either, load your project source into the Rakefile (like Rails would do) or define a dummy module with the name Cms on your project.
# Rakefile
module Cms; end
task :my_task do
# ..
end
If you are on rails, and this gem is a dependency, you just have to make your task dependent of the :environment rails' task.
# some_task.rake
task :my_task => :environment do
# ..
end
Hope this helps.