There are some things I keep cutting and pasting without understanding them, and I'd like to change that. One such is the various case statements in the PF passed to serve{} in RestHelper. Take this example from Simply Lift:
case "api" :: "static" :: _ XmlGet _ => <b>Static</b>
My understanding of _ is that it is a wildcard symbol meant to either ignore an unwanted parameter, or when passing a single-use parameter into a function. So:
1. Why are there no commas in that argument list? The first part is obviously a path, but I'd expect there to be a "," after the first "_". There isn't. I'm missing some language construct here, because my impulse is to add commas there somewhere...
2. What are those _s doing? My understanding must be incorrect, as I've never seen a case in which someone names the parameters and uses them in a REST API. So part of me thinks that they're unnecessary ceremony and wonders why they aren't removed, but then another thinks that surely I'm missing some edge case that, if they weren't present, would only mean that 90-95% of what is possible in a REST API is achievable by RestHelper.
You're definitely right that it looks like magic. I myself don't really understand it, but let's see if we can't get to a better understanding by going through the ScalaDocs together.
First, let's look at RestHelper<http://scala-tools.org/mvnsites/liftweb-2.4-M4/net/liftweb/http/rest/...>. Hmm, no serve definition there... Let's look at the actual RestHelper.scalafile. serve is there but it's protected. Oh, ok! Back to the ScalaDocs and chose 'Visibility All' instead of 'Visibility Public' near the top of the page. Moving on...
Add request handlers
serve takes a PartialFunction[Req, () => Box[LiftRepsonse]]. Ok, so we've obviously got A LOT of implicit conversions going on here. If we look for implicit defs we find a lot. First, and simplest, there is boxFuncToResp and boxToResp, explaining how we'll get that second type in the PartialFunctionsignature.
But you're trying to understand "api" :: "static" :: _ XmlGet _, which must eventually become a Req. Let's start with the one bit of code that we know Lift gives us, XmlGet.
The stable identifier for XmlGet. You can use it as an extractor.
Ok, this is interesting. Somehow it can be used as an extractor. Let's look at TestGet, specifically its unapply method since it's apparently used as an extractor.
Test to see if the request is a GET and expecting JSON in the response. The path and the Req instance are extracted.
Great, now this is it! The unapply method takes our mythical Req that the handler PartialFunction is referring to and returns an Option[(List[String], Req)]. Now, I've never written an unapply method that has a Tuple2 in its Option, but apparently if you do then the first element can be referenced before the object and the second after.
So, that means that "api" :: "static" :: _ is our List[String], which represents our path, and _ is again our Req. Why is there an underscore in our List[String]? Because we don't care about the end of our path as long as the beginning is correct. The remainder of the list isn't stored in a value since we don't need to refer to it.
Likewise we don't need to refer to the Req, so there too we don't even bother to store it as as a value. That being said, sometimes you might want to have the Req available in your body when preparing the response: I've used it when supporting conditional requests. This means we might have a case statement like case "api" :: "static" :: extraPathElements XmlGet request { request.ifModifiedSince match { case Full(date) => ... } }.
And that's how "api" :: "static" :: _ XmlGet _ is valid code!
Wow, that was a lot but I think I've explained it correctly and I hope you were able to follow it!
/me was silently waiting for someone to reply to this question.
Diego Sent from my android cell On Oct 7, 2011 4:41 PM, "Peter Robinett" <pe...@bubblefoundry.com> wrote:
> Hi Nolan,
> You're definitely right that it looks like magic. I myself don't really > understand it, but let's see if we can't get to a better understanding by > going through the ScalaDocs together.
> Hmm, no serve definition there... Let's look at the actual
RestHelper.scalafile.
> serve is there but it's protected. Oh, ok! Back to the ScalaDocs and chose > 'Visibility All' instead of 'Visibility Public' near the top of the > page. Moving on...
> Add request handlers > serve takes a PartialFunction[Req, () => Box[LiftRepsonse]]. Ok, so we've > obviously got A LOT of implicit conversions going on here. If we look for > implicit defs we find a lot. First, and simplest, there is boxFuncToResp and > boxToResp, explaining how we'll get that second type in the
PartialFunctionsignature.
> But you're trying to understand "api" :: "static" :: _ XmlGet _, which must > eventually become a Req. Let's start with the one bit of code that we know > Lift gives us, XmlGet.
> The stable identifier for XmlGet. You can use it as an extractor.
> Ok, this is interesting. Somehow it can be used as an extractor. Let's look > at TestGet, specifically its unapply method since it's apparently used as an > extractor.
> Test to see if the request is a GET and expecting JSON in the response. The > path and the Req instance are extracted.
> Great, now this is it! The unapply method takes our mythical Req that the handler > PartialFunction is referring to and returns an Option[(List[String], Req)]. > Now, I've never written an unapply method that has a Tuple2 in its Option, > but apparently if you do then the first element can be referenced before the > object and the second after.
> So, that means that "api" :: "static" :: _ is our List[String], which > represents our path, and _ is again our Req. Why is there an underscore in > our List[String]? Because we don't care about the end of our path as long as > the beginning is correct. The remainder of the list isn't stored in a value > since we don't need to refer to it.
> Likewise we don't need to refer to the Req, so there too we don't even > bother to store it as as a value. That being said, sometimes you might want > to have the Req available in your body when preparing the response: I've > used it when supporting conditional requests. This means we might have a > case statement like case "api" :: "static" :: extraPathElements XmlGet > request { request.ifModifiedSince match { case Full(date) => ... } }.
> And that's how "api" :: "static" :: _ XmlGet _ is valid code!
> Wow, that was a lot but I think I've explained it correctly and I hope you > were able to follow it!
> /me was silently waiting for someone to reply to this question.
> Diego > Sent from my android cell > On Oct 7, 2011 4:41 PM, "Peter Robinett" <pe...@bubblefoundry.com> wrote: > > Hi Nolan,
> > You're definitely right that it looks like magic. I myself don't really > > understand it, but let's see if we can't get to a better understanding by
> > Hmm, no serve definition there... Let's look at the actual > RestHelper.scalafile. > > serve is there but it's protected. Oh, ok! Back to the ScalaDocs and > chose > > 'Visibility All' instead of 'Visibility Public' near the top of the > > page. Moving on...
> > Add request handlers > > serve takes a PartialFunction[Req, () => Box[LiftRepsonse]]. Ok, so we've
> > obviously got A LOT of implicit conversions going on here. If we look for
> > implicit defs we find a lot. First, and simplest, there is boxFuncToResp > and > > boxToResp, explaining how we'll get that second type in the > PartialFunctionsignature.
> > But you're trying to understand "api" :: "static" :: _ XmlGet _, which > must > > eventually become a Req. Let's start with the one bit of code that we > know > > Lift gives us, XmlGet.
> > The stable identifier for XmlGet. You can use it as an extractor.
> > Ok, this is interesting. Somehow it can be used as an extractor. Let's > look > > at TestGet, specifically its unapply method since it's apparently used as > an > > extractor.
> > Test to see if the request is a GET and expecting JSON in the response. > The > > path and the Req instance are extracted.
> > Great, now this is it! The unapply method takes our mythical Req that the > handler > > PartialFunction is referring to and returns an Option[(List[String], > Req)]. > > Now, I've never written an unapply method that has a Tuple2 in its > Option, > > but apparently if you do then the first element can be referenced before > the > > object and the second after.
> > So, that means that "api" :: "static" :: _ is our List[String], which > > represents our path, and _ is again our Req. Why is there an underscore > in > > our List[String]? Because we don't care about the end of our path as long > as > > the beginning is correct. The remainder of the list isn't stored in a > value > > since we don't need to refer to it.
> > Likewise we don't need to refer to the Req, so there too we don't even > > bother to store it as as a value. That being said, sometimes you might > want > > to have the Req available in your body when preparing the response: I've > > used it when supporting conditional requests. This means we might have a > > case statement like case "api" :: "static" :: extraPathElements XmlGet > > request { request.ifModifiedSince match { case Full(date) => ... } }.
> > And that's how "api" :: "static" :: _ XmlGet _ is valid code!
> > Wow, that was a lot but I think I've explained it correctly and I hope > you > > were able to follow it!
Apologies for the delay in responding. I was sufficiently off-grid for most of the weekend and couldn't really give reading this the cycles it deserved.
But thanks so much for this. Just one final question:
What Scala magic is it that doesn't require a "," between Nil and JsonGet? I always want to enter it because I'd assume those are separate arguments in some unapply() extractor or other.
It's possible that you answered that and I'm just not connecting the dots. If so then I apologize.
> What Scala magic is it that doesn't require a "," between Nil and > JsonGet? I always want to enter it because I'd assume those are > separate arguments in some unapply() extractor or other.
Actually Peter mentioned that too:
"Great, now this is it! The unapply method takes our mythical Req that the handler PartialFunction is referring to and returns an Option[(List[String], Req)]. Now, I've never written an unapply method that has a Tuple2 in its Option, but apparently if you do then the first element can be referenced before the object and the second after."
I looked it up because I had for some reason forgotten about it even though I have used the exact same thing with combinator parsers. There it's used with a case class ~ for sequential composition which allows you to match something like a ~ b ~ c when constructing your AST.
It's basically a special case for extractors to allow for infix notation. It applies to constructor and extractor patterns. And it's not even only for binary patterns, x e (y, z) => e(x, y, z) too. That I think would be confusing though :)
Despite having raised it to 15s I'm still seeing my ajax-calls being aborted after 5s. and my LiftRules.ajaxDefaultFailure is not being called.
Any suggestions what this might be?
I'm using 2.4-SNAPSHOT with jQuery-1.6.4
I failed to mention (realized it my self after debugging) that this AJAX-request actually maps to a function in a comet-actor (render()) and it's that function which takes more than 5s to execute.
This code in LiftSession:655-669 is responsible for the 5s. timeout
val ret = toRun.map(_.owner).distinct.flatMap {
w =>
val f = toRun.filter(_.owner == w)
w match {
// if it's going to a CometActor, batch up the commands
case Full(id) if asyncById.contains(id) =>
asyncById.get(id).toList.
flatMap(a => a.!?(5000L, ActionMessageSet(f.map(i => buildFunc(i)), state)) match {
case Full(li: List[_]) => li
case li: List[_] => li
case other => Nil
})
case _ => f.map(i => buildFunc(i).apply())
}
}
I realize now that I should send a message in my render()-method asking some other actor to do the actual computation, instead of making the computation inline. Then the other actor should send my comet-actor a message back with the response.
Anyway: Any chanse this timeout could also be configurable? It would certainly make my life easier if it was configurable with a big fat text describing why you really shouln't mess with that timeout.
Shall I open a ticket and assign it to my self?
--
Andreas Joseph Krogh <andreak@officenet.no> - mob: +47 909 56 963
Senior Software Developer / CTO - OfficeNet AS - http://www.officenet.no
Public key: http://home.officenet.no/~andreak/public_key.asc
Somehow your messages about timeouts got attached to the pinned thread about RestHelper. Forum administrators, is there any way we could move them into another thread for the sake of clarity?
> Somehow your messages about timeouts got attached to the pinned thread > about RestHelper. Forum administrators, is there any way we could move > them into another thread for the sake of clarity?
<andr...@officenet.no> wrote: > On 10/11/2011 08:26 PM, Peter Robinett wrote: >> Hi Andreas,
>> Somehow your messages about timeouts got attached to the pinned thread >> about RestHelper. Forum administrators, is there any way we could move >> them into another thread for the sake of clarity?
> Oh - I certainly didn't do that on purpose:-)
> For some reason my first message has this header: