On Jan 29, 2006, at 10:32 PM, Edward Summers wrote:
Bruce, I'm interested in helping out with this. I'm pretty familiar
with both ruby and python but I don't have a good grasp on what
exactly you want to do. Assuming the library existed could you flesh
out how it would be used programatically? This is how
test-driven-development often is of great help because it forces you
to think about the API you are building before you actually build it
:-)
Yeah, that's kind of how I was thinking about it. I'll see if I can
post something tomorrow, but briefly:
Read a CSL file and construct a CitationStyle object; something like:
citation_style_file = "some_file.csl"
csl = CiteProc::CitationStyle.new(citation_style_file)
This should be pretty simple, as both Python and Ruby have nice XML
libraries, and I've figured out the structure of that class.
===
class CitationStyle
# need to still add some accessor methods
attr_reader :title, :bibliography_item_layout
def initialize(title,
contact_name = nil,
contact_email = nil,
date_created = nil,
date_modified = nil,
sources = Hash.new,
names_config = Hash.new,
terms_config = Hash.new,
citation_et_al_rules = Hash.new,
citation_formatting = FormattingNode.new("citation"),
citation_item_layout = Array.new,
bibliography_sort_algorithm = 'author-date',
bibliography_et_al_rules = Hash.new,
bibliography_formatting =
FormattingNode.new("bibliography"),
bibliography_item_layout = ItemLayout.new)
@title = title
@contact_name = contact_email
@date_created = date_created
@date_modified = date_modified
@sources = sources
@names_config = names_config
@terms_config = terms_config
@citation_et_al_rules = citation_et_al_rules
@citation_formatting = citation_formatting
@citation_item_layout = citation_item_layout
@bibliography_sort_algorithm = bibliography_sort_algorithm
@bibliography_et_al_rules = bibliography_et_al_rules
@bibliography_formatting = bibliography_formatting
@bibliography_item_layout = bibliography_item_layout
end
end
class ItemLayout
attr_reader :csl_defs
def initialize(csl_defs = Array.new)
@csl_defs = csl_defs
end
end
class FormattingNode
attr_reader :name, :prefix, :suffix, :font_family, :font_style,
:font_weight
def initialize(name, prefix=nil, suffix=nil, font_family=nil,
font_style=nil, font_weight=nil)
@name = name
@prefix = prefix
@suffix = suffix
@font_family = font_family
@font_style = font_style
@font_weight = font_weight
end
end
===
Anyway, APIs and such ...
Initialize, and then format, a reference list:
reference_list = CiteProc::ReferenceList.new
reference_list.to_odf
... where the formatting in the to_odf method, for example, would be
determined by the CitationStyle object.
Likewise, the contents of the reference list object would be
constructed based on the document citations. Maybe something like:
document = "foo.xml"
citations = CiteProc::CitationList.new(document)
BTW, here's my current code for the ReferenceList class:
===
class ReferenceList
include Enumerable
def initialize
@references = []
end
def each
@references.each {|reference| yield reference}
end
def add(reference)
@references.push(reference)
end
def <<(reference)
@references << reference
end
# sort
def sort_criteria
[
lambda { |ref| ref.creator.each.join{|i| i.sortname} },
lambda { |ref| ref.year },
lambda { |ref| ref.title }
]
end
def sorted
@references.sort_by_multiple(*sort_criteria)
end
# group
def group_criteria
[lambda {|ref| ref.creator.each.join{|i| i.sortname}}, lambda
{|ref| ref.year}]
end
def grouped
sorted.group_by_multiple(*group_criteria)
end
# process
def processed
sort_algorithm = "author-year"
if sort_algorithm == "cited" then process_cited
else process_author_date
end
end
def process_cited
end
def process_author_date
processed = []
grouped.keys.sort.each do |creator|
by_creator = grouped[creator]
first_by_creator = true
year_suffix = "a"
by_creator.keys.sort.each do |year|
by_year = by_creator[year]
first_by_year = true
suffix = true if by_year.size > 1
by_year.each_with_index do |ref, index|
ref.bibparams[:first_by_creator] = first_by_creator
# create year suffix value where relevant
if suffix then
ref.bibparams[:suffix] = year_suffix.dup
end
year_suffix.succ!
first_by_creator = first_by_year = false
processed << ref
end
end
end
return processed
end
# format
def format
processed.each do |reference|
reference.format
end
end
end
===
The grouping and sorting stuff are extensions to the Enumerable module:
===
module Enumerable
def group_by(store=Hash.new)
self.each do |elem|
group = yield elem
(store[group] ||= []) << elem
end
store
end
def group_by_multiple(*criteria)
return self if criteria.empty?
self.group_by do |item|
criteria.first.call(item)
end.inject({}) do |result, (key, items)|
subgrouped = items.group_by_multiple(*criteria[1 .. -1])
result.merge(key => subgrouped)
end
end
def sort_by_multiple(*criteria)
self.sort_by do |item|
criteria.map do |criterium|
criterium.call(item)
end
end
end
end
===
More tomorrow; gotta go to bed.
Bruce
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]