-
Notifications
You must be signed in to change notification settings - Fork 1
Conversation
This function will call argufy() on all of the functions within a package. Current implementation should work for all functions including S4 generics and methods.
old <- .libPaths() | ||
.libPaths(temp_lib) | ||
on.exit(.libPaths(old)) | ||
tools:::.install_packages("TestS4") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this will go through CRAN. Btw. why is it better than install.packages
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CRAN doesn't check code in tests, but I agree it is not better than install.packages
, I forgot you could pass file paths to install.packages
.
Hmmm. I am not really sure about this, to be honest. My problem is that the functions with the assertions are broken, unless you run I was actually first considering another approach, where the assertions are in comments, and then the functions are never broken. E.g. f <- function(
x = 5, #: is.numeric
y = "foo", #: is.character
) {
...
} But then decided that code should be in code, not in comments.... |
Version: 0.0.0.9000 | ||
Authors@R: person("Jim", "Hester", email = "[email protected]", role = c("aut", "cre")) | ||
Description: What the package does (one paragraph). | ||
Depends: R (>= 3.3.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need R 3.3.0 for this? That is kinda bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, devtools::create()
just puts the current R version in there by default, definitely can use prior versions.
Let me think about it a bit. Or can you convince me that this is a good idea? :) |
My main motivation is simply convenience, rather than having to wrap every function call you use with This also makes it easier IMHO to argufy an existing package incrementally, just by adding the annotations to the function arguments you want to check (and the While it is true the functions are broken until argufy'd I generally develop using calls to I guess the nice thing is if you want to use f1 <- function(x = ~ is.character(x)) { x }
all.equal(argufy(f1), argufy(argufy(f1))) So you can be explicit where you would like, and lazy elsewhere. |
I don't have strong objections. It is really a pity that (seemingly) there is no syntax we could use, that is just ignored by R (except for comments, of course). I mean, there are some options, but all I could come up with was rather clumsy. |
How about this: f <- function(
x = assert_integer(10)),
y = as_character("foo"),
z
) {
x
} and then we define It is worse than an operator, though, imho, less readable. EDIT: or we could define our own iterator, like f <- function(
x = 10 %where% is.integer,
y = "foo" %via% as.character,
z
) {
x
} |
I guess you could use magrittr pipes for this then f <- function(
x = 10 %>% assert_integer,
y = 100 %>% as_character,
z
) {
x * y
} |
Yeah, see my edits. (Probably using the pipes is overkill, though, they do too much, we just need a simple operator or two.) This is actually not too bad. Now all we need is to find some nice name(s) instead of the EDIT: The operator is also nice, because then we can just use ordinary functions like |
We could actually use `:=` <- function(x, y) x
f <- function(
x = 10 := is.integer,
y = "foo" := as.character,
z
) {
x
} |
Yeah, I thought about that. My problem is that if you have no default values, then you need a new syntax. The tilde is a nice operator, because it is both binary and unary. How would you specify arguments with no default values with |
My idea was something like . <- quote(expr = )
`:=` <- function(x, y) x
f <- function(
x = . := is.integer,
y = "foo" := as_character,
z
) {
x
} but then this error message is a little hard to interpret: > f()
Error in `:=`(., is.integer) (from assert.R!16681L2F#1) : object '.' not found |
Also, |
This seems to work `.` = "__placeholder__"
`:=` <- function(x, y) if (x == "__placeholder__") quote(expr=) else x
f <- function(
x = . := is.integer,
y = "foo" := as_character,
z
) {
x
}
|
How about `?` <- function(x, y) x
f <- function(
x = ?! is.integer,
y = "foo" ?! as_character,
z
) {
y
}
f() This is both unary and binary, and probably not used in packages at all, so it would be OK to import our |
I think this is getting good. I like the We can go with or without the placeholder, maybe without is better. If with, then it probably needs to be something else than a dot. Packages using |
We can also have |
I like the |
Yeah, we can have any combinations of unary operators, possibly starting with I guess the question is which one is the most readable. It would be nice to have a way to read out the function definition, including the assertions. |
Btw. do you think the |
|
Thanks. Both Btw. There is a discussion with Stefan about merging |
That is true (although I have never heard anyone use argufy as a word before 😄) Re: merging with |
|
I'll rewrite the package with
I'll merge this PR, once ready. If you are suffering with |
Not really sure why the tests are failing on the CI's, they pass both with |
# these statements are needed to get S4 functions to work properly | ||
was_s4 <- isS4(fun) | ||
old_attributes <- attributes(fun) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw. I think it is nice to have independent changes like this and the next chunk in a separate commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this is not quite good, because attr(, "srcref")
is copied as well, and it is used for printing the (new) function. I am not entirely sure what to do with this, though. If we don't copy, then the new function will have no srcref
, which might be a problem sometimes, no? But we also do not want to reparse the function....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is true. In some respects the srcref
version is more useful interactively, because the function definition is not cluttered by the additional checking code (which will become a larger problem when inlining functions (#6)). On the other hand the printed function is not exactly what is called by R, which may make things confusing.
It is possible to view the real source with print(fun, useSource = FALSE)
even with the copied srcref.
The only downside to not having a srcref
at all is that you lose comments and formatting, because R then simply prints the parsed expressions, it shouldn't actually cause any errors anywhere though.
I personally would lean towards leaving the srcref copied as it is, but if you feel it is confusing simply dropping that attribute shouldn't cause any problems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the code can be printed easily then it is fine as it is now. I'll just add it to the docs. This confused me until I debugged argufy()
, because it did not seem to do anything. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed I was confused as well, easy way to see the real function definition
is body(fun)
or print(fun, useSource = FALSE)
On Tue, Aug 11, 2015 at 4:41 PM, Gábor Csárdi [email protected]
wrote:
In R/package.R
#5 (comment):@@ -50,6 +50,10 @@
argufy <- function(fun, ...) {
if (!is.function(fun)) stop("'fun' must be a function")
these statements are needed to get S4 functions to work properly
- was_s4 <- isS4(fun)
- old_attributes <- attributes(fun)
If the code can be printed easily then it is fine as it is now. I'll just
add it to the docs. This confused me until I debugged argufy(), because
it did not seem to do anything. :)—
Reply to this email directly or view it on GitHub
https://github.com/gaborcsardi/argufy/pull/5/files#r36795931.
OK, so apart from the CI failures, is this ready to be merged? Or you want to do sg else? |
I modified the tests per your suggestions, so this can be merged, unless we want to figure out the CI issues first. |
We can figure them out later, maybe we just need |
Add an argufy_package function
|
I think On Tue, Aug 11, 2015 at 5:00 PM, Gábor Csárdi [email protected]
|
OK, basically done, I'll write the tests in the evening and then merge. |
This function will call argufy() on all of the functions within a
package. Current implementation should work for all functions including
S4 generics and methods.
I added a simple test case, I should probably flesh out the documentation more as well. I wanted to get some feedback before going further.
Let me know if the implementation is unclear, I happy to change things if needed!