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]

Reply via email to