diff --git a/DESCRIPTION b/DESCRIPTION index 03764e0..d90d2f7 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: eurlex Type: Package Title: Retrieve Data on European Union Law -Version: 0.4.6 +Version: 0.4.7 Authors@R: c(person(given = "Michal", family = "Ovadek", role = c("aut", "cre", "cph"), @@ -12,7 +12,7 @@ License: GPL-3 Encoding: UTF-8 Language: en-US Depends: - R (>= 3.4.0) + R (>= 3.5.0) Imports: magrittr, dplyr, @@ -36,7 +36,7 @@ Suggests: ggiraph, testthat (>= 3.0.0) URL: https://michalovadek.github.io/eurlex/ -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Roxygen: list(markdown = TRUE) VignetteBuilder: knitr Config/testthat/edition: 3 diff --git a/NEWS.md b/NEWS.md index 466515a..025c7e0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# eurlex 0.4.7 + +## Minor changes +- some http calls were still not failing gracefully +- some leftover .data in tidyselect + # eurlex 0.4.6 ## Minor changes diff --git a/R/elx_curia_list.R b/R/elx_curia_list.R index 4765282..7ad36e1 100644 --- a/R/elx_curia_list.R +++ b/R/elx_curia_list.R @@ -33,7 +33,6 @@ elx_curia_list <- function(data = c("all","ecj_old","ecj_new","gc_all","cst_all" else {data <- match.arg(data)} - if (data == "all"){ res_c1 <- elx_curia_scraper(url_c1) @@ -89,7 +88,6 @@ elx_curia_list <- function(data = c("all","ecj_old","ecj_new","gc_all","cst_all" } - } #' Curia scraper function @@ -118,8 +116,8 @@ elx_curia_scraper <- function(url, ...){ dplyr::mutate(dplyr::across(.cols = dplyr::everything(), .fns = ~dplyr::na_if(., ""))) %>% dplyr::filter(!is.na(.data$X1) & !is.na(.data$X2)) %>% - dplyr::rename(case_id = .data$X1, - case_info = .data$X2) %>% + dplyr::rename(case_id = "X1", + case_info = "X2") %>% dplyr::group_by(.data$case_id) %>% dplyr::mutate(n_id = dplyr::row_number()) %>% dplyr::ungroup() @@ -127,7 +125,7 @@ elx_curia_scraper <- function(url, ...){ hrefs <- page %>% xml2::xml_find_all('//a[contains(@href, "numdoc")]') - linked_id <- rvest::html_text(hrefs, "href") + linked_id <- rvest::html_text(hrefs, trim = TRUE) linked_celex <- rvest::html_attr(hrefs, "href") %>% stringr::str_extract("numdoc=.*") %>% @@ -141,7 +139,7 @@ elx_curia_scraper <- function(url, ...){ out <- dplyr::left_join(tab, linked, by = c("case_id"="linked_id","n_id"="n_id")) %>% dplyr::select("case_id", "linked_celex", "case_info") %>% - dplyr::rename(case_id_celex = linked_celex) + dplyr::rename(case_id_celex = "linked_celex") return(out) diff --git a/R/elx_run_query.R b/R/elx_run_query.R index 40fbf65..d06dc98 100644 --- a/R/elx_run_query.R +++ b/R/elx_run_query.R @@ -59,6 +59,11 @@ graceful_http <- function(remote_file, headers = NULL, body = NULL, return(invisible(NULL)) } + # if missing verb pick GET + if (missing(verb)){ + verb <- "GET" + } + # Make the HTTP request based on the verb make_request <- function(verb) { tryCatch({ @@ -72,11 +77,11 @@ graceful_http <- function(remote_file, headers = NULL, body = NULL, } }, error = function(e) { - message("Error: ", conditionMessage(e)) + message(conditionMessage(e), " (Error)") return(invisible(NULL)) }, warning = function(w) { - message("Warning: ", conditionMessage(w)) + message(conditionMessage(w), " (Warning)") return(invisible(NULL)) }) } @@ -84,13 +89,9 @@ graceful_http <- function(remote_file, headers = NULL, body = NULL, # Execute the request resp <- make_request(verb) - # Check for HTTP errors - if (httr::http_error(resp)) { - httr::message_for_status(resp) - return(invisible(NULL)) - } - + # return return(resp) + } #' Parse RDF/XML triplets to data frame diff --git a/docs/404.html b/docs/404.html index 89e0462..4cc0c41 100644 --- a/docs/404.html +++ b/docs/404.html @@ -39,7 +39,7 @@
diff --git a/docs/articles/council.html b/docs/articles/council.html index dce79f6..3f8bc59 100644 --- a/docs/articles/council.html +++ b/docs/articles/council.html @@ -40,7 +40,7 @@ @@ -81,8 +81,8 @@ - -Excluding votes where all governments voted in favour, we are left
-with between 109
and 81
votes per Member
+with between 110
and 81
votes per Member
State. While these numbers do not represent the entire historical voting
record, they should still help us lift the veil on variation in Member
States’ propensity to disagree. Note that due to opt-outs not all
@@ -224,8 +224,8 @@
The country comparison reveals substantial variation in the frequency +
+The country comparison reveals substantial variation in the frequency
of disagreement. The only Member State to ever exit the EU, the United
Kingdom, was particularly active when it comes to abstaining or voting
against legislation. On the other end of the scale is France, which has
diff --git a/docs/articles/council_files/girafe-binding-0.8.8/girafe.js b/docs/articles/council_files/girafe-binding-0.8.8/girafe.js
new file mode 100644
index 0000000..1c6a1ce
--- /dev/null
+++ b/docs/articles/council_files/girafe-binding-0.8.8/girafe.js
@@ -0,0 +1,5 @@
+HTMLWidgets.widget({
+ name: 'girafe',
+ type: 'output',
+ factory: ggiraphjs.factory(HTMLWidgets.shinyMode)
+});
diff --git a/docs/articles/council_files/htmlwidgets-1.6.4/htmlwidgets.js b/docs/articles/council_files/htmlwidgets-1.6.4/htmlwidgets.js
new file mode 100644
index 0000000..1067d02
--- /dev/null
+++ b/docs/articles/council_files/htmlwidgets-1.6.4/htmlwidgets.js
@@ -0,0 +1,901 @@
+(function() {
+ // If window.HTMLWidgets is already defined, then use it; otherwise create a
+ // new object. This allows preceding code to set options that affect the
+ // initialization process (though none currently exist).
+ window.HTMLWidgets = window.HTMLWidgets || {};
+
+ // See if we're running in a viewer pane. If not, we're in a web browser.
+ var viewerMode = window.HTMLWidgets.viewerMode =
+ /\bviewer_pane=1\b/.test(window.location);
+
+ // See if we're running in Shiny mode. If not, it's a static document.
+ // Note that static widgets can appear in both Shiny and static modes, but
+ // obviously, Shiny widgets can only appear in Shiny apps/documents.
+ var shinyMode = window.HTMLWidgets.shinyMode =
+ typeof(window.Shiny) !== "undefined" && !!window.Shiny.outputBindings;
+
+ // We can't count on jQuery being available, so we implement our own
+ // version if necessary.
+ function querySelectorAll(scope, selector) {
+ if (typeof(jQuery) !== "undefined" && scope instanceof jQuery) {
+ return scope.find(selector);
+ }
+ if (scope.querySelectorAll) {
+ return scope.querySelectorAll(selector);
+ }
+ }
+
+ function asArray(value) {
+ if (value === null)
+ return [];
+ if ($.isArray(value))
+ return value;
+ return [value];
+ }
+
+ // Implement jQuery's extend
+ function extend(target /*, ... */) {
+ if (arguments.length == 1) {
+ return target;
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+ for (var prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+ return target;
+ }
+
+ // IE8 doesn't support Array.forEach.
+ function forEach(values, callback, thisArg) {
+ if (values.forEach) {
+ values.forEach(callback, thisArg);
+ } else {
+ for (var i = 0; i < values.length; i++) {
+ callback.call(thisArg, values[i], i, values);
+ }
+ }
+ }
+
+ // Replaces the specified method with the return value of funcSource.
+ //
+ // Note that funcSource should not BE the new method, it should be a function
+ // that RETURNS the new method. funcSource receives a single argument that is
+ // the overridden method, it can be called from the new method. The overridden
+ // method can be called like a regular function, it has the target permanently
+ // bound to it so "this" will work correctly.
+ function overrideMethod(target, methodName, funcSource) {
+ var superFunc = target[methodName] || function() {};
+ var superFuncBound = function() {
+ return superFunc.apply(target, arguments);
+ };
+ target[methodName] = funcSource(superFuncBound);
+ }
+
+ // Add a method to delegator that, when invoked, calls
+ // delegatee.methodName. If there is no such method on
+ // the delegatee, but there was one on delegator before
+ // delegateMethod was called, then the original version
+ // is invoked instead.
+ // For example:
+ //
+ // var a = {
+ // method1: function() { console.log('a1'); }
+ // method2: function() { console.log('a2'); }
+ // };
+ // var b = {
+ // method1: function() { console.log('b1'); }
+ // };
+ // delegateMethod(a, b, "method1");
+ // delegateMethod(a, b, "method2");
+ // a.method1();
+ // a.method2();
+ //
+ // The output would be "b1", "a2".
+ function delegateMethod(delegator, delegatee, methodName) {
+ var inherited = delegator[methodName];
+ delegator[methodName] = function() {
+ var target = delegatee;
+ var method = delegatee[methodName];
+
+ // The method doesn't exist on the delegatee. Instead,
+ // call the method on the delegator, if it exists.
+ if (!method) {
+ target = delegator;
+ method = inherited;
+ }
+
+ if (method) {
+ return method.apply(target, arguments);
+ }
+ };
+ }
+
+ // Implement a vague facsimilie of jQuery's data method
+ function elementData(el, name, value) {
+ if (arguments.length == 2) {
+ return el["htmlwidget_data_" + name];
+ } else if (arguments.length == 3) {
+ el["htmlwidget_data_" + name] = value;
+ return el;
+ } else {
+ throw new Error("Wrong number of arguments for elementData: " +
+ arguments.length);
+ }
+ }
+
+ // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
+ function escapeRegExp(str) {
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ }
+
+ function hasClass(el, className) {
+ var re = new RegExp("\\b" + escapeRegExp(className) + "\\b");
+ return re.test(el.className);
+ }
+
+ // elements - array (or array-like object) of HTML elements
+ // className - class name to test for
+ // include - if true, only return elements with given className;
+ // if false, only return elements *without* given className
+ function filterByClass(elements, className, include) {
+ var results = [];
+ for (var i = 0; i < elements.length; i++) {
+ if (hasClass(elements[i], className) == include)
+ results.push(elements[i]);
+ }
+ return results;
+ }
+
+ function on(obj, eventName, func) {
+ if (obj.addEventListener) {
+ obj.addEventListener(eventName, func, false);
+ } else if (obj.attachEvent) {
+ obj.attachEvent(eventName, func);
+ }
+ }
+
+ function off(obj, eventName, func) {
+ if (obj.removeEventListener)
+ obj.removeEventListener(eventName, func, false);
+ else if (obj.detachEvent) {
+ obj.detachEvent(eventName, func);
+ }
+ }
+
+ // Translate array of values to top/right/bottom/left, as usual with
+ // the "padding" CSS property
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/padding
+ function unpackPadding(value) {
+ if (typeof(value) === "number")
+ value = [value];
+ if (value.length === 1) {
+ return {top: value[0], right: value[0], bottom: value[0], left: value[0]};
+ }
+ if (value.length === 2) {
+ return {top: value[0], right: value[1], bottom: value[0], left: value[1]};
+ }
+ if (value.length === 3) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[1]};
+ }
+ if (value.length === 4) {
+ return {top: value[0], right: value[1], bottom: value[2], left: value[3]};
+ }
+ }
+
+ // Convert an unpacked padding object to a CSS value
+ function paddingToCss(paddingObj) {
+ return paddingObj.top + "px " + paddingObj.right + "px " + paddingObj.bottom + "px " + paddingObj.left + "px";
+ }
+
+ // Makes a number suitable for CSS
+ function px(x) {
+ if (typeof(x) === "number")
+ return x + "px";
+ else
+ return x;
+ }
+
+ // Retrieves runtime widget sizing information for an element.
+ // The return value is either null, or an object with fill, padding,
+ // defaultWidth, defaultHeight fields.
+ function sizingPolicy(el) {
+ var sizingEl = document.querySelector("script[data-for='" + el.id + "'][type='application/htmlwidget-sizing']");
+ if (!sizingEl)
+ return null;
+ var sp = JSON.parse(sizingEl.textContent || sizingEl.text || "{}");
+ if (viewerMode) {
+ return sp.viewer;
+ } else {
+ return sp.browser;
+ }
+ }
+
+ // @param tasks Array of strings (or falsy value, in which case no-op).
+ // Each element must be a valid JavaScript expression that yields a
+ // function. Or, can be an array of objects with "code" and "data"
+ // properties; in this case, the "code" property should be a string
+ // of JS that's an expr that yields a function, and "data" should be
+ // an object that will be added as an additional argument when that
+ // function is called.
+ // @param target The object that will be "this" for each function
+ // execution.
+ // @param args Array of arguments to be passed to the functions. (The
+ // same arguments will be passed to all functions.)
+ function evalAndRun(tasks, target, args) {
+ if (tasks) {
+ forEach(tasks, function(task) {
+ var theseArgs = args;
+ if (typeof(task) === "object") {
+ theseArgs = theseArgs.concat([task.data]);
+ task = task.code;
+ }
+ var taskFunc = tryEval(task);
+ if (typeof(taskFunc) !== "function") {
+ throw new Error("Task must be a function! Source:\n" + task);
+ }
+ taskFunc.apply(target, theseArgs);
+ });
+ }
+ }
+
+ // Attempt eval() both with and without enclosing in parentheses.
+ // Note that enclosing coerces a function declaration into
+ // an expression that eval() can parse
+ // (otherwise, a SyntaxError is thrown)
+ function tryEval(code) {
+ var result = null;
+ try {
+ result = eval("(" + code + ")");
+ } catch(error) {
+ if (!(error instanceof SyntaxError)) {
+ throw error;
+ }
+ try {
+ result = eval(code);
+ } catch(e) {
+ if (e instanceof SyntaxError) {
+ throw error;
+ } else {
+ throw e;
+ }
+ }
+ }
+ return result;
+ }
+
+ function initSizing(el) {
+ var sizing = sizingPolicy(el);
+ if (!sizing)
+ return;
+
+ var cel = document.getElementById("htmlwidget_container");
+ if (!cel)
+ return;
+
+ if (typeof(sizing.padding) !== "undefined") {
+ document.body.style.margin = "0";
+ document.body.style.padding = paddingToCss(unpackPadding(sizing.padding));
+ }
+
+ if (sizing.fill) {
+ document.body.style.overflow = "hidden";
+ document.body.style.width = "100%";
+ document.body.style.height = "100%";
+ document.documentElement.style.width = "100%";
+ document.documentElement.style.height = "100%";
+ cel.style.position = "absolute";
+ var pad = unpackPadding(sizing.padding);
+ cel.style.top = pad.top + "px";
+ cel.style.right = pad.right + "px";
+ cel.style.bottom = pad.bottom + "px";
+ cel.style.left = pad.left + "px";
+ el.style.width = "100%";
+ el.style.height = "100%";
+
+ return {
+ getWidth: function() { return cel.getBoundingClientRect().width; },
+ getHeight: function() { return cel.getBoundingClientRect().height; }
+ };
+
+ } else {
+ el.style.width = px(sizing.width);
+ el.style.height = px(sizing.height);
+
+ return {
+ getWidth: function() { return cel.getBoundingClientRect().width; },
+ getHeight: function() { return cel.getBoundingClientRect().height; }
+ };
+ }
+ }
+
+ // Default implementations for methods
+ var defaults = {
+ find: function(scope) {
+ return querySelectorAll(scope, "." + this.name);
+ },
+ renderError: function(el, err) {
+ var $el = $(el);
+
+ this.clearError(el);
+
+ // Add all these error classes, as Shiny does
+ var errClass = "shiny-output-error";
+ if (err.type !== null) {
+ // use the classes of the error condition as CSS class names
+ errClass = errClass + " " + $.map(asArray(err.type), function(type) {
+ return errClass + "-" + type;
+ }).join(" ");
+ }
+ errClass = errClass + " htmlwidgets-error";
+
+ // Is el inline or block? If inline or inline-block, just display:none it
+ // and add an inline error.
+ var display = $el.css("display");
+ $el.data("restore-display-mode", display);
+
+ if (display === "inline" || display === "inline-block") {
+ $el.hide();
+ if (err.message !== "") {
+ var errorSpan = $("").addClass(errClass);
+ errorSpan.text(err.message);
+ $el.after(errorSpan);
+ }
+ } else if (display === "block") {
+ // If block, add an error just after the el, set visibility:none on the
+ // el, and position the error to be on top of the el.
+ // Mark it with a unique ID and CSS class so we can remove it later.
+ $el.css("visibility", "hidden");
+ if (err.message !== "") {
+ var errorDiv = $("
# elx_run_query()
as_tibble(results)
-#> # A tibble: 4,429 × 3
+#> # A tibble: 4,449 × 3
#> work type celex
#> <chr> <chr> <chr>
#> 1 469391ea-6c79-4680-84aa-c33db274e271 DIR 31979L0173
#> 2 e8fcaf0d-443a-40ec-b778-34b7d895d334 DIR 31989L0194
#> 3 52639f5f-ecaf-4f99-b633-e954cea5c8f3 DIR 31984L0378
#> 4 c7560407-689b-4752-9fb0-d0624ed83a19 DIR 31966L0683
-#> # ℹ 4,425 more rows
The function outputs a data.frame
where each column
corresponds to one of the requested variables, while the rows accumulate
observations of the resource type satisfying the query criteria.
diff --git a/docs/articles/eurlexpkg_files/figure-html/dirforce-1.png b/docs/articles/eurlexpkg_files/figure-html/dirforce-1.png
index 57bdf91..35fe9db 100644
Binary files a/docs/articles/eurlexpkg_files/figure-html/dirforce-1.png and b/docs/articles/eurlexpkg_files/figure-html/dirforce-1.png differ
diff --git a/docs/articles/eurlexpkg_files/figure-html/firstplot-1.png b/docs/articles/eurlexpkg_files/figure-html/firstplot-1.png
index 52240f4..eaa272e 100644
Binary files a/docs/articles/eurlexpkg_files/figure-html/firstplot-1.png and b/docs/articles/eurlexpkg_files/figure-html/firstplot-1.png differ
diff --git a/docs/articles/eurlexpkg_files/figure-html/wordcloud-1.png b/docs/articles/eurlexpkg_files/figure-html/wordcloud-1.png
index aeb0c30..2a1c15e 100644
Binary files a/docs/articles/eurlexpkg_files/figure-html/wordcloud-1.png and b/docs/articles/eurlexpkg_files/figure-html/wordcloud-1.png differ
diff --git a/docs/articles/index.html b/docs/articles/index.html
index 21ce608..057556c 100644
--- a/docs/articles/index.html
+++ b/docs/articles/index.html
@@ -17,7 +17,7 @@
diff --git a/docs/articles/sparql-queries.html b/docs/articles/sparql-queries.html
index f1ce905..4ccaece 100644
--- a/docs/articles/sparql-queries.html
+++ b/docs/articles/sparql-queries.html
@@ -40,7 +40,7 @@
diff --git a/docs/authors.html b/docs/authors.html
index 04ac7d6..955cc61 100644
--- a/docs/authors.html
+++ b/docs/authors.html
@@ -17,7 +17,7 @@
diff --git a/docs/index.html b/docs/index.html
index f67a5b2..25d65c3 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -40,7 +40,7 @@
diff --git a/docs/news/index.html b/docs/news/index.html
index d66adf1..2dfa544 100644
--- a/docs/news/index.html
+++ b/docs/news/index.html
@@ -17,7 +17,7 @@
@@ -58,13 +58,22 @@
elx_council_votes()
and elx_curia_list()
now fail gracefully# \donttest{
elx_curia_list(data = "cst_all", parse = FALSE)
-#> # A tibble: 1,759 × 3
-#> case_id case_id_celex case_info
-#> <chr> <chr> <chr>
-#> 1 F-1/05 * NA Judgment of 26 October 2006, Landgren / ETF (F-1/05…
-#> 2 F-1/05 NA Order of 22 May 2007, Landgren / ETF (F-1/05, ECR-S…
-#> 3 F-1/05 INT NA Order of 13 July 2007, Landgren / ETF (F-1/05 INT, …
-#> 4 F-1/05 NA Order of 9 November 2010, Landgren / ETF (F-1/05, u…
-#> 5 F-2/05 NA Removed from the register on 18 June 2008, Kröppeli…
-#> 6 F-3/05 NA Order of 15 May 2006, Schmit / Commission (F-3/05, …
-#> 7 F-4/05 NA Removed from the register on 18 June 2008, Huober /…
-#> 8 F-5/05 * NA Judgment of 28 April 2009, Violetti and others / Co…
-#> 9 F-6/05 NA Removed from the register on 18 June 2008, Kröppeli…
-#> 10 F-7/05 NA Schmit / Commission (F-7/05) , see Case F-5/05
-#> # ℹ 1,749 more rows
+#> Error in rvest::html_text(hrefs, "href"): `trim` must be `TRUE` or `FALSE`, not the string "href".
# }