Skip to content

Instantly share code, notes, and snippets.

@SethTisue
Last active December 7, 2015 05:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save SethTisue/3a5a04e5054fc5b75011 to your computer and use it in GitHub Desktop.
Save SethTisue/3a5a04e5054fc5b75011 to your computer and use it in GitHub Desktop.
#!/usr/bin/env sbt -Dsbt.version=0.13.9 -Dsbt.main.class=sbt.ScriptMain --error
// This script uses the Stack Exchange API to retrieve the most recent
// Stack Overflow questions tagged with "netlogo" and print their
// titles and URLs. The output is suitable for posting to the
// netlogo-users group on Yahoo, in messages such as
// http://netlogo-users.18673.x6.nabble.com/NetLogo-Q-A-on-Stack-Overflow-Mar-14-19-tp5004602.html
/***
scalaVersion := "2.11.7"
onLoadMessage := ""
scalacOptions ++= Seq(
"-deprecation", "-unchecked", "-feature", "-Xfatal-warnings")
libraryDependencies ++= Seq(
"net.databinder.dispatch" %% "dispatch-core" % "0.11.2",
"org.json4s" %% "json4s-native" % "3.2.11",
"org.slf4j" % "slf4j-nop" % "1.7.10",
"org.apache.commons" % "commons-lang3" % "3.3.2"
)
*/
import dispatch._, Defaults._
import org.json4s.JsonAST._
import org.json4s.native.JsonParser
import java.util.zip.GZIPInputStream
import org.apache.commons.lang3.StringEscapeUtils.{ unescapeHtml4 => unescape }
case class Question(name: String, url: String)
object Question {
def fromJson(j: JValue): Question = {
val JString(title) = j \ "title"
val JString(link) = j \ "share_link"
Question(unescape(title), link)
}
}
//
// Notes on our use of Dispatch:
//
// - By policy, Stack Exchange always responds with compressed data,
// so it isn't strictly necessary for us to set Accept-Encoding in our
// request, but at http://api.stackexchange.com/docs/compression
// they recommend doing it anyway.
//
// - The support for gzip-encoded responses that existed in Dispatch
// 0.8 seems not to exist in 0.9 and subsequent versions, so we
// bypass Dispatch's json4s integration, and bypass Dispatch's
// Future-based APIs, too and, drop down to dealing with InputStream
// directly. At least, that's the only way forward I was able to
// find. See https://github.com/dispatch/reboot/issues/52
//
// Notes on our use of the Stack Exchange API:
//
// - We want the "share" URL not the regular URL of the questions
// (it's no big deal, but IMO the regular ones are too long),
// but the share_link field isn't included in the default filter.
// So I made a new filter with the [edit] link near the bottom of
// http://api.stackexchange.com/docs/questions, checking the
// share_link box. When you make an edit like this the page shows
// a string you can use to refer to the filter you just made; so
// that's where "!9WgJf_3fM" came from.
//
val host = :/("api.stackexchange.com").secure <:<
Map("Accept-Encoding" -> "gzip")
val base = host / "2.2" / "questions"
def getQuestions(): List[Question] = {
val req = base <<? Map("site" -> "stackoverflow",
"tagged" -> "netlogo",
"sort" -> "creation",
"order" -> "desc",
"filter" -> "!9WgJf_3fM")
// println(req.toRequest.getRawUrl) // useful for debugging
val stream = Http(req OK as.Response(_.getResponseBodyAsStream)).apply
val result =
JsonParser.parse(
new java.io.InputStreamReader(
new GZIPInputStream(stream)))
val JArray(items) = result \ "items"
for (item <- items)
yield Question.fromJson(item)
}
println(
"""|Stack Overflow is a popular Q&A site for getting help with coding
|in all languages, including NetLogo. NetLogo questions are at:
|http://stackoverflow.com/questions/tagged/netlogo
|
|Here are some recent questions and answers.
|
|""".stripMargin)
for(Question(title, link) <- getQuestions()) {
println(title)
println(link)
println()
}
Http.shutdown()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment