I am trying to write some code that takes an URL, get the content from this URL, and saves it. The method to get the content from an URL is specific to the website, but then the content extracted uses a common format and can be saved in a database for example.
So I first define a type representing each supported URL:
trait Url(url: String)
case class Soundcloud(url: String) extends Url(url)
case class Youtube(url: String) extends Url(url)
Then a method that given a string return the correct URL type:
def matchUrl(s: String): Option[Url] =
val s_regex = "soundcloud.com".r
var y_regex = "youtube.com".r
s match
case s_regex() => Some(Soundcloud(s))
case y_regex() => Some(Youtube(s))
case _ => None
Then I define a trait for the content extractors:
trait GetContent[T <: Url]:
def get: Unit // should actually return something like `Content`
Here is my method to save an URL's content in the db:
def save[T <: Url](t: T)(using gc: GetContent[T]) =
gc.get
// save into db
Then I provide two implementations of GetContent, one for each URL type:
given GetContent[Soundcloud] with
def get = println("getting some content from soundcloud")
given GetContent[Youtube] with
def get = println("getting some content from youtube")
And finally I can plug it all together:
matchUrl("youtube.com").map(r => save(r))
The compiler complains that
no implicit argument of type GetContent[Url] was found for parameter gc of method save
If I call my method like this it works fine:
save(Soundcloud("http://soundcloud.com/some/content"))
I need to tell the compiler that matchUrl can only return an instance of Soundcloud or Youtube, never a Url.