Many BibTeX::Entry objects of type :inbook, :incollection, and :inproceedings have empty fields that should be populated from their parents as determined by :crossref. So it would be nice to have a method in BibTeX::Entry to allow all fields undefined in one entry to be populated from those defined in another entry.
I am happy to have a go at implementing such a method myself, but I am a Ruby novice and suspect I wouldn't do a very good job. I also suspect something quite simple may be possible by employing the convert() methods, but I am not sure. Any thoughts?
You're right, it makes a lot of sense to support cross references; we'll try to include this in the upcoming 2.0 release due (hopefully) in a couple of weeks.
Needless to say, your help would be much appreciated. For example, the first thing we'll need is to define the expected behavior from a very high level of abstraction as a new cucumber feature: you could add a simple BibTeX file with a couple of cross references and describe what behavior you would expect (e.g., if there is no 'booktitle' set in an :incollection entry it should return the 'title' of the referenced element). Then we'll extract a feature specification from the examples and decide how to implement it.
It would be excellent to see this in 2.0. I'm writing a Nesta plugin to support citations and reference lists, and this will make handling cross-references simple. I'll have a go at writing a Cucumber feature and get back to you.
Pull request is here.
Here's a quick fix I'm using to do this until there's a method built into the class itself: https://gist.github.com/1225498
So what functionality should we support?
A BibTeX::Entry should
:title => :booktitle
What do you think?
removed duplicate fields (#22)
it should not be necessary to duplicate title/booktitle entries in the parent entry
added spec examples for crossrefs (#22)
I added example specs for the functionality described above (some are still pending); feel free to add additional examples and/or modify them!
implemented #crossref, #has_crossref and #referenced_by (#22)
added #reference and #referenced_by plus aliases (#22)
implemented resolution of referenced fields (#22)
I've implemented the functionality suggested above. (This should make your cucumber features pass). Could you review the changes and let me know if you have any suggestions and/or additions or simply add any functionality you still require.
If these changes implement all your requirements it would be awesome if you could briefly document the new features in the Readme with one or two usage examples.
Thanks for your very rapid implementation of this! Here are some initial thoughts on the methods you have suggested. I'll think more about what else might be useful and get back to you.
I've confirmed that your new commits make crossref.feature pass. (Though in order to see this, I have to move crossref.feature from features/issues to features before running cucumber).
Really? This is strange; if invoked without arguments, cucumber should pick-up all feature files in the feature directory. If you run
$ bundle exec cucumber
it ought to work. Which version of Ruby do you have installed?
Yes, that works. I was running cucumber crossref.feature, which I now understand is not the way to do it...
One thing to keep in mind is that, because the BibTeX field is called 'crossref', we have the standard accessor #crossref (or entry[:crossref]) that will return a BibTeX::Value which is more or less a string. Apart from that we need consistent naming for the functionality above.
It's definitely useful to distinguish between valid and missing cross references. At the moment #has_crossref? returns true only for valid cross references, so we could implement #has_invalid_crossref? straight away as
has_field?(:crossref) && !has_crossref?
But I'm not convinced 'invalid' is the best name. Perhaps something like #crossref_missing??
Good point about the 'reference' being misleading; I would prefer 'cross_reference' over 'crossref' although that involves slightly more typing (that's why I originally shortened it to reference). In Ruby, you should typically not use 'is_' for predicates (e.g., Object#nil? not Object#is_nil?) – this is beneficial when using other libraries, such as RSpec, and allows you to use automatic matchers, such as:
Having said that, how about these names:
Some of these methods become awfully long ;-)
We should add the populate/resolve methods to the Bibliography as well; furthermore, we should add an option to all export methods for whether or not to include the referenced fields.
I've given this a little more thought, and I share your worry that the names are getting too long. I do think "valid" is the right term though. So here is another proposal for the names to consider: instead of "crossreference" and "crossreferenced" we could simply use "parent" and "children". So, in the same order as your last comment, we could simplify to:
Your other suggestions are good ones. What do you think of these method names? Final call is of course yours!
I've mulled this over and arrived at similar conclusions; I'm not sure about the parent/child diction yet, but I think to focus more on viewing the field as 'inherited' makes a lot of sense. I'll refactor the names when I have the time and if these functions offer all the functionality you require, we're good to go. Thanks a lot for getting this into BibTeX-Ruby!
Alright, I've opted for a parallel solution; basically, you can use the parent/child names or the longer cross_reference version. Here's a quick summary:
Generally, using Array accessors  or the new alias #get on an Entry will return the field's value or try to resolve it through the parent (and the parent's aliases). You can use #inherits?(name) to check if a value is inherited (i.e., not defined locally and provided by the parent). I also threw in a #fetch(name, default) which works like Hash#fetch.
refactores crossref methods and names (#22)
Sounds good to me. Thanks again for your very quick implementation—looking forward to cleaning up Maldini to take account.
FYI, I've pushed a pre-release gem 2.0.0pre1 that includes crossref support. I'll have to take a look at Nesta and Maldini (looks very promising, plus two great players!)