Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I reference specific tags in the bibentry class using the [] or [[]] convention?

Tags:

r

I'm trying to grab the values of specific tags out of a bib file. Whenever I try and us either entry["bibtype"] or entry[["bibtype"]] I get an error, but entry$bibtype works fine.

entry<-bibentry(
  bibtype = "Manual",
  title = "R: A Language and Environment for Statistical Computing",
  author = person("R Development Core Team"),
  organization = "R Foundation for Statistical Computing",
  address = "Vienna, Austria",
  year = 2010,
  isbn = "3-900051-07-0",
  url = "http://www.R-project.org/")

# the first two fail
entry["bibtype"]
entry[["bibtype"]]
entry$bibtype

foo <- list("bar" = "baz")

#all of these work
foo["bar"]
foo[["bar"]]
foo$bar

The error I'm getting is:

Error in switch(attr(paper, "bibtype"), Article = formatArticle(paper),  : 
  EXPR must be a length 1 vector

Has anyone solved this? Anyway to coerce bibentries into accepting this?

like image 713
Jon Keane Avatar asked Mar 19 '12 05:03

Jon Keane


1 Answers

tl;dr

"bibtype" is not a named component in a "bibentry" object, instead it is implemented as an attribute. The $ method for these objects has made a special case to access the attribute if it is the "thing" selected, whereas the [ and [[ methods do not have this "feature".

Using rref as defined below

> attributes(unclass(rref)[[1]])$bibtype
[1] "Manual"
> attr(unclass(rref)[[1]], "bibtype")
[1] "Manual"

See the long version for a wider exposition


You want the attributes of the object but these do not appear accessible to the use via the usual methods, for example using the example from ?bibentry:

## R reference
rref <- bibentry(bibtype = "Manual",
        title = "R: A Language and Environment for Statistical Computing",
        author = person("R Development Core Team"),
        organization = "R Foundation for Statistical Computing",
        address = "Vienna, Austria",
        year = 2010,
        isbn = "3-900051-07-0",
        url = "http://www.R-project.org/")

we note the attribute "bibtype" in the output from str()

> str(rref)
Class 'bibentry'  hidden list of 1
 $ :List of 7
  ..$ title       : chr "R: A Language and Environment for Statistical Computing"
  ..$ author      :Class 'person'  hidden list of 1
  .. ..$ :List of 5
  .. .. ..$ given  : chr "R Development Core Team"
  .. .. ..$ family : NULL
  .. .. ..$ role   : NULL
  .. .. ..$ email  : NULL
  .. .. ..$ comment: NULL
  ..$ organization: chr "R Foundation for Statistical Computing"
  ..$ address     : chr "Vienna, Austria"
  ..$ year        : chr "2010"
  ..$ isbn        : chr "3-900051-07-0"
  ..$ url         : chr "http://www.R-project.org/"
  ..- attr(*, "bibtype")= chr "Manual"

but we aren't able to access that attribute

> attr(rref, "bibtype")
NULL
> attr(rref[[1]], "bibtype")
NULL

The first fails because as far as R is concerned, the way objects of class "bibentry" are implemented in R (or rather methods applied to them) attributes() nor attr() can see this particular attribute. The only attributes visible are:

> attributes(rref)
$class
[1] "bibentry"

> attributes(rref[1])
$class
[1] "bibentry"

If we unclass() rref, then we need to realise the object is a list with as many components as bibentries. In this case the rref is a list with a single component, that is an object of class `"bibentry", which is a list of 7 components.

One naively would presume you could do this:

attr(rref[[1]], "bibtype")

which would take the first "bibentry" object from rref (there is only one) and look for the attributes on that. This doesn't work:

> attributes(rref[[1]])
$class
[1] "bibentry"

because of the way methods for [ and [[ are implemented for "bibentry" objects:

> utils:::`[[.bibentry`
function (x, i) 
{
    rval <- unclass(x)[i]
    class(rval) <- class(x)
    rval
}
<bytecode: 0x1a75938>
<environment: namespace:utils>

[The single [ method is implemented exactly the same way.] This means you can do silly things like this:

> rref[[1]][[1]][[1]][[1]]
R Development Core Team (2010). _R: A Language and Environment for
Statistical Computing_. R Foundation for Statistical Computing, Vienna,
Austria. ISBN 3-900051-07-0, <URL: http://www.R-project.org/>.

which doesn't make any sense but all the [[1]] are just referring to the same object, each time. I don't know if this is intentional or not; ?bibentry has

Note:

     The bibentry functionality is still experimental.

but it is suboptimal.

For now, you need to follow the implementation in utils:::`[.bibentry` and unclass() the object and then start subsetting and access the attributes:

> attributes(unclass(rref)[[1]])
$names
[1] "title"        "author"       "organization" "address"      "year"        
[6] "isbn"         "url"         

$bibtype
[1] "Manual"

> attributes(unclass(rref)[[1]])$bibtype
[1] "Manual"
> attr(unclass(rref)[[1]], "bibtype")
[1] "Manual"

Contrast the implementation of the utils:::`$.bibentry` method with that for utils:::`[[.bibentry`:

> utils:::`$.bibentry`
function (x, name) 
{
    is_attribute <- name %in% bibentry_attribute_names
    rval <- if (is_attribute) 
        lapply(unclass(x), attr, name)
    else lapply(unclass(x), "[[", name)
    if (length(rval) == 1L) 
        rval <- rval[[1L]]
    rval
}
<bytecode: 0x1b0fd70>
<environment: namespace:utils>

This method has specifically been designed to work with attributes. This all does seem somewhat non-standard behaviour in R. That explains why

> rref$bibtype
[1] "Manual"

works but the (naively) essentially equivalent

> str(rref[["bibtype"]])
Class 'bibentry'  hidden list of 1
 $ : NULL

fails because there isn't a component named "bibtype" in the unclassed list, so that returns the NULL component, whilst the error occurs when printing:

> foo <- rref[["bibtype"]]
> foo
Error in switch(attr(paper, "bibtype"), Article = formatArticle(paper),  : 
  EXPR must be a length 1 vector
like image 180
Gavin Simpson Avatar answered Sep 21 '22 01:09

Gavin Simpson