Calling functions from different ruby files in rake tasks - ruby-on-rails

I m working in rails.i want to call a function(show) of class "twitter" in searcht1 which is in "lib" within a same directory from rake task.
lib/task/search.rake:
require_relative "lib/Searcht1"
namespace :Searcht do
task :search => :environment do
obj=Twitter.new
obj.show
end
end
and the class inside the "searcht1.rb" is like this
class Twitter
def show
"anylogic"
end
end
but it is not calling that function.and i m not getting any result.
greatly aprreciate any help

I know this question is a bit outdated, but I had the problem in my rails5 app and this is how I keep my tasks clean :)
Please make a subdir searchdir in lib/tasks => lib/tasks/searchdir and put your referenced file searcht1.rb in there.
Now you can reference it in your rake file.
Please keep in mind: it is run from the referenced file.
# in lib/tasks/search.rake
namespace :Searcht do
task :search => :environment do
require_relative "searchdir/searcht1"
end
end
make your code run here:
# in lib/tasks/searchdir/searcht1.rb
class Twitter
def show
"anylogic"
end
end
obj=Twitter.new
obj.show

Related

rake task is not calling. from the controller action in rails.

I have created a rake task in the file called att_rec_for_emp.rake . in this file i have the following task.
task hello(parameter): :environment do
p "{parameter}"
end
how can i call this rake task in the controller action by passing parameters?
i have an action like this
def call_task
emp = Employee.first
Rake::Task[ 'att_rec_for_emp:hello("hello world")' ].invoke
redirect_to :root , :notice => "message fine"
end
and in config/initialisers/rake.rb i have the following statement.
Rake.load_rakefile Rails.root.join( 'lib','tasks','att_rec_for_emp.rake' )
but still the task is not executing. getting the error
Don't know how to build task 'att_rec_for_emp:hello'
I think I got it working. Tweak from here.
Here's what I did:
lib/tasks/att_rec_for_emp.rake
task :hello, [:parameter] => :environment do |t, args|
p "#{args[:parameter]}"
end
app/controllers/your_controller.rb
Rake::Task.clear
YourAppName::Application.load_tasks
class YourController < ApplicationController
def call_task
Rake::Task[:hello].reenable
Rake::Task[:hello].invoke('hi world')
end
end
You could also put those first two lines (above YourController class definition) in an initializer.
Note: Your approach of loading the Rake file in an initializer should work too but my setup is a little different. I have my entire lib directory loaded in application.rb.
config/application.rb
config.autoload_paths += Dir["#{config.root}/lib"]
Hope that helps!
Try adding this line to your controller:
YourAppName::Application.load_tasks
Or, change the directory name from initialisers to initializers.

Command to create a rake task with some folder

rails g task folder1/namespace1 task1
Above command will create the task1.rake inside lib/tasks/task1.rake
But, I need to keep my task1.rake inside lib/tasks/folder1/task1.rake
The rails g task generator does not work this way.
Here are the code for the TaskGenerator class
module Rails
module Generators
class TaskGenerator < NamedBase # :nodoc:
argument :actions, type: :array, default: [], banner: "action action"
def create_task_files
template 'task.rb', File.join('lib/tasks', "#{file_name}.rake")
end
end
end
end
As you see the lib/tasks path is hardcoded and you can not pass in options to alter the path.
I think this might be a great addition to the TaskGenerator class.
The answer to your question is that you have to make the folders manually.

Call methods from a task in Rake files

It is possible to call a method which is in the same rake file as the task? In the code below you can see that I have the method call get_search_url which will be assigned to url.
namespace :populate do
desc "ETC"
task :db => :environment do
Report.where(link: "").each do |word|
url = get_search_url(word.name)
doc = Nokogiri::HTML(open(url))
word.update_columns(link: link)
end
end
def get_search_url(keyword)
return "URL/keyword"
end
end
Yes it is absolutely possible. Just define those methods after the namespace ;)
namespace :populate do
desc "ETC"
task :db => :environment do
Report.where(link: "").each do |word|
url = get_search_url(word.name)
doc = Nokogiri::HTML(open(url))
word.update_columns(link: link)
end
end
end
def get_search_url(keyword)
return "URL/keyword"
end
However if you define the same method in two different rake tasks, they will both be globally loaded when running rake, and one of the method definitions will be redefined / overwritten by the other!
Better practice is to define methods in a separate module and then include that module in your rake file.
See https://kevinjalbert.com/defined_methods-in-rake-tasks-you-re-gonna-have-a-bad-time/ (Solution #3)

