├── .ruby-version ├── docs ├── css │ ├── common.css │ └── full_list.css ├── frames.html ├── file_list.html ├── MuseumProvenance │ ├── Certainty.html │ ├── Parsers │ │ ├── ProvenanceHelpers.html │ │ ├── DateParser.html │ │ ├── CertaintyTransform.html │ │ ├── DateStringParser.html │ │ ├── NoteSectionParser.html │ │ ├── NotesParser.html │ │ ├── PlaceParser.html │ │ ├── NamedEventParser.html │ │ ├── AuthorityParser.html │ │ └── SaleDataParser.html │ ├── Utilities.html │ ├── DateError.html │ ├── Transformers │ │ ├── PurchaseTransform.html │ │ ├── CertaintyTransform.html │ │ ├── AcquisitionTransform.html │ │ ├── TransferModeTransform.html │ │ └── AuthorityTransform.html │ ├── Transformers.html │ ├── Parsers.html │ └── Location.html ├── top-level-namespace.html └── Fixnum.html ├── Gemfile ├── lib ├── museum_provenance │ ├── version.rb │ ├── transformers │ │ ├── transfer_mode_tranform.rb │ │ ├── certainty_transform.rb │ │ ├── purchase_transform.rb │ │ ├── acquisition_transform.rb │ │ ├── note_insertion_transform.rb │ │ ├── paragraph_transform.rb │ │ ├── authority_transform.rb │ │ └── token_transform.rb │ ├── parsers │ │ ├── provenance_helpers.rb │ │ ├── place_parser.rb │ │ ├── acquisition_method_parser.rb │ │ ├── note_section_parser.rb │ │ ├── notes_parser.rb │ │ ├── authority_parser.rb │ │ ├── named_event_parser.rb │ │ ├── sale_data_parser.rb │ │ ├── paragraph_parser.rb │ │ ├── parser_helpers.rb │ │ └── actor_parser.rb │ ├── location.rb │ ├── party.rb │ ├── utilities │ │ └── to_bool.rb │ ├── entity.rb │ ├── period_output.rb │ ├── parser.rb │ ├── certainty.rb │ ├── fuzzy_date.rb │ └── acquisition_method.rb └── museum_provenance.rb ├── .gitignore ├── test ├── test_helper.rb ├── export_test.rb ├── transformers │ └── paragraph_transformer_test.rb ├── parsers │ ├── place_parser_test.rb │ ├── authority_parser_test.rb │ ├── named_event_parser_test.rb │ ├── note_section_parser_test.rb │ ├── notes_parser_test.rb │ ├── parser_test.rb │ ├── sale_data_parser_test.rb │ ├── actor_parser_test.rb │ └── paragraph_parser_test.rb └── acquisition_method_test.rb ├── old_tests ├── party_test.rb ├── provenance_json_test.rb ├── name_lookup_test.rb ├── period_output_test.rb ├── provenance_export_test.rb ├── more_specific_date_test.rb ├── time_span_test.rb └── timeline_test.rb ├── LICENSE.txt ├── Rakefile ├── museum_provenance.gemspec ├── TODO.md └── WORKING_NOTES.md /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.1 2 | -------------------------------------------------------------------------------- /docs/css/common.css: -------------------------------------------------------------------------------- 1 | /* Override this file with custom rules */ -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in museum_provenance.gemspec 4 | gemspec 5 | 6 | -------------------------------------------------------------------------------- /lib/museum_provenance/version.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | # Version number for this gem 3 | VERSION = "0.2.0.alpha" 4 | end 5 | -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/transfer_mode_tranform.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | module Transformers 3 | class TransferModeTransform < Parslet::Transform 4 | rule(:transfer_punctuation => simple(:x)) { x == ";"} 5 | end 6 | end 7 | end -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | .yardopts 7 | Gemfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.bundle 19 | *.so 20 | *.o 21 | *.a 22 | mkmf.log 23 | -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/certainty_transform.rb: -------------------------------------------------------------------------------- 1 | 2 | module MuseumProvenance 3 | module Transformers 4 | class CertaintyTransform < Parslet::Transform 5 | rule(:certainty_value => simple(:x)) { x != "?"} 6 | rule(:period_certainty_value => simple(:x)) { x.length == 0} 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/provenance_helpers.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | module Parsers 3 | module ProvenanceHelpers 4 | include Parslet 5 | 6 | rule (:ownership_start) { str("for") >> space } 7 | rule (:event_location_start) { str("in") >> space } 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/museum_provenance/location.rb: -------------------------------------------------------------------------------- 1 | require_relative "entity.rb" 2 | module MuseumProvenance 3 | # {Location} is a data structure for holding the location of a {Period}. 4 | # Currently, it does not have any functionality beyond that of a generic {Entity} 5 | # but it is intended be extended to include geographical functionality. 6 | class Location < Entity 7 | end 8 | end -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/spec' 2 | require 'minitest/autorun' 3 | require "minitest/pride" 4 | require "rake/testtask" 5 | 6 | $VERBOSE=nil 7 | 8 | require_relative '../lib/museum_provenance' 9 | 10 | include MuseumProvenance 11 | 12 | Rake::TestTask.new do |t| 13 | t.libs << "test" 14 | t.test_files = FileList['test/*_test.rb'] 15 | t.verbose = false 16 | t.warning = false 17 | end -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/purchase_transform.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | module Transformers 3 | class PurchaseTransform < Parslet::Transform 4 | rule(:value => simple(:val), :currency_symbol => simple(:cur)) do |dict| 5 | amt = dict[:val].to_s.gsub(",","") 6 | xamt= amt.gsub("M", "000000") 7 | {:value => amt, :currency_symbol => dict[:cur]} 8 | end 9 | end 10 | end 11 | end -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/acquisition_transform.rb: -------------------------------------------------------------------------------- 1 | require_relative "../acquisition_method" 2 | require_relative "../acquisition_method_list" 3 | module MuseumProvenance 4 | module Transformers 5 | class AcquisitionTransform < Parslet::Transform 6 | rule(:acquisition_method_string => simple(:x)) do 7 | str = AcquisitionMethod.find(x.to_s)&.id 8 | str ? "acq:#{str}" : nil 9 | end 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /docs/frames.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Documentation by YARD 0.9.8 6 | 7 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/note_insertion_transform.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | module Transformers 3 | class NoteInsertionTransform < Parslet::Transform 4 | def initialize(notes,citations) 5 | super() 6 | rule(:footnote_key => simple(:key)) do |dict| 7 | notes.find{|n| n[:key] == dict[:key]}[:string] 8 | end 9 | rule(:citation_key => simple(:key)) do |dict| 10 | citations.find{|n| n[:key] == dict[:key]}[:string] 11 | end 12 | end 13 | end 14 | end 15 | end -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/paragraph_transform.rb: -------------------------------------------------------------------------------- 1 | Dir["#{File.dirname(__FILE__)}/*.rb"].sort.each { |f| require_relative(f)} 2 | require "cultural_dates" 3 | 4 | module MuseumProvenance 5 | module Transformers 6 | class ParagraphTransform 7 | def apply(obj) 8 | obj = TransferModeTransform.new.apply(obj) 9 | obj = CertaintyTransform.new.apply(obj) 10 | obj = CulturalDates::DateTransform.new.apply(obj) 11 | obj = AcquisitionTransform.new.apply(obj) 12 | obj = PurchaseTransform.new.apply(obj) 13 | 14 | return obj 15 | end 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /test/export_test.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | describe "Provenance Files" do 4 | 5 | it "handles all existing files" do 6 | skip "Provenances need to be updated with the new acquisition methods" 7 | f = File.open( "#{File.dirname(__FILE__)}/sample_data/prov.txt", "r" ) 8 | f.each_line.with_index do |line,i| 9 | next if i % 2 == 0 10 | provenance = line 11 | prov = MuseumProvenance::Provenance.extract(provenance) 12 | prov.provenance.strip.must_equal provenance.strip 13 | prov.each do |line| 14 | line.parsable?.must_equal true 15 | end 16 | end 17 | end 18 | end -------------------------------------------------------------------------------- /lib/museum_provenance.rb: -------------------------------------------------------------------------------- 1 | require "museum_provenance/version" 2 | 3 | # Load dependent files 4 | require 'date' 5 | require 'parslet' 6 | require 'parslet/convenience' 7 | 8 | require 'active_support/core_ext/integer/inflections' 9 | 10 | 11 | require_relative "museum_provenance/certainty.rb" 12 | dev_only_dependencies = ["acquisition_method_documentation.rb"] 13 | 14 | Dir["#{File.dirname(__FILE__)}/museum_provenance/**/*.rb"].sort.each { |f| require(f) unless dev_only_dependencies.include?(File.basename(f))} 15 | 16 | # MuseumProvenance is a general-purpose library for cultural institutions 17 | # @todo Write this, please. 18 | module MuseumProvenance 19 | end 20 | -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/authority_transform.rb: -------------------------------------------------------------------------------- 1 | 2 | module MuseumProvenance 3 | module Transformers 4 | class AuthorityTransform < Parslet::Transform 5 | def self.reset_counter 6 | @@counter = 0 7 | end 8 | 9 | @@counter = 0 10 | rule(:string => simple(:string), :uri => simple(:uri)) do |dict| 11 | uri = dict[:uri].to_s.downcase.include?("no record found") ? nil : dict[:uri].to_s 12 | @@counter +=1 13 | @@counter = 1 if @@counter > 999999 14 | { 15 | token: "$AUTHORITY_TOKEN_#{@@counter}", 16 | string: dict[:string].to_s, 17 | uri: uri 18 | } 19 | end 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/place_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | 3 | module MuseumProvenance 4 | module Parsers 5 | # 6 | # This parser will parse a Actor entity block, for example: 7 | # > John Doe? [1910?-1995?], Boise, ID 8 | # 9 | # If it parses, it can return: 10 | # 11 | # * :stock_number # The text of the stock number phrase 12 | # 13 | # @author [@workergnome] 14 | # 15 | class PlaceParser < Parslet::Parser 16 | 17 | include ParserHelpers 18 | include Parslet 19 | root(:place) 20 | 21 | rule(:place) do 22 | ((( capitalized_word_phrase).as(:string) | captal_word.as(:string) | token.as(:token)) >> certainty).as(:place) 23 | end 24 | 25 | 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /old_tests/party_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | describe Party do 3 | 4 | let(:p) {Party.new("Roberta")} 5 | it "accepts a birth year" do 6 | p.birth = Date.new(1990) 7 | p.birth.must_equal Date.new(1990) 8 | end 9 | it "accepts a birth year" do 10 | p.death = Date.new(1990) 11 | p.death.must_equal Date.new(1990) 12 | end 13 | it "generates proper strings for birth and death" do 14 | p.birth = Date.new(1980) 15 | p.death = Date.new(1990) 16 | p.name_with_birth_death.must_equal "Roberta [1980-1990]" 17 | end 18 | it "generates proper strings without birth and death" do 19 | p.name_with_birth_death.must_equal "Roberta" 20 | end 21 | it "generates proper strings with death" do 22 | p.death = Date.new(1990) 23 | p.name_with_birth_death.must_equal "Roberta [-1990]" 24 | end 25 | it "generates proper strings with birth" do 26 | p.birth = Date.new(1980) 27 | p.name_with_birth_death.must_equal "Roberta [1980-]" 28 | end 29 | 30 | end -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/acquisition_method_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | 3 | module MuseumProvenance 4 | module Parsers 5 | class AcquisitionMethodParser < Parslet::Parser 6 | include Parslet 7 | include ParserHelpers 8 | 9 | def initialize(acq_methods) 10 | @acquisition_methods = acq_methods 11 | end 12 | 13 | def preferred_form 14 | all_forms = @acquisition_methods.collect do |m| 15 | str = String.new(m.preferred) 16 | str[0] = str[0].upcase if str[0] 17 | [m.preferred, str] 18 | end.compact.flatten 19 | all_forms = all_forms.sort_by{|t| t.length}.reverse 20 | 21 | (all_forms.reduce(false) do |parslet,val| 22 | parslet ? parslet | str(val).as(:acquisition_method_string) : str(val).as(:acquisition_method_string) 23 | end).as(:acquisition_method) 24 | end 25 | 26 | rule (:acquisition_method) {preferred_form >> space} 27 | 28 | root :acquisition_method 29 | 30 | 31 | end 32 | end 33 | end -------------------------------------------------------------------------------- /old_tests/provenance_json_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | 3 | describe "Provenance Records from JSON" do 4 | 5 | it "incepts" do 6 | @record_text = "Possibly purchased by David? [1950-2014?], Belgrade, by October 1990 until at least January 5, 2000, stock no. 1" 7 | @prov_text = "#{@record_text} [1]; another record. 1. I am a footnote." 8 | @timeline = Provenance.extract @prov_text 9 | @json = @timeline.to_json 10 | @computed_timeline = Provenance.from_json(@json) 11 | @computed_timeline.provenance.must_equal @timeline.provenance 12 | end 13 | it "handles the sample records" do 14 | f = File.open( "#{File.dirname(__FILE__)}/sample_data/prov.txt", "r" ) 15 | f.each_line.with_index do |line,i| 16 | next if i % 2 == 0 17 | provenance = line 18 | prov = MuseumProvenance::Provenance.extract(provenance) 19 | # puts "" 20 | # puts prov.to_json 21 | # puts "" 22 | reprov = Provenance.from_json(prov.to_json) 23 | prov.provenance.must_equal reprov.provenance 24 | end 25 | end 26 | end -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/note_section_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | 3 | module MuseumProvenance 4 | module Parsers 5 | # 6 | # This parser will parse a Citation or Note block, for example: 7 | # > [b]. C.L. Sulzberger, A Long Row of Candles, Macmillan, 1969, p. 8. 8 | # or 9 | # > [1]. Purchased for his daughter's birthday. 10 | 11 | # 12 | # If it parses, it will return an array of :notes 13 | # 14 | # * :note_id # The index letter or number 15 | # * :note_text # The text of the note 16 | # 17 | # @author [@workergnome] 18 | # 19 | class NoteSectionParser < Parslet::Parser 20 | 21 | include ParserHelpers 22 | include Parslet 23 | 24 | rule(:mark) {str("[") >> match["A-Za-z0-9"].repeat(1).as(:key) >> str("].")} 25 | rule(:text) {(str("\n").absent? >> any).repeat(1).as(:string) } 26 | rule(:note) {str("\n").repeat >> mark >> space >> text} 27 | rule(:notes) {note.repeat.as(:notes) >> str("\n").repeat} 28 | root(:notes) 29 | 30 | end 31 | end 32 | end -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/notes_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | 3 | module MuseumProvenance 4 | module Parsers 5 | # 6 | # This parser will parse a Actor entity block, for example: 7 | # > John Doe? [1910?-1995?], Boise, ID 8 | # 9 | # If it parses, it can return: 10 | # 11 | # * :stock_number # The text of the stock number phrase 12 | # 13 | # @author [@workergnome] 14 | # 15 | class NotesParser < Parslet::Parser 16 | include ParserHelpers 17 | include Parslet 18 | 19 | root(:notes) 20 | 21 | rule(:footnote) {str("[") >> (match["1-9"] >> match["0-9"].repeat).as(:footnote_key).as(:footnote) >> str("]")} 22 | 23 | rule(:citation) {(str("[") >> match["1-9"]).absent? >> str("[") >> match["A-Za-z"].repeat(1).as(:citation_key) >> str("]")} 24 | 25 | rule(:notes) do 26 | (footnote >> citation.repeat(1).as(:citations)) | 27 | (citation.repeat(1).as(:citations) >> footnote) | 28 | footnote | 29 | citation.repeat(1).as(:citations) 30 | end 31 | 32 | end 33 | end 34 | end -------------------------------------------------------------------------------- /lib/museum_provenance/party.rb: -------------------------------------------------------------------------------- 1 | require_relative "entity.rb" 2 | module MuseumProvenance 3 | # {Party} is a data structure for holding the associated information about the relevant party of a {Period}. 4 | # A Party is usually a person or organization that is involved with an artwork. 5 | # It extends {Entity} with birth and death information, 6 | # and is intended be extended to include name lookup and biographical functionality. 7 | class Party < Entity 8 | # @!attribute birth 9 | # @return [Date] The birth date of the party 10 | # @!attribute death 11 | # @return [Date] The death date of the party 12 | attr_accessor :birth, :death 13 | 14 | # @example 15 | # Party.new("Linda") 16 | # linda.birth = Date.new(1975) 17 | # linda.name_with_birth_death # "Linda [1975-]" 18 | # @return [String] The name of the party with birth and death dates appended. 19 | def name_with_birth_death 20 | if birth || death 21 | self.to_s + " [#{birth.to_s(:long) rescue ""}-#{death.to_s(:long) rescue ""}]" 22 | else 23 | self.to_s 24 | end 25 | end 26 | end 27 | end -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/authority_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | 3 | module MuseumProvenance 4 | module Parsers 5 | # 6 | # This parser will parse a Authority block, for example: 7 | # > Salvador Dali: http://vocab.getty.edu/ulan/500009365 8 | # > Cyrus L. Sulzberger: http://viaf.org/viaf/68936177 9 | # 10 | # If it parses, it will return an array of :authorities: 11 | # 12 | # * :token # The name of the entity 13 | # * :uri # The URI represented 14 | # 15 | # @author [@workergnome] 16 | # 17 | class AuthorityParser < Parslet::Parser 18 | 19 | include ParserHelpers 20 | include Parslet 21 | 22 | rule(:entity_name) {(str(":").absent? >> any).repeat(1).as(:string) >> str(":")} 23 | rule(:uri) {(str("\n").absent? >> any).repeat(1).as(:uri) >> str("\n").maybe } 24 | rule(:authority) {str("\n").repeat >> entity_name >> space >> uri} 25 | rule(:authorities) {authority.repeat.as(:authorities)>> str("\n").repeat} 26 | 27 | root(:authorities) 28 | 29 | end 30 | end 31 | end -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Carnegie Museum of Art 2 | MIT License 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/named_event_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | require_relative "actor_parser" 3 | 4 | module MuseumProvenance 5 | module Parsers 6 | # 7 | # This parser will parse a Named Event entity block, for example: 8 | # > John Doe? [1910?-1995?], Boise, ID 9 | # 10 | # If it parses, it can return: 11 | # 12 | # * :stock_number # The text of the stock number phrase 13 | # 14 | # @author [@workergnome] 15 | # 16 | class NamedEventParser < Parslet::Parser 17 | 18 | include ParserHelpers 19 | include Parslet 20 | root(:named_event) 21 | 22 | rule(:event) {(str("\"") >> ((word_phrase.as(:string) | token.as(:token)) >> certainty).as(:event) >> str("\""))} 23 | rule(:sellers_agent) {ActorParser.new.as(:sellers_agent)} 24 | 25 | rule(:both) {event >> comma >> sellers_agent} 26 | 27 | rule (:named_event) do 28 | (str("from") >> space >> (both | event | sellers_agent)) | 29 | (str("through") >> space >> sellers_agent >> ( (space | comma) >> str("from") >> space >> event).maybe) 30 | end 31 | 32 | 33 | end 34 | end 35 | end -------------------------------------------------------------------------------- /lib/museum_provenance/transformers/token_transform.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | module Transformers 3 | class TokenTransform < Parslet::Transform 4 | def initialize(tokens) 5 | super() 6 | 7 | # Replace tokens in parsed periods 8 | rule(:token => simple(:token), :certainty => simple(:certainty)) do |dict| 9 | token = tokens.find{|t| t[:token].to_s == dict[:token].to_s} 10 | { 11 | token: dict[:token], 12 | string: token[:string], 13 | uri: token[:uri], 14 | certainty: dict[:certainty] 15 | } 16 | end 17 | 18 | # Replace tokens in unparsable periods, 19 | # while maintaining the transfer directness 20 | rule(:unparsable => simple(:str), :direct_transfer=>simple(:transfer), :text=> simple(:text)) do |dict| 21 | str = dict[:str].clone.to_s 22 | 23 | tokens.each {|token| str.gsub!(token[:token], token[:string])} 24 | { 25 | :unparsable => str, 26 | :text => dict[:text], 27 | :direct_transfer => dict[:transfer] 28 | } 29 | end 30 | 31 | end 32 | end 33 | end 34 | end -------------------------------------------------------------------------------- /old_tests/name_lookup_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | 3 | describe Entity do 4 | 5 | let(:p) {Entity.new("David N.")} 6 | it "has a name" do 7 | p.name.must_equal "David N." 8 | end 9 | it "is certain by default" do 10 | p.certain?.must_equal true 11 | end 12 | it "allows uncertainty to be set" do 13 | p.certainty = false 14 | p.certain?.must_equal false 15 | end 16 | it "uses the name as a string" do 17 | p.to_s.must_equal "David N." 18 | end 19 | it "appends certainty to the name" do 20 | p.certainty = false 21 | p.to_s.must_equal "David N.?" 22 | end 23 | it "does not fail on nils" do 24 | n = Entity.new(nil) 25 | n.must_be_instance_of Entity 26 | n.name.must_be_nil 27 | end 28 | it "allows access to the raw name" do 29 | p.certainty = false 30 | p.name.must_equal "David N." 31 | end 32 | it "automatically determines certainty from strings" do 33 | p2 = Entity.new("Uncertain name?") 34 | p2.certain?.must_equal false 35 | end 36 | it "strips uncertainty from strings" do 37 | Entity::CertantyWords.each do |w| 38 | p2 = Entity.new("#{w} Uncertain name") 39 | p2.name.must_equal "Uncertain name" 40 | end 41 | end 42 | 43 | end -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require 'rake/testtask' 3 | require 'yard' 4 | 5 | 6 | Rake::TestTask.new do |t| 7 | t.libs.push "lib" 8 | t.test_files = FileList['test/**/*_test.rb'] 9 | end 10 | 11 | 12 | YARD::Rake::YardocTask.new do |t| 13 | t.files = ['lib/**/*.rb'] # optional 14 | t.stats_options = ['--list-undoc'] # optional 15 | end 16 | 17 | task :acq do 18 | require "graphviz" 19 | require "./lib/museum_provenance.rb" 20 | require "./lib/museum_provenance/utilities/acquisition_method_documentation.rb" 21 | require "fileutils" 22 | FileUtils.mkdir_p("./docs") 23 | MuseumProvenance::Utilities::AcquisitionMethodDocumentation.create_documentation("./docs") 24 | end 25 | 26 | task :acq_svg do 27 | require "graphviz" 28 | require "./lib/museum_provenance.rb" 29 | require "./lib/museum_provenance/utilities/acquisition_method_documentation.rb" 30 | require "fileutils" 31 | FileUtils.mkdir_p("./docs") 32 | MuseumProvenance::Utilities::AcquisitionMethodDocumentation.create_documentation("./docs", :svg) 33 | end 34 | 35 | task :acq_skos do 36 | require "./lib/museum_provenance.rb" 37 | require "./lib/museum_provenance/utilities/acquisition_method_documentation.rb" 38 | require "fileutils" 39 | FileUtils.mkdir_p("./docs") 40 | MuseumProvenance::Utilities::AcquisitionMethodDocumentation.create_skos("./docs") 41 | end 42 | 43 | desc "Clear the screen" 44 | task :cls do 45 | puts "Clearing the Screen \033c" 46 | end 47 | 48 | task :default => [:cls, :test, :yard] -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/sale_data_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | 3 | module MuseumProvenance 4 | module Parsers 5 | # 6 | # This parser will parse a standard sale info block, for example: 7 | # > (Stock no. 1, for $100) 8 | # 9 | # If it parses, it can return: 10 | # 11 | # * :stock_number # The text of the stock number phrase 12 | # * :sale_amount # A text representation of the sale amount 13 | # * :sale_currency_symbol # A symbol for the currency 14 | # * :sale_value # A numeric value for the sale amount 15 | # 16 | # Note that it may return the sale_amount OR the 17 | # sale_value/sale_currency_symbol, never both. 18 | # @author [davidnewbury] 19 | # 20 | class SaleDataParser < Parslet::Parser 21 | 22 | include ParserHelpers 23 | include Parslet 24 | root(:sale_clause) 25 | 26 | rule(:currency_value) { 27 | (currency_symbol.as(:currency_symbol) >> space? >> numeric.as(:value) >> rparen.present?) | 28 | (numeric.as(:value) >> space? >> currency_symbol.as(:currency_symbol) >> rparen.present?) 29 | } 30 | rule(:currency_phrase) {currency_value | texts_with_commas.as(:string)} 31 | rule(:stock_number) {str("for").absent? >> texts.as(:stock_number) >> comma.maybe} 32 | rule(:sale_amount) {str("for") >> space >> currency_phrase.as(:purchase)} 33 | rule(:sale_clause) {(space | comma).maybe >> lparen >> stock_number.maybe >> sale_amount.maybe >> rparen} 34 | 35 | end 36 | end 37 | end -------------------------------------------------------------------------------- /test/transformers/paragraph_transformer_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Transformers::ParagraphTransform do 3 | 4 | let(:p) {Parsers::ParagraphParser.new} 5 | 6 | def parse_and_tranform(str) 7 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Contextual.new) 8 | results = Transformers::ParagraphTransform.new.apply(results) 9 | end 10 | 11 | it "doesn't crash" do 12 | str = "David Newbury[a][b]." 13 | parse_and_tranform(str) 14 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Contextual.new) 15 | end 16 | 17 | it "fixes transfer punctuation" do 18 | results = parse_and_tranform("David Newbury.") 19 | results[0][:direct_transfer].must_equal false 20 | 21 | results = parse_and_tranform("David Newbury;") 22 | results[0][:direct_transfer].must_equal true 23 | end 24 | 25 | it "fixes period certainty" do 26 | results = parse_and_tranform("Possibly David Newbury.") 27 | results[0][:period_certainty].must_equal false 28 | 29 | results = parse_and_tranform("David Newbury.") 30 | results[0][:period_certainty].must_equal true 31 | end 32 | 33 | it "fixes entity certainty" do 34 | results = parse_and_tranform("David Newbury.") 35 | results[0][:owner][:name][:certainty].must_equal true 36 | 37 | results = parse_and_tranform("David Newbury?.") 38 | results[0][:owner][:name][:certainty].must_equal false 39 | end 40 | 41 | it "regularizes dates" do 42 | results = parse_and_tranform("David Newbury, the 1990s?.") 43 | results[0][:timespan].wont_be_nil 44 | end 45 | 46 | end -------------------------------------------------------------------------------- /lib/museum_provenance/utilities/to_bool.rb: -------------------------------------------------------------------------------- 1 | 2 | # Ruby built-in representation of strings. 3 | class String 4 | # Extends [String] for conversion to a boolean. 5 | # @return [Boolean] 6 | def to_bool 7 | return true if self == true || self =~ (/^(true|t|yes|y|1)$/i) 8 | return false if self == false || self.blank? || self =~ (/^(false|f|no|n|0)$/i) 9 | raise ArgumentError.new("invalid value for Boolean: \"#{self}\"") 10 | end 11 | end 12 | 13 | # Ruby built-in representation of integers, reopened to add additional functionality. 14 | class Fixnum 15 | # Extends [Fixnum] for conversion to a boolean. 16 | # @return [Boolean] 17 | def to_bool 18 | return true if self == 1 19 | return false if self == 0 20 | raise ArgumentError.new("invalid value for Boolean: \"#{self}\"") 21 | end 22 | end 23 | 24 | 25 | # Ruby built-in representation of True, reopened to add additional functionality. 26 | class TrueClass 27 | # Extends [TrueClass] for conversion to a [Fixnum]. 28 | # @return [1] 29 | def to_i; 1; end 30 | 31 | # Trival method to return true 32 | # @return [self] 33 | def to_bool; self; end 34 | end 35 | 36 | 37 | # Ruby built-in representation of False, reopened to add additional functionality. 38 | class FalseClass 39 | # Extends [FalseClass] for conversion to a [Fixnum]. 40 | # @return [0] 41 | def to_i; 0; end 42 | # Trival method to return false 43 | # @return [self] 44 | def to_bool; self; end 45 | end 46 | 47 | 48 | # Ruby built-in representation of Nil, reopened to add additional functionality. 49 | class NilClass 50 | # Extends [NilClass] for conversion to a boolean. 51 | # @return [false] 52 | def to_bool; false; end 53 | end -------------------------------------------------------------------------------- /docs/file_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | File List 19 | 20 | 21 | 22 |
23 |
24 |

