[med-svn] [r-cran-wikipedir] 01/01: New upstream version 1.5.0

Andreas Tille tille at debian.org
Mon Oct 2 13:05:56 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-wikipedir.

commit b8779dd4437c3e559118cb94a563dbe4e09f5638
Author: Andreas Tille <tille at debian.org>
Date:   Mon Oct 2 15:05:37 2017 +0200

    New upstream version 1.5.0
---
 DESCRIPTION                              |  22 +++
 LICENSE                                  |   2 +
 MD5                                      |  39 ++++
 NAMESPACE                                |  22 +++
 NEWS                                     |  82 ++++++++
 R/WikipediR.R                            |  12 ++
 R/categories.R                           | 159 ++++++++++++++++
 R/content.R                              | 311 +++++++++++++++++++++++++++++++
 R/generic_handlers.R                     |  14 ++
 R/metadata.R                             | 225 ++++++++++++++++++++++
 R/parse.R                                |  87 +++++++++
 R/query.R                                |  79 ++++++++
 R/recent_changes.R                       |  86 +++++++++
 R/user_info.R                            | 184 ++++++++++++++++++
 README.md                                |  41 ++++
 build/vignette.rds                       | Bin 0 -> 194 bytes
 inst/doc/WikipediR.Rmd                   |  17 ++
 inst/doc/WikipediR.html                  | 188 +++++++++++++++++++
 man/WikipediR.Rd                         |  16 ++
 man/categories_in_page.Rd                |  56 ++++++
 man/page_backlinks.Rd                    |  55 ++++++
 man/page_content.Rd                      |  52 ++++++
 man/page_external_links.Rd               |  44 +++++
 man/page_info.Rd                         |  43 +++++
 man/page_links.Rd                        |  50 +++++
 man/pages_in_category.Rd                 |  64 +++++++
 man/query.Rd                             |  26 +++
 man/random_page.Rd                       |  53 ++++++
 man/recent_changes.Rd                    |  61 ++++++
 man/revision_content.Rd                  |  56 ++++++
 man/revision_diff.Rd                     |  71 +++++++
 man/user_contributions.Rd                |  65 +++++++
 man/user_information.Rd                  |  77 ++++++++
 tests/testthat.R                         |   3 +
 tests/testthat/test_category_retrieval.R |  22 +++
 tests/testthat/test_content_retrieval.R  |  24 +++
 tests/testthat/test_metadata_retrieval.R |  33 ++++
 tests/testthat/test_recent_changes.R     |  17 ++
 vignettes/WikipediR.Rmd                  |  17 ++
 vignettes/WikipediR.md                   |  17 ++
 40 files changed, 2492 insertions(+)

diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..280e8e0
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,22 @@
+Package: WikipediR
+Type: Package
+Title: A MediaWiki API Wrapper
+Version: 1.5.0
+Date: 2017-02-04
+Author: Oliver Keyes [aut, cre], Brock Tilbert [ctb]
+Maintainer: Oliver Keyes <ironholds at gmail.com>
+Description: A wrapper for the MediaWiki API, aimed particularly at the
+    Wikimedia 'production' wikis, such as Wikipedia. It can be used to retrieve
+    page text, information about users or the history of pages, and elements of
+    the category tree.
+License: MIT + file LICENSE
+Imports: httr, jsonlite
+Suggests: testthat, knitr, WikidataR, pageviews
+BugReports: https://github.com/Ironholds/WikipediR/issues
+URL: https://github.com/Ironholds/WikipediR/
+VignetteBuilder: knitr
+RoxygenNote: 5.0.1
+NeedsCompilation: no
+Packaged: 2017-02-05 07:31:29 UTC; ironholds
+Repository: CRAN
+Date/Publication: 2017-02-05 08:44:55
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ebbb227
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2014
+COPYRIGHT HOLDER: Oliver Keyes
\ No newline at end of file
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..f932a72
--- /dev/null
+++ b/MD5
@@ -0,0 +1,39 @@
+c56517e17ba465a35c877d9dd2ca8925 *DESCRIPTION
+1d9678dbfe1732b5d2c521e07b2ceef0 *LICENSE
+59bca6c38b4dd174abd35265754dbaac *NAMESPACE
+4f85f4bc8d56477833d6e5518a0b93a5 *NEWS
+1e54e3f6f8361705f7dce17364f97430 *R/WikipediR.R
+47db868791ef84a18677104f83bbc85c *R/categories.R
+a271af8de3a815364ce54a3406215d86 *R/content.R
+3310e6008ce3c185829aa4fe5087baf2 *R/generic_handlers.R
+575f42d955707d9d73623271560c338b *R/metadata.R
+1ced59f29a930516f32227dd9fda43b0 *R/parse.R
+7d6b7516a10fa66ee830d20dcde26594 *R/query.R
+9e782c267ce639c3c333b567b93bf8d8 *R/recent_changes.R
+d342b68b573c60f806f711576831957e *R/user_info.R
+334d2da7c2fa09cf27c8f340b302b674 *README.md
+ae2a42d2f12c8dd03d8604f105d27873 *build/vignette.rds
+e5214179299ab80dd7b16e98346cd8f1 *inst/doc/WikipediR.Rmd
+8bd185cd6e77ed314d9c518ca3418dcc *inst/doc/WikipediR.html
+ef85646b107d30a725255d273f8dd1ac *man/WikipediR.Rd
+77a3943e956138edd5fc167d7a68a27f *man/categories_in_page.Rd
+de6546fc255dc7b2df0138e755256ebf *man/page_backlinks.Rd
+9cd25ed76e3afc3abba6de917b1bde80 *man/page_content.Rd
+19e2a4b9edc403757b86265e16fe0705 *man/page_external_links.Rd
+008bbdec408d2202de5820b89d5cd28c *man/page_info.Rd
+8bd343751aba855712c2c239dbb0281e *man/page_links.Rd
+c238bef9d7bcf7a52e3ac95260da290a *man/pages_in_category.Rd
+5a8b7527569c67d2ea9ecbbdb8309712 *man/query.Rd
+55fe37aa6df898eafe5d69bc6d348932 *man/random_page.Rd
+59b9848c8f6f70dee162cd7f798b7541 *man/recent_changes.Rd
+3513ac40e8b4fa06720188594bc102d9 *man/revision_content.Rd
+e29eb17cfc802db6df5d3e91b6b7d675 *man/revision_diff.Rd
+363ead1f5a08458593fc2703a02eda29 *man/user_contributions.Rd
+f0848ab5c0c2c7c8efafdfdcbcdcaf70 *man/user_information.Rd
+0258bf928f7abd1db4cf997cbff76363 *tests/testthat.R
+53ffc6bc1e7aa2dbd9dc2869d790eda5 *tests/testthat/test_category_retrieval.R
+b7411ca65708a2470392b156b6169527 *tests/testthat/test_content_retrieval.R
+0831734e1311415c947a56ca10a2b162 *tests/testthat/test_metadata_retrieval.R
+8554bd55596b5319e21bab345fbe6fb3 *tests/testthat/test_recent_changes.R
+e5214179299ab80dd7b16e98346cd8f1 *vignettes/WikipediR.Rmd
+72a6f591435d5e3a53a06336429abfca *vignettes/WikipediR.md
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..eba20ae
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,22 @@
+# Generated by roxygen2: do not edit by hand
+
+export(categories_in_page)
+export(page_backlinks)
+export(page_content)
+export(page_external_links)
+export(page_info)
+export(page_links)
+export(pages_in_category)
+export(query)
+export(random_page)
+export(recent_changes)
+export(revision_content)
+export(revision_diff)
+export(user_contributions)
+export(user_information)
+importFrom(httr,GET)
+importFrom(httr,content)
+importFrom(httr,stop_for_status)
+importFrom(httr,user_agent)
+importFrom(jsonlite,fromJSON)
+importFrom(utils,URLencode)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..6428e0e
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,82 @@
+Version 1.5.0
+------------------------------------------------------------------------------
+
+BUG FIXES
+* https is now the default for requests (Thanks to Hiroaki Yutani)
+* UTF-8 page names and similar are properly handled (Thanks to Hiroaki Yutani)
+
+Version 1.4.0
+------------------------------------------------------------------------------
+
+NEW FEATURES
+* `random_page` now allows you to return more than one page.
+* `page_backlinks` does as well; thanks to Brock Tibert for the code.
+
+DOCUMENTATION
+* Vignette tweaks made
+* Package-level documentation improved.
+
+DEVELOPMENT
+* "Depends" switched out for "Imports" to avoid annoying loading messages.
+
+Version 1.3.0
+------------------------------------------------------------------------------
+
+BUG FIXES
+
+* Various miscellaneous internal improvements.
+* `limit` introduced as an argument to pages_in_category - thanks to Ben Marwick for finding the bug.
+* `limit` introduced as an argument to page_links - thanks to Hui Li of the Universität Heidelberg for the initial report.
+
+Version 1.2.0
+------------------------------------------------------------------------------
+
+NEW FEATURES
+*Random pages can now be retrieved with random_page
+*pageID based querying is available
+*Custom user
+
+DEVELOPMENT
+*Doc tweaks and some simplification of argument parsing around page_content and random_page
+*Additional unit tests
+*query() marked as exportable to allow simple third-party plugins into WikipediR
+
+Version 1.0.1
+------------------------------------------------------------------------------
+* Roxygenised documentation, some R CHECK errors fixed.
+* Test suite added for error handlers.
+
+Version 1.0.0
+------------------------------------------------------------------------------
+* First release version
+* Introduction of wiki_usercontribs, which retrieves recent contributions for a specified username
+* Bugfixes to error handling routines
+* Bugfix to problems around wiki_con, where species or commons users were unable to take advantage of CurlOpts.
+
+Version 0.7.0
+------------------------------------------------------------------------------
+
+* wiki_page now returns the DOM of the relevant page, not the wikimarkup, in line with a suggestion from Scott Chamberlain. This should be parsable by the HTML tree parser in the XML package.
+
+Version 0.6.3
+------------------------------------------------------------------------------
+
+* Standardisation and cleanup of error handlers, and the introduction of a single central LimitHandler.
+
+Version 0.6.2
+------------------------------------------------------------------------------
+
+* Bug fix from Scott Chamberlain around wiki_page, switching the content type over to x-wikitext.
+* Introduction of w_timeout as a field in the connector object; will be extended to other CURL options in time.
+
+Version 0.6.1
+------------------------------------------------------------------------------
+
+* Support for Commons and Wikispecies
+* Addition of wiki_recentchanges(), which allows a useR to query the recentchanges feed.
+
+Version 0.5.1
+------------------------------------------------------------------------------
+
+* Format for wiki_revision changed from the (unacceptable-to-API) text/css to x/wikitext.
+* Error handling improved to pass the full error explanation through to the user, in the case of API errors.
\ No newline at end of file
diff --git a/R/WikipediR.R b/R/WikipediR.R
new file mode 100644
index 0000000..f259a7d
--- /dev/null
+++ b/R/WikipediR.R
@@ -0,0 +1,12 @@
+#' @title A client library for MediaWiki's API
+#' @name WikipediR
+#' @description This package provides functions for accessing the MediaWiki API, either for
+#' Wikimedia projects or any other MediaWiki instance. For more information, see the
+#' \href{https://CRAN.R-project.org/package=WikipediR/vignettes/WikipediR.html}{vignette}.
+#' 
+#' @seealso The \href{https://CRAN.R-project.org/package=WikipediR/vignettes/WikipediR.html}{package vignette}.
+#' @docType package
+#' @importFrom httr GET user_agent stop_for_status
+#' @importFrom utils URLencode
+#' @aliases WikipediR WikipediR-package
+NULL
\ No newline at end of file
diff --git a/R/categories.R b/R/categories.R
new file mode 100644
index 0000000..cc38255
--- /dev/null
+++ b/R/categories.R
@@ -0,0 +1,159 @@
+#'@title Retrieves categories associated with a page.
+#'
+#'@description
+#'Retrieves categories associated with a page (or list of pages) on a MediaWiki instance
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param pages A vector of page titles, with or without spaces, that you want to retrieve
+#'categories for.
+#'
+#'@param properties The properties you want to retrieve about the categories.
+#'Options are "sortkey" (the key that sorts the way the page is stored in each category),
+#'"timestamp" (when the category was added to that page) and "hidden" (tags those categories
+#'in the returned list that are 'hidden' from readers).
+#'
+#'@param limit The maximum number of categories you want to retrieve for each page. Set
+#'to 50 by default.
+#'
+#'@param show_hidden Whether or not to include 'hidden' categories in the categories
+#'that are retrieved - these are usually associated with the maintenance of Wikipedia
+#'and its internal processes. Set to FALSE by default.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@seealso \code{\link{pages_in_category}} for pages in a specified category.
+#'
+#'@examples
+#'
+#'#Retrieve the categories for the "New Age" article on en.wiki
+#'cats <- categories_in_page("en", "wikipedia", pages = "New Age")
+#'
+#'#Retrieve the categories for the "New Age" article on rationalwiki.
+#'rw_cats <- categories_in_page(domain = "rationalwiki.org", pages = "New Age")
+#'@export
+categories_in_page <- function(language = NULL, project = NULL, domain = NULL,
+                               pages, properties = c("sortkey","timestamp","hidden"),
+                               limit = 50, show_hidden = FALSE, clean_response = FALSE,
+                               ...){
+  
+  #Check, construct URL
+  properties <- match.arg(properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  pages <- handle_limits(pages, 50)
+  if(show_hidden){
+    show_hidden <- "hidden"
+  } else {
+    show_hidden <- "!hidden"
+  }
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action = "query",
+    prop   = "categories",
+    clprop = properties,
+    clshow = show_hidden,
+    cllimit= limit,
+    titles = pages
+  )
+  
+  #Retrieve, check, return
+  content <- query(url, "pagecats", clean_response, query_param = query_param, ...)
+  page_names <- names(unlist(content))
+  missing_pages <- sum(grepl(x = page_names, pattern = "missing"))
+  if(missing_pages){
+    warning("This request contained ",missing_pages," invalid page title(s)", call. = FALSE)
+  }
+  return(content)
+}
+
+#'@title 
+#'Retrieves a list of category members.
+#'
+#'@description
+#'wiki_catpages retrieves a list of pages, subcategories, files or all of the above
+#'in a specified category (or series of specified categories)
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param categories The names of the categories you want to gather information for.
+#'
+#'@param properties The properties you want to gather for each member of the category. 
+#'Options are "title" (the name of the member, including namespace), 
+#'"id" (the unique numeric identifier of the member), "sortkey" 
+#'(the hexadecimal key used to sort that member within the category), 
+#'"sortkeyprefix" (the human-readable sort key), "type"
+#'(whether the member is a page, a subcategory or a file) and 
+#'"timestamp" (when the member was added to the category)
+#'
+#'@param type The type of member you're interested in returning;
+#'options are any permutation of "page" (pages), "subcat" (subcategories) and "file" (files).
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param limit The maximum number of members to retrieve for each category. Set
+#'to 50 by default.
+#'
+#'@param ... further arguments to pass to httr's GET().
+#'
+#'@section warnings:
+#'Because of the way MediaWiki stores this data, both "the category you asked for doesn't exist"
+#'and "the category you asked for exists, but has no members" return in the same way.
+#'
+#'@seealso \code{\link{categories_in_page}} for finding categories that a specified page is a member of.
+#'
+#'@examples
+#'
+#'#Retrieve the pages in the "New Age" category on en.wiki
+#'cats <- pages_in_category("en", "wikipedia", categories = "New Age")
+#'
+#'#Retrieve the pages in the "New Age" category on rationalwiki.
+#'rw_cats <- pages_in_category(domain = "rationalwiki.org", categories = "New Age")
+#'@export
+pages_in_category <- function(language = NULL, project = NULL, domain = NULL, categories,
+                              properties = c("title","ids","sortkey","sortkeyprefix","type","timestamp"),
+                              type = c("page","subcat","file"), clean_response = FALSE, limit = 50,
+                              ...){
+  
+  #Format and check
+  categories <- gsub(x = categories, pattern = "^", replacement = "Category:")
+  categories <- handle_limits(categories, 50)
+  properties <- match.arg(properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  type <- match.arg(type, several.ok = TRUE)
+  type <- paste(type, collapse = "|")
+  
+  #Construct URL
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action  = "query",
+    list    = "categorymembers",
+    cmtitle = categories,
+    cmprop  = properties,
+    cmtype  = type,
+    cmlimit = limit
+  )
+  
+  #Query and return
+  content <- query(url, "catpages", clean_response, query_param = query_param, ...)
+  return(content)
+}
\ No newline at end of file
diff --git a/R/content.R b/R/content.R
new file mode 100644
index 0000000..df745d9
--- /dev/null
+++ b/R/content.R
@@ -0,0 +1,311 @@
+#Checks for invalid revision IDs, warns if they're found.
+invalid_revs <- function(parsed_response){
+  if(!is.null(parsed_response$query$badrevids)){
+    warning("This request contained ",length(parsed_response$query$badrevids)," invalid revisionID(s)", call. = FALSE)
+  }
+  return(invisible())
+}
+
+#'@title Retrieve the page content of a random MediaWiki page
+#'
+#'@description
+#'wiki_page retrieves the DOM of a particular MediaWiki page,
+#'as a HTML blob inside a JSON object.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param  namespaces The namespaces to consider pages from. By default, pages from any namespace are
+#'considered; alternately, a numeric vector of accepted namespaces (which are described
+#'\href{https://www.mediawiki.org/wiki/Manual:Namespace#Built-in_namespaces}{here}) can be
+#'provided, and only pages within those namespaces will be considered.
+#'
+#'@param as_wikitext whether to retrieve the wikimarkup (TRUE) or the HTML (FALSE).
+#'Set to FALSE by default.
+#'
+#'@param limit the number of pages to return. 1 by default.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@seealso \code{\link{page_content}} for retrieving the content of a specific page,
+#'\code{\link{revision_diff}} for retrieving 'diffs' between revisions,
+#'\code{\link{revision_content}} for retrieving the text of specified revisions.
+#'
+#'@examples
+#'#A page from Wikipedia
+#'wp_content <- random_page("en","wikipedia")
+#'
+#'#A page from the mainspace on Wikipedia
+#'wp_article_content <- random_page("en","wikipedia", namespaces = 0)
+#'@export
+random_page <- function(language = NULL, project = NULL, domain = NULL,
+                        namespaces = NULL, as_wikitext = FALSE, limit = 1,
+                        clean_response = FALSE, ...){
+  
+  
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action  = "query",
+    list    = "random",
+    rnlimit = limit
+  )
+  
+  if(!is.null(namespaces)){
+    query_param$rnnamespace <- paste(namespaces, collapse = "|")
+  }
+  pages <- query(url, NULL, FALSE, query_param = query_param)$query$random
+  
+  return(lapply(pages, function(page, language, project, domain, page_name, as_wikitext,
+                         clean_response, ...){
+    content <- page_content(language = language, project = project, domain = domain,
+                            page_name = page$title, as_wikitext = as_wikitext,
+                            clean_response = clean_response, ...)
+    content$parse$text <- content$parse$text[[1]]
+    return(content$parse)
+  }, language = language, project = project, domain = domain, as_wikitext = as_wikitext,
+  clean_response = clean_response, ...))
+}
+
+#'@title Retrieves MediaWiki page content
+#'
+#'@description
+#'wiki_page retrieves the DOM of a particular MediaWiki page,
+#'as a HTML blob inside a JSON object.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param page_name The title of the page you want to retrieve
+#'
+#'@param page_id the pageID of the page you want to retrieve. Set to NULL by default,
+#'and an alternative to page_name; if both are provided, page_id will be used.
+#'
+#'@param as_wikitext whether to retrieve the wikimarkup (TRUE) or the HTML (FALSE).
+#'Set to FALSE by default.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@seealso \code{\link{revision_diff}} for retrieving 'diffs' between revisions,
+#'\code{\link{revision_content}} for retrieving the text of specified revisions.
+#'
+#'@examples
+#'#Content from a Wikimedia project
+#'wp_content <- page_content("en","wikipedia", page_name = "Aaron Halfaker")
+#'
+#'#Content by ID
+#'wp_content <- page_content("en", "wikipedia", page_id = 12)
+#'
+#'#Content from a non-Wikimedia project
+#'rw_content <- page_content(domain = "rationalwiki.org", page_name = "New Age")
+#'@export
+page_content <- function(language = NULL, project = NULL, domain = NULL,
+                         page_name, page_id = NULL, as_wikitext = FALSE, clean_response = FALSE, ...){
+  
+  #Format and construct URL.
+  if(as_wikitext){
+    properties <- "wikitext|revid"
+  } else {
+    properties <- "text|revid"
+  }
+  properties <- paste(properties, collapse = "|")
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action = "parse",
+    prop   = properties
+  )
+  if(!is.null(page_id)){
+    query_param$page_id <- handle_limits(page_id, 1)
+  } else {
+    query_param$page <- handle_limits(page_name, 1)
+  }
+  
+  #Run  
+  content <- query(url, "pcontent", clean_response, query_param = query_param, ...)
+  
+  #Return
+  return(content)
+}
+
+#'@title Retrieves MediaWiki revisions
+#'
+#'@description
+#'Retrieves the content of a provided list of revisions from whichever MediaWiki instance you're
+#'querying. Returns as wikimarkup.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param revisions The revision IDs of each desired revision.
+#'
+#'@param properties Properties you're trying to retrieve about that revision, should you want to;
+#'options include "ids" (the revision ID of the revision...which is pointless),
+#'"flags" (whether the revision was 'minor' or not), "timestamp" (the timestamp of the revision),
+#'"user" (the username of the person who made that revision), "userid"
+#'(the userID of the person who made the revision),
+#'"size" (the size, in uncompressed bytes, of the revision), "sha1" (the SHA-1 hash of
+#'the revision text), "contentmodel" (the content model of the page, usually "wikitext"),
+#'"comment" (the revision summary associated with the revision), "parsedcomment" (the same,
+#'but parsed, generating HTML from any wikitext in that comment), "tags" (any tags associated
+#'with the revision) and "flagged" (the revision's status under Flagged Revisions).
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@seealso
+#'\code{\link{revision_diff}} for diffs between revisions,
+#'and \code{\link{page_content}} for the content a specific page currently has.
+#'
+#'@examples
+#'
+#'#Revision content from a Wikimedia project
+#'wp_content <- revision_content("en","wikipedia", revisions = 552373187)
+#'
+#'#Revision content from a non-Wikimedia project
+#'rw_content <- revision_content(domain = "rationalwiki.org", revisions = 88616)
+#'@export
+revision_content <- function(language = NULL, project = NULL, domain = NULL,
+                             revisions, properties = c("content","ids","flags","timestamp",
+                                                       "user","userid","size",
+                                                       "sha1","contentmodel","comment",
+                                                       "parsedcomment","tags"),
+                             clean_response = FALSE, ...){
+  
+  #Format, construct URL.
+  properties <- match.arg(arg = properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  revisions <- handle_limits(revisions, 50)
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    rvcontentformat = "text/x-wiki",
+    action = "query",
+    prop   = "revisions",
+    rvprop = properties,
+    revids = revisions
+  )
+  
+  #Run
+  content <- query(url, "rcontent", clean_response, query_param = query_param, ...)
+  
+  #Check for invalid RevIDs
+  invalid_revs(content)
+  
+  #Return
+  return(content)
+}
+
+#'@title Generates a "diff" between a pair of revisions
+#'
+#'@description
+#'revision_diff generates a diff between two revisions in a MediaWiki page.
+#'This is provided as an XML-parsable blob inside the returned JSON object.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param revisions The revision IDs of each "start" revision.
+#'
+#'@param properties Properties you're trying to retrieve about that revision, should you want to;
+#'options include "ids" (the revision ID of the revision...which is pointless),
+#'"flags" (whether the revision was 'minor' or not), "timestamp","user" (the username of the person
+#'who made that revision), "userid" (the userID of the person who made the revision),
+#'"size" (the size, in uncompressed bytes, of the revision), "sha1" (the SHA-1 hash of
+#'the revision text), "contentmodel" (the content model of the page, usually "wikitext"),
+#'"comment" (the revision summary associated with the revision), "parsedcomment" (the same,
+#'but parsed, generating HTML from any wikitext in that comment), "tags" (any tags associated
+#'with the revision) and "flagged" (the revision's status under Flagged Revisions).
+#'
+#'@param direction The direction you want the diff to go in from the revisionID you have provided.
+#'Options are "prev" (compare to the previous revision on that page), "next" (compare to the next
+#'revision on that page) and "cur" (compare to the current, extant version of the page).
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@section Warnings:
+#'
+#'MediaWiki's API is deliberately designed to restrict users' ability to make computing-intense requests
+#'- such as diff computation. As a result, the API only allows requests for one uncached diff in
+#'each request. If you ask for multiple diffs, some uncached and some cached, you will be provided
+#' with the cached diffs, one of the uncached diffs, and a warning.
+#' 
+#'If you're going to be asking for a lot of diffs, some of which may not be cached, it may be more
+#'sensible to retrieve the revisions themselves using \code{\link{revision_content}} and compute the
+#'diffs yourself.
+#'
+#'@seealso \code{\link{page_content}} for retrieving the current content of a specific page, and
+#'\code{\link{revision_content}} for retrieving the text of specific revisions.
+#'
+#'@examples
+#'
+#'#Wikimedia diff
+#'wp_diff <- revision_diff("en","wikipedia", revisions = 552373187, direction = "next")
+#'
+#'#Non-Wikimedia diff
+#'rw_diff <- revision_diff(domain = "rationalwiki.org", revisions = 88616, direction = "next")
+#'@export
+revision_diff <- function(language = NULL, project = NULL, domain = NULL,
+                          revisions, properties = c("ids","flags","timestamp","user","userid","size",
+                                                    "sha1","contentmodel","comment","parsedcomment",
+                                                    "tags","flagged"),
+                          direction, clean_response = FALSE, ...){
+  
+  #Check and construct URL
+  direction <- match.arg(direction, c("prev","next","cur"))
+  properties <- match.arg(properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  revisions <- handle_limits(revisions, 50)
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action   = "query",
+    prop     = "revisions",
+    rvprop   = properties, 
+    rvdiffto = direction,
+    rvcontentformat = "text/css",
+    revids   = revisions
+  )
+  
+  #Retrieve the content, check for invalid RevIDs and uncached diffs,
+  #return.
+  content <- query(url, "rdiff", clean_response, query_param = query_param, ...)
+  invalid_revs(content)
+  if(sum(grepl(x = names(unlist(content)), pattern = "diff.notcached"))){
+    warning("This request contained uncached diffs; these will not be returned", call. = FALSE)
+  }
+  return(content)
+}
\ No newline at end of file
diff --git a/R/generic_handlers.R b/R/generic_handlers.R
new file mode 100644
index 0000000..157860e
--- /dev/null
+++ b/R/generic_handlers.R
@@ -0,0 +1,14 @@
+#Handles limitations on the number of unique values you can pass in.
+#Takes an input set of params and a limit, and warns of the length of one
+#is greather than the other, limiting the set if so, and either way,
+#collapsing for incorporation into the API query.
+handle_limits <- function(parameters, limit){
+  if(length(parameters) > limit){
+    warning("This option accepts ", limit, " values; you have provided ", length(parameters),
+            ". Only the first ", limit, " will be returned.", call. = FALSE)
+    parameters <- paste(parameters[1:limit], collapse = "|")
+  } else {
+    parameters <- paste(parameters, collapse = "|")
+  }
+  return(parameters)
+}
\ No newline at end of file
diff --git a/R/metadata.R b/R/metadata.R
new file mode 100644
index 0000000..6981004
--- /dev/null
+++ b/R/metadata.R
@@ -0,0 +1,225 @@
+#'@title Retrieve a page's backlinks
+#'
+#'@description
+#'page_backlinks, when provided with a page title, retrieves backlinks to that
+#'page. Output can be filtered to specific namespaces.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param page the title of the page you want the backlinks of.
+#'
+#'@param limit the number of backlinks to return. Set to 50 (the maximum) by default.
+#'
+#'@param direction the direction to order the backlinks in, by linking page ID: "ascending"
+#'or "descending". Set to "ascending" by default.
+#'
+#'@param namespaces The namespaces to filter to. By default, backlinks from any namespace
+#'are retrieved: alternately, a numeric vector of accepted namespaces (which are described
+#'\href{https://www.mediawiki.org/wiki/Manual:Namespace#Built-in_namespaces}{here}) can be
+#'provided, and only backlinks from pages within those namespaces will be returned.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@section Warnings: as with \code{\link{pages_in_category}}, if the page
+#'you are linking to does not exist, an empty list will be returned, without
+#'any indication of an error.
+#'
+#'@examples
+#'#Backlink
+#'all_bls <- page_backlinks("en","wikipedia", page = "Aaron Halfaker")
+#'
+#'#Namespace-specific backlinks
+#'mainspace_bls <- page_backlinks("en","wikipedia", page = "Aaron Halfaker", namespaces = 0)
+#'@export
+page_backlinks <- function(language = NULL, project = NULL, domain = NULL,
+                           page, limit = 50, direction = "ascending", namespaces = NULL,
+                           clean_response = FALSE, ...){
+  
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action  = "query",
+    list    = "backlinks",
+    bltitle = page,
+    bldir   = direction,
+    bllimit = limit
+  )
+  
+  if(!is.null(namespaces)){
+    query_param$blnamespace <- paste(namespaces, collapse = "|")
+  }
+  content <- query(url, "blink", clean_response, query_param = query_param, ...)
+  return(content)
+}
+
+#'@title Retrieve a page's links
+#'
+#'@description
+#'page_links, when provided with a page title, retrieves internal wikilinks from the
+#'current revision of that page.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param page the title of the page you want the links of.
+#'
+#'@param limit the number of links to retrieve. 50 by default; a maximum of 500 is set server-side.
+#'
+#'@param direction the direction to order the links in, by destination page ID: "ascending"
+#'or "descending". Set to "ascending" by default.
+#'
+#'@param namespaces The namespaces to filter to. By default, links to any namespace
+#'are retrieved: alternately, a numeric vector of accepted namespaces (which are described
+#'\href{https://www.mediawiki.org/wiki/Manual:Namespace#Built-in_namespaces}{here}) can be
+#'provided, and only backlinks from pages within those namespaces will be returned.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@examples
+#'#Links
+#'links <- page_links("en","wikipedia", page = "Aaron Halfaker")
+#'
+#'#Namespace-specific links
+#'mainspace_links <- page_links("en","wikipedia", page = "Aaron Halfaker", namespaces = 0)
+#'@export
+page_links <- function(language = NULL, project = NULL, domain = NULL,
+                       page, limit = 50, direction = "ascending", namespaces = NULL,
+                       clean_response = FALSE, ...){
+  
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action  = "query",
+    prop    = "links",
+    titles  = page,
+    pldir   = direction,
+    pllimit = limit
+  )
+  
+  if(!is.null(namespaces)){
+    query_param$plnamespace <- paste(namespaces, collapse = "|")
+  }
+  content <- query(url, "plink", clean_response, query_param = query_param, ...)
+  return(content)  
+}
+
+#'@title Retrieve a page's links
+#'
+#'@description
+#'page_external_links, when provided with a page title, retrieves external wikilinks from the
+#'current revision of that page.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param page the title of the page you want the links of.
+#'
+#'@param protocol limit links to those with certain link protocols. Options are listed
+#'in Special:ApiSandbox's
+#'\href{https://en.wikipedia.org/wiki/Special:ApiSandbox#action=query&prop=extlinks}{elprotocol field}.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@examples
+#'#Links
+#'external_links <- page_external_links("en","wikipedia", page = "Aaron Halfaker")
+#'
+#'#Protocol-specific links
+#'external_http_links <- page_external_links("en","wikipedia",
+#'                                           page = "Aaron Halfaker", protocol = "http")
+#'@export
+page_external_links <- function(language = NULL, project = NULL, domain = NULL,
+                                page, protocol = NULL, clean_response = FALSE,
+                                ...){
+  
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action = "query",
+    prop   = "extlinks",
+    titles = page
+  )
+  if(!is.null(protocol)){
+    query_param$elprotocol <- protocol
+  }
+  content <- query(url, "elink", clean_response, query_param  = query_param, ...)
+  return(content)
+}
+
+#'@title Retrieve information about a particular page
+#'
+#'@description
+#'page_info, when provided with a page title, retrieves metadata about that page.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param page the title of the page you want the metadata of.
+#'
+#'@param properties the properties you'd like to retrieve. Some properties (the pageID, namespace,
+#'title, language, length and most recent revision ID, for example) are retrieved by default,
+#'whatever is passed to \code{properties}: properties that can be explicitly retrieved include
+#'the page's protection level ("protection"), the ID of the associated talk page, if applicable
+#'("talkid"), the full, canonical URL ("url"), and the displayed page title ("displaytitle").
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@examples
+#'#Metadata
+#'page_metadata <- page_info("en","wikipedia", page = "Aaron Halfaker")
+#'
+#'@export
+page_info <- function(language = NULL, project = NULL, domain = NULL, 
+                      page, properties = c("protection","talkid","url", "displaytitle"),
+                      clean_response = FALSE, ...){
+  
+  properties <- match.arg(arg = properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action = "query",
+    prop   = "info",
+    inprop = properties,
+    titles = page
+  )
+  content <- query(url, "pageinfo", clean_response, query_param = query_param, ...)
+  return(content)
+}
\ No newline at end of file
diff --git a/R/parse.R b/R/parse.R
new file mode 100644
index 0000000..3a32dfb
--- /dev/null
+++ b/R/parse.R
@@ -0,0 +1,87 @@
+parse_response <- function(x){
+  UseMethod("parse_response", x)
+}
+
+parse_response.rchanges <- function(x){
+  x <- x$query$recentchanges
+  return(x)
+}
+parse_response.rcontent <- function(x){
+  x <- x$query$pages
+  names(x) <- NULL
+  return(x)
+}
+
+parse_response.rdiff <- function(x){
+  x <- x$query$pages
+  names(x) <- NULL
+  return(x)
+}
+
+parse_response.uinfo <- function(x){
+  x <- x$query$users
+  return(x)
+}
+
+parse_response.ucontribs <- function(x){
+  x <- x$query$usercontribs
+  results <- unlist(x)
+  results <- data.frame(matrix(results, nrow = length(x), byrow = TRUE),
+                        stringsAsFactors = FALSE)
+  names(results) <- names(x[[1]])
+  return(results)
+}
+parse_response.catpages <- function(x){
+  x <- x$query$categorymembers
+  results <- unlist(x)
+  results <- data.frame(matrix(results, nrow = length(x), byrow = TRUE),
+                        stringsAsFactors = F)
+  names(results) <- names(x[[1]])
+  return(results)
+}
+parse_response.pagecats <- function(x){
+  x <- x$query$pages
+  names(x) <- NULL
+  results <- lapply(x,function(x){
+    cats <- unlist(x$categories)
+    cats <- data.frame(matrix(cats, nrow = length(x$categories), byrow = TRUE),
+                       stringsAsFactors = FALSE)
+    names(cats) <- names(x$categories[[1]])
+    x$categories <- cats
+    return(x)
+  })
+  return(results)
+}
+parse_response.blink <- function(x){
+  x <- x$query$backlinks
+  results <- lapply(x,unlist)
+  return(results)
+}
+parse_response.plink <- function(x){
+  x <- x$query$pages
+  names(x) <- NULL
+  results <- lapply(x, function(x){
+    x$links <- lapply(x$links,unlist)
+    return(x)
+  })
+  return(results)
+}
+parse_response.elink <- function(x){
+  x <- x$query$pages
+  names(x) <- NULL
+  results <- lapply(x, function(x){
+    x$extlinks <- unlist(x$extlinks)
+    names(x$extlinks) <- NULL
+    return(x)
+  })
+  return(results)
+}
+parse_response.pageinfo <- function(x){
+  x <- x$query$pages
+  names(x) <- NULL
+  results <- lapply(x, function(x){
+    x$restrictiontypes <- unlist(x$restrictiontypes)
+    return(x)
+  })
+  return(results)
+}
\ No newline at end of file
diff --git a/R/query.R b/R/query.R
new file mode 100644
index 0000000..000c281
--- /dev/null
+++ b/R/query.R
@@ -0,0 +1,79 @@
+#General functions and error handlers for
+#generic queries and query construction.
+
+#'@title base query function
+#'@description not designed to be used by anyone except
+#'a third-party reuser package, such as WikidataR
+#'@param url a URL body
+#'@param out_class the class to set on the output object; used within
+#'WikidataR to indicate what response-cleaning method should be applied.
+#'
+#'@param clean_response whether to clean the response, using the method assigned
+#'by out_class, or not.
+#'
+#'@param query_param query parameters
+#'
+#'@param ... further arguments to httr's GET.
+#'@export
+query <- function(url, out_class, clean_response = FALSE, query_param = list(), ...){
+  # Common query parameters
+  if(is.null(query_param$format)) {
+    query_param$format <- "json"
+  }
+  
+  args <- list(...)
+  if(length(args) > 0 && "config" %in% class(args[[1]]) && "useragent" %in% names(args[[1]])){
+    response <- httr::GET(url, query = query_param, ...)
+  } else {
+    response <- httr::GET(url, query = query_param, httr::user_agent("WikipediR - https://github.com/Ironholds/WikipediR"), ...)
+  }
+  
+  #Check the validity of the response
+  httr::stop_for_status(response)
+  
+  #Parse the response, check for API errors, return
+  parsed_response <- response_parse(response = response, out_class = out_class)
+  if(!is.null(parsed_response$error)){
+    stop("The API returned an error: ", parsed_response$error$code,
+         " - ", parsed_response$error$info)
+  }
+  if(clean_response){
+    parsed_response <- parse_response(parsed_response)
+  }
+  
+  return(parsed_response)
+}
+
+#Constructor for the URL
+url_gen <- function(language, project, domain = NULL, ...){
+  
+  if(is.null(domain)){
+    #Commons and Wikispecies have different URL formats, so those have to be handled in a hinky way.
+    if(project %in% c("commons","species")){
+      url <- sprintf("https://%s.wikimedia.org/w/api.php", project)
+    } else {
+      url <- sprintf("https://%s.%s.org/w/api.php", language, project)
+    }
+  } else {
+    url <- sprintf("http://%s/w/api.php", domain)
+  }
+  
+  #Return
+  return(url)
+}
+
+#'@importFrom httr content
+#'@importFrom jsonlite fromJSON
+response_parse <- function(response, out_class){
+  
+  #Convert it into a character vector
+  response_text <- httr::content(x = response, as = "text")
+  
+  #From there, turn it into an R object from JSON
+  parsed_text <- jsonlite::fromJSON(txt = response_text, simplifyVector = FALSE)
+  class(parsed_text) <- out_class
+  
+  #Return
+  return(parsed_text)
+  
+}
diff --git a/R/recent_changes.R b/R/recent_changes.R
new file mode 100644
index 0000000..0eefc08
--- /dev/null
+++ b/R/recent_changes.R
@@ -0,0 +1,86 @@
+#'@title Retrieves entries from the RecentChanges feed
+#'
+#'@description
+#'wiki_recentchanges retrieves a stream of entries from Special:RecentChanges, with a variety of
+#'associated metadata and filtering (of both entries *and* that metadata.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param properties Properties you're trying to retrieve about each entry, Options include
+#'"user" (the username of the person responsible for that entry), "userid" (the userID of said
+#'person), "comment" (the edit summary associated with the entry), "parsedcomment" (the same,
+#'but parsed, generating HTML from any wikitext in that comment), "flags" (whether the revision
+#'was 'minor' or not), "timestamp", "title" (the name of the page the entry affected), "ids"
+#'(the page id, along with the old and new revision IDs when applicable) "sizes" (the size,
+#'in uncompressed bytes, of the entry, and, in the case of revisions, the size of the edit
+#'it displaced), "tags" (any tags associated with the revision) and "loginfo" (applicable only
+#'to log entries, and consisting of log ID numbers, log types and actions, and so on) and "sha1"
+#'(the SHA-1 hash of the revision text).
+#'
+#'@param type The type of entry you want to retrieve; can be any permutation of "edit" (edits to existing pages),
+#'"external" (external actions that impact on the project - primarily wikidata changes),
+#'"new" (the creation of new pages) and "log" (log entries). By default, all of these entry types
+#'are included.
+#'
+#'@param tag Only return items with particular "tags", such as "mobile edit". NULL by
+#'default.
+#'
+#'@param dir Should it go from newest to oldest ("newer"), or oldest to newest ("older")?
+#'By default, set to "newer".
+#'
+#'@param limit The number of entries you'd like to return. By default, set to 50, which is
+#'also the maximum number per-request for logged-out users.
+#'
+#'@param top Should the request only return "top" entries - in other words, the most recent
+#'entry on a page? Set to FALSE by default.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@export
+recent_changes <- function(language = NULL, project = NULL, domain = NULL,
+                           properties = c("user","userid","comment",
+                                          "parsedcomment","flags","timestamp",
+                                          "title","ids","sizes","redirect",
+                                          "loginfo","tags","sha1"),
+                           type = c("edit","external","new","log"),
+                           tag = NULL, dir = "newer", limit = 50, top = FALSE, 
+                           clean_response = FALSE, ...) {
+  
+  #Format and standardise, construct URL
+  type <- match.arg(arg = type, several.ok = TRUE)
+  type <- paste(type, collapse = "|")
+  properties <- match.arg(arg = properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action = "query",
+    list   = "recentchanges",
+    rcdir  = dir,
+    rcprop = properties,
+    rctype = type,
+    rclimit= limit
+  )
+  if(!is.null(tag)){
+    query_param$rctag <-  paste(tag, collapse = "|")
+  }
+  if(top){
+    query_param$rctoponly <- ""
+  }
+  
+  #Query
+  content <- query(url, "rchanges", clean_response, query_param = query_param, ...)
+  
+  #Return
+  return(content)
+}
\ No newline at end of file
diff --git a/R/user_info.R b/R/user_info.R
new file mode 100644
index 0000000..5645671
--- /dev/null
+++ b/R/user_info.R
@@ -0,0 +1,184 @@
+#Missing user handler for user_information/user_contributions
+missing_users <- function(parsed_response){
+  
+  #Check for missing values
+  names_to_check <- names(unlist(parsed_response))
+  missing_names <- sum(grepl(x = names_to_check, pattern = "users\\.missing"))
+  if(missing_names){
+    warning(missing_names," of the provided usernames did not exist", call. = FALSE)
+  }
+  return(invisible())
+}
+
+#'@title Retrieve user contributions
+#'
+#'@description Retrieves metadata associated with the most recent contributions by a
+#'specified user.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param username The username of the user whose contributions you want to retrieve.
+#'Due to limitations at the API end, you can only retrieve edits for one user at a time.
+#'
+#'@param properties The metadata you want associated with each edit. Potential metadata includes "ids"
+#'(the revision ID of the revision, which can be passed into \code{\link{revision_content}}),
+#'"title" (the name of the page that was edited), "timestamp", "comment" (the edit summary associated
+#'with the revision), "parsedcomment" (the same, but parsed, generating HTML from any wikitext
+#'in that comment), "size" (the size, in uncompressed bytes, of the edit), "sizediff" (the size
+#'delta between this edit, and the last edit to the page), "flags" (whether the revision was 
+#''minor' or not), and "tags" (any tags associated with the revision).
+#'
+#'@param mainspace A boolean flag; FALSE retrieves all of the most recent contributions, while
+#'TRUE limits the retrieved contributions to those in the 'mainspace' - in other words, edits to
+#'actual articles. Set to FALSE by default
+#'
+#'@param limit The number of edits to be retrieved. 50 is the maximum for logged-out API users,
+#'and putting in more than 50 will generate a warning.
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@seealso \code{\link{user_information}} for information about a specific user (or group of users),
+#'and \code{recent_changes} for non-user-specific recent actions.
+#'
+#'@examples
+#'
+#'#Retrieve the timestamps of a user's recent contributions to the English-language Wikipedia
+#'contribs <- user_contributions("en", "wikipedia", username = "Ironholds",
+#'                               properties = "timestamp")
+#'
+#'#Retrieve the timestamps of a user's recent contributions to a non-Wikimedia wiki.
+#'rw_contribs <- user_contributions(domain = "rationalwiki.org", username = "David Gerard",
+#'                                  properties = "ids", limit = 1)
+#'                            
+#'@export
+user_contributions <- function(language = NULL, project = NULL, domain = NULL,
+                               username, properties = c("ids", "title", "timestamp",
+                                                        "comment", "parsedcomment", "size", 
+                                                        "sizediff", "flags", "tags"),
+                               mainspace = FALSE, limit = 50, clean_response = FALSE,
+                               ...){
+  
+  #Perform checks, construct URL
+  properties <- match.arg(properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  username <- handle_limits(username, 1)
+  url <- url_gen(language, project, domain)
+  query_param <- list(
+    action  = "query",
+    list    = "usercontribs",
+    uclimit = limit,
+    ucuser  = username,
+    ucprop  = properties
+  )
+  
+  #If only article contributions are desired, note that.
+  if(mainspace){
+    query_param$ucnamespace <- 0
+  }
+  
+  #Get, check and return
+  contribs_content <- query(url, "ucontribs", clean_response, query_param = query_param, ...)
+  missing_users(contribs_content)
+  return(contribs_content)
+}
+
+#'@title Retrieve user information
+#'
+#'@description
+#'Retrieves information about a user, or set of users, from the MediaWiki API,
+#'including registration date, gender and editcount.
+#'
+#'@param language The language code of the project you wish to query,
+#'if appropriate.
+#'
+#'@param project The project you wish to query ("wikiquote"), if appropriate.
+#'Should be provided in conjunction with \code{language}.
+#'
+#'@param domain as an alternative to a \code{language} and \code{project} combination,
+#'you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+#'for the querying of non-Wikimedia MediaWiki instances.
+#'
+#'@param user_names The username(s) of the users you want information on - this should be provided
+#'as a vector. There is a hard limit of 50 distinct users per query, set by MediaWiki's API;
+#'in the event that you go over this, a warning will be issued and the query will only be
+#'performed for the first 50 names in the vector.
+#'
+#'@param properties The user properties you're interested in. Applicable properties are
+#'"blockinfo" (details about the user's block, if they are currently blocked), "groups"
+#'(the user groups the user is a member of), "implicitgroups" (groups they are a member of
+#'through inheritance, as a result of membership in other groups), "rights" (what permissions
+#'their group membership grants them), "editcount" (how many non-deleted edits they have),
+#'"registration" (the date when they registered), "emailable" (whether they are contactable
+#'through Special:EmailUser) and "gender" (their provided gender).
+#'
+#'@param clean_response whether to do some basic sanitising of the resulting data structure.
+#'Set to FALSE by default.
+#'
+#'@param ... further arguments to pass to httr's GET.
+#'
+#'@section Warnings:
+#'There are a few caveats with the data provided by \code{user_information}, mostly stemming from
+#'historical inconsistencies and peculiarities in MediaWiki.
+#'
+#'\code{groups} and \code{implicitgroups} gives you the user's permissions and group membership
+#'on the project you are querying, not their membership on all projects - while you can find out
+#'if "Ironholds" is not a sysop on, say, enwiki, that doesn't mean they aren't a sysop elsewhere
+#'- there is no universal, API-accessible user groups listing.
+#'
+#'As an extension of the lack of centrality in Wikimedia's infrastructure, \code{registration}
+#'tells you the date their account was created on the wiki you are querying. If they initially
+#'registered on that wiki, this is accurate - if they registered on a different wiki,
+#'this instead reflects the date and time that they first visited the wiki you're querying
+#'while logged-in. For users registered before 2006, when registration logging was introduced,
+#'the \code{registration} value represents not when they first registered, but when their first
+#'edit was, since that was used as an estimator for existing accounts when the field was first
+#'populated.
+#'
+#'@seealso \code{\link{user_contributions}} for retrieving recent contributions made by
+#'a particular user.
+#'
+#'@examples
+#'#Retrieving information from a Wikimedia project
+#'user_info <- user_information("en", "wikipedia", user_names = "David Gerard",
+#'                              properties = "registration")
+#'
+#'#Non-Wikimedia projects
+#'user_info <- user_information(domain = "rationalwiki.org", user_names = "David Gerard",
+#'                              properties = "registration")
+#'@export
+user_information <- function(language = NULL, project = NULL, domain = NULL,
+                             user_names, properties = c("blockinfo","groups","implicitgroups",
+                                                       "rights","editcount","registration",
+                                                       "emailable","gender"),
+                             clean_response = FALSE, ...){
+  
+  #Check, construct URL
+  properties <- match.arg(properties, several.ok = TRUE)
+  properties <- paste(properties, collapse = "|")
+  user_names <- handle_limits(user_names, 50)
+  url <- url_gen(language, project, domain)
+  query_param = list(
+    action  = "query",
+    list    = "users",
+    usprop  = properties,
+    ususers = user_names
+    
+  )
+
+  #Retrieve the content, check it, return.
+  user_content <- query(url, "uinfo", clean_response, query_param = query_param, ...)
+  missing_users(user_content)
+  return(user_content)
+  
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d25652e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+WikipediR
+=========
+
+An R API wrapper for MediaWiki, optimised for the Wikimedia Foundation MediaWiki instances, such as Wikipedia.
+
+__Author:__ Oliver Keyes<br/>
+__License:__ [MIT](http://opensource.org/licenses/MIT)<br/>
+__Status:__ Stable
+
+![downloads](http://cranlogs.r-pkg.org/badges/grand-total/WikipediR)
+
+Description
+======
+_WikipediR_ is a wrapper around the MediaWiki API, optimised for the Wikimedia Foundation's production sites, such as Wikipedia. It is written in and for R, a statistical environment and associated programming language in heavy use by HCI researchers that, somehow, escaped having an API wrapper until now.
+
+Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms.
+
+Installation
+======
+
+For the most recent version, on CRAN:
+
+    install.packages("WikipediR")
+    
+For the development version:
+
+    library(devtools)
+    devtools::install_github("ironholds/WikipediR")
+    
+Limitations
+======
+WikipediR currently lacks:
+* Quite a few possible API calls;
+* Direct authentication, through MediaWiki or OAuth.
+
+These issues will be solved in time; if there is a particular feature you want, open an issue here on github: I can't prioritise if I don't know what people are trying to do :).
+
+Dependencies
+======
+* R. Doy.
+* [httr](https://cran.r-project.org/package=httr) and its dependencies.
diff --git a/build/vignette.rds b/build/vignette.rds
new file mode 100644
index 0000000..d610ae2
Binary files /dev/null and b/build/vignette.rds differ
diff --git a/inst/doc/WikipediR.Rmd b/inst/doc/WikipediR.Rmd
new file mode 100644
index 0000000..bd9e6d7
--- /dev/null
+++ b/inst/doc/WikipediR.Rmd
@@ -0,0 +1,17 @@
+<!--
+%\VignetteEngine{knitr::knitr}
+%\VignetteIndexEntry{WikipediR}
+-->
+
+#WikipediR: A MediaWiki API client library
+Many websites run on versions of MediaWiki, most prominently Wikipedia and its sister sites. WikipediR is an API client library that allows you to conveniently make requests for content and associated metadata against MediaWiki instances.
+
+## Retrieving content
+"content" can mean a lot of different things - but mostly, we mean the text of an article, either its current version or any previous versions. Current versions can be retrieved using <code>page\_content</code>, which provides both HTML and wikitext as possible output formats. Older, individual revisions can be retrieved with <code>revision\_content</code>. These functions also return a range of possible metadata about the revisions or articles in question.
+
+Diffs between revisions can be generated using <code>revision\_diff</code>, while individual ''elements'' of a page's content - particularly links - can be extracted using <code>page\_links</code>, <code>page\_backlinks</code>, and <code>page\_external\_links</code>. And if the interest is in changes to content, rather than content itself, <code>recent\_changes</code> can be used to grab a slice of a project's Special:RecentChanges feed.
+
+## Retrieving metadata
+Page-related information can be accessed using <code>page\_info</code>, while categories that a page possesses can be retrieved with <code>categories\_in\_page</code> - the inverse of this operation (what pages are in a particular category?) uses <code>pages\_in\_category</code>.
+
+User-related info can be accessed with <code>user\_information</code>, while <code>user\_contributions</code> allows access to recent contributions by a particular user: this can be conveniently linked up with <code>revision\_content</code>, mentioned above, to retrieve the content of the last N edits by a particular editor, or metadata about those edits.
\ No newline at end of file
diff --git a/inst/doc/WikipediR.html b/inst/doc/WikipediR.html
new file mode 100644
index 0000000..a36e6dc
--- /dev/null
+++ b/inst/doc/WikipediR.html
@@ -0,0 +1,188 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+<title>Retrieving content</title>
+
+<script type="text/javascript">
+window.onload = function() {
+  var imgs = document.getElementsByTagName('img'), i, img;
+  for (i = 0; i < imgs.length; i++) {
+    img = imgs[i];
+    // center an image if it is the only element of its parent
+    if (img.parentElement.childElementCount === 1)
+      img.parentElement.style.textAlign = 'center';
+  }
+};
+</script>
+
+
+
+
+
+<style type="text/css">
+body, td {
+   font-family: sans-serif;
+   background-color: white;
+   font-size: 13px;
+}
+
+body {
+  max-width: 800px;
+  margin: auto;
+  padding: 1em;
+  line-height: 20px;
+}
+
+tt, code, pre {
+   font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace;
+}
+
+h1 {
+   font-size:2.2em;
+}
+
+h2 {
+   font-size:1.8em;
+}
+
+h3 {
+   font-size:1.4em;
+}
+
+h4 {
+   font-size:1.0em;
+}
+
+h5 {
+   font-size:0.9em;
+}
+
+h6 {
+   font-size:0.8em;
+}
+
+a:visited {
+   color: rgb(50%, 0%, 50%);
+}
+
+pre, img {
+  max-width: 100%;
+}
+pre {
+  overflow-x: auto;
+}
+pre code {
+   display: block; padding: 0.5em;
+}
+
+code {
+  font-size: 92%;
+  border: 1px solid #ccc;
+}
+
+code[class] {
+  background-color: #F8F8F8;
+}
+
+table, td, th {
+  border: none;
+}
+
+blockquote {
+   color:#666666;
+   margin:0;
+   padding-left: 1em;
+   border-left: 0.5em #EEE solid;
+}
+
+hr {
+   height: 0px;
+   border-bottom: none;
+   border-top-width: thin;
+   border-top-style: dotted;
+   border-top-color: #999999;
+}
+
+ at media print {
+   * {
+      background: transparent !important;
+      color: black !important;
+      filter:none !important;
+      -ms-filter: none !important;
+   }
+
+   body {
+      font-size:12pt;
+      max-width:100%;
+   }
+
+   a, a:visited {
+      text-decoration: underline;
+   }
+
+   hr {
+      visibility: hidden;
+      page-break-before: always;
+   }
+
+   pre, blockquote {
+      padding-right: 1em;
+      page-break-inside: avoid;
+   }
+
+   tr, img {
+      page-break-inside: avoid;
+   }
+
+   img {
+      max-width: 100% !important;
+   }
+
+   @page :left {
+      margin: 15mm 20mm 15mm 10mm;
+   }
+
+   @page :right {
+      margin: 15mm 10mm 15mm 20mm;
+   }
+
+   p, h2, h3 {
+      orphans: 3; widows: 3;
+   }
+
+   h2, h3 {
+      page-break-after: avoid;
+   }
+}
+</style>
+
+
+
+</head>
+
+<body>
+<!--
+%\VignetteEngine{knitr::knitr}
+%\VignetteIndexEntry{WikipediR}
+-->
+
+<p>#WikipediR: A MediaWiki API client library
+Many websites run on versions of MediaWiki, most prominently Wikipedia and its sister sites. WikipediR is an API client library that allows you to conveniently make requests for content and associated metadata against MediaWiki instances.</p>
+
+<h2>Retrieving content</h2>
+
+<p>“content” can mean a lot of different things - but mostly, we mean the text of an article, either its current version or any previous versions. Current versions can be retrieved using <code>page_content</code>, which provides both HTML and wikitext as possible output formats. Older, individual revisions can be retrieved with <code>revision_content</code>. These functions also return a range of possible metadata about the revisions or articles in question.</p>
+
+<p>Diffs between revisions can be generated using <code>revision_diff</code>, while individual ''elements'' of a page's content - particularly links - can be extracted using <code>page_links</code>, <code>page_backlinks</code>, and <code>page_external_links</code>. And if the interest is in changes to content, rather than content itself, <code>recent_changes</code> can be used to grab a slice of a project's Special:RecentChanges feed.</p>
+
+<h2>Retrieving metadata</h2>
+
+<p>Page-related information can be accessed using <code>page_info</code>, while categories that a page possesses can be retrieved with <code>categories_in_page</code> - the inverse of this operation (what pages are in a particular category?) uses <code>pages_in_category</code>.</p>
+
+<p>User-related info can be accessed with <code>user_information</code>, while <code>user_contributions</code> allows access to recent contributions by a particular user: this can be conveniently linked up with <code>revision_content</code>, mentioned above, to retrieve the content of the last N edits by a particular editor, or metadata about those edits.</p>
+
+</body>
+
+</html>
diff --git a/man/WikipediR.Rd b/man/WikipediR.Rd
new file mode 100644
index 0000000..e788218
--- /dev/null
+++ b/man/WikipediR.Rd
@@ -0,0 +1,16 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/WikipediR.R
+\docType{package}
+\name{WikipediR}
+\alias{WikipediR}
+\alias{WikipediR-package}
+\title{A client library for MediaWiki's API}
+\description{
+This package provides functions for accessing the MediaWiki API, either for
+Wikimedia projects or any other MediaWiki instance. For more information, see the
+\href{https://CRAN.R-project.org/package=WikipediR/vignettes/WikipediR.html}{vignette}.
+}
+\seealso{
+The \href{https://CRAN.R-project.org/package=WikipediR/vignettes/WikipediR.html}{package vignette}.
+}
+
diff --git a/man/categories_in_page.Rd b/man/categories_in_page.Rd
new file mode 100644
index 0000000..50fed50
--- /dev/null
+++ b/man/categories_in_page.Rd
@@ -0,0 +1,56 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/categories.R
+\name{categories_in_page}
+\alias{categories_in_page}
+\title{Retrieves categories associated with a page.}
+\usage{
+categories_in_page(language = NULL, project = NULL, domain = NULL, pages,
+  properties = c("sortkey", "timestamp", "hidden"), limit = 50,
+  show_hidden = FALSE, clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{pages}{A vector of page titles, with or without spaces, that you want to retrieve
+categories for.}
+
+\item{properties}{The properties you want to retrieve about the categories.
+Options are "sortkey" (the key that sorts the way the page is stored in each category),
+"timestamp" (when the category was added to that page) and "hidden" (tags those categories
+in the returned list that are 'hidden' from readers).}
+
+\item{limit}{The maximum number of categories you want to retrieve for each page. Set
+to 50 by default.}
+
+\item{show_hidden}{Whether or not to include 'hidden' categories in the categories
+that are retrieved - these are usually associated with the maintenance of Wikipedia
+and its internal processes. Set to FALSE by default.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+Retrieves categories associated with a page (or list of pages) on a MediaWiki instance
+}
+\examples{
+
+#Retrieve the categories for the "New Age" article on en.wiki
+cats <- categories_in_page("en", "wikipedia", pages = "New Age")
+
+#Retrieve the categories for the "New Age" article on rationalwiki.
+rw_cats <- categories_in_page(domain = "rationalwiki.org", pages = "New Age")
+}
+\seealso{
+\code{\link{pages_in_category}} for pages in a specified category.
+}
+
diff --git a/man/page_backlinks.Rd b/man/page_backlinks.Rd
new file mode 100644
index 0000000..c772bab
--- /dev/null
+++ b/man/page_backlinks.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/metadata.R
+\name{page_backlinks}
+\alias{page_backlinks}
+\title{Retrieve a page's backlinks}
+\usage{
+page_backlinks(language = NULL, project = NULL, domain = NULL, page,
+  limit = 50, direction = "ascending", namespaces = NULL,
+  clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{page}{the title of the page you want the backlinks of.}
+
+\item{limit}{the number of backlinks to return. Set to 50 (the maximum) by default.}
+
+\item{direction}{the direction to order the backlinks in, by linking page ID: "ascending"
+or "descending". Set to "ascending" by default.}
+
+\item{namespaces}{The namespaces to filter to. By default, backlinks from any namespace
+are retrieved: alternately, a numeric vector of accepted namespaces (which are described
+\href{https://www.mediawiki.org/wiki/Manual:Namespace#Built-in_namespaces}{here}) can be
+provided, and only backlinks from pages within those namespaces will be returned.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+page_backlinks, when provided with a page title, retrieves backlinks to that
+page. Output can be filtered to specific namespaces.
+}
+\section{Warnings}{
+ as with \code{\link{pages_in_category}}, if the page
+you are linking to does not exist, an empty list will be returned, without
+any indication of an error.
+}
+\examples{
+#Backlink
+all_bls <- page_backlinks("en","wikipedia", page = "Aaron Halfaker")
+
+#Namespace-specific backlinks
+mainspace_bls <- page_backlinks("en","wikipedia", page = "Aaron Halfaker", namespaces = 0)
+}
+
diff --git a/man/page_content.Rd b/man/page_content.Rd
new file mode 100644
index 0000000..18f9dea
--- /dev/null
+++ b/man/page_content.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/content.R
+\name{page_content}
+\alias{page_content}
+\title{Retrieves MediaWiki page content}
+\usage{
+page_content(language = NULL, project = NULL, domain = NULL, page_name,
+  page_id = NULL, as_wikitext = FALSE, clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{page_name}{The title of the page you want to retrieve}
+
+\item{page_id}{the pageID of the page you want to retrieve. Set to NULL by default,
+and an alternative to page_name; if both are provided, page_id will be used.}
+
+\item{as_wikitext}{whether to retrieve the wikimarkup (TRUE) or the HTML (FALSE).
+Set to FALSE by default.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+wiki_page retrieves the DOM of a particular MediaWiki page,
+as a HTML blob inside a JSON object.
+}
+\examples{
+#Content from a Wikimedia project
+wp_content <- page_content("en","wikipedia", page_name = "Aaron Halfaker")
+
+#Content by ID
+wp_content <- page_content("en", "wikipedia", page_id = 12)
+
+#Content from a non-Wikimedia project
+rw_content <- page_content(domain = "rationalwiki.org", page_name = "New Age")
+}
+\seealso{
+\code{\link{revision_diff}} for retrieving 'diffs' between revisions,
+\code{\link{revision_content}} for retrieving the text of specified revisions.
+}
+
diff --git a/man/page_external_links.Rd b/man/page_external_links.Rd
new file mode 100644
index 0000000..1c614f9
--- /dev/null
+++ b/man/page_external_links.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/metadata.R
+\name{page_external_links}
+\alias{page_external_links}
+\title{Retrieve a page's links}
+\usage{
+page_external_links(language = NULL, project = NULL, domain = NULL, page,
+  protocol = NULL, clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{page}{the title of the page you want the links of.}
+
+\item{protocol}{limit links to those with certain link protocols. Options are listed
+in Special:ApiSandbox's
+\href{https://en.wikipedia.org/wiki/Special:ApiSandbox#action=query&prop=extlinks}{elprotocol field}.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+page_external_links, when provided with a page title, retrieves external wikilinks from the
+current revision of that page.
+}
+\examples{
+#Links
+external_links <- page_external_links("en","wikipedia", page = "Aaron Halfaker")
+
+#Protocol-specific links
+external_http_links <- page_external_links("en","wikipedia",
+                                          page = "Aaron Halfaker", protocol = "http")
+}
+
diff --git a/man/page_info.Rd b/man/page_info.Rd
new file mode 100644
index 0000000..0f4ab03
--- /dev/null
+++ b/man/page_info.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/metadata.R
+\name{page_info}
+\alias{page_info}
+\title{Retrieve information about a particular page}
+\usage{
+page_info(language = NULL, project = NULL, domain = NULL, page,
+  properties = c("protection", "talkid", "url", "displaytitle"),
+  clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{page}{the title of the page you want the metadata of.}
+
+\item{properties}{the properties you'd like to retrieve. Some properties (the pageID, namespace,
+title, language, length and most recent revision ID, for example) are retrieved by default,
+whatever is passed to \code{properties}: properties that can be explicitly retrieved include
+the page's protection level ("protection"), the ID of the associated talk page, if applicable
+("talkid"), the full, canonical URL ("url"), and the displayed page title ("displaytitle").}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+page_info, when provided with a page title, retrieves metadata about that page.
+}
+\examples{
+#Metadata
+page_metadata <- page_info("en","wikipedia", page = "Aaron Halfaker")
+
+}
+
diff --git a/man/page_links.Rd b/man/page_links.Rd
new file mode 100644
index 0000000..fbb2442
--- /dev/null
+++ b/man/page_links.Rd
@@ -0,0 +1,50 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/metadata.R
+\name{page_links}
+\alias{page_links}
+\title{Retrieve a page's links}
+\usage{
+page_links(language = NULL, project = NULL, domain = NULL, page,
+  limit = 50, direction = "ascending", namespaces = NULL,
+  clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{page}{the title of the page you want the links of.}
+
+\item{limit}{the number of links to retrieve. 50 by default; a maximum of 500 is set server-side.}
+
+\item{direction}{the direction to order the links in, by destination page ID: "ascending"
+or "descending". Set to "ascending" by default.}
+
+\item{namespaces}{The namespaces to filter to. By default, links to any namespace
+are retrieved: alternately, a numeric vector of accepted namespaces (which are described
+\href{https://www.mediawiki.org/wiki/Manual:Namespace#Built-in_namespaces}{here}) can be
+provided, and only backlinks from pages within those namespaces will be returned.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+page_links, when provided with a page title, retrieves internal wikilinks from the
+current revision of that page.
+}
+\examples{
+#Links
+links <- page_links("en","wikipedia", page = "Aaron Halfaker")
+
+#Namespace-specific links
+mainspace_links <- page_links("en","wikipedia", page = "Aaron Halfaker", namespaces = 0)
+}
+
diff --git a/man/pages_in_category.Rd b/man/pages_in_category.Rd
new file mode 100644
index 0000000..3835867
--- /dev/null
+++ b/man/pages_in_category.Rd
@@ -0,0 +1,64 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/categories.R
+\name{pages_in_category}
+\alias{pages_in_category}
+\title{Retrieves a list of category members.}
+\usage{
+pages_in_category(language = NULL, project = NULL, domain = NULL,
+  categories, properties = c("title", "ids", "sortkey", "sortkeyprefix",
+  "type", "timestamp"), type = c("page", "subcat", "file"),
+  clean_response = FALSE, limit = 50, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{categories}{The names of the categories you want to gather information for.}
+
+\item{properties}{The properties you want to gather for each member of the category. 
+Options are "title" (the name of the member, including namespace), 
+"id" (the unique numeric identifier of the member), "sortkey" 
+(the hexadecimal key used to sort that member within the category), 
+"sortkeyprefix" (the human-readable sort key), "type"
+(whether the member is a page, a subcategory or a file) and 
+"timestamp" (when the member was added to the category)}
+
+\item{type}{The type of member you're interested in returning;
+options are any permutation of "page" (pages), "subcat" (subcategories) and "file" (files).}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{limit}{The maximum number of members to retrieve for each category. Set
+to 50 by default.}
+
+\item{...}{further arguments to pass to httr's GET().}
+}
+\description{
+wiki_catpages retrieves a list of pages, subcategories, files or all of the above
+in a specified category (or series of specified categories)
+}
+\section{warnings}{
+
+Because of the way MediaWiki stores this data, both "the category you asked for doesn't exist"
+and "the category you asked for exists, but has no members" return in the same way.
+}
+\examples{
+
+#Retrieve the pages in the "New Age" category on en.wiki
+cats <- pages_in_category("en", "wikipedia", categories = "New Age")
+
+#Retrieve the pages in the "New Age" category on rationalwiki.
+rw_cats <- pages_in_category(domain = "rationalwiki.org", categories = "New Age")
+}
+\seealso{
+\code{\link{categories_in_page}} for finding categories that a specified page is a member of.
+}
+
diff --git a/man/query.Rd b/man/query.Rd
new file mode 100644
index 0000000..26f7cbf
--- /dev/null
+++ b/man/query.Rd
@@ -0,0 +1,26 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/query.R
+\name{query}
+\alias{query}
+\title{base query function}
+\usage{
+query(url, out_class, clean_response = FALSE, query_param = list(), ...)
+}
+\arguments{
+\item{url}{a URL body}
+
+\item{out_class}{the class to set on the output object; used within
+WikidataR to indicate what response-cleaning method should be applied.}
+
+\item{clean_response}{whether to clean the response, using the method assigned
+by out_class, or not.}
+
+\item{query_param}{query parameters}
+
+\item{...}{further arguments to httr's GET.}
+}
+\description{
+not designed to be used by anyone except
+a third-party reuser package, such as WikidataR
+}
+
diff --git a/man/random_page.Rd b/man/random_page.Rd
new file mode 100644
index 0000000..ed74be9
--- /dev/null
+++ b/man/random_page.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/content.R
+\name{random_page}
+\alias{random_page}
+\title{Retrieve the page content of a random MediaWiki page}
+\usage{
+random_page(language = NULL, project = NULL, domain = NULL,
+  namespaces = NULL, as_wikitext = FALSE, limit = 1,
+  clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{namespaces}{The namespaces to consider pages from. By default, pages from any namespace are
+considered; alternately, a numeric vector of accepted namespaces (which are described
+\href{https://www.mediawiki.org/wiki/Manual:Namespace#Built-in_namespaces}{here}) can be
+provided, and only pages within those namespaces will be considered.}
+
+\item{as_wikitext}{whether to retrieve the wikimarkup (TRUE) or the HTML (FALSE).
+Set to FALSE by default.}
+
+\item{limit}{the number of pages to return. 1 by default.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+wiki_page retrieves the DOM of a particular MediaWiki page,
+as a HTML blob inside a JSON object.
+}
+\examples{
+#A page from Wikipedia
+wp_content <- random_page("en","wikipedia")
+
+#A page from the mainspace on Wikipedia
+wp_article_content <- random_page("en","wikipedia", namespaces = 0)
+}
+\seealso{
+\code{\link{page_content}} for retrieving the content of a specific page,
+\code{\link{revision_diff}} for retrieving 'diffs' between revisions,
+\code{\link{revision_content}} for retrieving the text of specified revisions.
+}
+
diff --git a/man/recent_changes.Rd b/man/recent_changes.Rd
new file mode 100644
index 0000000..cec02ab
--- /dev/null
+++ b/man/recent_changes.Rd
@@ -0,0 +1,61 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/recent_changes.R
+\name{recent_changes}
+\alias{recent_changes}
+\title{Retrieves entries from the RecentChanges feed}
+\usage{
+recent_changes(language = NULL, project = NULL, domain = NULL,
+  properties = c("user", "userid", "comment", "parsedcomment", "flags",
+  "timestamp", "title", "ids", "sizes", "redirect", "loginfo", "tags", "sha1"),
+  type = c("edit", "external", "new", "log"), tag = NULL, dir = "newer",
+  limit = 50, top = FALSE, clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{properties}{Properties you're trying to retrieve about each entry, Options include
+"user" (the username of the person responsible for that entry), "userid" (the userID of said
+person), "comment" (the edit summary associated with the entry), "parsedcomment" (the same,
+but parsed, generating HTML from any wikitext in that comment), "flags" (whether the revision
+was 'minor' or not), "timestamp", "title" (the name of the page the entry affected), "ids"
+(the page id, along with the old and new revision IDs when applicable) "sizes" (the size,
+in uncompressed bytes, of the entry, and, in the case of revisions, the size of the edit
+it displaced), "tags" (any tags associated with the revision) and "loginfo" (applicable only
+to log entries, and consisting of log ID numbers, log types and actions, and so on) and "sha1"
+(the SHA-1 hash of the revision text).}
+
+\item{type}{The type of entry you want to retrieve; can be any permutation of "edit" (edits to existing pages),
+"external" (external actions that impact on the project - primarily wikidata changes),
+"new" (the creation of new pages) and "log" (log entries). By default, all of these entry types
+are included.}
+
+\item{tag}{Only return items with particular "tags", such as "mobile edit". NULL by
+default.}
+
+\item{dir}{Should it go from newest to oldest ("newer"), or oldest to newest ("older")?
+By default, set to "newer".}
+
+\item{limit}{The number of entries you'd like to return. By default, set to 50, which is
+also the maximum number per-request for logged-out users.}
+
+\item{top}{Should the request only return "top" entries - in other words, the most recent
+entry on a page? Set to FALSE by default.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+wiki_recentchanges retrieves a stream of entries from Special:RecentChanges, with a variety of
+associated metadata and filtering (of both entries *and* that metadata.
+}
+
diff --git a/man/revision_content.Rd b/man/revision_content.Rd
new file mode 100644
index 0000000..5481727
--- /dev/null
+++ b/man/revision_content.Rd
@@ -0,0 +1,56 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/content.R
+\name{revision_content}
+\alias{revision_content}
+\title{Retrieves MediaWiki revisions}
+\usage{
+revision_content(language = NULL, project = NULL, domain = NULL,
+  revisions, properties = c("content", "ids", "flags", "timestamp", "user",
+  "userid", "size", "sha1", "contentmodel", "comment", "parsedcomment", "tags"),
+  clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{revisions}{The revision IDs of each desired revision.}
+
+\item{properties}{Properties you're trying to retrieve about that revision, should you want to;
+options include "ids" (the revision ID of the revision...which is pointless),
+"flags" (whether the revision was 'minor' or not), "timestamp" (the timestamp of the revision),
+"user" (the username of the person who made that revision), "userid"
+(the userID of the person who made the revision),
+"size" (the size, in uncompressed bytes, of the revision), "sha1" (the SHA-1 hash of
+the revision text), "contentmodel" (the content model of the page, usually "wikitext"),
+"comment" (the revision summary associated with the revision), "parsedcomment" (the same,
+but parsed, generating HTML from any wikitext in that comment), "tags" (any tags associated
+with the revision) and "flagged" (the revision's status under Flagged Revisions).}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+Retrieves the content of a provided list of revisions from whichever MediaWiki instance you're
+querying. Returns as wikimarkup.
+}
+\examples{
+
+#Revision content from a Wikimedia project
+wp_content <- revision_content("en","wikipedia", revisions = 552373187)
+
+#Revision content from a non-Wikimedia project
+rw_content <- revision_content(domain = "rationalwiki.org", revisions = 88616)
+}
+\seealso{
+\code{\link{revision_diff}} for diffs between revisions,
+and \code{\link{page_content}} for the content a specific page currently has.
+}
+
diff --git a/man/revision_diff.Rd b/man/revision_diff.Rd
new file mode 100644
index 0000000..e47f595
--- /dev/null
+++ b/man/revision_diff.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/content.R
+\name{revision_diff}
+\alias{revision_diff}
+\title{Generates a "diff" between a pair of revisions}
+\usage{
+revision_diff(language = NULL, project = NULL, domain = NULL, revisions,
+  properties = c("ids", "flags", "timestamp", "user", "userid", "size",
+  "sha1", "contentmodel", "comment", "parsedcomment", "tags", "flagged"),
+  direction, clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{revisions}{The revision IDs of each "start" revision.}
+
+\item{properties}{Properties you're trying to retrieve about that revision, should you want to;
+options include "ids" (the revision ID of the revision...which is pointless),
+"flags" (whether the revision was 'minor' or not), "timestamp","user" (the username of the person
+who made that revision), "userid" (the userID of the person who made the revision),
+"size" (the size, in uncompressed bytes, of the revision), "sha1" (the SHA-1 hash of
+the revision text), "contentmodel" (the content model of the page, usually "wikitext"),
+"comment" (the revision summary associated with the revision), "parsedcomment" (the same,
+but parsed, generating HTML from any wikitext in that comment), "tags" (any tags associated
+with the revision) and "flagged" (the revision's status under Flagged Revisions).}
+
+\item{direction}{The direction you want the diff to go in from the revisionID you have provided.
+Options are "prev" (compare to the previous revision on that page), "next" (compare to the next
+revision on that page) and "cur" (compare to the current, extant version of the page).}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+revision_diff generates a diff between two revisions in a MediaWiki page.
+This is provided as an XML-parsable blob inside the returned JSON object.
+}
+\section{Warnings}{
+
+
+MediaWiki's API is deliberately designed to restrict users' ability to make computing-intense requests
+- such as diff computation. As a result, the API only allows requests for one uncached diff in
+each request. If you ask for multiple diffs, some uncached and some cached, you will be provided
+with the cached diffs, one of the uncached diffs, and a warning.
+
+If you're going to be asking for a lot of diffs, some of which may not be cached, it may be more
+sensible to retrieve the revisions themselves using \code{\link{revision_content}} and compute the
+diffs yourself.
+}
+\examples{
+
+#Wikimedia diff
+wp_diff <- revision_diff("en","wikipedia", revisions = 552373187, direction = "next")
+
+#Non-Wikimedia diff
+rw_diff <- revision_diff(domain = "rationalwiki.org", revisions = 88616, direction = "next")
+}
+\seealso{
+\code{\link{page_content}} for retrieving the current content of a specific page, and
+\code{\link{revision_content}} for retrieving the text of specific revisions.
+}
+
diff --git a/man/user_contributions.Rd b/man/user_contributions.Rd
new file mode 100644
index 0000000..e7ae5bf
--- /dev/null
+++ b/man/user_contributions.Rd
@@ -0,0 +1,65 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/user_info.R
+\name{user_contributions}
+\alias{user_contributions}
+\title{Retrieve user contributions}
+\usage{
+user_contributions(language = NULL, project = NULL, domain = NULL,
+  username, properties = c("ids", "title", "timestamp", "comment",
+  "parsedcomment", "size", "sizediff", "flags", "tags"), mainspace = FALSE,
+  limit = 50, clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{username}{The username of the user whose contributions you want to retrieve.
+Due to limitations at the API end, you can only retrieve edits for one user at a time.}
+
+\item{properties}{The metadata you want associated with each edit. Potential metadata includes "ids"
+(the revision ID of the revision, which can be passed into \code{\link{revision_content}}),
+"title" (the name of the page that was edited), "timestamp", "comment" (the edit summary associated
+with the revision), "parsedcomment" (the same, but parsed, generating HTML from any wikitext
+in that comment), "size" (the size, in uncompressed bytes, of the edit), "sizediff" (the size
+delta between this edit, and the last edit to the page), "flags" (whether the revision was 
+'minor' or not), and "tags" (any tags associated with the revision).}
+
+\item{mainspace}{A boolean flag; FALSE retrieves all of the most recent contributions, while
+TRUE limits the retrieved contributions to those in the 'mainspace' - in other words, edits to
+actual articles. Set to FALSE by default}
+
+\item{limit}{The number of edits to be retrieved. 50 is the maximum for logged-out API users,
+and putting in more than 50 will generate a warning.}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+Retrieves metadata associated with the most recent contributions by a
+specified user.
+}
+\examples{
+
+#Retrieve the timestamps of a user's recent contributions to the English-language Wikipedia
+contribs <- user_contributions("en", "wikipedia", username = "Ironholds",
+                              properties = "timestamp")
+
+#Retrieve the timestamps of a user's recent contributions to a non-Wikimedia wiki.
+rw_contribs <- user_contributions(domain = "rationalwiki.org", username = "David Gerard",
+                                 properties = "ids", limit = 1)
+                           
+}
+\seealso{
+\code{\link{user_information}} for information about a specific user (or group of users),
+and \code{recent_changes} for non-user-specific recent actions.
+}
+
diff --git a/man/user_information.Rd b/man/user_information.Rd
new file mode 100644
index 0000000..01617b7
--- /dev/null
+++ b/man/user_information.Rd
@@ -0,0 +1,77 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/user_info.R
+\name{user_information}
+\alias{user_information}
+\title{Retrieve user information}
+\usage{
+user_information(language = NULL, project = NULL, domain = NULL,
+  user_names, properties = c("blockinfo", "groups", "implicitgroups",
+  "rights", "editcount", "registration", "emailable", "gender"),
+  clean_response = FALSE, ...)
+}
+\arguments{
+\item{language}{The language code of the project you wish to query,
+if appropriate.}
+
+\item{project}{The project you wish to query ("wikiquote"), if appropriate.
+Should be provided in conjunction with \code{language}.}
+
+\item{domain}{as an alternative to a \code{language} and \code{project} combination,
+you can also provide a domain ("rationalwiki.org") to the URL constructor, allowing
+for the querying of non-Wikimedia MediaWiki instances.}
+
+\item{user_names}{The username(s) of the users you want information on - this should be provided
+as a vector. There is a hard limit of 50 distinct users per query, set by MediaWiki's API;
+in the event that you go over this, a warning will be issued and the query will only be
+performed for the first 50 names in the vector.}
+
+\item{properties}{The user properties you're interested in. Applicable properties are
+"blockinfo" (details about the user's block, if they are currently blocked), "groups"
+(the user groups the user is a member of), "implicitgroups" (groups they are a member of
+through inheritance, as a result of membership in other groups), "rights" (what permissions
+their group membership grants them), "editcount" (how many non-deleted edits they have),
+"registration" (the date when they registered), "emailable" (whether they are contactable
+through Special:EmailUser) and "gender" (their provided gender).}
+
+\item{clean_response}{whether to do some basic sanitising of the resulting data structure.
+Set to FALSE by default.}
+
+\item{...}{further arguments to pass to httr's GET.}
+}
+\description{
+Retrieves information about a user, or set of users, from the MediaWiki API,
+including registration date, gender and editcount.
+}
+\section{Warnings}{
+
+There are a few caveats with the data provided by \code{user_information}, mostly stemming from
+historical inconsistencies and peculiarities in MediaWiki.
+
+\code{groups} and \code{implicitgroups} gives you the user's permissions and group membership
+on the project you are querying, not their membership on all projects - while you can find out
+if "Ironholds" is not a sysop on, say, enwiki, that doesn't mean they aren't a sysop elsewhere
+- there is no universal, API-accessible user groups listing.
+
+As an extension of the lack of centrality in Wikimedia's infrastructure, \code{registration}
+tells you the date their account was created on the wiki you are querying. If they initially
+registered on that wiki, this is accurate - if they registered on a different wiki,
+this instead reflects the date and time that they first visited the wiki you're querying
+while logged-in. For users registered before 2006, when registration logging was introduced,
+the \code{registration} value represents not when they first registered, but when their first
+edit was, since that was used as an estimator for existing accounts when the field was first
+populated.
+}
+\examples{
+#Retrieving information from a Wikimedia project
+user_info <- user_information("en", "wikipedia", user_names = "David Gerard",
+                             properties = "registration")
+
+#Non-Wikimedia projects
+user_info <- user_information(domain = "rationalwiki.org", user_names = "David Gerard",
+                             properties = "registration")
+}
+\seealso{
+\code{\link{user_contributions}} for retrieving recent contributions made by
+a particular user.
+}
+
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000..1a61edd
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,3 @@
+library(WikipediR)
+library(testthat)
+test_check("WikipediR")
diff --git a/tests/testthat/test_category_retrieval.R b/tests/testthat/test_category_retrieval.R
new file mode 100644
index 0000000..69949b3
--- /dev/null
+++ b/tests/testthat/test_category_retrieval.R
@@ -0,0 +1,22 @@
+context("Category retrieval")
+
+test_that("page categories can be retrieved through categories_in_page", {
+  expect_true({categories_in_page("en","wikipedia", page = "Barack Obama");TRUE})
+})
+
+test_that("Hidden page categories can be retrieved through categories_in_page", {
+  expect_true({categories_in_page("en","wikipedia", page = "Barack Obama", show_hidden=T);TRUE})
+})
+
+test_that("Category members can be retrieved through categories_in_page", {
+  expect_true({pages_in_category("en","wikipedia", categories = "1920 births");TRUE})
+})
+
+test_that("Category members can be retrieved through categories_in_page", {
+  expect_true({pages_in_category("en","wikipedia", categories = "1920s births", type = "subcat");TRUE})
+})
+
+test_that("page categories can be retrieved through categories_in_page  with non-ASCII query", {
+  # \u30dd\u30b1\u30e2\u30f3 is "Pokemon" in Japanese letters
+  expect_true({categories_in_page("en","wikipedia", page = "\u30dd\u30b1\u30e2\u30f3");TRUE})
+})
\ No newline at end of file
diff --git a/tests/testthat/test_content_retrieval.R b/tests/testthat/test_content_retrieval.R
new file mode 100644
index 0000000..18ecbab
--- /dev/null
+++ b/tests/testthat/test_content_retrieval.R
@@ -0,0 +1,24 @@
+context("Content retrieval")
+
+test_that("Wikitext content can be retrieved through page_content", {
+  expect_true({page_content("en","wikipedia", page_name = "Barack Obama", as_wikitext=TRUE);TRUE})
+  expect_true({page_content("en","wikipedia", page_id = "534366", as_wikitext=TRUE);TRUE})
+})
+
+test_that("HTML content can be retrieved through page_content", {
+  expect_true({page_content("en","wikipedia", page_name = "Barack Obama", as_wikitext=FALSE);TRUE})
+  expect_true({page_content("en","wikipedia", page_id = "534366", as_wikitext=FALSE);TRUE})
+})
+
+test_that("HTML content can be retrieved through revision_content", {
+  expect_true({revision_content("en","wikipedia", revisions = "102342934");TRUE})
+})
+
+test_that("Diffs can be retrieved through revision_content", {
+  expect_true({revision_diff("en","wikipedia", revisions = "129122231", direction = "next");TRUE})
+})
+
+test_that("Wikitext content can be retrieved through page_content with non-ASCII query", {
+  # \u30dd\u30b1\u30e2\u30f3 is "Pokemon" in Japanese letters
+  expect_true({page_content("en","wikipedia", page_name = "\u30dd\u30b1\u30e2\u30f3", as_wikitext=TRUE);TRUE})
+})
\ No newline at end of file
diff --git a/tests/testthat/test_metadata_retrieval.R b/tests/testthat/test_metadata_retrieval.R
new file mode 100644
index 0000000..90accb1
--- /dev/null
+++ b/tests/testthat/test_metadata_retrieval.R
@@ -0,0 +1,33 @@
+context("Metadata")
+
+test_that("backlinks can be retrieved through page_backlinks", {
+  expect_true({page_backlinks("en","wikipedia", page = "Aaron Halfaker");TRUE})
+})
+
+test_that("backlinks from a specific namespace can be retrieved through page_backlinks", {
+  expect_true({page_backlinks("en","wikipedia", page = "Aaron Halfaker", namespaces = 0);TRUE})
+})
+
+test_that("links can be retrieved through page_links", {
+  expect_true({page_links("en","wikipedia", page = "Aaron Halfaker");TRUE})
+})
+
+test_that("links from a specific namespace can be retrieved through page_links", {
+  expect_true({page_links("en","wikipedia", page = "Aaron Halfaker", namespaces = 0);TRUE})
+})
+
+test_that("external links can be retrieved through page_links", {
+  expect_true({page_external_links("en","wikipedia", page = "Aaron Halfaker");TRUE})
+})
+
+test_that("external links with a particular protocol can be retrieved through page_links", {
+  expect_true({page_external_links("en","wikipedia", page = "Aaron Halfaker", protocol = "http");TRUE})
+})
+
+test_that("page info can be retrieved through page_info", {
+  expect_true({page_info("en","wikipedia", page = "Aaron Halfaker");TRUE})
+})
+
+test_that("page info with specified params can be retrieved through page_info", {
+  expect_true({page_info("en","wikipedia", page = "Aaron Halfaker", properties = "talkid");TRUE})
+})
diff --git a/tests/testthat/test_recent_changes.R b/tests/testthat/test_recent_changes.R
new file mode 100644
index 0000000..a49209c
--- /dev/null
+++ b/tests/testthat/test_recent_changes.R
@@ -0,0 +1,17 @@
+context("Recent changes")
+
+test_that("Recentchanges feed entries can be retrieved through recent_changes", {
+  expect_true({recent_changes("en","wikipedia", limit=1);TRUE})
+})
+
+test_that("recent_changes respects tags", {
+  expect_true({recent_changes("en","wikipedia", limit=1, tag = "mobile edit");TRUE})
+})
+
+test_that("recent_changes respects types", {
+  expect_true({recent_changes("en","wikipedia", limit=1, type = "new");TRUE})
+})
+
+test_that("recent_changes respects directional changes", {
+  expect_true({recent_changes("en","wikipedia", limit=1, top = TRUE);TRUE})
+})
diff --git a/vignettes/WikipediR.Rmd b/vignettes/WikipediR.Rmd
new file mode 100644
index 0000000..bd9e6d7
--- /dev/null
+++ b/vignettes/WikipediR.Rmd
@@ -0,0 +1,17 @@
+<!--
+%\VignetteEngine{knitr::knitr}
+%\VignetteIndexEntry{WikipediR}
+-->
+
+#WikipediR: A MediaWiki API client library
+Many websites run on versions of MediaWiki, most prominently Wikipedia and its sister sites. WikipediR is an API client library that allows you to conveniently make requests for content and associated metadata against MediaWiki instances.
+
+## Retrieving content
+"content" can mean a lot of different things - but mostly, we mean the text of an article, either its current version or any previous versions. Current versions can be retrieved using <code>page\_content</code>, which provides both HTML and wikitext as possible output formats. Older, individual revisions can be retrieved with <code>revision\_content</code>. These functions also return a range of possible metadata about the revisions or articles in question.
+
+Diffs between revisions can be generated using <code>revision\_diff</code>, while individual ''elements'' of a page's content - particularly links - can be extracted using <code>page\_links</code>, <code>page\_backlinks</code>, and <code>page\_external\_links</code>. And if the interest is in changes to content, rather than content itself, <code>recent\_changes</code> can be used to grab a slice of a project's Special:RecentChanges feed.
+
+## Retrieving metadata
+Page-related information can be accessed using <code>page\_info</code>, while categories that a page possesses can be retrieved with <code>categories\_in\_page</code> - the inverse of this operation (what pages are in a particular category?) uses <code>pages\_in\_category</code>.
+
+User-related info can be accessed with <code>user\_information</code>, while <code>user\_contributions</code> allows access to recent contributions by a particular user: this can be conveniently linked up with <code>revision\_content</code>, mentioned above, to retrieve the content of the last N edits by a particular editor, or metadata about those edits.
\ No newline at end of file
diff --git a/vignettes/WikipediR.md b/vignettes/WikipediR.md
new file mode 100644
index 0000000..cbb6eda
--- /dev/null
+++ b/vignettes/WikipediR.md
@@ -0,0 +1,17 @@
+<!--
+%\VignetteEngine{knitr::knitr}
+%\VignetteIndexEntry{WikipediR}
+-->
+
+#WikipediR: A MediaWiki API client library
+Many websites run on versions of MediaWiki, most prominently Wikipedia and its sister sites. WikipediR is an API client library that allows you to conveniently make requests for content and associated metadata against MediaWiki instances.
+
+## Retrieving content
+"content" can mean a lot of different things - but mostly, we mean the text of an article, either its current version or any previous versions. Current versions can be retrieved using <code>page\_content</code>, which provides both HTML and wikitext as possible output formats. Older, individual revisions can be retrieved with <code>revision\_content</code>. These functions also return a range of possible metadata about the revisions or articles in question.
+
+Diffs between revisions can be generated using <code>revision\_diff</code>, while individual ''elements'' of a page's content - particularly links - can be extracted using <code>page\_links</code>, <code>page\_backlinks</code>, and <code>page\_external\_links</code>. And if the interest is in changes to content, rather than content itself, <code>recent\_changes</code> can be used to grab a slice of a project's Special:RecentChanges feed.
+
+## Retrieving metadata
+Page-related information can be accessed using <code>page\_info</code>, while categories that a page possesses can be retrieved with <code>categories\_in\_page</code> - the inverse of this operation (what pages are in a particular category?) uses <code>pages\_in\_category</code>.
+
+User-related info can be accessed with <code>user\_information</code>, while <code>user\_contributions</code> allows access to recent contributions by a particular user: this can be conveniently linked up with <code>revision\_content</code>, mentioned above, to retrieve the content of the last N edits by a particular editor, or metadata about those edits.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-wikipedir.git



More information about the debian-med-commit mailing list