Re: [dev-biblio] Re: porting citeproc; wanna help?
On Jan 29, 2006, at 11:03 PM, Bruce D'Arcus wrote: More tomorrow; gotta go to bed. Heh, doesn't look like you need much help from me for programming :-) Still, I think it bears repeating that looking at your library from the outside first might help in this design process. //Ed - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
On Jan 30, 2006, at 8:31 AM, Edward Summers wrote: Heh, doesn't look like you need much help from me for programming :-) Well, I did have help with some of the hard stuff. I had no clue how to do the grouping and sorting stuff for the author-date class! Still, I think it bears repeating that looking at your library from the outside first might help in this design process. So what would that look like? A series of class and method descriptions? Suggestions appreciated. I'm wondering, if that's the case, if it might make sense to do that alongside an analysis of the existing OOo equivalents. Bruce - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
OK, here's a simple unit test that passes: #! /usr/bin/env ruby require 'citeproc' require 'test/unit' class TestReference Test::Unit::TestCase include CiteProc def data [ { :creator = [Doe, Jane, Jane Doe], :title = Some title, :year = 1999, :type = book } ] end def test_load data.each do |reference| t = reference[:title] y = reference[:year] ty = reference[:type] au = reference[:creator].each{|a| Person.new(a[0], a[1])} Reference.new(title=t, creator=au, year=y, type=ty) end end end I still need to wrap my head around this (particularly exactly what kinds of methods to create tests for), but I guess the idea is to create a file full of this sort of stuff? Bruce - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
On 1/30/06, Bruce D'Arcus [EMAIL PROTECTED] wrote: I still need to wrap my head around this (particularly exactly what kinds of methods to create tests for), but I guess the idea is to create a file full of this sort of stuff? Yep, write tests for the code that doesn't exist and run them and watch them fail. Then start filling in the code until you can get tests to start passing. When all the tests pass you're done! //Ed - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
On Jan 30, 2006, at 12:08 PM, Ed Summers wrote: Yep, write tests for the code that doesn't exist and run them and watch them fail. Then start filling in the code until you can get tests to start passing. When all the tests pass you're done! Yes, but how find-grained do you get? Take a method like format for ReferenceList. That involves calling a series of other methods. So do I just write for that one, and we fill in the code until that works? Or write one for each step of the way? The latter would take a long time. Bruce - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
You typically want to test how a user will want to use your library. You don't want to write tests for internal stuff. If there are a sequence of interpendent events that need to be tested I tend to bundle them in an individual test method. Testing does take time. When you first start writing them it feels like wasted time. But I've found it's an invaluable tool for figuring out what your API should look like before you start making it...and more importantly they serve as a safety net as you refactor stuff later on. It's very liberating to have a nice test suite that allows you to go in and monkey with internals, and then run the test suite afterwards to reassure yourself that things are working properly. I guess I'm starting to sound religious about this. I'm not a disciple of extreme programming, but I do think testing is one of the best things to come out of that methodology. //Ed - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
On 1/30/06, Ed Summers [EMAIL PROTECTED] wrote: You typically want to test how a user will want to use your library. You don't want to write tests for internal stuff. If there are a sequence of interpendent events that need to be tested I tend to bundle them in an individual test method. That makes sense. So here's the classes and test methods I'm thinking of as a start then (this for Ruby,but it's close to Python): Reference new author_names to_s (could test output against test input data) ReferenceList === new (load data based on list of citations) add to_s CitationStyle == new (load external CSL file and create object) info (print metadata) I'm still not sure about the citations per se. Would that be a good start? After playing with this a bit, I realize I was doing this testing informally, so it's nice to be shown the light! Bruce - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
On Jan 30, 2006, at 5:35 PM, Bruce D'Arcus wrote: CitationStyle == new (load external CSL file and create object) OK, here's a start; sorry, just easier for me to think in Ruby. Feel free to jump in and translate to Python if you want. I'm posting this step by step just to make sure I'm on the right track. #! /usr/bin/env ruby require 'citeproc' require 'rubygems' require_gem 'xml-simple' require 'test/unit' class TestCitationStyle Test::Unit::TestCase include CiteProc def csl_file # for Python, I think elementtree would be appropriate (?) XmlSimple.xml_in(File.open(../test/apa-en.csl)) end def test_load assert_not_nil(csl_file) end def test_build_object csl = CitationStyle.new(csl_file) # the only reason this one passes is because it's default assert(csl.bibliography_sort_algorithm == author-date) # this fails because there is no code yet to construct the object # from the XML assert(csl.title == APA) # check if bib layout array is correctly built assert(csl.bibliography_item_layout[book][2].key == title) end end - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
On Jan 28, 2006, at 10:08 AM, Bruce D'Arcus wrote: On Jan 28, 2006, at 10:43 AM, Bruce D'Arcus wrote: I really don't care whether it's Python or Ruby, since both are object-oriented, and both are easy to read. At any rate, ultimately I'd like to see both citeproc-rb (think a module that could be included trivially in rails apps for example), AND citeproc-py (think integrating citation processing into, oh, textile processing). I don't care much how we get there though ;-) Also, obviously c++ or obj-c would be good, but it seems like the dynamic languages would be better for quick coding, and code that can be a good blue-print for other implementations. 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 :-) //Ed - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
I agree that test-driven development will help a lot here.One starting point would be tests that show you can load data into some object from the RDF serialization suggested by Bruce then re-serialize it back out. Trivial to implement at first, but needs to be there as more code gets built. Bruce, you certainly have the skills to write unit tests that show how the objects should behave, and hope that others can help fill in the code. Ed - do you have test frameworks in mind for Python / Ruby? (I know there are a couple of options in Python - I've used py.test but not others)On 1/30/06, Edward Summers [EMAIL PROTECTED] wrote: On Jan 28, 2006, at 10:08 AM, Bruce D'Arcus wrote: On Jan 28, 2006, at 10:43 AM, Bruce D'Arcus wrote: I really don't care whether it's Python or Ruby, since both are object-oriented, and both are easy to read. At any rate, ultimately I'd like to see both citeproc-rb (think a module that could be included trivially in rails apps for example), AND citeproc-py (think integrating citation processing into, oh, textile processing). I don't care much how we get there though ;-) Also, obviously c++ or obj-c would be good, but it seems like the dynamic languages would be better for quick coding, and code that can be a good blue-print for other implementations.Bruce, I'm interested in helping out with this. I'm pretty familiarwith both ruby and python but I don't have a good grasp on whatexactly 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 thinkabout the API you are building before you actually build it :-)//Ed -To unsubscribe, e-mail: [EMAIL PROTECTED]For additional commands, e-mail: [EMAIL PROTECTED]-- Peter (pt) SeftonToowoomba 4350Queensland, AustraliaPhone: +61 4 1032 6955 Web: http://ptsefton.comEmail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
On Jan 29, 2006, at 9:52 PM, pt wrote: I agree that test-driven development will help a lot here. One starting point would be tests that show you can load data into some object from the RDF serialization suggested by Bruce then re- serialize it back out. Trivial to implement at first, but needs to be there as more code gets built. Bruce, you certainly have the skills to write unit tests that show how the objects should behave, and hope that others can help fill in the code. Ed - do you have test frameworks in mind for Python / Ruby? (I know there are a couple of options in Python - I've used py.test but not others) I've used a few different ones, but since I'm in ruby, python and java pretty frequently I've found myself using unittest, Test::Unit and junit since they all follow the same xunit pattern. py.test might be the simplest way to move forward though. I saw Ian Bicking talk [1] about py.test at a local python meeting and was pretty impressed with its simplicity. I'm psyched you agree pt :-) Defining a set of tests that illustrate how to use the API might be a good way for us to visualize how the library could be used, and for us to measure our success as the library gets fleshed out. //Ed [1] http://ianbicking.org/docs/pytest-presentation/pytest-slides.html - To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
Re: [dev-biblio] Re: porting citeproc; wanna help?
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