I am working with an S4 object (PairwiseAlignmentsSingleSubject). When I type the name of an instance of this class into the console and hit enter, I get something like the following:
Global PairwiseAlignmentsSingleSubject (1 of 1)
pattern: ATCGATCGATCGATCG
subject: -TCGATCG-TCGATC-
score: -16.23717
The actual class is much larger than just this, so I assume some print function for the class is being called. I really want to see the code used in this print function, but I cannot figure out how to pull it up. Could someone please offer some insights into this?
Thank you
Edit based on JDL's answer:
I was able to use selectMethod (I guess this class inherits its "print" function). However, the result is just:
> selectMethod("print",signature(x="BioStrings"))
Method Definition (Class "derivedDefaultMethod"):
function (x, ...)
UseMethod("print")
<bytecode: 0x5572111b6d58>
<environment: namespace:base>
Signatures:
x
target "BioStrings"
defined "ANY"
Which is still not very informative and definitely not the full code for the function. Does anyone know how I can take this further?
To get the code associated with a method, the function to use is getMethod. If you know the class you are interested in then the call is of the form below
getMethod("print",signature(x="numeric"))
which in your specific case is
getMethod("print",signature(x="PairwiseAlignmentsSingleSubject")).
If you have an object obj and want to see what code will be applied to it when you call print, then a slight modification allows this:
getMethod("print",signature(x=class(obj)))
This also works for any generic function, you can substitute "plot" etc. in place of "print".
Note that this only works for methods defined for the exact class you specified. If there isn't such a method (i.e. one based on inheritance was used instead), then replace getMethod with selectMethod.
For further information, consult the help page at ?getMethod which documents these and some similar functions.
Looking through their github is usually useful :)
They don't use 'print' but 'show'.
If you look at the source code for the class PairwiseAlignmentsSingleSubject you can see a show method, but it's only for the class PairwiseAlignmentsSingleSubjectSummary.
But in the last method for 'PairwiseAlignmentsSingleSubject' you see it creates a 'newPairwiseAlignments' and if you look a the source code for the class PairwiseAlignments you'll find the "show" method starting at line 398.
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### The "show" method
###
### TODO: Maybe make the "show" method format the alignment in a SGD fashion
### i.e. split in 60-letter blocks and use the "|" character to highlight
### exact matches.
###
.show_PairwiseAlignments <- function(x)
{
x_len <- length(x)
if (x_len == 0L)
cat("Empty ")
cat(switch(type(x), "global"="Global", "overlap"="Overlap",
"local"="Local", "global-local" = "Global-Local",
"local-global"="Local-Global"),
" ", class(x), sep="")
if (x_len == 0L) {
cat("\n")
return()
}
cat(" (1 of ", x_len, ")\n", sep="")
x1 <- x[1L]
x_type <- type(x)
global.pattern <- x_type %in% c("global", "global-local")
global.subject <- x_type %in% c("global", "local-global")
p1start <- if (global.pattern)
""
else
paste0("[", start(x1#pattern#range), "]")
s1start <- if (global.subject)
""
else
paste0("[", start(x1#subject#range), "]")
width <- max(nchar(p1start), nchar(s1start))
if (width != 0L) {
width <- width + 1L
p1start <- format(p1start, justify="right", width=width)
s1start <- format(s1start, justify="right", width=width)
}
width <- getOption("width") - 9L - width
pattern1 <- toSeqSnippet(alignedPattern(x1)[[1L]], width)
subject1 <- toSeqSnippet(alignedSubject(x1)[[1L]], width)
cat("pattern:", p1start, " ", add_colors(pattern1), "\n", sep="")
cat("subject:", s1start, " ", add_colors(subject1), "\n", sep="")
cat("score:", score(x1), "\n")
}
setMethod("show", "PairwiseAlignments",
function(object) .show_PairwiseAlignments(object)
)
Related
I'm writing my own package and check some of the inputs. When the inputs aren't in the required format I want to stop with an error. However, I want to add a custom message to the default error.
However, something like this has the problem that the indentation of the default and cutom error message doesn't look nice depending on the input. E.g. could be that the second line is indented by a few chars.
test <- function(x, y, z)
{
if (x != 1)
stop(paste0("oops!", "\n", "x is not 1!"))
}
test(x= 2, y = "this is just a test", z = "we need to make the line very long")
leads to:
Error in test(x = 2, y = "this is just a test", z = "we need to make the line very long") :
oops!
x is not 1!
See how the second line is indented by two characters.
So I thought I write a function this way:
create_stops <- function(error_location, error_message)
{
stop(error_location, "\n", error_message, call. = FALSE)
}
test <- function(x, y, z)
{
if (x != 1)
{
error_location <- match.call()
error_message <- paste0("oops!", "\n", "x is not 1!")
create_stops(error_location, error_message)
}
}
test(x= 2, y = "this is just a test", z = "we need to make the line very long")
which returns:
Error: test2this is just a testwe need to make the line very long
oops!
x is not 1!
So here the problem is that the match.call() part doesn't return the full message compared to using teh "normal" stop function.
Any idea how I can get the full function call?
Bonus: is there any way how I can prevent having to use the error_location = match.call() in my main test function and instead use match.call in the create_stops function, but it would return the parent function, i.e. "Error in test", not "Error in create_stops"?
Background
I want to show part of my bookmarks on my Hugo website. The bookmarks from Firefox can be saved in JSON format, this is the source. The result should represent the nested structure somehow, in a format of a nested list, treeview or accordion. The source files of contents on the website are written in markdown. I want to generate a markdown file from the JSON input.
As I searched for possible solutions:
treeview or accordion: HTML, CSS and Javascript needed. I could not nest accordions with the <details> tag. Also, seems like overkill at the moment.
unordered list: can be done with bare markdown.
I chose to generate an unordered nested list from JSON. I would like to do this with R.
Input/output
Input sample: https://gist.github.com/hermanp/c01365b8f4931ea7ff9d1aee1cbbc391
Preferred output (indentation with two spaces):
- Info
- Python
- [The Ultimate Python Beginner's Handbook](https://www.freecodecamp.org/news/the-python-guide-for-beginners/)
- [Python Like You Mean It](https://www.pythonlikeyoumeanit.com/index.html)
- [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/)
- [Data science Python notebooks](https://github.com/donnemartin/data-science-ipython-notebooks)
- Frontend
- [CodePen](https://codepen.io/)
- [JavaScript](https://www.javascript.com/)
- [CSS-Tricks](https://css-tricks.com/)
- [Butterick’s Practical Typography](https://practicaltypography.com/)
- [Front-end Developer Handbook 2019](https://frontendmasters.com/books/front-end-handbook/2019/)
- [Using Ethics In Web Design](https://www.smashingmagazine.com/2018/03/using-ethics-in-web-design/)
- [Client-Side Web Development](https://info340.github.io/)
- [Stack Overflow](https://stackoverflow.com/)
- [HUP](https://hup.hu/)
- [Hope in Source](https://hopeinsource.com/)
Bonus preferred output: show favicons before links, like below (other suggestion welcomed, like loading them from the website's server instead of linking):
- ![https://cdn.sstatic.net/Sites/stackoverflow/Img/apple-touch-icon.png?v=c78bd457575a][Stack Overflow](https://stackoverflow.com/)
Attempt
generate_md <- function (file) {
# Encoding problem with tidyjson::read_json
bmarks_json_lite <- jsonlite::fromJSON(
txt = paste0("https://gist.githubusercontent.com/hermanp/",
"c01365b8f4931ea7ff9d1aee1cbbc391/raw/",
"33c21c88dad35145e2792b6258ede9c882c580ec/",
"bookmarks-example.json"))
# This is the start point, a data frame
level1 <- bmarks_json_lite$children$children[[2]]
# Get the name of the variable to modify it.
# Just felt that some abstraction needed.
varname <- deparse(substitute(level1))
varlevel <- as.integer(substr(varname, nchar(varname), nchar(varname)))
# Get through the data frame by its rows.
for (i in seq_len(nrow(get(varname)))) {
# If the type of the element in the row is "text/x-moz-place",
# then get its title and create a markdown list element from it.
if (get(varname)["type"][i] == "text/x-moz-place"){
# The two space indentation shall be multiplied as many times
# as deeply nested in the lists (minus one).
md_title <- paste0(strrep(" ", varlevel - 1),
"- ",
get(varname)["title"][i],
"\n")
# Otherwise do this and also get inside the next level.
} else if (get(varname)["type"][i] == "text/x-moz-place-container") {
md_title <- paste0(strrep(" ", varlevel - 1),
"- ",
get(varname)["title"][i],
"\n")
# I know this is not good, just want to express my thought.
# Create the next, deeper level's variable, whoose name shall
# represent the depth in the nest.
# Otherwise how can I multiply the indentation for the markdown
# list elements? It depends on the name of this variable.
varname <- paste0(regmatches(varname, regexpr("[[:alpha:]]+", varname)),
varlevel + 1L)
varlevel <- varlevel + 1L
assign(varname, get(varname)["children"][[i]])
# The same goes on as seen at the higher level.
for (j in seq_len(nrow(get(varname)))){
if (get(varname)["type"][i] == "text/x-moz-place"){
md_title <- paste0(strrep(" ", varlevel - 1),
"- ",
get(varname)["title"][i],
"\n")
} else if (get(varname)["type"][i] == "text/x-moz-place-container") {
md_title <- paste0(strrep(" ", varlevel - 1),
"- ",
get(varname)["title"][i],
"\n")
varname <- paste0(regmatches(varname, regexpr("[[:alpha:]]+", varname)),
varlevel + 1L)
varlevel <- varlevel + 1L
assign(varname, get(varname)["children"][[i]])
for (k in seq_len(nrow(get(varname)))){
# I don't know where this goes...
# Also I need to paste somewhere the md_title strings to get the
# final markdown output...
}
}
}
}
}
}
Question
How can I recursively grab and paste strings from this JSON file? I tried to search for tips in recursion, but it's quite a hard topic. Any suggestion, package, function, link will be welcomed!
I know you asked for a solution in R.
Just as a suggestion, here is a solution using jq, as it is very suitable for json transformations.
#!/bin/bash
BOOKMARKS='FirefoxBookmarks.json'
jq -r '
def bookmark($iconuri; $title; $uri):
if $iconuri != null then "![\($iconuri)]" else "" end +
"[\($title)](\($uri))";
def bookmarks:
(objects | to_entries[]
| if .value | type == "array" then (.value | bookmarks)
else .value end ) //
(arrays[] | [bookmarks] | " - \(.[0])", " \(.[1:][])" );
(.. | .children? | arrays)
|= map(if .uri != null then {bookmark: bookmark(.iconuri; .title; .uri)}
else {title} end +
{children})
| del(..| select(length == 0)) # remove empty children and empty titles
| del(..| select(length == 0)) # remove objects that got empty because of previous deletion
| del(..| objects | select(has("title") and (.children | length == 0))) # remove objects with title but no children
| .children # remove root level
| bookmarks
' < "$BOOKMARKS"
output:
- Könyvjelzők eszköztár
- Info
- Python
- ![fake-favicon-uri:https://www.freecodecamp.org/news/the-python-guide-for-beginners/][The Ultimate Python Beginner's Handbook](https://www.freecodecamp.org/news/the-python-guide-for-beginners/)
- [Python Like You Mean It](https://www.pythonlikeyoumeanit.com/index.html)
- [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/)
- ![https://github.githubassets.com/favicons/favicon.svg][Data science Python notebooks](https://github.com/donnemartin/data-science-ipython-notebooks)
- Frontend
- ![https://static.codepen.io/assets/favicon/favicon-touch-de50acbf5d634ec6791894eba4ba9cf490f709b3d742597c6fc4b734e6492a5a.png][CodePen](https://codepen.io/)
- ![https://www.javascript.com/etc/clientlibs/pluralsight/main/images/favicons/android-chrome-192x192.png][JavaScript](https://www.javascript.com/)
- ![https://css-tricks.com/apple-touch-icon.png][CSS-Tricks](https://css-tricks.com/)
- [Butterick’s Practical Typography](https://practicaltypography.com/)
- [Front-end Developer Handbook 2019](https://frontendmasters.com/books/front-end-handbook/2019/)
- ![https://www.smashingmagazine.com/images/favicon/app-icon-512x512.png][Using Ethics In Web Design](https://www.smashingmagazine.com/2018/03/using-ethics-in-web-design/)
- ![https://info340.github.io/img/busy-spider-icon.png][Client-Side Web Development](https://info340.github.io/)
- ![https://cdn.sstatic.net/Sites/stackoverflow/Img/apple-touch-icon.png?v=c78bd457575a][Stack Overflow](https://stackoverflow.com/)
- ![https://hup.hu/profiles/hupper/themes/hup_theme/favicon.ico][HUP](https://hup.hu/)
- [Hope in Source](https://hopeinsource.com/)
After I watched a few videos on recursion and saw a few code examples, I tried, manually stepped through the code and somehow managed to do it with recursion. This solution is independent on the nestedness of the bookmarks, therefore a generalized solution for everyone.
Note: all the bookmarks were in the Bookmarks Toolbar in Firefox. This is highlighted in the generate_md function. You can tackle with it there. If I improve the answer later, I will make it more general.
library(jsonlite)
# This function recursively converts the bookmark titles to unordered
# list items.
recursive_func <- function (level) {
md_result <- character()
# Iterate through the current data frame, which may have a children
# column nested with other data frames.
for (i in seq_len(nrow(level))) {
# If this element is a bookmark and not a folder, then grab
# the title and construct a list item from it.
if (level[i, "type"] == "text/x-moz-place"){
md_title <- level[i, "title"]
md_uri <- level[i, "uri"]
md_iconuri <- level[i, "iconuri"]
# Condition: the URLs all have schema (http or https) part.
# If not, filname will be a zero length character vector.
host_url <- regmatches(x = md_uri,
m = regexpr(pattern = "(?<=://)[[:alnum:].-]+",
text = md_uri,
perl = T))
md_link <- paste0("[", md_title, "]", "(", md_uri, ")")
md_listitem <- paste0("- ", md_link, "\n")
# If this element is a folder, then get into it, call this
# function over it. Insert two space (for indentation) in
# the generated sting before every list item. Paste this
# list of items to the folder list item.
} else if (level[i, "type"] == "text/x-moz-place-container") {
md_title <- level[i, "title"]
md_listitem <- paste0("- ", md_title, "\n")
md_recurs <- recursive_func(level = level[i, "children"][[1]])
md_recurs <- gsub("(?<!(\\w ))-(?= )", " -", md_recurs, perl = T)
md_listitem <- paste0(md_listitem, md_recurs)
}
# Collect and paste the list items of the current data frame.
md_result <- paste0(md_result, md_listitem)
}
# Return the (sub)list of the data frame.
return(md_result)
}
generate_md <- function (jsonfile) {
# Encoding problem with tidyjson::read_json
bmarks_json_lite <- fromJSON(txt = jsonfile)
# This is the start point, a data frame. It represents the
# elements inside the Bookmarks Toolbar in Firefox.
level1 <- bmarks_json_lite$children$children[[2]]
# Do not know how to make it prettier, but it works.
markdown_result <- recursive_func(level = level1)
return(markdown_result)
}
You can run the generate_md function with the example.
generate_md(paste0("https://gist.githubusercontent.com/hermanp/",
"c01365b8f4931ea7ff9d1aee1cbbc391/raw/",
"33c21c88dad35145e2792b6258ede9c882c580ec/",
"bookmarks-example.json"))
# Output
[1] "- Info\n - Python\n - [The Ultimate Python Beginner's Handbook](https://www.freecodecamp.org/news/the-python-guide-for-beginners/)\n - [Python Like You Mean It](https://www.pythonlikeyoumeanit.com/index.html)\n - [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/)\n - [Data science Python notebooks](https://github.com/donnemartin/data-science-ipython-notebooks)\n - Frontend\n - [CodePen](https://codepen.io/)\n - [JavaScript](https://www.javascript.com/)\n - [CSS-Tricks](https://css-tricks.com/)\n - [Butterick’s Practical Typography](https://practicaltypography.com/)\n - [Front-end Developer Handbook 2019](https://frontendmasters.com/books/front-end-handbook/2019/)\n - [Using Ethics In Web Design](https://www.smashingmagazine.com/2018/03/using-ethics-in-web-design/)\n - [Client-Side Web Development](https://info340.github.io/)\n - [Stack Overflow](https://stackoverflow.com/)\n - [HUP](https://hup.hu/)\n - [Hope in Source](https://hopeinsource.com/)\n"
You can cat it and write it to a file also with writeLines. But bevare! In Windows environments, you probably need to turn useBytes = TRUE to get the correct characters in the file. Reference: UTF-8 file output in R
cat(generate_md(paste0("https://gist.githubusercontent.com/hermanp/",
"c01365b8f4931ea7ff9d1aee1cbbc391/raw/",
"33c21c88dad35145e2792b6258ede9c882c580ec/",
"bookmarks-example.json")))
# Output
- Info
- Python
- [The Ultimate Python Beginner's Handbook](https://www.freecodecamp.org/news/the-python-guide-for-beginners/)
- [Python Like You Mean It](https://www.pythonlikeyoumeanit.com/index.html)
- [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/)
- [Data science Python notebooks](https://github.com/donnemartin/data-science-ipython-notebooks)
- Frontend
- [CodePen](https://codepen.io/)
- [JavaScript](https://www.javascript.com/)
- [CSS-Tricks](https://css-tricks.com/)
- [Butterick’s Practical Typography](https://practicaltypography.com/)
- [Front-end Developer Handbook 2019](https://frontendmasters.com/books/front-end-handbook/2019/)
- [Using Ethics In Web Design](https://www.smashingmagazine.com/2018/03/using-ethics-in-web-design/)
- [Client-Side Web Development](https://info340.github.io/)
- [Stack Overflow](https://stackoverflow.com/)
- [HUP](https://hup.hu/)
- [Hope in Source](https://hopeinsource.com/)
There was a problem with the regex part. If there are bookmarks with some - title (space, hyphen, space) characters in their titles, these hyphens will also be "indented" as the list items.
# Input JSON
https://gist.github.com/hermanp/381eaf9f2bf5f2b9cdf22f5295e73eb5
cat(generate_md(paste0("https://gist.githubusercontent.com/hermanp/",
"381eaf9f2bf5f2b9cdf22f5295e73eb5/raw/",
"76b74b2c3b5e34c2410e99a3f1b6ef06977b2ec7/",
"bookmarks-example-hyphen.json")))
# Output (two space indentation) markdown:
- Info
- Python
- [The Ultimate Python Beginner's Handbook](https://www.freecodecamp.org/news/the-python-guide-for-beginners/)
- [Python Like You Mean It](https://www.pythonlikeyoumeanit.com/index.html)
- [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/)
- [Data science Python notebooks](https://github.com/donnemartin/data-science-ipython-notebooks)
- Frontend
- [CodePen](https://codepen.io/)
- [JavaScript - Wikipedia](https://en.wikipedia.org/wiki/JavaScript) # correct
- [CSS-Tricks](https://css-tricks.com/)
- [Butterick’s Practical Typography](https://practicaltypography.com/)
- [Front-end Developer Handbook 2019](https://frontendmasters.com/books/front-end-handbook/2019/)
- [Using Ethics In Web Design](https://www.smashingmagazine.com/2018/03/using-ethics-in-web-design/)
- [Client-Side Web Development](https://info340.github.io/)
- [Stack Overflow](https://stackoverflow.com/)
- [HUP](https://hup.hu/)
- [Hope in Source](https://hopeinsource.com/)
I posted another question about this problem. After some hint and try I answered my own question.
I have an R script that retrieves CSV files from a daily email in my outlook and then depending whether the date in email subject is greater than a set date, moves them to a specific folder.
The code is splitting the subject line to extract the date - the position of which can be in one of two places in the string, due to recent changes.
I have an if statement built which can successfully locate the date within the string in either circumstance, but I can't then use a second if statement to see if the output from the first if statement is greater than the sample date.
Below is the code I am trying to execute (I have included data that can be reproduced):
# Test data
testLoop <- c("[EXTERNAL] Test Promo Sessions was executed at 28062019 100005",
"[EXTERNAL] Test Promo Sessions was executed at 29062019 100023",
"Test Promo Sessions was executed at 30062019 100007",
"Test Promo Sessions was executed at 01072019 100043",
"Test Promo Sessions was executed at 02072019 100049",
"Test Promo Sessions was executed at 03072019 100001")
# Example date
todaysDateFormatted2 <- '30062019'
# Loop
for(i in testLoop){
if(if(nchar(i) == 51){
strptime(sapply(strsplit(i, "\\s+"), "[", 7),"%d%m%Y")
} else {
strptime(sapply(strsplit(i, "\\s+"), "[", 8),"%d%m%Y")
} > strptime(todaysDateFormatted2,"%d%m%Y")){
print("greater than - move file")
} else {
print("not greater than - do nothing")
}
}
When attempting the execute this code, I get the following error, however I'm not sure how to interpret it:
[1] "not greater than - do nothing"
[1] "not greater than - do nothing"
Error in if (if (nchar(i) == 51) { :
argument is not interpretable as logical
In addition: Warning message:
In if (if (nchar(i) == 51) { :
the condition has length > 1 and only the first element will be used
There were several flaws in your code. The duplicated if was weird, and you strptime into nowhere if you don't assign it to something, below t. Also you may want to assign the else condition to t. Now you can compare t to todaysDateFormatted2 and print the result for each iteration.
for (i in testLoop) {
if (nchar(i) == 51) {
t <- strptime(sapply(strsplit(i, "\\s+"), "[", 7),"%d%m%Y")
} else {
t <- strptime(sapply(strsplit(i, "\\s+"), "[", 8),"%d%m%Y")
}
if (t > strptime(todaysDateFormatted2,"%d%m%Y")) {
print("greater than - move file")
} else {
print("not greater than - do nothing")
}
}
# [1] "not greater than - do nothing"
# [1] "not greater than - do nothing"
# [1] "not greater than - do nothing"
# [1] "greater than - move file"
# [1] "greater than - move file"
# [1] "greater than - move file"
The code in the OP fails because R does not consistently resolve the inner if() statement to a vector of length 1, which causes the outer if() to fail as described in the OP.
If the intent of the code is to decide whether to move a file based on the date in a file name, a simpler version of the code can accomplish what is desired. Here, we reduce the levels of nesting by using lapply() and saving the output from the original inner if() clause to an object. We then compare the saved object to the object representing today's date and write a message to the R log.
# Test data
testLoop <- c("[EXTERNAL] Test Promo Sessions was executed at 28062019 100005",
"[EXTERNAL] Test Promo Sessions was executed at 29062019 100023",
"Test Promo Sessions was executed at 30062019 100007",
"Test Promo Sessions was executed at 01072019 100043",
"Test Promo Sessions was executed at 02072019 100049",
"Test Promo Sessions was executed at 03072019 100001")
# Example date
todaysDateFormatted2 <- '30062019'
datesProcessed <- lapply(testLoop,function(x){
if(nchar(x) == 51) y <- strptime(sapply(strsplit(x, "\\s+"), "[", 7),"%d%m%Y")
else y <- strptime(sapply(strsplit(x, "\\s+"), "[", 8),"%d%m%Y")
if(y > strptime(todaysDateFormatted2,"%d%m%Y")) message("greater than - move file")
else message("not greater than - do nothing")
y
})
...and the output:
> datesProcessed <- lapply(testLoop,function(x){
+ if(nchar(x) == 51) y <- strptime(sapply(strsplit(x, "\\s+"), "[", 7),"%d%m%Y")
+ else y <- strptime(sapply(strsplit(x, "\\s+"), "[", 8),"%d%m%Y")
+ if(y > strptime(todaysDateFormatted2,"%d%m%Y")) message("greater than - move file")
+ else message("not greater than - do nothing")
+ y
+ })
not greater than - do nothing
not greater than - do nothing
not greater than - do nothing
greater than - move file
greater than - move file
greater than - move file
>
I'm new to R and have some trouble of understanding so called "envirionments" and way to use them properly. What I miss a lot in R language are static variables (like in Java).
I'm writing a program with couple of functions that will need to initialize during first run. To achieve this for each function I've created new environment which will be only accessed by this particular function (for example "f1" will be only accessed from inside "myfunction1").
What I don't like about my solution is that there is some additional code outside of function body and it's not too readable. Is there any simpler way to achieve the same? And if yes then it would be nice if you could provide me with modified example to show me how it works. Thank you.
f1 <- new.env()
f1$initialized <- FALSE
f1$o <- NULL
f1$length <- NULL
f1$compute
myfunction1 <- function(x) {
if(f1$initialized == FALSE){
f1$initialized <- TRUE
f1$compute <- 2*pi^2+3
}
if(is.null(f1$length) || f1$length!=length(x)){
f1$length <- length(x)
if(f1$length==2) {f1$o<-read.table("data_1.txt")}
else {f1$o<-read.table("data_2.txt")}
}
print("Lets print something!")
return(f1$o * f1$compute * x + 1000)
}
If you are familiar with Java then maybe using RefrenceClasses would be a good way to go. This seems to do what you are looking for:
myclass <- setRefClass('myclass', fields = list(initilized = 'logical',
o = 'data.frame',
len = 'numeric',
compute = 'numeric'))
#constructor
myclass$methods(initialize = function(initialized, len){
initilized <<- initialized
len <<- len
})
#method
myclass$methods(myfunction1 = function(x){
if(initilized == FALSE){
initilized <<- TRUE
compute <<- 2*pi^2+3
}
if(is.null(len) || len != length(x)){
len <<- length(x)
if(len==2) {o <<- read.table("data_1.txt")}
else {o <<- read.table("data_2.txt")}
}
print("Lets print something!")
return(o * compute * x + 1000)
})
obj <- myclass$new(FALSE, 0)
obj$myfunction1(2)
Check out ?ReferenceClasses for information on what's going on here (much more OOP styled and has some support for class inheritance, which sounds like what you want anyway).
Another follow up to this and this.
Actual question
Question 1
Upon running into some condition (say a simpleError), how can I invoke a respective restart handler that systematically tests a range of actual handler functions until one is found that does not result in another condition? If the last available handler has been tried, the default abortion restart handler should be invoked (invokeRestart("abort")). The implementation should allow for a flexible specification of the actual "handler suite" to use.
Question 2
I don't understand how a) the a test function that is specified alongside a restart handler works and b) where it would make sense to use it. Any suggestions? A short example would be great!
The help page of withRestarts says:
The most flexible form of a restart specification is as a list that can include several fields, including handler, description, and test. The test field should contain a function of one argument, a condition, that returns TRUE if the restart applies to the condition and FALSE if it does not; the default function returns TRUE for all conditions.
For those interested in more details
Below you'll find my first approach with respect to question 1, but I'm sure there's something much more cleaner/more straight-forward out there ;-)
foo <- function(x, y) x + y
fooHandled <- function(
x,
y,
warning=function(cond, ...) {
invokeRestart("warninghandler", cond=cond, ...)},
error=function(
cond,
handlers=list(
expr=expression(x+"b"),
expr=expression(x+"c"),
expr=expression(x+100)
),
...) {
invokeRestart("errorhandler", cond=cond, handlers=handlers, ...)
}
) {
expr <- expression(foo(x=x, y=y))
withRestarts(
withCallingHandlers(
expr=eval(expr),
warning=warning,
error=error
),
warninghandler=function(cond, ...) warning(cond),
errorhandler=function(cond, handlers, ...) {
idx <- 1
do.continue <- TRUE
while (do.continue) {
message(paste("handler:", idx))
expr <- handlers[[idx]]
out <- withRestarts(
tryCatch(
expr=eval(expr),
error=function(cond, ...) {
print(cond)
message("trying next handler ...")
return(cond)
}
)
)
idx <- idx + 1
do.continue <- inherits(out, "simpleError")
}
return(out)
}
)
}
> fooHandled(x=1, y=1)
[1] 2
> fooHandled(x=1, y="a")
handler: 1
<simpleError in x + "b": non-numeric argument to binary operator>
trying next handler ...
handler: 2
<simpleError in x + "c": non-numeric argument to binary operator>
trying next handler ...
handler: 3
[1] 101
EDIT
I'd also be interested in hearing how to substitute the tryCatch part with a withCallingHandlers part. Seems like withCallingHandlers() doesn't really return anything that could be picked up to determine the value of do.continue