File List

25 |
26 | 27 | 28 | Classes 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | Files 37 | 38 | 39 |
40 | 41 | 42 |
43 | 44 | 54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /lib/museum_provenance/entity.rb: -------------------------------------------------------------------------------- 1 | require_relative "certainty.rb" 2 | 3 | module MuseumProvenance 4 | # {Entity} is a data structure for holding information about generic entiries used in a {Period}. 5 | # It is not currently used on it's own, but as a generic structure to be extended by {Party} and {Location}. 6 | class Entity 7 | prepend MuseumProvenance::Certainty 8 | 9 | # @param name [String] the name of the entity. see {#name=} for more info. 10 | # @return The name. 11 | def initialize(name) 12 | self.name = name 13 | end 14 | 15 | # @return [String] The name, with the uncertainty signifier appended. 16 | def to_s 17 | self.name 18 | end 19 | 20 | # Setting the name will detect and remove any indicators of uncertainty. 21 | # @see MuseumProvenance::Certainty 22 | # @param _name [String] the desired name of the entity. 23 | # @return The name. 24 | def name=(_name) 25 | return if _name.nil? 26 | self.certainty = !detect_uncertainty(_name) 27 | @name = remove_uncertainty(_name).strip.chomp(",") 28 | end 29 | 30 | # @return [String] the name of the entity 31 | def name 32 | @name 33 | end 34 | 35 | # Compare an entity to another entity. Equality is based on both name and certainty. 36 | # 37 | # @example 38 | # jane_1 = Entity.new("Jane") 39 | # jane_2 = Entity.new("Jane") 40 | # jane_1 == Jane_2 # -> true 41 | # 42 | # jane_1.certainty = false 43 | # jane_1 == Jane_2 # -> false 44 | # 45 | # @param other [Entity] The entity to compare 46 | # @return [Boolean] 47 | def ==(other) 48 | self.name == other.name && self.certain? == other.certain? 49 | end 50 | end 51 | end -------------------------------------------------------------------------------- /museum_provenance.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'museum_provenance/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "museum_provenance" 8 | spec.version = MuseumProvenance::VERSION 9 | spec.authors = ["David Newbury"] 10 | spec.email = ["david.newbury@gmail.com"] 11 | spec.summary = %q{A library for extracting structured data from museum provenance records.} 12 | spec.description = %q{museum_provenance is a Ruby library developed to help cultural institutions manage and understand the provenance of the objects within their collection. It does this by parsing semi-structured provenance texts into structured data. Developed as part of the Art Tracks project at the Carnegie Museum of Art.} 13 | spec.homepage = "http://museumprovenance.com" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files -z`.split("\x0") 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | spec.has_rdoc = 'yard' 21 | spec.required_ruby_version = '~> 2.3.1' 22 | 23 | spec.add_development_dependency "bundler", "~> 1.13" 24 | spec.add_development_dependency "rake", '< 11' 25 | spec.add_development_dependency "minitest" 26 | spec.add_development_dependency 'yard' 27 | spec.add_development_dependency "ruby-graphviz", "1.2.2" 28 | spec.add_development_dependency 'linkeddata' 29 | 30 | spec.add_runtime_dependency 'edtf', ">= 3.0.1" 31 | spec.add_runtime_dependency 'cultural_dates' 32 | spec.add_runtime_dependency 'parslet' 33 | spec.add_runtime_dependency 'activesupport', '~> 4.2' 34 | end 35 | -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/paragraph_parser.rb: -------------------------------------------------------------------------------- 1 | Dir["#{File.dirname(__FILE__)}/*.rb"].sort.each { |f| require(f) } 2 | require 'cultural_dates' 3 | 4 | module MuseumProvenance 5 | module Parsers 6 | class ParagraphParser < Parslet::Parser 7 | include Parslet 8 | include ParserHelpers 9 | 10 | def initialize(opts = {}) 11 | @acquisition_methods = opts[:acquisition_methods] || AcquisitionMethod.valid_methods 12 | end 13 | 14 | # Is the period certain or uncertain? 15 | rule (:period_certainty) { ((str_i("Possibly").as(:period_certainty_value) >> space) | str("").as(:period_certainty_value)).as(:period_certainty)} 16 | 17 | # "agent for owner" or just "owner" 18 | actor = ActorParser.new 19 | rule (:actors) do 20 | (actor.as(:purchasing_agent) >> (comma | space) >> str("for") >> space >> actor.as(:owner)) | 21 | actor.as(:owner) 22 | end 23 | 24 | # Where did the transaction take place? 25 | rule (:transfer_location) do 26 | str("in") >> space >> PlaceParser.new.as(:transfer_location) 27 | end 28 | 29 | rule(:period) {( 30 | period_certainty >> 31 | AcquisitionMethodParser.new(@acquisition_methods).maybe >> 32 | actors >> 33 | ((comma | space) >> NamedEventParser.new).maybe >> 34 | (comma.maybe >> transfer_location).maybe >> 35 | (comma.maybe >> CulturalDates::DateStringParser.new.as(:timespan)).maybe >> 36 | (comma.maybe >> SaleDataParser.new).maybe >> 37 | (space.maybe >> NotesParser.new).maybe >> 38 | period_end.as(:direct_transfer)) 39 | } 40 | 41 | rule(:fallback) { ((period_end.absent? >> any).repeat(1,nil).as(:unparsable) >> period_end.as(:direct_transfer)) } 42 | 43 | 44 | rule(:provenance) {(period | fallback).repeat(1)} 45 | root :provenance 46 | 47 | end 48 | end 49 | end -------------------------------------------------------------------------------- /test/parsers/place_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parsers::PlaceParser do 3 | 4 | let(:p) {Parsers::PlaceParser.new} 5 | 6 | it "generically works" do 7 | begin 8 | results = p.parse("Boise, ID") 9 | puts "\nPLACE STRUCTURE:\n#{JSON.pretty_generate results}" if ENV["DEBUG"] 10 | rescue Parslet::ParseFailed => failure 11 | puts failure.cause.ascii_tree 12 | end 13 | end 14 | it "works with a comma" do 15 | results = p.parse("Boise, ID") 16 | results[:place][:string].must_equal "Boise, ID" 17 | end 18 | 19 | it "does not consume following comma" do 20 | proc { p.parse("Boise, ID,") }.must_raise(Parslet::ParseFailed) 21 | # results[:place][:string].must_equal "Boise, ID" 22 | end 23 | 24 | it "does not consume following period" do 25 | proc { p.parse("Boise, ID.") }.must_raise(Parslet::ParseFailed) 26 | # results[:place][:string].must_equal "Boise, ID" 27 | end 28 | 29 | it "does not consume following 'for'" do 30 | proc { p.parse("Boise, ID, for") }.must_raise(Parslet::ParseFailed) 31 | # results[:place][:string].must_equal "Boise, ID" 32 | end 33 | 34 | it "works without a comma" do 35 | results = p.parse("France") 36 | results[:place][:string].must_equal "France" 37 | end 38 | it "works with three clauses" do 39 | results = p.parse("Westminster Abbey, London, England") 40 | results[:place][:string].must_equal "Westminster Abbey, London, England" 41 | end 42 | it "works with uncertainty" do 43 | results = p.parse("London, England?") 44 | results[:place][:string].must_equal "London, England" 45 | results[:place][:certainty][:certainty_value].must_equal "?" 46 | end 47 | 48 | it "works with a token" do 49 | results = p.parse("$AUTHORITY_TOKEN_123456") 50 | results[:place][:token].must_equal "$AUTHORITY_TOKEN_123456" 51 | end 52 | 53 | end -------------------------------------------------------------------------------- /lib/museum_provenance/period_output.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | # A class for holding all the information about a period, used for export and import. 3 | # Converted from a struct. 4 | class PeriodOutput 5 | @@attributes = [:period_certainty, 6 | :acquisition_method, 7 | :party, 8 | :party_certainty, 9 | :birth, 10 | :birth_certainty, 11 | :death, 12 | :death_certainty, 13 | :location, 14 | :location_certainty, 15 | :botb, 16 | :botb_certainty, 17 | :botb_precision, 18 | :eotb, 19 | :eotb_certainty, 20 | :eotb_precision, 21 | :bote, 22 | :bote_certainty, 23 | :bote_precision, 24 | :eote, 25 | :eote_certainty, 26 | :eote_precision, 27 | :original_text, 28 | :provenance, 29 | :parsable, 30 | :direct_transfer, 31 | :stock_number, 32 | :footnote, 33 | :primary_owner, 34 | :earliest_possible, 35 | :earliest_definite, 36 | :latest_definite, 37 | :latest_possible 38 | ] 39 | 40 | attr_accessor *@@attributes 41 | 42 | def PeriodOutput.members 43 | @@attributes 44 | end 45 | 46 | def to_a 47 | @@attributes.collect {|attr| self.send(attr)} 48 | end 49 | 50 | def to_h 51 | hash = {} 52 | @@attributes.each {|attr| hash[attr] = self.send(attr)} 53 | hash 54 | end 55 | end 56 | end -------------------------------------------------------------------------------- /test/parsers/authority_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parsers::AuthorityParser do 3 | 4 | let(:p) {Parsers::AuthorityParser.new} 5 | 6 | it "generically works" do 7 | begin 8 | str = <<~EOF 9 | Salvador Dali: http://vocab.getty.edu/ulan/500009365 10 | Cyrus L. Sulzberger: http://viaf.org/viaf/68936177 11 | Pittsburgh, PA: https://whosonfirst.mapzen.com/data/101/718/805/101718805.geojson 12 | International Exhibition of Paintings: no record found. 13 | Carnegie Institute: http://vocab.getty.edu/ulan/500311352 14 | unnamed dealer: no record found. 15 | Thomas J. Watson: http://viaf.org/viaf/8189962 16 | IBM: http://vocab.getty.edu/ulan/500217526 17 | Nesuhi Ertegun and Selma Ertegun: http://viaf.org/viaf/46943188 18 | New York, NY: https://whosonfirst.mapzen.com/data/859/775/39/85977539.geojson 19 | unknown private collection: no record found. 20 | Fundació Gala-Salvador Dalí: http://viaf.org/viaf/155673422 21 | EOF 22 | 23 | results = p.parse(str) 24 | puts "\mAUTHORITY STRUCTURE:\n#{JSON.pretty_generate results}" if ENV["DEBUG"] 25 | rescue Parslet::ParseFailed => failure 26 | puts failure.cause.ascii_tree 27 | end 28 | end 29 | 30 | it "works with leading newlines" do 31 | results = p.parse("\n\nJohn Doe: uri") 32 | results[:authorities].first[:string].must_equal "John Doe" 33 | results[:authorities].first[:uri].must_equal "uri" 34 | end 35 | 36 | it "works with trailing newlines" do 37 | results = p.parse("John Doe: uri\n\n") 38 | results[:authorities].first[:string].must_equal "John Doe" 39 | results[:authorities].first[:uri].must_equal "uri" 40 | end 41 | end -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | TODO: Confirm year zero implementation 2 | add date link into standard 3 | confirm that 200BCE dates can be used in death dates 4 | 5 | TODO: recorded in "Graves Art Sales"? 6 | 7 | 8 | ## Additional Testing 9 | * [ ] Rebuild acquisition tests 10 | * [ ] Date String Tests 11 | 12 | * [ ] Reclassify acquisitions using CRM events: purchase/custody/ownership/creation. 13 | * [ ] Document the EDTF pattern 14 | * [ ] Find AAT type for "place associated with" 15 | * [ ] add in the ownership period and the other date relationships to the model 16 | * [ ] make sure the model covers all possible fields 17 | 18 | 19 | ## High Level Components 20 | * [ ] JSON -> CIDOC-CRM 21 | * [ ] JSON -> Text 22 | * [ ] JSON -> HTML 23 | * [ ] Extract out Date logic 24 | * [ ] Extract Acquisitions 25 | * [ ] Microthesaurii 26 | * [ ] MicroAuthority 27 | * [ ] Determine what parts of the base system are still needed. 28 | 29 | ## Features 30 | * [ ] Handle Open Dates 31 | * [ ] Look into EDTF intervals? 32 | * [ ] clause/location either order 33 | * [ ] see if I can remove date specificity 34 | 35 | 36 | ## Todos for Acquisition Methods 37 | * [ ] Integrate into m_p codebase 38 | * [ ] Finish extracting self-documentation into class 39 | * [ ] Think about `suffix`/`prefix` 40 | * [ ] Think about types 41 | * [ ] Think about OWL 42 | * [ ] Think about OWL import? 43 | * [ ] Move documentation into subfolder 44 | * [ ] HTML instead of markdown? 45 | 46 | 47 | ---- 48 | 49 | 50 | ## Done 51 | 52 | * [x] Convert Date into EDTF 53 | * [x] Convert Date into String 54 | * [x] Convert Date into earliest/latest pair (through EDTF?) 55 | * [x] Token 56 | * [X] No Dates 57 | * [X] String/Token replacement in unparsable things 58 | * [x] Footnotes and Citation marks 59 | * [x] Get raw string (maybe through the offsets of the direct transfers?) 60 | * [X] Test for No Date in full parser 61 | * [x] Add citations 62 | * [x] Add footnotes 63 | * [X] should decade precision be 199u-uu-uu, not 199x? 64 | * [X] "purchase": {"string": "$11M"} 65 | * [X] write up a AST for something with everything filled out 66 | * [X] write a test for it! 67 | -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/parser_helpers.rb: -------------------------------------------------------------------------------- 1 | require 'cultural_dates' 2 | 3 | module MuseumProvenance 4 | module Parsers 5 | module ParserHelpers 6 | include Parslet 7 | include CulturalDates::DateWordHelpers 8 | 9 | def str_i(str) 10 | key_chars = str.split(//) 11 | key_chars. 12 | collect! { |char| match["#{char.upcase}#{char.downcase}"] }. 13 | reduce(:>>) 14 | end 15 | 16 | rule(:space) { match('\s').repeat(1) } 17 | rule(:space?) { space.maybe } 18 | rule(:eof) { any.absent? } 19 | 20 | rule(:stop_words) {str("for") | str("in") | str("from") | month_names_tc} 21 | 22 | # Word rules 23 | rule(:word_parts) { match["[[:alpha:]]'-"]} 24 | rule(:word) { word_parts.repeat(1) } 25 | rule(:initial) { match["[[:upper:]]"] >> period } 26 | rule(:captal_word) { initial | match["[[:upper:]]"] >> word } 27 | rule(:words) { (word | space >> word).repeat(1)} 28 | rule(:word_phrase) { (word | space >> word | comma >> stop_words.absent? >> word).repeat(1)} 29 | rule(:capitalized_word_phrase) { (captal_word | space >> stop_words.absent? >> word | comma >> stop_words.absent? >> captal_word).repeat(1)} 30 | rule(:text) { (word | match["0-9."] | currency_symbol).repeat(1) } 31 | rule(:texts) { (text | space >> text).repeat(1)} 32 | rule(:text_with_commas) { text >> comma | text } 33 | rule(:texts_with_commas){ (text_with_commas | space >> text_with_commas).repeat(1)} 34 | rule(:numeric) { match(["0-9.,M"]).repeat(1) } 35 | rule(:currency_symbol) {match(["$ƒ£€¢¥₱"])} 36 | 37 | # Token Rules 38 | rule(:token) {str("$AUTHORITY_TOKEN_") >> match["0-9"].repeat(1)} 39 | 40 | # Punctuation 41 | rule(:comma) { str(",") >> space } 42 | rule(:period) { str(".") >> space } 43 | rule(:period_end) { (str(".") | str(";")).as(:transfer_punctuation) >> space.maybe } 44 | rule(:certainty) { (str("?") | str("")).as(:certainty_value).as(:certainty)} 45 | rule(:lparen) { str("(")} 46 | rule(:rparen) { str(")")} 47 | 48 | end 49 | end 50 | end -------------------------------------------------------------------------------- /old_tests/period_output_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | 3 | describe PeriodOutput do 4 | 5 | let (:prov_text) {"Possibly purchased by David? [1950-2014?], Belgrade, by October 1990 until at least January 5, 2000, stock no. 1"} 6 | let (:prov) {Provenance.extract prov_text} 7 | let (:output) {prov[0].generate_output} 8 | let (:sample_data) { {:period_certainty=>false, 9 | :acquisition_method=>"Sale", 10 | :party=>"David", 11 | :party_certainty=>false, 12 | :birth=>Date.new(1950), 13 | :birth_certainty=>true, 14 | :death=>Date.new(2014).latest, 15 | :death_certainty=>false, 16 | :location=>"Belgrade", 17 | :location_certainty=>true, 18 | :botb=>nil, 19 | :botb_certainty=>nil, 20 | :botb_precision=>0, 21 | :eotb=>Date.new(1990,10), 22 | :eotb_certainty=>true, 23 | :eotb_precision=>2, 24 | :bote=>Date.new(2000,1,5), 25 | :bote_certainty=>true, 26 | :bote_precision=>3, 27 | :eote=>nil, 28 | :eote_certainty=>nil, 29 | :eote_precision=>0, 30 | :original_text=> prov_text, 31 | :provenance=> prov_text, 32 | :parsable=>true, 33 | :direct_transfer=>nil, 34 | :stock_number=>"stock no. 1", 35 | :footnote=>"", 36 | :primary_owner=>true, 37 | :earliest_possible=>nil, 38 | :earliest_definite=>nil, 39 | :latest_definite=>nil, 40 | :latest_possible=>nil 41 | } 42 | } 43 | 44 | describe "as a class" do 45 | it "lists members" do 46 | PeriodOutput.members.must_be_instance_of Array 47 | PeriodOutput.members.must_equal sample_data.collect{|key,val| key} 48 | end 49 | end 50 | 51 | it "exists" do 52 | output.must_be_instance_of PeriodOutput 53 | 54 | end 55 | 56 | it "converts to an array" do 57 | output.to_a.must_be_instance_of Array 58 | output.to_a.must_equal sample_data.collect{|key,val| val} 59 | end 60 | 61 | it "converts to a hash" do 62 | output.to_h.must_be_instance_of Hash 63 | output.to_h.must_equal sample_data 64 | end 65 | end -------------------------------------------------------------------------------- /lib/museum_provenance/parser.rb: -------------------------------------------------------------------------------- 1 | Dir["#{File.dirname(__FILE__)}/parsers/*.rb"].sort.each { |f| require(f)} 2 | Dir["#{File.dirname(__FILE__)}/transformers/*.rb"].sort.each { |f| require(f)} 3 | 4 | module MuseumProvenance 5 | class Parser 6 | include Parsers 7 | include MuseumProvenance::Transformers 8 | attr_reader :authorities, :paragraph, :notes, :citations, :original 9 | def initialize(str) 10 | @original = str 11 | split(str) 12 | 13 | if @authorities 14 | @authorities = AuthorityParser.new.parse(@authorities) 15 | @authorities = AuthorityTransform.new.apply(@authorities)[:authorities] 16 | @authorities.each do |auth| 17 | @paragraph.gsub!(auth[:string],auth[:token]) 18 | end 19 | end 20 | 21 | if @notes 22 | @notes = NoteSectionParser.new.parse(@notes)[:notes] 23 | end 24 | 25 | if @citations 26 | @citations = NoteSectionParser.new.parse(@citations)[:notes] 27 | end 28 | 29 | @paragraph = ParagraphParser.new.parse(@paragraph) 30 | 31 | add_original_text_to_periods 32 | 33 | @paragraph = ParagraphTransform.new.apply(@paragraph) 34 | @paragraph = TokenTransform.new(@authorities).apply(@paragraph) 35 | @paragraph = NoteInsertionTransform.new(@notes,@citations).apply(@paragraph) 36 | end 37 | 38 | 39 | # Make it enumerable 40 | include Enumerable 41 | 42 | def each &block 43 | @paragraph.each{|member| block.call(member)} 44 | end 45 | 46 | def [](n) 47 | @paragraph[n] 48 | end 49 | def last 50 | @paragraph.last 51 | end 52 | 53 | # Add a easy JSONification 54 | def to_json 55 | JSON.pretty_generate(@paragraph) 56 | end 57 | 58 | private 59 | 60 | def add_original_text_to_periods 61 | return unless @authorities 62 | 63 | fake_original = @original.clone 64 | 65 | @authorities.reverse.each do |auth| 66 | fake_original.gsub!(auth[:string],auth[:token]) 67 | end 68 | 69 | prev_offset = 0 70 | @paragraph.each do |para| 71 | offset = para[:direct_transfer][:transfer_punctuation].offset 72 | val = fake_original[prev_offset..offset] 73 | prev_offset = offset +2 74 | 75 | @authorities.reverse.each do |auth| 76 | val.gsub!(auth[:token],auth[:string]) 77 | end 78 | 79 | para[:text] = val 80 | end 81 | end 82 | 83 | def split(str) 84 | rest, @citations = str.split("\nCitations:\n") 85 | rest, @authorities = rest.split("\nAuthorities:\n") 86 | @paragraph, @notes = rest.split("\nNotes:\n") 87 | end 88 | 89 | end 90 | end -------------------------------------------------------------------------------- /test/parsers/named_event_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parsers::PlaceParser do 3 | 4 | let(:p) {Parsers::NamedEventParser.new} 5 | 6 | it "generically works" do 7 | begin 8 | results = p.parse(%{from "Sale of Pleasant Goods", Christie's, London}) 9 | puts "\nNAMED EVENT STRUCTURE:\n#{JSON.pretty_generate results}" if ENV["DEBUG"] 10 | rescue Parslet::ParseFailed => failure 11 | puts failure.cause.ascii_tree 12 | end 13 | end 14 | it "works with a comma" do 15 | results = p.parse(%{from "Sale of Pleasant, Lovely Goods", Christie's}) 16 | results[:event][:string].must_equal "Sale of Pleasant, Lovely Goods" 17 | results[:sellers_agent][:name][:string].must_equal "Christie's" 18 | end 19 | 20 | it "works with a token" do 21 | results = p.parse(%{from "$AUTHORITY_TOKEN_123456"}) 22 | results[:event][:token].must_equal "$AUTHORITY_TOKEN_123456" 23 | end 24 | 25 | it "works without a party" do 26 | results = p.parse(%{from "Sale of Pleasant, Lovely Goods"}) 27 | results[:event][:string].must_equal "Sale of Pleasant, Lovely Goods" 28 | end 29 | 30 | it "works without an event" do 31 | results = p.parse(%{from Paul PurchasingAgent}) 32 | results[:sellers_agent][:name][:string].must_equal "Paul PurchasingAgent" 33 | end 34 | 35 | it "works with a through" do 36 | results = p.parse(%{through Paul PurchasingAgent}) 37 | results[:sellers_agent][:name][:string].must_equal "Paul PurchasingAgent" 38 | end 39 | 40 | it "works with a through and an at" do 41 | results = p.parse(%{through Paul PurchasingAgent from "Sale of Pleasant, Lovely Goods"}) 42 | results[:sellers_agent][:name][:string].must_equal "Paul PurchasingAgent" 43 | results[:event][:string].must_equal "Sale of Pleasant, Lovely Goods" 44 | end 45 | it "works with a through and an from w/location " do 46 | results = p.parse_with_debug(%{through Paul PurchasingAgent, London, England, from "Sale of Pleasant, Lovely Goods"}) 47 | results[:sellers_agent][:name][:string].must_equal "Paul PurchasingAgent" 48 | results[:sellers_agent][:place][:string].must_equal "London, England" 49 | results[:event][:string].must_equal "Sale of Pleasant, Lovely Goods" 50 | end 51 | it "works with a through and an from w/location without a comma " do 52 | results = p.parse_with_debug(%{through Paul PurchasingAgent, London, England from "Sale of Pleasant, Lovely Goods"}) 53 | results[:sellers_agent][:name][:string].must_equal "Paul PurchasingAgent" 54 | results[:sellers_agent][:place][:string].must_equal "London, England" 55 | results[:event][:string].must_equal "Sale of Pleasant, Lovely Goods" 56 | end 57 | 58 | end -------------------------------------------------------------------------------- /test/parsers/note_section_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parsers::NoteSectionParser do 3 | 4 | let(:p) {Parsers::NoteSectionParser.new} 5 | 6 | it "generically works" do 7 | begin 8 | results = p.parse("[b]. C.L. Sulzberger, A Long Row of Candles, Macmillan, 1969, p. 8.") 9 | puts "\nNOTE STRUCTURE:\n#{JSON.pretty_generate results}" if ENV["DEBUG"] 10 | rescue Parslet::ParseFailed => failure 11 | puts failure.cause.ascii_tree 12 | raise failure 13 | end 14 | end 15 | 16 | it "works with a single citation" do 17 | str = "[b]. Note Content." 18 | results = p.parse(str) 19 | results[:notes].first[:key].must_equal "b" 20 | results[:notes].first[:string].must_equal "Note Content." 21 | end 22 | 23 | it "works with a single footnote" do 24 | str = "[1]. Note Content." 25 | results = p.parse(str) 26 | results[:notes].first[:key].must_equal "1" 27 | results[:notes].first[:string].must_equal "Note Content." 28 | end 29 | 30 | it "works with a leading lines" do 31 | str = "\n\n[1]. Note Content." 32 | results = p.parse(str) 33 | results[:notes].first[:key].must_equal "1" 34 | results[:notes].first[:string].must_equal "Note Content." 35 | end 36 | 37 | it "works with a trailing lines" do 38 | str = "[1]. Note Content.\n\n" 39 | results = p.parse(str) 40 | results[:notes].first[:key].must_equal "1" 41 | results[:notes].first[:string].must_equal "Note Content." 42 | end 43 | 44 | it "works with a two footnotes" do 45 | str = "[1]. Note Content 1.\n[2]. Note Content 2." 46 | results = p.parse(str) 47 | results[:notes].first[:key].must_equal "1" 48 | results[:notes].first[:string].must_equal "Note Content 1." 49 | results[:notes].last[:key].must_equal "2" 50 | results[:notes].last[:string].must_equal "Note Content 2." 51 | end 52 | 53 | it "works with a two citations" do 54 | str = "[a]. Note Content 1.\n[b]. Note Content 2." 55 | results = p.parse(str) 56 | results[:notes].first[:key].must_equal "a" 57 | results[:notes].first[:string].must_equal "Note Content 1." 58 | results[:notes].last[:key].must_equal "b" 59 | results[:notes].last[:string].must_equal "Note Content 2." 60 | end 61 | 62 | it "works with extra lines between footnotes" do 63 | str = "[1]. Note Content 1.\n\n[2]. Note Content 2." 64 | results = p.parse(str) 65 | results[:notes].count.must_equal 2 66 | results[:notes].first[:key].must_equal "1" 67 | results[:notes].first[:string].must_equal "Note Content 1." 68 | results[:notes].last[:key].must_equal "2" 69 | results[:notes].last[:string].must_equal "Note Content 2." 70 | end 71 | 72 | end -------------------------------------------------------------------------------- /test/parsers/notes_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parsers::NotesParser do 3 | 4 | let(:p) {Parsers::NotesParser.new} 5 | 6 | it "generically works" do 7 | begin 8 | results = p.parse("[A][a][1]") 9 | puts "\nNOTE SECTION STRUCTURE:\n#{JSON.pretty_generate results}" if ENV["DEBUG"] 10 | rescue Parslet::ParseFailed => failure 11 | puts failure.cause.ascii_tree 12 | end 13 | end 14 | 15 | it "works with just a citation" do 16 | results = p.parse("[a]") 17 | results[:citations].first[:citation_key].must_equal "a" 18 | end 19 | 20 | it "works with capitalized citations" do 21 | results = p.parse("[A]") 22 | results[:citations].first[:citation_key].must_equal "A" 23 | end 24 | 25 | it "works with multiletter citations" do 26 | results = p.parse("[AA]") 27 | results[:citations].first[:citation_key].must_equal "AA" 28 | end 29 | 30 | it "works with only a footnote" do 31 | results = p.parse("[1]") 32 | results[:footnote][:footnote_key].must_equal "1" 33 | end 34 | 35 | it "works with footnotes greater than 9" do 36 | results = p.parse("[100]") 37 | results[:footnote][:footnote_key].must_equal "100" 38 | end 39 | 40 | it "works with a footnote preceding a citation" do 41 | results = p.parse("[1][a]") 42 | results[:footnote][:footnote_key].must_equal "1" 43 | results[:citations].first[:citation_key].must_equal "a" 44 | end 45 | 46 | it "works with a citation preceding a footnote" do 47 | results = p.parse("[a][1]") 48 | results[:footnote][:footnote_key].must_equal "1" 49 | results[:citations].first[:citation_key].must_equal "a" 50 | end 51 | 52 | it "works with N citations preceding a footnote" do 53 | results = p.parse("[a][b][1]") 54 | results[:footnote][:footnote_key].must_equal "1" 55 | results[:citations].first[:citation_key].must_equal "a" 56 | results[:citations].last[:citation_key].must_equal "b" 57 | end 58 | 59 | it "works with a footnote preceding two citations" do 60 | results = p.parse("[1][a][b]") 61 | results[:footnote][:footnote_key].must_equal "1" 62 | results[:citations].first[:citation_key].must_equal "a" 63 | results[:citations].last[:citation_key].must_equal "b" 64 | end 65 | 66 | it "fails with more than one footnote" do 67 | proc{results = p.parse("[1][2]")}.must_raise Parslet::ParseFailed 68 | end 69 | 70 | it "cannot handle citations on both sides of a footnote" do 71 | proc{results = p.parse("[a][1][b]")}.must_raise Parslet::ParseFailed 72 | end 73 | 74 | it "cannot handle footnote 0" do 75 | proc{results = p.parse("[0]")}.must_raise Parslet::ParseFailed 76 | end 77 | 78 | it "cannot handle footnotes with leading 0" do 79 | proc{results = p.parse("[01]")}.must_raise Parslet::ParseFailed 80 | end 81 | 82 | 83 | end -------------------------------------------------------------------------------- /lib/museum_provenance/certainty.rb: -------------------------------------------------------------------------------- 1 | # Extends nil to support certainty. 2 | class NilClass 3 | # @return [nil] 4 | def certainty 5 | return nil 6 | end 7 | alias :certain? :certainty 8 | end 9 | 10 | module MuseumProvenance 11 | 12 | # Extends a class to allow certainty and uncertaintly to be added to the class. 13 | # it overrides {#to_s} to add a question mark after the value if the value is uncertain. 14 | module Certainty 15 | 16 | # # A list of possible words that indicate that a String could be uncertain. 17 | # CertantyWords = ["?", "possibly", "Possibly", "probably", "Probably", "Likely", "likely", "Potentially","potentially", "Presumably", "presumably", "Said to be", "said to be"] 18 | # # The string which should be appended if a value is uncertain. 19 | # CertaintyString = "?" 20 | 21 | # # Sets the certainty of an object. 22 | # # @param certainty_value [Boolean] 23 | # # @return [Boolean] the value set. 24 | # def certainty=(certainty_value) 25 | # @certain = !!certainty_value 26 | # end 27 | # alias :certain= :certainty= 28 | 29 | # # Gets the certainty of an object. 30 | # # By default, objects are certain. 31 | # # @return [Boolean] returns the certainty. 32 | # def certainty 33 | # @certain = true if @certain.nil? 34 | # @certain 35 | # end 36 | # alias :certain? :certainty 37 | # alias :certain :certainty 38 | 39 | # # Adds a question mark to a uncertain object's string representation. 40 | # # @example 41 | # # test = "I am a banana" 42 | # # test.certainty = false 43 | # # test.to_s # "I am a banana?" 44 | # def to_s(*args) 45 | # str = super(*args) 46 | # str += CertaintyString unless self.certain? 47 | # str 48 | # end 49 | 50 | # # Scan a string for {CertantyWords} 51 | # # 52 | # # @param str [String] A string to scan. 53 | # # @return [Boolean] returns true if a {CertantyWords} is found in the string. 54 | # def detect_uncertainty(str) 55 | # is_certain = false 56 | # CertantyWords.each do |certainty_word| 57 | # is_certain = true if str.downcase.include?(certainty_word) 58 | # end 59 | # return is_certain 60 | # end 61 | 62 | # # Remove {CertantyWords} from a string. 63 | # # 64 | # # @param str [String] A string to scan. 65 | # # @return [String] str with {CertantyWords} removed. 66 | # def remove_uncertainty(str) 67 | # phrase = str 68 | # CertantyWords.each do |certainty_word| 69 | # phrase = phrase.gsub(certainty_word, "") 70 | # end 71 | # return phrase.strip 72 | # end 73 | 74 | # # @return [CertaintyString,""] The appended value if uncertain, otherwise a blank string. 75 | # def certain_string 76 | # self.certain? ? "" : CertaintyString 77 | # end 78 | end 79 | end -------------------------------------------------------------------------------- /WORKING_NOTES.md: -------------------------------------------------------------------------------- 1 | PERIOD: ["Possibly"] ["in" ] [("by"|"to") ( ] ["for" ] [] [] <";"|"."> 2 | 3 | PARTY ENTITY: | ( ) 4 | LOCATION ENTITY: | 5 | 6 | 7 | Possibly purchased in Pittsburgh, PA by David Newbury [1980-], Emlenton, PA for Jane Pendleton [1962-], Chicago, IL sometime between 1998 and May 10, 2001 [1]. 8 | 9 | 10 | Notes: 11 | 12 | 1. This is the footnote for the first period. 13 | 14 | 15 | Bibliography: 16 | 17 | 18 | References: 19 | 20 | See also Pittsburgh: geonames:123456; Pittsburgh, PA: geonames: 23456. 21 | See also Durand Ruel Galleries: viaf:12345. 22 | 23 | David Newbury: http://records.cmoa.org/parties/12345567 24 | 25 | 26 | --- 27 | 28 | Outstanding Questions: 29 | - Do we want to add nuance to an entire record? 30 | - Dealer transactions. Are they still needed? 31 | - Named Entity Recognition for footnotes? 32 | 33 | 34 | 35 | 36 | --- 37 | 38 | 39 | Dynasties for dates? 40 | - Lookup list for dynasties to dates? 41 | - Online Encyclopedia of Ancient 42 | 43 | 44 | Special Case "With"??? 45 | 46 | Do we need to think about "At??" 47 | 48 | ---- 49 | 50 | Repatriated vs Restituted 51 | - see unesco 52 | 53 | - Returned to 54 | "The term ‘return’ should apply to cases where objects left their countries of origin prior to the crystallization of national and international law on the protection of cultural property. Such transfers of ownership were often made from a colonized territory to the territory of the colonial power or from a territory under foreign occupation. In many cases, they were the result of an exchange, gift or sale and did not therefore infringe any laws existing at the time. In some cases, however, the legitimacy of the transfer can be questioned. Among the many variants of such a process is the removal of objects from a colonial territory by people who were not nationals of the colonial power. There may have also been cases of political or economic dependence which made it possible to effect transfers of ownership from one territory to another which would not be envisaged today." 55 | - Restituted to 56 | "the term ‘restitution’ should be used ‘in case of illicit appropriation’, i.e. when objects have left their countries of origin illegally, according to the relevant national legislations and with particular reference to UNESCO’s 1970 Convention on the subject." 57 | - Recovered by 58 | "recovery should not mean totality" 59 | - Repatriated to 60 | State to tribe or culture? 61 | - Retrieved by 62 | "retrieval should be at the initiative of the country of origin" 63 | 64 | 65 | 66 | 67 | https://github.com/vkaravir/bib-publication-list 68 | 69 | http://d-nb.info/standards/elementset/agrelon.owl#RelatedAgent 70 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Certainty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: MuseumProvenance::Certainty 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: MuseumProvenance::Certainty 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 |
Defined in:
81 |
lib/museum_provenance/certainty.rb
82 |
83 | 84 |
85 | 86 |