Method namespace clashing when running rake tasks in Rails

Using Rails 2.3.10
If my lib/tasks looks like this
lib/tasks
- a.rake
- b.rake
a.rake looks like this:
namespace :a do
desc "Task A"
task(:a=>:environment)do
msg('I AM TASK A')
end
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
b.rake looks like this
namespace :b do
desc "Task B"
task(:b=>:environment)do
msg('I AM TASK B')
end
def msg(msg)
puts "MSG SENT FROM Task B: #{msg}"
end
end
Then when I run task a
rake a RAILS_ENV=sandbox
The output is
"MSG SENT FROM Task B: I AM TASK A"
So the msg() helper method defined in a.rake does not get called. Rather that defined in b.rake gets called. (What's more, if I have a c.rake - then it's msg helper method gets called when I run task a.
Is this method namespace clashing known behavior?
I would have thought the namespacing would have prevented this.
Thanks
What you observe is that methods in rake files namespaces redefine previously defined methods with the same name. The reason for this is that Rake namespaces are very different than Ruby namespaces (classes or modules), in fact they only serve as a namespace for the names of the tasks defined in them, but nothing else. Thus, task a becomes task a:a if placed in the a namespace but other code outside the tasks shares the same global namespace.
This fact, together with the fact that Rake loads all tasks before running the given task, explains why the method gets redefined.
TL;DR: Solutions / hints for the name clashes
You cannot expect that two methods with the same name (or any other code) placed inside separate namespaces but outside tasks will work properly. Nevertheless, here are a couple of hints to solve such situation:
Place the methods inside the tasks. If both msg methods were defined inside the a:a and b:b tasks, then both rake tasks would run properly and would display the expected messages.
If you need to use the code from the rake's namespace in multiple rake tasks, extract the methods / code to a real Ruby namespace, such as two modules, and include the code in the tasks that need it. Consider this rewrite of the sample rakes:
# lib/tasks/a.rake:
module HelperMethodsA
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
namespace :a do
desc "Task A"
task(:a => :environment) do
include HelperMethodsA
msg('I AM TASK A')
end
end
# lib/tasks/b.rake:
module HelperMethodsB
def msg(msg)
puts "MSG SENT FROM Task B: #{msg}"
end
end
namespace :b do
desc "Task B"
task(:b => :environment) do
include HelperMethodsB
msg('I AM TASK B')
end
end
Because the two modules have different names and because they are included in the respective tasks, both rake tasks will again run as expected.
Now, let's prove the above claims with the help of the source code...
Proof that Rake loads all tasks first and why it does so
This one's easy. In the main Rakefile you'll always find the following line:
Rails.application.load_tasks
This method eventually calls the following code from the Rails engine:
def run_tasks_blocks(*) #:nodoc:
super
paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
end
Thus, it searches the lib/tasks directories for all rake files and loads them one after each other, in a sorted order. That's why the b.rake file will be loaded after a.rake and whatever is inside it will potentially redefine the code from a.rake and all previously loaded rake files.
Rake has to load all rake files simply because the rake namespace names do not have to be the same as rake filenames, so the rake filename cannot be inferred from the task / namespace name.
Proof that rake's namespaces don't constitute a real Ruby-like namespace
Upon loading the rake files, the Rake DSL statements get executed, and also the namespace method. The method takes the block of code defined inside it and executes it (using yield) in the context of the Rake.application object which is a singleton object of the Rake::Application class that is shared among all rake tasks. There is no dynamic module / class created for the namespace, it's just executed in the main object context.
# this reuses the shared Rake.application object and executes the namespace code inside it
def namespace(name=nil, &block)
# ...
Rake.application.in_namespace(name, &block)
end
# the namespace block is yielded in the context of Rake.application shared object
def in_namespace(name)
# ...
#scope = Scope.new(name, #scope)
ns = NameSpace.new(self, #scope)
yield(ns)
# ...
end
See the relevant sources here and here.
Rake tasks DO constitute ruby namespaces
With Rake tasks themselves, the situation is different, though. For each task, a separate object of the Rake::Task class (or of a similar class) is created and the task code is run inside this object's context. The creation of the object is done in the intern method in the task manager:
def intern(task_class, task_name)
#tasks[task_name.to_s] ||= task_class.new(task_name, self)
end
A quote form the Rake's author
Finally, all this is confirmed by this interesting discussion on github that deals with a very similar and related issue, and from which we can quote Jim Weirich, the original author of Rake:
Since namespaces don't introduce real method scopes, the only real possibility for a scope is the DSL module.
...
Perhaps, someday, the Rake namespaces will become full class scoped entities with a place to hang lazy let definitions, but we are not there yet.
Use namespace like the following:
namespace :rake_a do
desc "Task A"
task(:a=>:environment)do
msg('I AM TASK A')
end
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
The rake namespace is only intended for rake tasks.
See the Rake documentations:
The NameSpace class will lookup task names in the the scope defined by a namespace command.
You can create a module along with your rake namespace to cover this problem:
module A do
module_functions
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
namespace :a do
desc "Task A"
task(:a=>:environment)do
A.msg('I AM TASK A')
end
end

Scope of rakes in a rails project?

I have a number of parsers I run with rakes in a project I'm working on. When using a method name that already exists in another rake, and because they both use the same environment, I get a conflict.
Is there a way to limit the scope of rake files within their namespace? I thought that was the whole point of the namespace?
Example:
namespace :test do
task :test_task => :environment do
...
end
def test_method(argument)
...
end
end
namespace :other_test do
task :test_task => :environment do
...
end
def test_method(argument, argument2)
...
end
end
In this case, when running rake test:test_task I'll receive an invalid amount of arguments error. On the other hand, if I define the method within the task itself, I have to keep the method at the top of the rake file in order. This gets kind of confusing and ugly.
Is that just a necessary evil?
Thanks!
I see the namespaces for rake tasks as serving the same purpose as directories in a file system: they're about organization rather than encapsulation. That's why database tasks are in db:, Rails tasks in rails:, etc.
Rake namespaces are not classes so you need to ask yourself what class you're adding test_method to when you define it within a Rake namespace. The answer is Object. So, when you hit your second task, Object already has a test_method method that takes one parameter and Ruby rightly complains.
The best solution is to make your Rake tasks very thin (just like controllers) and put any supporting methods (such as test_method) off in some library file somewhere sensible. A Rake task should usually just do a bit of set up and then call a library method to do the real work (i.e. the same general layout as a controller).
Executive summary: put all the real work and heavy lifting somewhere in your library files and make your Rake tasks thin wrappers for your libraries. This should make your problem go away through proper code organization.
module Anonymous
namespace :test do
# brabra
end
end
self.class.send(:remove_const, :Anonymous)
module Anonymous
namespace :another_test do
# brabra
end
end
self.class.send(:remove_const, :Anonymous)
Module.new do end block needs you self:: before any definition. To avoid this, you need to name the module and remove it.
I've figured out a way to namespace the methods in Rake tasks so same-named methods don't collide.
Wrap each outer namespace in a uniquely-named module.
extend Rake::DSL
Change your methods to class methods (with self.).
I've tested this, and it still allows one rake task to invoke or depend on another rake task that is in a different module.
Example:
module Test
extend Rake::DSL
namespace :test do
task :test_task => :environment do
...
end
def self.test_method(argument)
...
end
end
end
module OtherTest
extend Rake::DSL
namespace :other_test do
task :test_task => :environment do
...
end
def self.test_method(argument, argument2)
...
end
end
end

Resources