Skip to content

Commit aa377c4

Browse files
committed
import rlang and later
1 parent e85285a commit aa377c4

File tree

9 files changed

+32
-38
lines changed

9 files changed

+32
-38
lines changed

DESCRIPTION

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ SystemRequirements: 'libfswatch', or 'cmake' to compile from package sources
2121
Depends:
2222
R (>= 3.6)
2323
Imports:
24-
R6
25-
Suggests:
2624
later,
25+
R6,
26+
rlang
27+
Suggests:
2728
testthat (>= 3.0.0)
2829
RoxygenNote: 7.3.2
2930
Roxygen: list(markdown = TRUE)

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
export(watcher)
44
importFrom(R6,R6Class)
5+
importFrom(later,run_now)
56
useDynLib(watcher, .registration = TRUE)

R/watch.R

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@
44
#' background.
55
#'
66
#' A limited subset of filesystem events are watched, namely: Created, Updated,
7-
#' Removed and Renamed. Default latency is 1s.
7+
#' Removed and Renamed. Events are 'bubbled' such that if a single event
8+
#' triggers multiple event flag types, the callback will be called only once.
9+
#' Default latency is 1s.
810
#'
911
#' @param path character path to a file or directory to watch. Defaults to the
1012
#' current working directory.
1113
#' @param recursive logical value, default TRUE, whether to recursively scan
1214
#' `path`, including all subdirectories.
1315
#' @param callback (optional) a function (taking no arguments) to be called each
14-
#' time an event is triggered - requires the \pkg{later} package. The default,
15-
#' `NULL`, causes event paths and types to be written to `stdout` instead.
16+
#' time an event is triggered. The default, `NULL`, causes event flag types
17+
#' and paths to be written to `stdout` instead.
1618
#'
1719
#' @return A 'Watcher' R6 class object. Start and stop background monitoring
1820
#' using the `$start()` and `$stop()` methods - these return a logical value
@@ -35,15 +37,16 @@ Watcher <- R6Class(
3537
"Watcher",
3638
public = list(
3739
active = FALSE,
38-
callback = NULL,
3940
path = NULL,
4041
recursive = NULL,
4142
initialize = function(path = getwd(), recursive = TRUE, callback = NULL) {
4243
if (is.null(self$path)) {
4344
self$path <- path.expand(path)
4445
self$recursive <- as.logical(recursive)
45-
self$callback <- callback
46-
private$watch <- .Call(watcher_create, self$path, self$recursive, self$callback)
46+
if (!is.null(callback) && !is.function(callback)) {
47+
callback <- rlang::as_function(callback)
48+
}
49+
private$watch <- .Call(watcher_create, self$path, self$recursive, callback)
4750
}
4851
invisible(self)
4952
},

R/watcher-package.R

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1+
#' @importFrom later run_now
12
#' @importFrom R6 R6Class
23
#' @useDynLib watcher, .registration = TRUE
34
#' @keywords internal
45
"_PACKAGE"
6+
7+
# for R CMD check note: All declared Imports should be used.
8+
# rlang is not loaded unless used, later is loaded but used only at C level
9+
.internal <- function() {
10+
if (FALSE) rlang::as_function(identity)(later::run_now())
11+
}

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ w
5151
#> <Watcher>
5252
#> Public:
5353
#> active: FALSE
54-
#> callback: function ()
55-
#> initialize: function (path = getwd(), recursive = TRUE, callback = NULL)
56-
#> path: /tmp/Rtmp8wU9e9/watcher-example
54+
#> initialize: function (path, recursive, callback, latency)
55+
#> path: /tmp/RtmpvAax6s/watcher-example
5756
#> recursive: TRUE
5857
#> start: function ()
5958
#> stop: function ()

man/watcher.Rd

Lines changed: 5 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/init.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "watcher.h"
22

3+
void (*eln2)(void (*)(void *), void *, double, int);
4+
35
static const R_CallMethodDef callMethods[] = {
46
{"watcher_create", (DL_FUNC) &watcher_create, 3},
57
{"watcher_start_monitor", (DL_FUNC) &watcher_start_monitor, 1},
@@ -9,6 +11,7 @@ static const R_CallMethodDef callMethods[] = {
911

1012
void attribute_visible R_init_watcher(DllInfo* dll) {
1113
if (fsw_init_library() != FSW_OK) return;
14+
eln2 = (void (*)(void (*)(void *), void *, double, int)) R_GetCCallable("later", "execLaterNative2");
1215
R_registerRoutines(dll, NULL, callMethods, NULL, NULL);
1316
R_useDynamicSymbols(dll, FALSE);
1417
R_forceSymbols(dll, TRUE);

src/watcher.c

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@ static void session_finalizer(SEXP xptr) {
2020
fsw_destroy_session(handle);
2121
}
2222

23-
void (*eln2)(void (*)(void *), void *, double, int) = NULL;
24-
25-
static void load_later_safe(void *data) {
26-
SEXP call, fn = (SEXP) data;
27-
PROTECT(call = Rf_lang2(fn, Rf_mkString("later")));
28-
Rf_eval(call, R_GlobalEnv);
29-
UNPROTECT(1);
30-
}
31-
3223
static void exec_later(void *data) {
3324
SEXP call, fn = (SEXP) data;
3425
PROTECT(call = Rf_lcons(fn, R_NilValue));
@@ -50,7 +41,7 @@ static void get_event_flag_name(const int flag, char *buf) {
5041
}
5142

5243
static void process_events(fsw_cevent const *const events, const unsigned int event_num, void *data) {
53-
if (data != R_NilValue && eln2 != NULL) {
44+
if (data != R_NilValue) {
5445
eln2(exec_later, data, 0, 0);
5546
} else {
5647
char buf[8]; // large enough for subset of events handled by get_event_flag_name()
@@ -76,11 +67,6 @@ SEXP watcher_create(SEXP path, SEXP recursive, SEXP callback) {
7667

7768
const char *watch_path = CHAR(STRING_ELT(path, 0));
7869
const int recurse = LOGICAL(recursive)[0];
79-
if (callback != R_NilValue) {
80-
SEXPTYPE typ = TYPEOF(callback);
81-
if (typ != CLOSXP && typ != BUILTINSXP && typ != SPECIALSXP)
82-
Rf_error("'callback' must be a function");
83-
}
8470

8571
FSW_HANDLE handle = fsw_init_session(system_default_monitor_type);
8672
if (handle == NULL) {
@@ -121,15 +107,11 @@ SEXP watcher_create(SEXP path, SEXP recursive, SEXP callback) {
121107
SEXP watcher_start_monitor(SEXP session) {
122108

123109
FSW_HANDLE handle = (FSW_HANDLE) R_ExternalPtrAddr(session);
110+
124111
pthread_t thr;
125112
pthread_attr_t attr;
126-
127113
pthread_attr_init(&attr);
128114
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
129-
130-
if (eln2 == NULL && R_ToplevelExec(load_later_safe, (void *) Rf_install("loadNamespace"))) {
131-
eln2 = (void (*)(void (*)(void *), void *, double, int)) R_GetCCallable("later", "execLaterNative2");
132-
}
133115
const int ret = pthread_create(&thr, &attr, &watcher_thread, handle);
134116
pthread_attr_destroy(&attr);
135117

tests/testthat/test-watch.R

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,4 @@ test_that("watcher() callbacks", {
5757
rm(w)
5858
})
5959

60-
test_that("watcher() validation", {
61-
expect_error(watcher(callback = "callback"), "must be a function")
62-
})
63-
6460
unlink(dir, recursive = TRUE, force = TRUE)

0 commit comments

Comments
 (0)