Overview

87 |
88 | 89 |

Extends a class to allow certainty and uncertaintly to be added to the 90 | class. it overrides #to_s to add a question mark after the value if the 91 | value is uncertain.

92 | 93 | 94 |
95 |
96 |
97 | 98 | 99 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
109 | 110 | 115 | 116 |
117 | 118 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/ProvenanceHelpers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: MuseumProvenance::Parsers::ProvenanceHelpers 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: MuseumProvenance::Parsers::ProvenanceHelpers 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 |
75 |
Includes:
76 |
Parslet
77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 |
85 |
Defined in:
86 |
lib/museum_provenance/parsers/provenance_helpers.rb
87 |
88 | 89 |
90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 |
102 | 103 | 108 | 109 |
110 | 111 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Utilities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: MuseumProvenance::Utilities 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: MuseumProvenance::Utilities 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 |
Defined in:
81 |
lib/museum_provenance/utilities/acquisition_method_documentation.rb
82 |
83 | 84 |
85 | 86 |

Defined Under Namespace

87 |

88 | 89 | 90 | 91 | 92 | Classes: AcquisitionMethodDocumentation 93 | 94 | 95 |

96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
106 | 107 | 112 | 113 |
114 | 115 | -------------------------------------------------------------------------------- /docs/top-level-namespace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Top Level Namespace 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Top Level Namespace 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 | 81 |

