From b120c6a45017176b7b517135530d993bd4d48535 Mon Sep 17 00:00:00 2001 From: hrbrmstr Date: Tue, 26 Jan 2021 21:37:41 -0500 Subject: [PATCH] README --- DESCRIPTION | 3 +- NAMESPACE | 2 ++ R/swift-function.R | 15 ++++++--- R/utils-pipe.R | 11 ++++++ README.Rmd | 46 ++++++++++++++++++++++++++ README.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++--- man/pipe.Rd | 12 +++++++ man/swift_function.Rd | 11 +++++- 8 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 R/utils-pipe.R create mode 100644 man/pipe.Rd diff --git a/DESCRIPTION b/DESCRIPTION index f4c8977..18c8610 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -20,6 +20,7 @@ Depends: Imports: rprojroot, usethis, - stringi + stringi, + magrittr Roxygen: list(markdown = TRUE) RoxygenNote: 7.1.1 diff --git a/NAMESPACE b/NAMESPACE index 6f5d004..5f44c98 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,7 +1,9 @@ # Generated by roxygen2: do not edit by hand +export("%>%") export(add_registration_glue) export(swift_function) import(rprojroot) import(stringi) import(usethis) +importFrom(magrittr,"%>%") diff --git a/R/swift-function.R b/R/swift-function.R index 70c986f..fe84600 100644 --- a/R/swift-function.R +++ b/R/swift-function.R @@ -5,6 +5,7 @@ #' that uses `.Call` to invoke the library. #' #' @param code Source code for the Swift function definition. +#' @param env Environment where the R functions and modules should be made available. #' @param imports Character vector of Swift frameworks to import. #' @param cache_dir Directory to use for caching shared libraries. The default #' value of [tempdir()] results in the cache being valid only for the current @@ -12,7 +13,7 @@ #' @note Remember that the function need to be `public` and that you need to put #' the required `@@_cdecl ("…")` decorator before the function definition. #' @export -swift_function <- function(code, imports = c("Foundation"), cache_dir = tempdir()) { +swift_function <- function(code, env = globalenv(), imports = c("Foundation"), cache_dir = tempdir()) { arch <- sprintf("--%s", Sys.info()["machine"]) @@ -22,7 +23,7 @@ swift_function <- function(code, imports = c("Foundation"), cache_dir = tempdir( source_file <- basename(tempfile(fileext = ".swift")) - module_name <- sprintf("swift_%s", digest::digest(code)) + module_name <- sprintf("swiftr_%s", digest::digest(code)) writeLines( text = c( @@ -143,7 +144,7 @@ swift_function <- function(code, imports = c("Foundation"), cache_dir = tempdir( collapse = "\n" ) -> ƒ - eval.parent(parse(text = ƒ), 2) + eval(parse(text = ƒ), envir = env) # list( # fname = fname, @@ -154,13 +155,17 @@ swift_function <- function(code, imports = c("Foundation"), cache_dir = tempdir( } else { - cat(readLines(stderr)) + message("COMPILATION ERROR") + + # cat(readLines(stderr)) } } else { - cat(readLines(stderr)) + message("SYNTAX ERROR") + + # cat(readLines(stderr)) } diff --git a/R/utils-pipe.R b/R/utils-pipe.R new file mode 100644 index 0000000..e79f3d8 --- /dev/null +++ b/R/utils-pipe.R @@ -0,0 +1,11 @@ +#' Pipe operator +#' +#' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +#' +#' @name %>% +#' @rdname pipe +#' @keywords internal +#' @export +#' @importFrom magrittr %>% +#' @usage lhs \%>\% rhs +NULL diff --git a/README.Rmd b/README.Rmd index b04a241..376173f 100644 --- a/README.Rmd +++ b/README.Rmd @@ -39,6 +39,52 @@ packageVersion("swiftr") ``` +```{r ex01} +swift_function( + code = ' + +func ignored() { + print(""" +this will be ignored by swift_function() but you could use private +functions as helpers for the main public Swift function which will be +made available to R. +""") +} + +@_cdecl ("read_plist") +public func read_plist(path: SEXP) -> SEXP { + + var out: SEXP = R_NilValue + + do { + // read in the raw plist + let plistRaw = try Data(contentsOf: URL(fileURLWithPath: String(cString: R_CHAR(STRING_ELT(path, 0))))) + + // convert it to a PropertyList + let plist = try PropertyListSerialization.propertyList(from: plistRaw, options: [], format: nil) as! [String:Any] + + // serialize it to JSON + let jsonData = try JSONSerialization.data(withJSONObject: plist , options: .prettyPrinted) + + // setup the JSON string return + String(data: jsonData, encoding: .utf8)?.withCString { + cstr in out = Rf_mkString(cstr) + } + + } catch { + debugPrint("\\(error)") + } + + return(out) + +} +') + +read_plist("/Applications/RStudio.app/Contents/Info.plist") %>% + jsonlite::fromJSON() %>% + str(1) +``` + ## swiftr Metrics ```{r cloc, echo=FALSE} diff --git a/README.md b/README.md index cc3e8c2..ce4b116 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ by](https://img.shields.io/badge/Keybase-Verified-brightgreen.svg)](https://keyb ![Signed commit %](https://img.shields.io/badge/Signed_Commits-100%25-lightgrey.svg) [![Linux build -Status](https://travis-ci.org/hrbrmstr/swiftr.svg?branch=master)](https://travis-ci.org/hrbrmstr/swiftr) +Status](https://travis-ci.org/hrbrmstr/swiftr.svg?branch=master)](https://travis-ci.org/hrbrmstr/swiftr) +[![Coverage +Status](https://codecov.io/gh/hrbrmstr/swiftr/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/swiftr) ![Minimal R Version](https://img.shields.io/badge/R%3E%3D-3.6.0-blue.svg) ![License](https://img.shields.io/badge/License-MIT-blue.svg) @@ -26,6 +28,7 @@ The following functions are implemented: - `add_registration_glue`: This examines a package swift file and builds the necessary registration glue code +- `swift_function`: Define an R Function with a Swift Implementation ## Installation @@ -33,6 +36,8 @@ The following functions are implemented: remotes::install_git("https://git.rud.is/hrbrmstr/swiftr.git") # or remotes::install_gitlab("hrbrmstr/swiftr") +# or +remotes::install_github("hrbrmstr/swiftr") ``` NOTE: To use the ‘remotes’ install options you will need to have the @@ -48,13 +53,92 @@ packageVersion("swiftr") ## [1] '0.1.0' ``` +``` r +swift_function( + code = ' + +func ignored() { + print(""" +this will be ignored by swift_function() but you could use private +functions as helpers for the main public Swift function which will be +made available to R. +""") +} + +@_cdecl ("read_plist") +public func read_plist(path: SEXP) -> SEXP { + + var out: SEXP = R_NilValue + + do { + // read in the raw plist + let plistRaw = try Data(contentsOf: URL(fileURLWithPath: String(cString: R_CHAR(STRING_ELT(path, 0))))) + + // convert it to a PropertyList + let plist = try PropertyListSerialization.propertyList(from: plistRaw, options: [], format: nil) as! [String:Any] + + // serialize it to JSON + let jsonData = try JSONSerialization.data(withJSONObject: plist , options: .prettyPrinted) + + // setup the JSON string return + String(data: jsonData, encoding: .utf8)?.withCString { + cstr in out = Rf_mkString(cstr) + } + + } catch { + debugPrint("\\(error)") + } + + return(out) + +} +') + +read_plist("/Applications/RStudio.app/Contents/Info.plist") %>% + jsonlite::fromJSON() %>% + str(1) +## List of 32 +## $ NSCalendarsUsageDescription : chr "R wants to access calendars." +## $ LSRequiresCarbon : logi TRUE +## $ NSPhotoLibraryAddUsageDescription : chr "R wants write access to the photo library." +## $ CFBundlePackageType : chr "APPL" +## $ NSRemindersUsageDescription : chr "R wants to access the reminders." +## $ CFBundleIdentifier : chr "org.rstudio.RStudio" +## $ NSLocationWhenInUseUsageDescription : chr "R wants to access location information." +## $ NSMicrophoneUsageDescription : chr "R wants to access the microphone." +## $ LSApplicationCategoryType : chr "public.app-category.developer-tools" +## $ NSHumanReadableCopyright : chr "RStudio 1.4.1093-1, © 2009-2020 RStudio, PBC" +## $ CFBundleIconFile : chr "RStudio.icns" +## $ NSAppleScriptEnabled : logi TRUE +## $ CFBundleVersion : chr "1.4.1093-1" +## $ CFBundleInfoDictionaryVersion : chr "6.0" +## $ CFBundleGetInfoString : chr "RStudio 1.4.1093-1, © 2009-2020 RStudio, PBC" +## $ CSResourcesFileMapped : logi TRUE +## $ CFBundleName : chr "RStudio" +## $ NSHighResolutionCapable : logi TRUE +## $ NSContactsUsageDescription : chr "R wants to access contacts." +## $ NSSupportsAutomaticGraphicsSwitching : logi TRUE +## $ NSCameraUsageDescription : chr "R wants to access the camera." +## $ NSAppleEventsUsageDescription : chr "R wants to run AppleScript." +## $ NSPrincipalClass : chr "NSApplication" +## $ OSAScriptingDefinition : chr "RStudio.sdef" +## $ NSBluetoothPeripheralUsageDescription: chr "R wants to access bluetooth." +## $ CFBundleDocumentTypes :'data.frame': 16 obs. of 8 variables: +## $ CFBundleShortVersionString : chr "1.4.1093-1" +## $ CFBundleDevelopmentRegion : chr "English" +## $ NSPhotoLibraryUsageDescription : chr "R wants to access the photo library." +## $ CFBundleLongVersionString : chr "1.4.1093-1" +## $ CFBundleSignature : chr "Rstd" +## $ CFBundleExecutable : chr "RStudio" +``` + ## swiftr Metrics | Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) | |:-----|---------:|-----:|----:|-----:|------------:|-----:|---------:|-----:| -| R | 3 | 0.38 | 87 | 0.46 | 32 | 0.34 | 15 | 0.17 | -| Rmd | 1 | 0.12 | 8 | 0.04 | 15 | 0.16 | 28 | 0.33 | -| SUM | 4 | 0.50 | 95 | 0.50 | 47 | 0.50 | 43 | 0.50 | +| R | 5 | 0.42 | 199 | 0.42 | 69 | 0.36 | 49 | 0.31 | +| Rmd | 1 | 0.08 | 40 | 0.08 | 27 | 0.14 | 30 | 0.19 | +| SUM | 6 | 0.50 | 239 | 0.50 | 96 | 0.50 | 79 | 0.50 | clock Package Metrics for swiftr diff --git a/man/pipe.Rd b/man/pipe.Rd new file mode 100644 index 0000000..0eec752 --- /dev/null +++ b/man/pipe.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils-pipe.R +\name{\%>\%} +\alias{\%>\%} +\title{Pipe operator} +\usage{ +lhs \%>\% rhs +} +\description{ +See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. +} +\keyword{internal} diff --git a/man/swift_function.Rd b/man/swift_function.Rd index e3954da..ca0f1cc 100644 --- a/man/swift_function.Rd +++ b/man/swift_function.Rd @@ -4,11 +4,20 @@ \alias{swift_function} \title{Define an R Function with a Swift Implementation} \usage{ -swift_function(code, cache_dir = tempdir()) +swift_function( + code, + env = globalenv(), + imports = c("Foundation"), + cache_dir = tempdir() +) } \arguments{ \item{code}{Source code for the Swift function definition.} +\item{env}{Environment where the R functions and modules should be made available.} + +\item{imports}{Character vector of Swift frameworks to import.} + \item{cache_dir}{Directory to use for caching shared libraries. The default value of \code{\link[=tempdir]{tempdir()}} results in the cache being valid only for the current R session. Pass an alternate directory to preserve the cache across R sessions.}