What does the **
prefix do in this method call using Crystal-lang? This is from the shrine file package. Can you explain how I would use a double splat?
class FileImport::AssetUploader < Shrine
def generate_location(io : IO | UploadedFile, metadata, context, **options) HERE
name = super(io, metadata, **options)
File.join("imports", context[:model].id.to_s, name)
end
end
FileImport::AssetUploader.upload(file, "store", context: { model: YOUR_ORM_MODEL } })
According to the official docs:
A double splat (**) captures named arguments that were not matched by other parameters. The type of the parameter is a NamedTuple.
def foo(x, **other)
# Return the captured named arguments as a NamedTuple
return other
end
foo 1, y: 2, z: 3 # => {y: 2, z: 3}
foo y: 2, x: 1, z: 3 # => {y: 2, z: 3}
The usefulness of the double splat is that it captures all named arguments. For example, you may create a function that handles any number of keyword arguments.
def print_any_tuple_with_any_keys(**named_tuple)
named_tuple.each { |k, v| puts "Options #{k}: #{v}" }
end
print_any_tuple_with_any_keys(api: "localhost")
print_any_tuple_with_any_keys(fruit: "banana", color: "yellow")
print_any_tuple_with_any_keys(hash: "123", power: "2", cypher: "AES")
This will output:
Options api: localhost
Options fruit: banana
Options color: yellow
Options hash: 123
Options power: 2
Options cypher: AES
In the code you provided, all the other named arguments passed to generate_location
that do not match io
, metadata
, or context
will be passed down to the super function that is calling the parent class, in this case, a Shrine
class.
The use for Shrine specifically, is that they provide a generic upload function for different storage engines, any extra arguments may or may not be used down the call tree, and in the case of AWS S3 storage, there may be a metadata argument that adds metadata to the file.