Defined Under Namespace

82 |

83 | 84 | 85 | Modules: MuseumProvenance 86 | 87 | 88 | 89 | Classes: Date, FalseClass, Fixnum, NilClass, String, TrueClass 90 | 91 | 92 |

93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 | 104 | 109 | 110 |
111 | 112 | -------------------------------------------------------------------------------- /lib/museum_provenance/parsers/actor_parser.rb: -------------------------------------------------------------------------------- 1 | require_relative "parser_helpers" 2 | require_relative "place_parser" 3 | require 'cultural_dates' 4 | 5 | module MuseumProvenance 6 | module Parsers 7 | # 8 | # This parser will parse a Actor entity block, for example: 9 | # > John Doe? [1910?-1995?], Boise, ID 10 | # 11 | # If it parses, it can return: 12 | # 13 | # * :birth # The birthdate of the actor (as a :date) 14 | # * :death # The deathdate of the actor (as a :date) 15 | # * :clause # a qualifiers for the actor; familial or artist 16 | # * :name # The name of the artist, either a :string or a :token 17 | # * :place # The location associated with the artist as a :place, 18 | # # containing neither a :string or a :token 19 | # 20 | # (Valid clauses are either "the artist" or "his/her/their ", 21 | # for example "his brother". It will also accept them as 22 | # " of previous", for example "sister of previous." This is 23 | # perhaps a better form, since it does not assign a gender to the previous 24 | # entity, and does a better job of conveying the semantic meaning of the 25 | # clause.) 26 | # 27 | # @author [@workergnome] 28 | # 29 | class ActorParser < Parslet::Parser 30 | 31 | include ParserHelpers 32 | include Parslet 33 | 34 | RELATIONSHIP_WORDS = %w{brother sister sibling mother father parent son daughter child grandchild grandparent nephew niece uncle aunt husband wife spouse relative} 35 | 36 | root(:actor) 37 | 38 | rule (:life_dates) do 39 | space >> 40 | str("[") >> 41 | (CulturalDates::DateParser.new.maybe).as(:birth) >> 42 | (str("-") | str(" - ")) >> 43 | (CulturalDates::DateParser.new.maybe).as(:death) >> 44 | str("]") 45 | end 46 | 47 | # Descriptive Clause stuff 48 | rule (:relationship) do 49 | RELATIONSHIP_WORDS.collect{ |word| str("#{word}") }.reduce(:|) 50 | end 51 | 52 | rule (:gendered_clause) {str("his") | str("her") | str("their")} 53 | rule (:familial_relationship) {proper_name >> str("'s") >> space >> relationship.as(:type) >> comma} 54 | rule (:the_artist) {str("the artist")} 55 | rule (:actor_clause) {comma >> (the_artist).as(:clause)} 56 | 57 | rule(:unpossesive_word) { ((str("'s") >> space >> relationship).absent? >> word_parts).repeat(1) } 58 | rule(:unpossessive_captal_word) { initial | match["[[:upper:]]"] >> unpossesive_word | match["[[:upper:]]"] } 59 | rule(:unpossesive_words) { (unpossesive_word | space >> unpossesive_word).repeat(1)} 60 | rule(:unpossesive_capitalized_words) { ((initial | unpossessive_captal_word) | space >> stop_words.absent? >> (initial | unpossessive_captal_word) ).repeat(1)} 61 | 62 | 63 | # Name Stuff 64 | rule(:proper_name) {(((unpossesive_capitalized_words | unpossesive_words).as(:string) | token.as(:token)) >> certainty).as(:name) >> life_dates.maybe} 65 | rule(:actor) {familial_relationship.as(:relationship).maybe >> proper_name >> actor_clause.maybe >> (comma >> PlaceParser.new).maybe} 66 | 67 | end 68 | end 69 | end -------------------------------------------------------------------------------- /test/parsers/parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parser do 3 | 4 | def p(obj={}) 5 | paragraph = obj.fetch(:paragraph, "David Newbury, 1990[1][a].") 6 | notes = obj.fetch(:notes, "[1]. Footnote.") 7 | citations = obj.fetch(:citations, "[a]. Citation.") 8 | authorities = obj.fetch(:authorities, "David Newbury: http://www.davidnewbury.com") 9 | 10 | <<~EOF 11 | #{paragraph} 12 | 13 | #{"Notes:" if notes} 14 | 15 | #{notes} 16 | 17 | #{"Authorities:" if authorities} 18 | 19 | #{authorities} 20 | 21 | #{"Citations:" if citations} 22 | 23 | #{citations} 24 | EOF 25 | end 26 | 27 | it "preserves the original text" do 28 | results = Parser.new(p) 29 | results.original.must_equal p 30 | end 31 | 32 | it "maintains the original text of each period" do 33 | parag = "David Newbury, 1990. John Doe, 1995." 34 | str = p({paragraph: parag}) 35 | results = Parser.new(str) 36 | results.first[:text].must_equal "David Newbury, 1990." 37 | results.last[:text].must_equal "John Doe, 1995." 38 | results.collect{|n| n[:text]}.join(" ").must_equal parag 39 | end 40 | 41 | 42 | describe "Dates and Timespans" do 43 | it "works without dates" do 44 | str = p({paragraph: "David Newbury."}) 45 | results = Parser.new(str) 46 | results.first[:timespan].must_be_nil 47 | end 48 | end 49 | 50 | 51 | 52 | 53 | it "works without notes" do 54 | str = p({notes: nil, paragraph: "David Newbury, 1990[a]."}) 55 | results = Parser.new(str) 56 | results.first[:footnote].must_be_nil 57 | results.first[:owner][:name][:string].must_equal "David Newbury" 58 | end 59 | 60 | it "works without citations" do 61 | str = p({citations: nil, paragraph: "David Newbury, 1990[1]."}) 62 | results = Parser.new(str) 63 | results.first[:citations].must_be_nil 64 | results.first[:owner][:name][:string].must_equal "David Newbury" 65 | end 66 | 67 | it "works without authorities" do 68 | str = p({authorities: nil, paragraph: "David Newbury, 1990[1][a]."}) 69 | results = Parser.new(str) 70 | results.first[:owner][:name][:string].must_equal "David Newbury" 71 | results.first[:owner][:name][:uri].must_be_nil 72 | end 73 | 74 | it "works with only a paragraph" do 75 | str = p({authorities: nil, citations: nil, notes: nil, paragraph: "David Newbury, 1990."}) 76 | results = Parser.new(str) 77 | results.first[:owner][:name][:string].must_equal "David Newbury" 78 | results.first[:owner][:name][:uri].must_be_nil 79 | # puts results 80 | end 81 | 82 | it "allows reuse of authorities" do 83 | str = p({authorities: nil, paragraph: "David Newbury, 1990[1][a]; David Newbury, 1999."}) 84 | results = Parser.new(str) 85 | results.first[:owner][:name][:string].must_equal "David Newbury" 86 | results.last[:owner][:name][:string].must_equal "David Newbury" 87 | end 88 | 89 | it "replaces tokens in garbage test" do 90 | str = p({paragraph: "David Newbury; David Newbury ain't nobody, (yo)."}) 91 | results = Parser.new(str) 92 | results.count.must_equal 2 93 | results.first[:owner][:name][:string].must_equal "David Newbury" 94 | results.last[:unparsable].to_s.must_include "David Newbury" 95 | end 96 | 97 | end -------------------------------------------------------------------------------- /old_tests/provenance_export_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | 3 | describe "Provenance Export" do 4 | skip 5 | before do 6 | @record_text = "Possibly purchased by David? [1950-2014?], Belgrade, by October 1990 until at least January 5, 2000, stock no. 1" 7 | @prov_text = "#{@record_text} [1]; another record. 1. I am a footnote." 8 | @timeline = Provenance.extract @prov_text 9 | @output = @timeline[0].generate_output 10 | end 11 | 12 | it "generates a PeriodOutput" do 13 | @output.must_be_instance_of PeriodOutput 14 | end 15 | 16 | it "generate provenance" do 17 | @output.provenance.must_equal @record_text 18 | end 19 | 20 | it "captures parsability" do 21 | @output.parsable.must_equal true 22 | end 23 | 24 | it "captures botb" do 25 | @output.botb.must_be_nil 26 | end 27 | it "captures botb precision" do 28 | @output.botb_precision.must_equal DateTimePrecision::NONE 29 | end 30 | it "captures botb certainty" do 31 | @output.botb_certainty.must_be_nil 32 | end 33 | 34 | it "captures eotb" do 35 | @output.eotb.must_equal Date.new(1990,10) 36 | end 37 | it "captures eotb precision" do 38 | @output.eotb_precision.must_equal DateTimePrecision::MONTH 39 | end 40 | it "captures eotb certainty" do 41 | @output.eotb_certainty.must_equal true 42 | end 43 | 44 | it "captures eote" do 45 | @output.eote.must_be_nil 46 | end 47 | it "captures eote precision" do 48 | @output.eote_precision.must_equal DateTimePrecision::NONE 49 | end 50 | it "captures eote certainty" do 51 | @output.eote_certainty.must_be_nil 52 | end 53 | 54 | it "captures bote" do 55 | @output.bote.must_equal Date.new(2000,1,5) 56 | end 57 | it "captures bote precision" do 58 | @output.bote_precision.must_equal DateTimePrecision::DAY 59 | end 60 | it "captures bote certainty" do 61 | @output.bote_certainty.must_equal true 62 | end 63 | 64 | it "captures certainty" do 65 | @output.period_certainty.must_equal false 66 | end 67 | it "captures party" do 68 | @output.party.must_equal "David" 69 | end 70 | it "captures party certainty" do 71 | @output.party_certainty.must_equal false 72 | end 73 | it "captures location" do 74 | @output.location.must_equal "Belgrade" 75 | end 76 | it "captures location certainty" do 77 | @output.location_certainty.must_equal true 78 | end 79 | it "captures acquisition method" do 80 | @output.acquisition_method.must_equal "Sale" 81 | end 82 | it "captures direct transfer" do 83 | @output.direct_transfer.must_equal true 84 | end 85 | it "captures footnotes" do 86 | @output.footnote.must_equal "I am a footnote." 87 | end 88 | it "captures original text" do 89 | @output.original_text.must_equal @record_text 90 | end 91 | it "captures birth date" do 92 | @output.birth.must_equal Date.new(1950) 93 | end 94 | it "captures birth certainty" do 95 | @output.birth_certainty.must_equal true 96 | end 97 | it "captures death date" do 98 | @output.death.must_equal Date.new(2014).latest 99 | end 100 | it "captures death certainty" do 101 | @output.death_certainty.must_equal false 102 | end 103 | it "captures stock number" do 104 | @output.stock_number.must_equal "stock no. 1" 105 | end 106 | 107 | end -------------------------------------------------------------------------------- /lib/museum_provenance/fuzzy_date.rb: -------------------------------------------------------------------------------- 1 | # Extensions to the base Date class to support certainty and ranges 2 | class Date 3 | prepend MuseumProvenance::Certainty 4 | 5 | def smart_to_s(*args) 6 | str = "" 7 | if self.precision > DateTimePrecision::MONTH 8 | str = self.strftime("%B %e, ") 9 | if year >=1 10 | year_str = self.year.to_s 11 | year_str += " CE" if year < 1000 12 | elsif year == 0 13 | year_str = "1 BCE" 14 | else 15 | year_str = "#{-year} BCE" 16 | end 17 | 18 | str += year_str 19 | elsif self.precision == DateTimePrecision::MONTH 20 | str = self.to_s(*args).gsub(certain_string,"") 21 | splits = str.split(" ") 22 | splits[1].gsub!(/^0+/,"") 23 | str = splits.join(" ") 24 | str += " CE" if year < 1000 25 | elsif self.precision == DateTimePrecision::YEAR 26 | if year >=1 27 | str = self.year.to_s 28 | str += " CE" if year < 1000 29 | elsif year == 0 30 | str = "1 BCE" 31 | else 32 | str = "#{-year} BCE" 33 | end 34 | elsif self.precision == DateTimePrecision::DECADE 35 | str = "the #{self.year}s" 36 | else 37 | bce = false 38 | year = (self.century/100+1) 39 | if year <= 0 40 | year = -(year-2) 41 | bce = true 42 | end 43 | str = "the #{year.ordinalize} century" 44 | str += " CE" if year >= 1 && year < 10 && !bce 45 | str += " BCE" if bce 46 | str 47 | end 48 | str += certain_string unless self.certain? 49 | str.gsub!(" ", " ") 50 | str 51 | end 52 | 53 | unless method_defined?(:earliest) 54 | # The earliest date for an inprecise date. 55 | # The returned date will have DateTimePrecision::DAY 56 | # @example 57 | # date = Date.new(1990) 58 | # date.earliest == Date.new(1990,1,1) 59 | # 60 | # date = Date.new(1990,10) 61 | # date.earliest == Date.new(1990,10,1) 62 | # @return [Date] A new Date containing the date of the first day in an date. 63 | def earliest 64 | earliest = case precision 65 | when DateTimePrecision::CENTURY then Date.new(year,1,1) 66 | when DateTimePrecision::DECADE then Date.new(year,1,1) 67 | when DateTimePrecision::YEAR then Date.new(year,1,1) 68 | when DateTimePrecision::MONTH then Date.new(year,month,1) 69 | else self.clone 70 | end 71 | earliest.certainty = self.certainty 72 | earliest 73 | end 74 | end 75 | 76 | unless method_defined?(:latest) 77 | # The latest date for an inprecise date. 78 | # The returned date will have DateTimePrecision::DAY. 79 | # @example 80 | # date = Date.new(1990) 81 | # date.latest == Date.new(1990,12,31) 82 | # 83 | # date = Date.new(1990,10) 84 | # date.latest == Date.new(1990,10,31) 85 | # @return [Date] A new Date containing the date of the last day in an date. 86 | def latest 87 | latest = case precision 88 | when DateTimePrecision::CENTURY then Date.new(year+99,-1,-1) 89 | when DateTimePrecision::DECADE then Date.new(year+9,-1,-1) 90 | when DateTimePrecision::YEAR then Date.new(year,-1,-1) 91 | when DateTimePrecision::MONTH then Date.new(year,month,-1) 92 | else self.clone 93 | end 94 | latest.certainty = self.certainty 95 | latest 96 | end 97 | end 98 | end -------------------------------------------------------------------------------- /docs/MuseumProvenance/DateError.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Exception: MuseumProvenance::DateError 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Exception: MuseumProvenance::DateError 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | StandardError 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/time_span.rb
100 |
101 | 102 |
103 | 104 |

