I'm well aware of Ruby's splats and double-splats in methods
def method(*arg, **kwarg)
:
end
method('foo', bar: 'baz') # arg = ['foo'], kwarg = { bar: 'baz' }
but how would one do that processing with an array which looks like those argument, i.e.,
['foo', { bar: 'baz' }]
I can see a heavy-handed check if the last argument is a hash etc, etc, but this is Ruby, surely there is an elegant and economical one-liner for this.
Motivation:
I'm writing an ActiveJob
which destroys an "ingestion", I'm doing that as a job since it takes a couple of minutes to run (a cascade of DB deletions of assets associated with it). So I have in that job
def perform(ingestion:)
ingestion.destroy!
end
Now, once this job has been enqueued, I'd want the front-end to know that this is the case, so I've added a deleted_at
attribute and a #delete_pending!
method which sets it to now; I want to call that as soon as the job is enqueued, and ActiveJob has callbacks which are a good place to do that:
before_enqueue do |job|
:
end
and in that block, job.arguments
is an array of the form of the arguments passed to the perform
. Hence my question.
For completeness, using the accepted answer (for which, many thanks) my callback now looks like
before_enqueue do |job|
job
.arguments
.clone
.extract_options!
.fetch(:ingestion)
.delete_pending!
end
the #clone
needed since #extract_options!
modifies the caller, and I don't want that.
this is Ruby, surely there is an elegant and economical one-liner for this.
There isn't. This is why Rails makes use of extract_options!
to pull the final hash out of an array of arguments, you probably want to do the same.
In your case:
def foo_method(*args)
opts = args.extract_options!
puts "args: #{args}"
puts "opts: #{opts}"
end
args = ['foo', { bar: 'baz' }]
foo_method(*args)
# args: ["foo"]
# opts: {:bar=>"baz"}