Overview

105 |
106 | 107 |

Generic error. No additional functionality.

108 | 109 | 110 |
111 |
112 |
113 | 114 | 115 |
116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 | 132 | 133 |
134 | 135 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/DateParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: MuseumProvenance::Parsers::DateParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: MuseumProvenance::Parsers::DateParser 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 |
75 |
Includes:
76 |
ParserHelpers, Parslet
77 |
78 | 79 | 80 | 81 | 82 |
83 |
Included in:
84 |
DateStringParser
85 |
86 | 87 | 88 | 89 |
90 |
Defined in:
91 |
lib/museum_provenance/parsers/date_parser.rb
92 |
93 | 94 |
95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 |
114 | 115 | 120 | 121 |
122 | 123 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/CertaintyTransform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::CertaintyTransform 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::CertaintyTransform 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Transform 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/parsers/certainty_transform.rb
100 |
101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 | 121 | 122 |
123 | 124 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Transformers/PurchaseTransform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Transformers::PurchaseTransform 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Transformers::PurchaseTransform 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Transform 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/transformers/purchase_transform.rb
100 |
101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 | 121 | 122 |
123 | 124 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Transformers/CertaintyTransform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Transformers::CertaintyTransform 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Transformers::CertaintyTransform 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Transform 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/transformers/certainty_transform.rb
100 |
101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 | 121 | 122 |
123 | 124 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Transformers/AcquisitionTransform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Transformers::AcquisitionTransform 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Transformers::AcquisitionTransform 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Transform 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/transformers/acquisition_transform.rb
100 |
101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 | 121 | 122 |
123 | 124 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Transformers/TransferModeTransform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Transformers::TransferModeTransform 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Transformers::TransferModeTransform 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Transform 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/transformers/transfer_mode_tranform.rb
100 |
101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 | 121 | 122 |
123 | 124 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/DateStringParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::DateStringParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::DateStringParser 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Parser 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
Includes:
94 |
DateParser, ParserHelpers
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 |
Defined in:
104 |
lib/museum_provenance/parsers/date_string_parser.rb
105 |
106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 |
134 | 135 | 140 | 141 |
142 | 143 | -------------------------------------------------------------------------------- /test/parsers/sale_data_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parsers::SaleDataParser do 3 | 4 | 5 | let(:p) {Parsers::SaleDataParser.new} 6 | 7 | it "generically works" do 8 | begin 9 | results = p.parse("(stock no. 1, for $100)") 10 | results[:stock_number].must_equal "stock no. 1" 11 | results[:purchase][:currency_symbol].must_equal "$" 12 | results[:purchase][:value].must_equal "100" 13 | results[:purchase][:string].must_be_nil 14 | puts "\nSALE DATA STRUCTURE:\n#{JSON.pretty_generate results}" if ENV["DEBUG"] 15 | 16 | 17 | rescue Parslet::ParseFailed => failure 18 | puts failure.cause.ascii_tree 19 | end 20 | end 21 | 22 | it "handles only money amounts" do 23 | results = p.parse("(for $100)") 24 | results[:stock_number].must_be_nil 25 | results[:purchase][:currency_symbol].must_equal "$" 26 | results[:purchase][:value].must_equal "100" 27 | results[:purchase][:string].must_be_nil 28 | 29 | end 30 | 31 | it "handles money amounts followed by letters" do 32 | results = p.parse("(for $100M)") 33 | results[:stock_number].must_be_nil 34 | results[:purchase][:currency_symbol].must_equal "$" 35 | results[:purchase][:value].must_equal "100M" 36 | results[:purchase][:string].must_be_nil 37 | 38 | end 39 | 40 | 41 | it "handles alternate currency symbols and locations" do 42 | "$ƒ£€¢¥₱".split("").each do |sym| 43 | results = p.parse("(for #{sym}100)") 44 | results[:stock_number].must_be_nil 45 | results[:purchase][:currency_symbol].must_equal sym 46 | results[:purchase][:value].must_equal "100" 47 | results[:purchase][:string].must_be_nil 48 | 49 | 50 | results = p.parse("(for #{sym} 100)") 51 | results[:stock_number].must_be_nil 52 | results[:purchase][:currency_symbol].must_equal sym 53 | results[:purchase][:value].must_equal "100" 54 | results[:purchase][:string].must_be_nil 55 | 56 | 57 | results = p.parse("(for 100#{sym})") 58 | results[:stock_number].must_be_nil 59 | results[:purchase][:currency_symbol].must_equal sym 60 | results[:purchase][:value].must_equal "100" 61 | results[:purchase][:string].must_be_nil 62 | 63 | 64 | results = p.parse("(for 100 #{sym})") 65 | results[:stock_number].must_be_nil 66 | results[:purchase][:currency_symbol].must_equal sym 67 | results[:purchase][:value].must_equal "100" 68 | results[:purchase][:string].must_be_nil 69 | 70 | end 71 | end 72 | 73 | it "handles only stock numbers" do 74 | results = p.parse("(stock no. 1)") 75 | results[:stock_number].must_equal "stock no. 1" 76 | results[:purchase].must_be_nil 77 | 78 | end 79 | 80 | it "handles money amounts with commas" do 81 | results = p.parse("(for $100,000)") 82 | results[:stock_number].must_be_nil 83 | results[:purchase][:currency_symbol].must_equal "$" 84 | results[:purchase][:value].must_equal "100,000" 85 | results[:purchase][:string].must_be_nil 86 | 87 | end 88 | 89 | it "handles money amounts with decimal places" do 90 | results = p.parse("(for $10.50)") 91 | results[:stock_number].must_be_nil 92 | results[:purchase][:currency_symbol].must_equal "$" 93 | results[:purchase][:value].must_equal "10.50" 94 | results[:purchase][:string].must_be_nil 95 | end 96 | 97 | it "handles strange money amounts" do 98 | results = p.parse("(for 100 florins)") 99 | results[:stock_number].must_be_nil 100 | results[:purchase][:string].must_equal "100 florins" 101 | results[:purchase][:value].must_be_nil 102 | results[:purchase][:currency_symbol].must_be_nil 103 | end 104 | 105 | it "handles strange money amounts with commas" do 106 | results = p.parse("(for 5 shillings, three pence)") 107 | results[:stock_number].must_be_nil 108 | results[:purchase][:string].must_equal "5 shillings, three pence" 109 | results[:purchase][:value].must_be_nil 110 | results[:purchase][:currency_symbol].must_be_nil 111 | end 112 | end -------------------------------------------------------------------------------- /test/parsers/actor_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe Parsers::ActorParser do 3 | 4 | let(:p) {Parsers::ActorParser.new} 5 | 6 | it "generically works" do 7 | begin 8 | results = p.parse("John Doe? [1910?-1995?], the artist, Boise, ID") 9 | puts "\nACTOR STRUCTURE:\n#{JSON.pretty_generate results}" if ENV["DEBUG"] 10 | rescue Parslet::ParseFailed => failure 11 | puts failure.cause.ascii_tree 12 | end 13 | end 14 | 15 | it "works with just a name" do 16 | results = p.parse("John Doe") 17 | results[:name][:string].must_equal "John Doe" 18 | end 19 | 20 | it "works with all lowercase names" do 21 | str = "an unnamed dealer" 22 | results = p.parse(str) 23 | results[:name][:string].must_equal str 24 | end 25 | 26 | it "works with a name with a single letter" do 27 | str = "John G Doe" 28 | results = p.parse_with_debug(str) 29 | results[:name][:string].must_equal str 30 | end 31 | 32 | it "works with a name with an initial" do 33 | str = "John G. Doe" 34 | results = p.parse_with_debug(str) 35 | results[:name][:string].must_equal str 36 | end 37 | 38 | it "works with unicode names" do 39 | str = "Fundació Gala-Salvador Dalí" 40 | results = p.parse_with_debug(str) 41 | results[:name][:string].must_equal str 42 | end 43 | 44 | it "works with a all caps name" do 45 | str = "IBM" 46 | results = p.parse_with_debug(str) 47 | results[:name][:string].must_equal str 48 | end 49 | 50 | 51 | it "works with a name and a previous relationship" do 52 | results = p.parse_with_debug("Jane Doe's son, John Doe", reporter: Parslet::ErrorReporter::Deepest.new) 53 | results[:name][:string].must_equal "John Doe" 54 | results[:relationship][:name][:string].must_equal "Jane Doe" 55 | results[:relationship][:type].must_equal "son" 56 | end 57 | 58 | 59 | it "works for artists" do 60 | results = p.parse("John Doe, the artist") 61 | results[:name][:string].must_equal "John Doe" 62 | results[:clause].must_equal "the artist" 63 | end 64 | 65 | it "works with a name token" do 66 | results = p.parse("$AUTHORITY_TOKEN_123456") 67 | results[:name][:token].must_equal "$AUTHORITY_TOKEN_123456" 68 | end 69 | 70 | 71 | it "works with a name and life dates" do 72 | results = p.parse("John Doe [1990-1991]") 73 | results[:name][:string].must_equal "John Doe" 74 | results[:birth][:date][:year].must_equal "1990" 75 | results[:death][:date][:year].must_equal "1991" 76 | results[:birth][:date][:certainty][:certainty_value].must_equal "" 77 | results[:death][:date][:certainty][:certainty_value].must_equal "" 78 | end 79 | 80 | it "works with just birth dates" do 81 | results = p.parse("John Doe [1990-]") 82 | results[:name][:string].must_equal "John Doe" 83 | results[:birth][:date][:year].must_equal "1990" 84 | results[:birth][:date][:certainty][:certainty_value].must_equal "" 85 | results[:death].must_be_nil 86 | end 87 | 88 | it "works with just death dates" do 89 | results = p.parse("John Doe [-1990]") 90 | results[:name][:string].must_equal "John Doe" 91 | results[:death][:date][:year].must_equal "1990" 92 | results[:death][:date][:certainty][:certainty_value].must_equal "" 93 | results[:birth].must_be_nil 94 | end 95 | 96 | it "works with BCE years" do 97 | results = p.parse("John Doe [-1990 BCE]") 98 | 99 | results[:name][:string].must_equal "John Doe" 100 | results[:death][:date][:year].must_equal "1990" 101 | results[:death][:date][:era].must_equal "BCE" 102 | results[:birth].must_be_nil 103 | results[:death][:date][:certainty][:certainty_value].must_equal "" 104 | end 105 | 106 | it "works with CE years" do 107 | results = p.parse("John Doe [-1990 CE]") 108 | results[:name][:string].must_equal "John Doe" 109 | results[:death][:date][:year].must_equal "1990" 110 | results[:death][:date][:era].must_equal "CE" 111 | results[:death][:date][:certainty][:certainty_value].must_equal "" 112 | results[:birth].must_be_nil 113 | end 114 | end -------------------------------------------------------------------------------- /test/parsers/paragraph_parser_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "../test_helper.rb" 2 | describe "Full Text Parser" do 3 | 4 | 5 | 6 | let(:p) {Parsers::ParagraphParser.new} 7 | 8 | 9 | it "generically works" do 10 | str = "Possibly " 11 | str += "purchased at auction by " 12 | str += "John Doe? [1910?-1995?], " 13 | str += "Boise, ID, " 14 | str += "for John Doe's wife, Sally Moe, " 15 | str += %{from "Sale of Pleasant Goods", Christie's, London, } 16 | str += "in London, England, " 17 | str += "sometime after November 5, 1975 " 18 | str += "(stock no. 10, for $1000)" 19 | str += " [1][a][b]" 20 | str += "; " 21 | str += "David Newbury." 22 | # puts "\n" 23 | # puts str 24 | # puts (0..20).collect{|n| "#{n}0".ljust(10)}.join("") 25 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Deepest.new) 26 | results[0][:owner][:name][:string].must_equal "Sally Moe" 27 | end 28 | 29 | it "works with sale info" do 30 | results = p.parse_with_debug("John Doe, Boise, ID (for $100).", reporter: Parslet::ErrorReporter::Contextual.new) 31 | results[0][:owner][:name][:string].must_equal "John Doe" 32 | results[0][:owner][:place][:string].must_equal "Boise, ID" 33 | results[0][:purchase][:value].must_equal("100") 34 | results[0][:purchase][:currency_symbol].must_equal("$") 35 | end 36 | 37 | it "works with both types of agents" do 38 | str = "Paul PurchaserAgent for Owen Owner from Sally SellerAgent." 39 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Deepest.new) 40 | results[0][:owner][:name][:string].must_equal "Owen Owner" 41 | results[0][:purchasing_agent][:name][:string].must_equal "Paul PurchaserAgent" 42 | results[0][:sellers_agent][:name][:string].must_equal "Sally SellerAgent" 43 | end 44 | 45 | it "doesn't eat dates as part of places" do 46 | str = "Carnegie Institute, in Pittsburgh, PA, November 5, 1934;" 47 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Contextual.new) 48 | results[0][:owner][:name][:string].must_equal "Carnegie Institute" 49 | results[0][:transfer_location][:place][:string].must_equal "Pittsburgh, PA" 50 | 51 | end 52 | it "works with acquisition info" do 53 | results = p.parse_with_debug("Purchased by John Doe.", reporter: Parslet::ErrorReporter::Contextual.new) 54 | results[0][:owner][:name][:string].must_equal "John Doe" 55 | results[0][:acquisition_method][:acquisition_method_string].must_equal "Purchased by" 56 | end 57 | 58 | it "works with acquisition info as lowercase" do 59 | results = p.parse_with_debug("via marriage, to John Doe.", reporter: Parslet::ErrorReporter::Contextual.new) 60 | results[0][:owner][:name][:string].must_equal "John Doe" 61 | results[0][:acquisition_method][:acquisition_method_string].must_equal "via marriage, to" 62 | end 63 | 64 | it "handles garbage periods" do 65 | str = "John Doe; yo, I ain't somthing Febuary; Larry King." 66 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Contextual.new) 67 | results[0][:owner][:name][:string].must_equal "John Doe" 68 | results[1][:unparsable].must_equal("yo, I ain't somthing Febuary") 69 | results[2][:owner][:name][:string].must_equal "Larry King" 70 | end 71 | 72 | it "handles period uncertainty" do 73 | str = "Possibly John Doe." 74 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Contextual.new) 75 | results[0][:owner][:name][:string].must_equal "John Doe" 76 | results[0][:period_certainty][:period_certainty_value].must_equal "Possibly" 77 | end 78 | 79 | it "works with dali test" do 80 | str = %{Created by Salvador Dali [1904-1989], the artist, 1934. Purchased by Cyrus L. Sulzberger [1912-1993], Pittsburgh, PA, at "International Exhibition of Paintings", Carnegie Institute, in Pittsburgh, PA, November 5, 1934 (for $350) [1][a]; purchased by unnamed dealer, sometime in 1938? [b]; purchased by Thomas J. Watson [1874-1956] for IBM, sometime before May 1939 [2][c]; purchased by Cyrus L. Sulzberger, 1942 until at least 1969 [3][d]. Purchased by Nesuhi Ertegun and Selma Ertegun, New York, NY, sometime before June 1999 [e]; purchased by unknown private collection? [f]; purchased by Fundació Gala-Salvador Dalí, sometime before May 2011 (for $11M) [g].} 81 | results = p.parse_with_debug(str, reporter: Parslet::ErrorReporter::Contextual.new) 82 | results[0][:owner][:name][:string].must_equal "Salvador Dali" 83 | end 84 | end -------------------------------------------------------------------------------- /test/acquisition_method_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | 3 | describe AcquisitionMethod do 4 | 5 | let(:opts1) { 6 | { 7 | id: :acquisition, 8 | title: "name", 9 | prefix: "prefix", 10 | suffix: "suffix", 11 | description: "definition", 12 | explanation: "This is the default method for acquisitions and is the base type for all acquisitions.It should be used if there are no additional details available. If there is not an explicit acquisition method mentioned, this will be assumed.", 13 | preferred_form: AcquisitionMethod::Prefix, 14 | synonyms: ["alternate"], 15 | } 16 | } 17 | let(:opts2) { 18 | { 19 | id: :acquisition, 20 | title: "name", 21 | prefix: "prefix", 22 | suffix: "suffix", 23 | description: "definition", 24 | explanation: "This is the default method for acquisitions and is the base type for all acquisitions.It should be used if there are no additional details available. If there is not an explicit acquisition method mentioned, this will be assumed.", 25 | preferred_form: AcquisitionMethod::Suffix, 26 | synonyms: ["alternate", "other_alternate"], 27 | } 28 | } 29 | 30 | let(:m1) {AcquisitionMethod.new opts1} 31 | let(:m2) {AcquisitionMethod.new opts2} 32 | 33 | it "has a class constant for prefix and suffix" do 34 | AcquisitionMethod::Prefix.must_be_instance_of Symbol 35 | AcquisitionMethod::Prefix.must_equal :prefix 36 | AcquisitionMethod::Suffix.must_be_instance_of Symbol 37 | AcquisitionMethod::Suffix.must_equal :suffix 38 | end 39 | 40 | it "can be initialized" do 41 | m1.name.must_equal "name" 42 | m1.prefix.must_equal "prefix" 43 | m1.suffix.must_equal "suffix" 44 | m1.definition.must_equal "definition" 45 | m1.forms.must_include "alternate" 46 | end 47 | 48 | it "is immutable" do 49 | lambda {m1.name = "new name"}.must_raise NoMethodError 50 | lambda {m1.prefix = "new prefix"}.must_raise NoMethodError 51 | lambda {m1.suffix = "new suffix"}.must_raise NoMethodError 52 | lambda {m1.definition = "new def"}.must_raise NoMethodError 53 | lambda {m1.synonyms = "new synonym"}.must_raise NoMethodError 54 | end 55 | 56 | it "lists forms" do 57 | m1.forms.must_be_kind_of Array 58 | m1.forms.count.must_equal 3 59 | m1.forms.must_include "alternate" 60 | m1.forms.must_include "suffix" 61 | m1.forms.must_include "prefix" 62 | m2.forms.count.must_equal 4 63 | m2.forms.must_include "suffix" 64 | m2.forms.must_include "alternate" 65 | m2.forms.must_include "prefix" 66 | m2.forms.must_include "other_alternate" 67 | end 68 | 69 | it "lists other forms" do 70 | m1.other_forms.must_be_kind_of Array 71 | m1.other_forms.count.must_equal 2 72 | m1.other_forms.must_include "alternate" 73 | m1.other_forms.must_include "suffix" 74 | m2.other_forms.count.must_equal 3 75 | m2.other_forms.must_include "alternate" 76 | m2.other_forms.must_include "prefix" 77 | m2.other_forms.must_include "other_alternate" 78 | end 79 | 80 | it "prints its name when cast to string" do 81 | m1.to_s.must_equal m1.name 82 | end 83 | 84 | it "attaches itself to a name" do 85 | m1.attach_to_name("Party").must_equal "#{m1.prefix} Party" 86 | m2.attach_to_name('Party').must_equal "Party #{m1.suffix}" 87 | end 88 | 89 | describe "Global Find" do 90 | it "uses the default when there's nothing there" do 91 | method = AcquisitionMethod.find("David Newbury [1995,200].") 92 | method.must_equal AcquisitionMethod.find_by_id(:acquisition) 93 | end 94 | 95 | it "finds standard acquisition methods" do 96 | method = AcquisitionMethod.find("Purchased by David Newbury [1995,200].") 97 | method.must_be_instance_of AcquisitionMethod 98 | method.must_equal AcquisitionMethod.find_by_id(:sale) 99 | end 100 | end 101 | describe "Name Find" do 102 | it "does not find when there's nothing there" do 103 | method = AcquisitionMethod.find_by_name("Regurgitated") 104 | method.must_be_nil 105 | 106 | end 107 | it "finds standard acquisition methods" do 108 | method = AcquisitionMethod.find_by_name("On Loan") 109 | method.must_be_instance_of AcquisitionMethod 110 | method.must_equal AcquisitionMethod.find_by_id(:on_loan) 111 | end 112 | end 113 | end -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/NoteSectionParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::NoteSectionParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::NoteSectionParser 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Parser 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
Includes:
94 |
ParserHelpers, Parslet
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 |
Defined in:
104 |
lib/museum_provenance/parsers/note_section_parser.rb
105 |
106 | 107 |
108 | 109 |

Overview

110 |
111 | 112 |

If it parses, it will return an array of :notes

113 |
  • 114 |

    :note_id # The index letter or number

    115 |
  • 116 |

    :note_text # The text of the note

    117 |
118 | 119 | 120 |
121 |
122 |
123 | 124 |

Author:

125 |
    126 | 127 |
  • 128 | 129 | 130 | 131 | 132 | 133 |
    @workergnome 134 |
    135 |
    136 | 137 |
  • 138 | 139 |
140 | 141 |
142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |

Method Summary

157 | 158 |

Methods included from ParserHelpers

159 |

#str_i

160 | 161 | 162 | 163 | 164 | 165 |
166 | 167 | 172 | 173 |
174 | 175 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/NotesParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::NotesParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::NotesParser 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Parser 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
Includes:
94 |
ParserHelpers, Parslet
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 |
Defined in:
104 |
lib/museum_provenance/parsers/notes_parser.rb
105 |
106 | 107 |
108 | 109 |

Overview

110 |
111 | 112 |

This parser will parse a Actor entity block, for example: > John Doe? 113 | [1910?-1995?], Boise, ID

114 | 115 |

If it parses, it can return:

116 |
  • 117 |

    :stock_number # The text of the stock number phrase

    118 |
119 | 120 | 121 |
122 |
123 |
124 | 125 |

Author:

126 |
    127 | 128 |
  • 129 | 130 | 131 | 132 | 133 | 134 |
    @workergnome 135 |
    136 |
    137 | 138 |
  • 139 | 140 |
141 | 142 |
143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 |

Method Summary

158 | 159 |

Methods included from ParserHelpers

160 |

#str_i

161 | 162 | 163 | 164 | 165 | 166 |
167 | 168 | 173 | 174 |
175 | 176 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/PlaceParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::PlaceParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::PlaceParser 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Parser 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
Includes:
94 |
ParserHelpers, Parslet
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 |
Defined in:
104 |
lib/museum_provenance/parsers/place_parser.rb
105 |
106 | 107 |
108 | 109 |

Overview

110 |
111 | 112 |

This parser will parse a Actor entity block, for example: > John Doe? 113 | [1910?-1995?], Boise, ID

114 | 115 |

If it parses, it can return:

116 |
  • 117 |

    :stock_number # The text of the stock number phrase

    118 |
119 | 120 | 121 |
122 |
123 |
124 | 125 |

Author:

126 |
    127 | 128 |
  • 129 | 130 | 131 | 132 | 133 | 134 |
    @workergnome 135 |
    136 |
    137 | 138 |
  • 139 | 140 |
141 | 142 |
143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 |

Method Summary

158 | 159 |

Methods included from ParserHelpers

160 |

#str_i

161 | 162 | 163 | 164 | 165 | 166 |
167 | 168 | 173 | 174 |
175 | 176 | -------------------------------------------------------------------------------- /old_tests/more_specific_date_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | def check(pattern,result) 3 | 4 | string = "John Doe, Paris, France, " 5 | 6 | part_a, part_b = pattern.split("...") 7 | botb,eotb = part_a.split("-") 8 | bote,eote = part_b.split("-") 9 | 10 | 11 | botb = case botb 12 | when "?" then nil 13 | when "X" then @x 14 | when "Y" then @y 15 | when "Z" then @z 16 | when "A" then @a 17 | end 18 | 19 | bote = case bote 20 | when "?" then nil 21 | when "X" then @x 22 | when "Y" then @y 23 | when "Z" then @z 24 | when "A" then @a 25 | end 26 | 27 | eotb = case eotb 28 | when "?" then nil 29 | when "X" then @x 30 | when "Y" then @y 31 | when "Z" then @z 32 | when "A" then @a 33 | end 34 | 35 | eote = case eote 36 | when "?" then nil 37 | when "X" then @x 38 | when "Y" then @y 39 | when "Z" then @z 40 | when "A" then @a 41 | end 42 | 43 | it "handles #{pattern} for '#{result}'" do 44 | skip 45 | 46 | p.parse_time_string string + result 47 | if p.beginning 48 | if p.beginning.earliest_raw 49 | p.beginning.earliest_raw.smart_to_s(:long).must_equal botb 50 | else 51 | botb.must_be_nil 52 | end 53 | if p.beginning.latest_raw 54 | p.beginning.latest_raw.smart_to_s(:long).must_equal eotb 55 | else 56 | eotb.must_be_nil 57 | end 58 | else 59 | botb.must_be_nil 60 | eotb.must_be_nil 61 | end 62 | if p.ending 63 | if p.ending.earliest_raw 64 | p.ending.earliest_raw.smart_to_s(:long).must_equal bote 65 | else 66 | bote.must_be_nil 67 | end 68 | if p.ending.latest_raw 69 | p.ending.latest_raw.smart_to_s(:long).must_equal eote 70 | else 71 | eote.must_be_nil 72 | end 73 | else 74 | eote.must_be_nil 75 | bote.must_be_nil 76 | end 77 | p.time_string.must_equal result 78 | end 79 | end 80 | 81 | describe "Specific date checks" do 82 | 83 | let(:p) {Period.new("Date Test Period")} 84 | 85 | # x_dates = ["the 18th century", "the 1700s", "1707", "June 1709", "June 1, 1707"] 86 | # y_dates = ["the 19th century", "the 1800s", "1807", "June 1807", "June 1, 1807"] 87 | # z_dates = ["the 20th century", "the 1900s", "1907", "June 1907", "June 1, 1907"] 88 | # a_dates = ["the 21st century", "the 2000s", "2007", "June 2007", "June 1, 2007"] 89 | 90 | x_dates = ["June 1, 1707"] 91 | y_dates = ["June 1, 1807"] 92 | z_dates = ["June 1, 1907"] 93 | a_dates = ["June 1, 2007"] 94 | 95 | 96 | #check "?-?...?-?", "" 97 | x_dates.each do |x| 98 | @y,@z,@a = nil 99 | @x = x 100 | 101 | check "X-?...?-?", "after #{x}" 102 | check "?-X...?-?", "by #{x}" 103 | check "?-?...X-?", "until at least #{x}" 104 | check "?-?...?-X", "until sometime before #{x}" 105 | check "X-X...?-?", "#{x}" 106 | check "?-?...X-X", "until #{x}" 107 | check "X-X...X-X", "on #{x}" 108 | 109 | 110 | # check "?-X...X-?", "in #{x}"// OR on july 1, 1995 (if known to the day) 111 | y_dates.each do |y| 112 | @z,@a = nil 113 | @y = y 114 | 115 | check "X-Y...?-?", "sometime between #{x} and #{y}" 116 | check "X-?...Y-?", "after #{x} until at least #{y}" 117 | check "X-?...?-Y", "after #{x} until sometime before #{y}" 118 | check "?-X...Y-?", "by #{x} until at least #{y}" 119 | check "?-X...?-Y", "by #{x} until sometime before #{y}" 120 | check "?-?...X-Y", "until sometime between #{x} and #{y}" 121 | check "X-X...Y-?", "#{x} until at least #{y}" 122 | # check "X-Y...Y-?", "sometime between 1995 and 1996 until at least 1996 (after 1995, in 1996)?" 123 | check "X-X...?-Y", "#{x} until sometime before #{y}" 124 | check "?-X...Y-Y", "by #{x} until #{y}" 125 | check "?-X...X-Y", "in #{x} until sometime before #{y}" 126 | check "X-?...Y-Y", "after #{x} until #{y}" 127 | check "X-X...Y-Y", "#{x} until #{y}" 128 | 129 | z_dates.each do |z| 130 | @a = nil 131 | @z = z 132 | check "X-Y...Z-?", "sometime between #{x} and #{y} until at least #{z}" 133 | check "X-Y...?-Z", "sometime between #{x} and #{y} until sometime before #{z}" 134 | check "?-X...Y-Z", "by #{x} until sometime between #{y} and #{z}" 135 | check "X-?...Y-Z", "after #{x} until sometime between #{y} and #{z}" 136 | check "X-X...Y-Z", "#{x} until sometime between #{y} and #{z}" 137 | check "X-Y...Z-Z", "sometime between #{x} and #{y} until #{z}" 138 | 139 | a_dates.each do |a| 140 | @a = a 141 | check "X-Y...Z-A", "sometime between #{x} and #{y} until sometime between #{z} and #{a}" 142 | end 143 | end 144 | end 145 | end 146 | 147 | end -------------------------------------------------------------------------------- /docs/MuseumProvenance/Transformers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: MuseumProvenance::Transformers 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: MuseumProvenance::Transformers 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 |
Included in:
79 |
Parser
80 |
81 | 82 | 83 | 84 |
85 |
Defined in:
86 |
lib/museum_provenance/transformers/token_transform.rb,
87 | lib/museum_provenance/transformers/purchase_transform.rb,
lib/museum_provenance/transformers/authority_transform.rb,
lib/museum_provenance/transformers/certainty_transform.rb,
lib/museum_provenance/transformers/paragraph_transform.rb,
lib/museum_provenance/transformers/acquisition_transform.rb,
lib/museum_provenance/transformers/transfer_mode_tranform.rb,
lib/museum_provenance/transformers/note_insertion_transform.rb
88 |
89 |
90 | 91 |
92 | 93 |

Defined Under Namespace

94 |

95 | 96 | 97 | 98 | 99 | Classes: AcquisitionTransform, AuthorityTransform, CertaintyTransform, NoteInsertionTransform, ParagraphTransform, PurchaseTransform, TokenTransform, TransferModeTransform 100 | 101 | 102 |

103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 | 114 | 119 | 120 |
121 | 122 | -------------------------------------------------------------------------------- /old_tests/time_span_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | describe TimeSpan do 3 | 4 | let(:y) {Date.new(2014)} 5 | let(:m) {Date.new(2014,10)} 6 | let(:d) {Date.new(2014,10,17)} 7 | 8 | it "handles equality tests" do 9 | y.==(y).must_equal true 10 | y. ==(m).wont_equal true 11 | end 12 | 13 | it "is nil by default" do 14 | t1 = TimeSpan.new 15 | t1.must_be_nil 16 | end 17 | 18 | it "is not nil if it has a beginning" do 19 | t1 = TimeSpan.new(y) 20 | t1.wont_be_nil 21 | end 22 | it "is not nil if it has a ending" do 23 | t1 = TimeSpan.new(nil,y) 24 | t1.wont_be_nil 25 | end 26 | 27 | it "initializes properly without dates" do 28 | t1 = TimeSpan.new 29 | t1.earliest.must_be_nil 30 | t1.latest.must_be_nil 31 | t1.to_s.must_be_nil 32 | t1.defined?.must_equal false 33 | t1.same?.must_equal false 34 | t1.precise?.must_equal false 35 | end 36 | 37 | it "initializes with a single date" do 38 | t1 = TimeSpan.new(y) 39 | t1.earliest.must_equal y.earliest 40 | t1.latest.must_be_nil 41 | t1.defined?.must_equal true 42 | t1.same?.must_equal false 43 | t1.precise?.must_equal false 44 | end 45 | it "initializes with only an end date" do 46 | t1 = TimeSpan.new(nil,y) 47 | t1.earliest.must_be_nil 48 | t1.latest.must_equal y.latest 49 | t1.defined?.must_equal true 50 | t1.same?.must_equal false 51 | t1.precise?.must_equal false 52 | end 53 | it "initializes with two dates" do 54 | t1 = TimeSpan.new(y,m) 55 | t1.earliest.must_equal y.earliest 56 | t1.latest.must_equal m.latest 57 | t1.defined?.must_equal true 58 | t1.same?.must_equal false 59 | t1.precise?.must_equal false 60 | end 61 | 62 | it "initializes reorders dates" do 63 | t1 = TimeSpan.new(m,y) 64 | t1.earliest.must_equal y.earliest 65 | t1.latest.must_equal m.latest 66 | end 67 | 68 | it "provides access to raw dates" do 69 | t1 = TimeSpan.new(y,m) 70 | t1.earliest_raw.must_equal y 71 | t1.earliest_raw.precision.must_equal y.precision 72 | t1.latest_raw.must_equal m 73 | t1.latest_raw.precision.must_equal m.precision 74 | end 75 | 76 | it "initializes with two identical vague dates" do 77 | t1 = TimeSpan.new(y,y) 78 | t1.same?.must_equal true 79 | t1.precise?.must_equal false 80 | end 81 | 82 | it "initializes with two identical precise dates" do 83 | t1 = TimeSpan.new(d,d) 84 | t1.same?.must_equal true 85 | t1.precise?.must_equal true 86 | end 87 | 88 | it "reports well with a beginning date" do 89 | t1 = TimeSpan.new(y) 90 | t1.to_s.must_equal "after #{y.year}" 91 | end 92 | it "reports well with an uncertain beginning date" do 93 | y.certain = false 94 | t1 = TimeSpan.new(y) 95 | t1.to_s.must_equal "after 2014?" 96 | end 97 | 98 | it "reports well with a end date" do 99 | t1 = TimeSpan.new(nil,y) 100 | t1.to_s.must_equal "by #{y.year}" 101 | t2 = TimeSpan.new(nil,m) 102 | t2.to_s.must_equal "by October 2014" 103 | t2 = TimeSpan.new(nil,d) 104 | t2.to_s.must_equal "by October 17, 2014" 105 | end 106 | it "reports well with a precise date" do 107 | t1 = TimeSpan.new(d,d) 108 | t1.to_s.must_equal d.to_s(:long) 109 | end 110 | it "reports well with a precise uncertain date" do 111 | d.certain = false 112 | t1 = TimeSpan.new(d,d) 113 | t1.to_s.must_equal "October 17, 2014?" 114 | end 115 | it "reports well with a vague date" do 116 | t1 = TimeSpan.new(y,m) 117 | t1.to_s.must_equal "sometime between 2014 and October 2014" 118 | end 119 | describe "Parsing" do 120 | it "can take a date as a beginning" do 121 | t = TimeSpan.parse Date.new(2014) 122 | t.must_be_instance_of TimeSpan 123 | t.earliest.must_equal Date.new(2014,1,1) 124 | t.latest.must_equal Date.new(2014,12,31) 125 | end 126 | it "can take a TimeSpan as a beginning" do 127 | t = TimeSpan.parse TimeSpan.new(Date.new(2013),Date.new(2014)) 128 | t.must_be_instance_of TimeSpan 129 | t.earliest.must_equal Date.new(2013,1,1) 130 | t.latest.must_equal Date.new(2014,12,31) 131 | end 132 | it "can take a number as a beginning" do 133 | date_as_epoch = Date.new(2014,10,17).to_time.utc.to_i 134 | t = TimeSpan.parse date_as_epoch 135 | t.must_be_instance_of TimeSpan 136 | t.earliest.must_equal Date.new(2014,10,17) 137 | end 138 | it "can take a string as a beginning" do 139 | t = TimeSpan.parse "October 17, 2014" 140 | t.must_be_instance_of TimeSpan 141 | t.earliest.must_equal Date.new(2014,10,17) 142 | end 143 | it "throws invalid date if it does not recognize the string" do 144 | proc {t = TimeSpan.parse "Ice cream sandwiches"}.must_raise MuseumProvenance::DateError 145 | end 146 | end 147 | end -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/NamedEventParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::NamedEventParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::NamedEventParser 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Parser 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
Includes:
94 |
ParserHelpers, Parslet
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 |
Defined in:
104 |
lib/museum_provenance/parsers/named_event_parser.rb
105 |
106 | 107 |
108 | 109 |

Overview

110 |
111 | 112 |

This parser will parse a Named Event entity block, for example: > John 113 | Doe? [1910?-1995?], Boise, ID

114 | 115 |

If it parses, it can return:

116 |
  • 117 |

    :stock_number # The text of the stock number phrase

    118 |
119 | 120 | 121 |
122 |
123 |
124 | 125 |

Author:

126 |
    127 | 128 |
  • 129 | 130 | 131 | 132 | 133 | 134 |
    @workergnome 135 |
    136 |
    137 | 138 |
  • 139 | 140 |
141 | 142 |
143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 |

Method Summary

158 | 159 |

Methods included from ParserHelpers

160 |

#str_i

161 | 162 | 163 | 164 | 165 | 166 |
167 | 168 | 173 | 174 |
175 | 176 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/AuthorityParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::AuthorityParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::AuthorityParser 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Parser 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
Includes:
94 |
ParserHelpers, Parslet
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 |
Defined in:
104 |
lib/museum_provenance/parsers/authority_parser.rb
105 |
106 | 107 |
108 | 109 |

Overview

110 |
111 | 112 |

This parser will parse a Authority block, for example: > Salvador Dali: 113 | vocab.getty.edu/ulan/500009365 115 | > Cyrus L. Sulzberger: viaf.org/viaf/68936177

117 | 118 |

If it parses, it will return an array of :authorities:

119 |
  • 120 |

    :token # The name of the entity

    121 |
  • 122 |

    :uri # The URI represented

    123 |
124 | 125 | 126 |
127 |
128 |
129 | 130 |

Author:

131 |
    132 | 133 |
  • 134 | 135 | 136 | 137 | 138 | 139 |
    @workergnome 140 |
    141 |
    142 | 143 |
  • 144 | 145 |
146 | 147 |
148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 |

Method Summary

163 | 164 |

Methods included from ParserHelpers

165 |

#str_i

166 | 167 | 168 | 169 | 170 | 171 |
172 | 173 | 178 | 179 |
180 | 181 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers/SaleDataParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Parsers::SaleDataParser 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Parsers::SaleDataParser 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Parser 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
Includes:
94 |
ParserHelpers, Parslet
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 |
Defined in:
104 |
lib/museum_provenance/parsers/sale_data_parser.rb
105 |
106 | 107 |
108 | 109 |

Overview

110 |
111 | 112 |

This parser will parse a standard sale info block, for example: > (Stock 113 | no. 1, for $100)

114 | 115 |

If it parses, it can return:

116 |
  • 117 |

    :stock_number # The text of the stock number phrase

    118 |
  • 119 |

    :sale_amount # A text representation of the sale amount

    120 |
  • 121 |

    :sale_currency_symbol # A symbol for the currency

    122 |
  • 123 |

    :sale_value # A numeric value for the sale amount

    124 |
125 | 126 |

Note that it may return the sale_amount OR the 127 | sale_value/sale_currency_symbol, never both.

128 | 129 | 130 |
131 |
132 |
133 | 134 |

Author:

135 |
    136 | 137 |
  • 138 | 139 | 140 | 141 | 142 | 143 |
    davidnewbury 144 |
    145 |
    146 | 147 |
  • 148 | 149 |
150 | 151 |
152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 |

Method Summary

167 | 168 |

Methods included from ParserHelpers

169 |

#str_i

170 | 171 | 172 | 173 | 174 | 175 |
176 | 177 | 182 | 183 |
184 | 185 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Parsers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Module: MuseumProvenance::Parsers 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Module: MuseumProvenance::Parsers 63 | 64 | 65 | 66 |

67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 |
Included in:
79 |
Parser
80 |
81 | 82 | 83 | 84 |
85 |
Defined in:
86 |
lib/museum_provenance/parsers/actor_parser.rb,
87 | lib/museum_provenance/parsers/notes_parser.rb,
lib/museum_provenance/parsers/place_parser.rb,
lib/museum_provenance/parsers/parser_helpers.rb,
lib/museum_provenance/parsers/authority_parser.rb,
lib/museum_provenance/parsers/paragraph_parser.rb,
lib/museum_provenance/parsers/sale_data_parser.rb,
lib/museum_provenance/parsers/named_event_parser.rb,
lib/museum_provenance/parsers/provenance_helpers.rb,
lib/museum_provenance/parsers/note_section_parser.rb,
lib/museum_provenance/parsers/acquisition_method_parser.rb
88 |
89 |
90 | 91 |
92 | 93 |

Defined Under Namespace

94 |

95 | 96 | 97 | Modules: ParserHelpers, ProvenanceHelpers 98 | 99 | 100 | 101 | Classes: AcquisitionMethodParser, ActorParser, AuthorityParser, NamedEventParser, NoteSectionParser, NotesParser, ParagraphParser, PlaceParser, SaleDataParser 102 | 103 | 104 |

105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | 116 | 121 | 122 |
123 | 124 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Location.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Location 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Location 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Entity 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/location.rb
100 |
101 | 102 |
103 | 104 |

Overview

105 |
106 | 107 |

Location is a data structure for holding the location of a Period.

108 | 109 |

Currently, it does not have any functionality beyond that of a generic 110 | Entity but it is intended be extended to include geographical 111 | functionality.

112 | 113 | 114 |
115 |
116 |
117 | 118 | 119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 |

Method Summary

134 | 135 |

Methods inherited from Entity

136 |

#==, #initialize, #name, #name=, #to_s

137 |
138 |

Constructor Details

139 | 140 |

This class inherits a constructor from MuseumProvenance::Entity

141 | 142 |
143 | 144 | 145 |
146 | 147 | 152 | 153 |
154 | 155 | -------------------------------------------------------------------------------- /docs/MuseumProvenance/Transformers/AuthorityTransform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: MuseumProvenance::Transformers::AuthorityTransform 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: MuseumProvenance::Transformers::AuthorityTransform 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Parslet::Transform 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 | 80 | 81 |
82 | show all 83 | 84 |
85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
Defined in:
99 |
lib/museum_provenance/transformers/authority_transform.rb
100 |
101 | 102 |
103 | 104 | 105 |

Constant Summary

106 |
107 | 108 |
@@counter = 109 | 110 |
111 |
0
112 | 113 |
114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |

123 | Class Method Summary 124 | collapse 125 |

126 | 127 |
    128 | 129 |
  • 130 | 131 | 132 | .reset_counter ⇒ Object 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 |
    147 | 148 |
  • 149 | 150 | 151 |
152 | 153 | 154 | 155 | 156 | 157 |
158 |

Class Method Details

159 | 160 | 161 |
162 |

163 | 164 | .reset_counterObject 165 | 166 | 167 | 168 | 169 | 170 |

171 | 172 | 180 | 187 | 188 |
173 |
174 | 
175 | 
176 | 5
177 | 6
178 | 7
179 |
181 |
# File 'lib/museum_provenance/transformers/authority_transform.rb', line 5
182 | 
183 | def self.reset_counter
184 |   @@counter = 0
185 | end
186 |
189 |
190 | 191 |
192 | 193 |
194 | 195 | 200 | 201 |
202 | 203 | -------------------------------------------------------------------------------- /docs/css/full_list.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; 4 | font-size: 13px; 5 | height: 101%; 6 | overflow-x: hidden; 7 | background: #fafafa; 8 | } 9 | 10 | h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } 11 | .clear { clear: both; } 12 | .fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } 13 | #search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } 14 | #content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } 15 | #full_list { padding: 0; list-style: none; margin-left: 0; margin-top: 80px; font-size: 1.1em; } 16 | #full_list ul { padding: 0; } 17 | #full_list li { padding: 0; margin: 0; list-style: none; } 18 | #full_list li .item { padding: 5px 5px 5px 12px; } 19 | #noresults { padding: 7px 12px; background: #fff; } 20 | #content.insearch #noresults { margin-left: 7px; } 21 | li.collapsed ul { display: none; } 22 | li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } 23 | li.collapsed a.toggle { opacity: 0.5; cursor: default; background-position: top left; } 24 | li { color: #888; cursor: pointer; } 25 | li.deprecated { text-decoration: line-through; font-style: italic; } 26 | li.odd { background: #f0f0f0; } 27 | li.even { background: #fafafa; } 28 | .item:hover { background: #ddd; } 29 | li small:before { content: "("; } 30 | li small:after { content: ")"; } 31 | li small.search_info { display: none; } 32 | a, a:visited { text-decoration: none; color: #05a; } 33 | li.clicked > .item { background: #05a; color: #ccc; } 34 | li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } 35 | li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } 36 | li.collapsed.clicked a.toggle { background-position: top right; } 37 | #search input { border: 1px solid #bbb; border-radius: 3px; } 38 | #full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } 39 | #full_list_nav a, #nav a:visited { color: #358; } 40 | #full_list_nav a:hover { background: transparent; color: #5af; } 41 | #full_list_nav span:after { content: ' | '; } 42 | #full_list_nav span:last-child:after { content: ''; } 43 | 44 | #content h1 { margin-top: 0; } 45 | li { white-space: nowrap; cursor: normal; } 46 | li small { display: block; font-size: 0.8em; } 47 | li small:before { content: ""; } 48 | li small:after { content: ""; } 49 | li small.search_info { display: none; } 50 | #search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; } 51 | #content.insearch #search { background-position: center right; } 52 | #search input { width: 110px; } 53 | 54 | #full_list.insearch ul { display: block; } 55 | #full_list.insearch .item { display: none; } 56 | #full_list.insearch .found { display: block; padding-left: 11px !important; } 57 | #full_list.insearch li a.toggle { display: none; } 58 | #full_list.insearch li small.search_info { display: block; } 59 | -------------------------------------------------------------------------------- /lib/museum_provenance/acquisition_method.rb: -------------------------------------------------------------------------------- 1 | module MuseumProvenance 2 | # AcquisitionMethod is a data structure designed to hold forms of acqusition for lookup. 3 | # Each method can hold multiple valid forms, some of which go before the name, and some 4 | # of which go after the name. 5 | # 6 | # It also contains a human-readable definition of the form for display. 7 | # AcquisitionMethod is a data structure designed to hold forms of acquisition for lookup. 8 | # Each method can hold multiple valid forms, some of which go before the name, and some 9 | # of which go after the name. 10 | # 11 | # It also contains a human-readable definition of the form for display. 12 | class AcquisitionMethod 13 | 14 | # Signifies that the form's preferred location is before the name. 15 | Prefix = :prefix 16 | # Signifies that the form's preferred location is after the name. 17 | Suffix = :suffix 18 | 19 | # Returns a list of valid AcquisitionMethod instances 20 | # 21 | # @return [Array] A list of all loaded acquisition methods 22 | def self.valid_methods 23 | @@all_methods ||= [] 24 | end 25 | 26 | # Finds an instance of {AcquisitionMethod} with a given name. 27 | # 28 | # Returns nil if no match is found. 29 | # 30 | # @param name [String] a string containing the acquisition method name. 31 | # @return [AcquisitionMethod] the found acquisition method. 32 | def AcquisitionMethod.find_by_name(name) 33 | @@all_methods.find{|method| method.name == name} 34 | end 35 | 36 | 37 | # Finds an instance of {AcquisitionMethod} with a given id. 38 | # 39 | # Returns nil if no match is found. 40 | # 41 | # @param id [Symbol] a symbol of an acquisition method id. 42 | # @return [AcquisitionMethod] the found acquisition method. 43 | def AcquisitionMethod.find_by_id(id) 44 | @@all_methods.find{|method| method.id == id} 45 | end 46 | 47 | # Finds an instance of {AcquisitionMethod} containing the provided text 48 | # 49 | # If multiple forms match, this will return the most explicit form. 50 | # Returns nil if no match is found. 51 | # 52 | # @param str [String] a string potentially containing a form of acquisition. 53 | # @return [AcquisitionMethod] the found acquisition method. 54 | def AcquisitionMethod.find(str) 55 | valid_methods = [] 56 | @@all_methods.each do |method| 57 | method.forms.each do |form| 58 | valid_methods.push [method,form.downcase] if str.downcase.include? form.downcase 59 | end 60 | end 61 | valid_methods.compact 62 | return nil if valid_methods.empty? 63 | valid_methods.sort_by!{|t| t[1].length}.reverse.first[0] 64 | end 65 | 66 | 67 | # @!attribute [r] name 68 | # @return [String] the name of the method 69 | # @!attribute [r] prefix 70 | # @return [String] the preferred prefix form of the method 71 | # @!attribute [r] suffix 72 | # @return [String] the preferred suffix form of the method 73 | # @!attribute [r] definition 74 | # @return [String] A human readable definition of the method 75 | # @!attribute [r] preferred_form 76 | # @return [Symbol] Which form is preferred for this method 77 | # @!attribute [r] explanation 78 | # @return [String] A longer explanation of the method 79 | 80 | 81 | attr_reader :name, :prefix, :suffix, :definition, :preferred_form, :explanation, :type, :id, :parent, :class_description, :custody_transfer, :ownership_transfer 82 | 83 | # Creates a new instance of AttributionMethod. 84 | # Note that this will also add it to the Class-level list of Attribution Methods, which can be queried via @AttributionMethod::valid_methods 85 | def initialize(opts) 86 | @id = opts[:id] 87 | @name = opts[:title] 88 | @prefix = opts.fetch(:prefix, nil) 89 | @suffix = opts.fetch(:suffix, nil) 90 | @definition = opts.fetch(:description, nil) 91 | @explanation = opts.fetch(:explanation, nil) 92 | @preferred_form = opts.fetch(:preferred_form) 93 | @synonyms = opts.fetch(:synonyms, []) 94 | @@all_methods ||= [] 95 | @@all_methods.push self 96 | 97 | @parent = AcquisitionMethod.find_by_id opts[:parent] 98 | 99 | @type = opts.fetch(:type, @parent && @parent.type) 100 | @ownership_transfer = opts.fetch(:ownership_transfer, @parent && @parent.ownership_transfer) 101 | @custody_transfer = opts.fetch(:custody_transfer, @parent && @parent.custody_transfer) 102 | @class_description = opts.fetch(:class_description , @parent && @parent.class_description) 103 | end 104 | 105 | # Concatenates the preferred form with a given name. 106 | # Will properly handle both prefixes and suffixes, which is why we need a method to do this. 107 | # 108 | # @param name [String] The name to which you wish to attach the method. 109 | # @return [String] the given name with the preferred form attached to it. 110 | # @example For 'Gift of' 111 | # attach_to_name("David") # -> "Gift of David" 112 | def attach_to_name(name) 113 | if preferred_form == Prefix 114 | s= [prefix,name].compact.join(" ") 115 | else 116 | s = [name,suffix].compact.join(" ") 117 | end 118 | s.strip 119 | end 120 | 121 | # @return [String] The preferred form. 122 | def preferred 123 | self.send(preferred_form) 124 | end 125 | 126 | # @return [Array] A list of all forms of the Method. 127 | def forms 128 | [preferred,other_forms].flatten.compact 129 | end 130 | 131 | # @return [Array] A list of all forms of the Method EXCEPT the preferred form. 132 | def other_forms 133 | if preferred_form == Prefix 134 | [suffix,@synonyms].flatten.compact 135 | else 136 | [prefix,@synonyms].flatten.compact 137 | end 138 | end 139 | 140 | # @return [String] Returns the name of the method. 141 | def to_s 142 | name 143 | end 144 | alias :inspect :to_s 145 | end 146 | end -------------------------------------------------------------------------------- /docs/Fixnum.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Class: Fixnum 8 | 9 | — Documentation by YARD 0.9.8 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 |
36 | 61 | 62 |

Class: Fixnum 63 | 64 | 65 | 66 |

67 |
68 | 69 |
70 |
Inherits:
71 |
72 | Object 73 | 74 |
    75 |
  • Object
  • 76 | 77 | 78 | 79 |
80 | show all 81 | 82 |
83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
96 |
Defined in:
97 |
lib/museum_provenance/utilities/to_bool.rb
98 |
99 | 100 |
101 | 102 |

Overview

103 |
104 | 105 |

Ruby built-in representation of integers, reopened to add additional 106 | functionality.

107 | 108 | 109 |
110 |
111 |
112 | 113 | 114 |
115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |

123 | Instance Method Summary 124 | collapse 125 |

126 | 127 |
    128 | 129 |
  • 130 | 131 | 132 | #to_bool ⇒ Boolean 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 |
    147 |

    Extends [Fixnum] for conversion to a boolean.

    148 |
    149 | 150 |
  • 151 | 152 | 153 |
154 | 155 | 156 | 157 | 158 |
159 |

Instance Method Details

160 | 161 | 162 |
163 |

164 | 165 | #to_boolBoolean 166 | 167 | 168 | 169 | 170 | 171 |

172 |
173 | 174 |

Extends [Fixnum] for conversion to a boolean.

175 | 176 | 177 |
178 |
179 |
180 | 181 |

Returns:

182 |
    183 | 184 |
  • 185 | 186 | 187 | (Boolean) 188 | 189 | 190 | 191 |
  • 192 | 193 |
194 |

Raises:

195 |
    196 | 197 |
  • 198 | 199 | 200 | (ArgumentError) 201 | 202 | 203 | 204 |
  • 205 | 206 |
207 | 208 |
209 | 210 | 220 | 229 | 230 |
211 |
212 | 
213 | 
214 | 17
215 | 18
216 | 19
217 | 20
218 | 21
219 |
221 |
# File 'lib/museum_provenance/utilities/to_bool.rb', line 17
222 | 
223 | def to_bool
224 |   return true if self == 1
225 |   return false if self == 0
226 |   raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
227 | end
228 |
231 |
232 | 233 |
234 | 235 |
236 | 237 | 242 | 243 |
244 | 245 | -------------------------------------------------------------------------------- /old_tests/timeline_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper.rb" 2 | 3 | describe Timeline do 4 | 5 | let(:t) {Timeline.new} 6 | let(:p1) {Period.new("P1")} 7 | let(:p2) {Period.new("P2")} 8 | let(:p3) {Period.new("P3")} 9 | let(:p4) {Period.new("P4")} 10 | 11 | it "begins empty" do 12 | t.earliest.must_be_nil 13 | t.latest.must_be_nil 14 | t.count.must_equal 0 15 | end 16 | 17 | it "returns nil for bad access" do 18 | t.first.must_be_nil 19 | t.last.must_be_nil 20 | t[0].must_be_nil 21 | end 22 | 23 | it "handles insertion" do 24 | t.insert(p1) 25 | t.earliest.must_equal p1 26 | t.latest.must_equal p1 27 | end 28 | 29 | it "handles multiple instertions" do 30 | t.insert_earliest(p1) 31 | t.insert_latest(p2) 32 | t.earliest.must_equal p1 33 | t.latest.must_equal p2 34 | end 35 | 36 | it "handles array access" do 37 | t.insert p1 38 | t.insert p2 39 | t.insert p3 40 | t[0].must_equal p1 41 | t[1].must_equal p2 42 | t[2].must_equal p3 43 | end 44 | 45 | it "handles last" do 46 | t.insert p1 47 | t.insert p2 48 | t.insert p3 49 | t.last.must_equal p3 50 | end 51 | 52 | it "handles multiple instertions at the beginning" do 53 | t.insert_earliest(p1) 54 | t.insert_earliest(p2) 55 | t.earliest.must_equal p2 56 | t.latest.must_equal p1 57 | end 58 | 59 | it "handles instertions after something" do 60 | t.insert(p1) 61 | t.insert_before(p1, p2) 62 | t.earliest.must_equal p2 63 | t.latest.must_equal p1 64 | end 65 | 66 | it "handles instertions after something" do 67 | t.insert_earliest(p1) 68 | t.insert_earliest(p2) 69 | t.insert_after(p2, p3) 70 | t.earliest.must_equal p2 71 | t.latest.must_equal p1 72 | t.count.must_equal 3 73 | end 74 | 75 | describe "Provenance Records" do 76 | before do 77 | t.insert(p1) 78 | t.insert(p2) 79 | end 80 | it "generates a record" do 81 | t.provenance.must_be_instance_of String 82 | end 83 | it "connects transfers with periods" do 84 | t.provenance.must_equal "#{p1.provenance}. #{p2.provenance}." 85 | end 86 | it "connects several direct transfers with semicolons" do 87 | t.insert_direct(p3) 88 | t.provenance.must_equal "#{p1.provenance}. #{p2.provenance}; #{p3.provenance}." 89 | end 90 | it "handles linking footnotes to elements" do 91 | p1.note = "note 1" 92 | p2.note = "note 2" 93 | t.provenance.must_include Period.formatted_footnote(1, "note 1") 94 | t.provenance.must_include Period.formatted_footnote(2, "note 2") 95 | end 96 | 97 | it "handles earliest dates" do 98 | p1.beginning = Date.new(2000,10,17) 99 | t.provenance.must_include p1.beginning.to_s 100 | end 101 | end 102 | 103 | describe "Meeting" do 104 | 105 | it "does not assume meetings" do 106 | p1.direct_transfer.must_be_nil 107 | end 108 | 109 | it "defaults to false" do 110 | t.insert(p1) 111 | t.insert(p2) 112 | p1.direct_transfer.must_equal false 113 | end 114 | 115 | it "will not allow a transfer to nothing" do 116 | t.insert(p1) 117 | t.insert(p2) 118 | p2.direct_transfer = true 119 | p2.direct_transfer.must_be_nil 120 | end 121 | 122 | it "allows explicit meetings" do 123 | t.insert(p1) 124 | t.insert(p2) 125 | p1.direct_transfer = true 126 | p1.direct_transfer.must_equal true 127 | p2.was_directly_transferred.must_equal true 128 | end 129 | 130 | it "does not carry over with new assignments" do 131 | t.insert(p1) 132 | t.insert(p2) 133 | p1.direct_transfer = true 134 | t.insert_after(p1,p3) 135 | p1.direct_transfer.must_equal false 136 | p2.was_directly_transferred.must_equal false 137 | end 138 | 139 | it "does not carry over when the met party changes" do 140 | t.insert(p1) 141 | t.insert(p2) 142 | p1.direct_transfer = true 143 | t.insert_before(p2,p3) 144 | p1.direct_transfer.must_equal false 145 | p2.was_directly_transferred.must_equal false 146 | end 147 | 148 | it "allows explicit insertion" do 149 | t.insert(p1) 150 | t.insert_directly_after(p1,p2) 151 | p1.direct_transfer.must_equal true 152 | p2.was_directly_transferred.must_equal true 153 | end 154 | 155 | it "allows shortcut explicit insertion" do 156 | t.insert_direct(p1) 157 | p1.direct_transfer.must_be_nil 158 | t.insert_direct(p2) 159 | p1.direct_transfer.must_equal true 160 | t.insert_after(p1,p3) 161 | p1.direct_transfer.must_equal false 162 | end 163 | end 164 | 165 | describe "Linking" do 166 | before do 167 | t.insert(p1) 168 | end 169 | it "links to previous and next objects" do 170 | t.insert_before(p1,p2) 171 | assert_equal p1, p2.next_period 172 | assert_equal p2, p1.previous_period 173 | end 174 | it "does not let things precede themselves" do 175 | p1.is_before?(p1).must_equal false 176 | p1.is_after?(p1).must_equal false 177 | end 178 | it "doesn't assume is_before" do 179 | p1.is_before?(p3).must_equal false 180 | p1.is_after?(p3).must_equal false 181 | end 182 | it "handles single is_before?" do 183 | t.insert_before(p1,p2) 184 | p2.is_before?(p1).must_equal true 185 | p1.is_after?(p2).must_equal true 186 | end 187 | it "follows forward links " do 188 | t.insert_before(p1,p2) 189 | t.insert_before(p2,p3) 190 | p3.is_before?(p1).must_equal true 191 | p1.is_after?(p3).must_equal true 192 | end 193 | it "has no default siblings" do 194 | assert_equal p1.siblings.size, 1 195 | assert_includes p1.siblings, p1 196 | end 197 | it "gathers siblings" do 198 | t.insert_before(p1,p2) 199 | t.insert_before(p2,p3) 200 | t.insert_after(p2,p4) 201 | assert_equal p1.siblings.size, 4 202 | assert_includes p1.siblings, p4 203 | end 204 | it "orders siblings" do 205 | t.insert_before(p1,p2) 206 | t.insert_before(p2,p3) 207 | t.insert_after(p1,p4) 208 | assert_equal p1.siblings.first, p3 209 | assert_equal p1.siblings.last, p4 210 | end 211 | end 212 | end --------------------------------------------------------------------------------