relaton-bib 1.14.4 → 1.14.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/lib/relaton_bib/bib_item_locality.rb +2 -1
- data/lib/relaton_bib/bibliographic_item.rb +8 -429
- data/lib/relaton_bib/bibtex_parser.rb +1 -0
- data/lib/relaton_bib/forename.rb +1 -1
- data/lib/relaton_bib/formatted_string.rb +1 -1
- data/lib/relaton_bib/hash_converter.rb +4 -2
- data/lib/relaton_bib/hit.rb +3 -1
- data/lib/relaton_bib/medium.rb +1 -1
- data/lib/relaton_bib/renderer/bibtex_builder.rb +312 -0
- data/lib/relaton_bib/renderer/bibxml.rb +290 -0
- data/lib/relaton_bib/version.rb +1 -1
- data/lib/relaton_bib.rb +7 -3
- data/relaton-bib.gemspec +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a4d2a5d90a56a9b93f34acc0d037d101130c36b34a4d436c28c6dc8c53496eb
|
4
|
+
data.tar.gz: 2b99e61f20b08a6ca48a2b42c16abef7cfe0e9f4340e413d1e37a4ff3e098969
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d1f0ec61452cdc6bdedde4bd1025a2aa9d3baeeeaa65f3e3b212aa56cd2753afee04dccc13870a1bea5e88b388a97e086adea56353272204a49251b46145384
|
7
|
+
data.tar.gz: 880ddde78e8fc665caf7b7a104efecd476c5787d34f839f73a7f1bc70425b6872dcd68bdaa7305fc751eb7cfe6e5c3395fa9df69771bec0634ceccdfdf66f890
|
data/.rubocop.yml
CHANGED
@@ -62,9 +62,10 @@ module RelatonBib
|
|
62
62
|
when "chapter" then item.chapter = reference_from
|
63
63
|
when "page"
|
64
64
|
value = reference_from
|
65
|
-
value += "
|
65
|
+
value += "--#{reference_to}" if reference_to
|
66
66
|
item.pages = value
|
67
67
|
when "volume" then item.volume = reference_from
|
68
|
+
when "issue" then item.number = reference_from
|
68
69
|
end
|
69
70
|
end
|
70
71
|
end
|
@@ -151,7 +151,7 @@ module RelatonBib
|
|
151
151
|
# @param series [Array<RelatonBib::Series>]
|
152
152
|
# @param medium [RelatonBib::Medium, nil]
|
153
153
|
# @param place [Array<String, RelatonBib::Place>]
|
154
|
-
# @param extent [Array<
|
154
|
+
# @param extent [Array<RelatonBib::Locality, RelatonBib::LocalityStack>]
|
155
155
|
# @param accesslocation [Array<String>]
|
156
156
|
# @param classification [Array<RelatonBib::Classification>]
|
157
157
|
# @param validity [RelatonBib:Validity, nil]
|
@@ -378,13 +378,7 @@ module RelatonBib
|
|
378
378
|
# @return [String, Nokogiri::XML::Builder::NodeBuilder] XML
|
379
379
|
#
|
380
380
|
def to_bibxml(builder = nil, include_keywords: false)
|
381
|
-
|
382
|
-
render_bibxml builder, include_keywords
|
383
|
-
else
|
384
|
-
Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
385
|
-
render_bibxml xml, include_keywords
|
386
|
-
end.doc.root.to_xml
|
387
|
-
end
|
381
|
+
Renderer::BibXML.new(self).render builder: builder, include_keywords: include_keywords
|
388
382
|
end
|
389
383
|
|
390
384
|
# @return [Hash]
|
@@ -448,7 +442,7 @@ module RelatonBib
|
|
448
442
|
# @return [String]
|
449
443
|
#
|
450
444
|
def to_bibtex(bibtex = nil)
|
451
|
-
|
445
|
+
Renderer::BibtexBuilder.build(self, bibtex).to_s
|
452
446
|
end
|
453
447
|
|
454
448
|
#
|
@@ -459,7 +453,9 @@ module RelatonBib
|
|
459
453
|
# @return [Hash] citeproc
|
460
454
|
#
|
461
455
|
def to_citeproc(bibtex = nil)
|
462
|
-
|
456
|
+
Renderer::BibtexBuilder.build(self, bibtex).to_citeproc.map do |cp|
|
457
|
+
cp.transform_keys(&:to_s)
|
458
|
+
end
|
463
459
|
end
|
464
460
|
|
465
461
|
# @param lang [String, nil] language code Iso639
|
@@ -497,6 +493,8 @@ module RelatonBib
|
|
497
493
|
ttl = me.title.select do |t|
|
498
494
|
t.type != "main" && t.title.language&.include?(l)
|
499
495
|
end
|
496
|
+
next if ttl.empty?
|
497
|
+
|
500
498
|
tm_en = ttl.map { |t| t.title.content }.join " – "
|
501
499
|
me.title.detect do |t|
|
502
500
|
t.type == "main" && t.title.language&.include?(l)
|
@@ -590,162 +588,6 @@ module RelatonBib
|
|
590
588
|
|
591
589
|
private
|
592
590
|
|
593
|
-
#
|
594
|
-
# Create BibTeX item for this document
|
595
|
-
#
|
596
|
-
# @param [BibTeX::Bibliography, nil] bibtex <description>
|
597
|
-
#
|
598
|
-
# @return [BibTeX::Bibliography] BibTeX bibliography
|
599
|
-
#
|
600
|
-
def bibtext_item(bibtex) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
601
|
-
item = BibTeX::Entry.new
|
602
|
-
item.type = bibtex_type
|
603
|
-
item.key = id
|
604
|
-
title.to_bibtex item
|
605
|
-
item.edition = edition.content if edition
|
606
|
-
bibtex_author item
|
607
|
-
bibtex_contributor item
|
608
|
-
item.address = place.first.name if place.any?
|
609
|
-
bibtex_note item
|
610
|
-
bibtex_relation item
|
611
|
-
bibtex_extent item
|
612
|
-
bibtex_date item
|
613
|
-
bibtex_series item
|
614
|
-
bibtex_classification item
|
615
|
-
item.keywords = keyword.map(&:content).join(", ") if keyword.any?
|
616
|
-
bibtex_docidentifier item
|
617
|
-
item.timestamp = fetched.to_s if fetched
|
618
|
-
bibtex_link item
|
619
|
-
bibtex ||= BibTeX::Bibliography.new
|
620
|
-
bibtex << item
|
621
|
-
bibtex
|
622
|
-
end
|
623
|
-
|
624
|
-
# @return [String]
|
625
|
-
def bibtex_type
|
626
|
-
case type
|
627
|
-
when "standard", nil then "misc"
|
628
|
-
else type
|
629
|
-
end
|
630
|
-
end
|
631
|
-
|
632
|
-
# @param [BibTeX::Entry]
|
633
|
-
def bibtex_author(item) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
|
634
|
-
authors = contributor.select do |c|
|
635
|
-
c.entity.is_a?(Person) && c.role.map(&:type).include?("author")
|
636
|
-
end.map &:entity
|
637
|
-
|
638
|
-
return unless authors.any?
|
639
|
-
|
640
|
-
item.author = authors.map do |a|
|
641
|
-
if a.name.surname
|
642
|
-
"#{a.name.surname}, #{a.name.forename.map(&:to_s).join(' ')}"
|
643
|
-
else
|
644
|
-
a.name.completename.to_s
|
645
|
-
end
|
646
|
-
end.join " and "
|
647
|
-
end
|
648
|
-
|
649
|
-
# @param [BibTeX::Entry]
|
650
|
-
def bibtex_contributor(item) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength
|
651
|
-
contributor.each do |c|
|
652
|
-
rls = c.role.map(&:type)
|
653
|
-
if rls.include?("publisher") then item.publisher = c.entity.name
|
654
|
-
elsif rls.include?("distributor")
|
655
|
-
case type
|
656
|
-
when "techreport" then item.institution = c.entity.name
|
657
|
-
when "inproceedings", "conference", "manual", "proceedings"
|
658
|
-
item.organization = c.entity.name
|
659
|
-
when "mastersthesis", "phdthesis" then item.school = c.entity.name
|
660
|
-
end
|
661
|
-
end
|
662
|
-
end
|
663
|
-
end
|
664
|
-
|
665
|
-
# @param [BibTeX::Entry]
|
666
|
-
def bibtex_note(item) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/AbcSize
|
667
|
-
biblionote.each do |n|
|
668
|
-
case n.type
|
669
|
-
when "annote" then item.annote = n.content
|
670
|
-
when "howpublished" then item.howpublished = n.content
|
671
|
-
when "comment" then item.comment = n.content
|
672
|
-
when "tableOfContents" then item.content = n.content
|
673
|
-
when nil then item.note = n.content
|
674
|
-
end
|
675
|
-
end
|
676
|
-
end
|
677
|
-
|
678
|
-
# @param [BibTeX::Entry]
|
679
|
-
def bibtex_relation(item)
|
680
|
-
rel = relation.detect { |r| r.type == "partOf" }
|
681
|
-
if rel
|
682
|
-
title_main = rel.bibitem.title.detect { |t| t.type == "main" }
|
683
|
-
item.booktitle = title_main.title.content
|
684
|
-
end
|
685
|
-
end
|
686
|
-
|
687
|
-
# @param [BibTeX::Entry]
|
688
|
-
def bibtex_extent(item)
|
689
|
-
extent.each { |e| e.to_bibtex(item) }
|
690
|
-
end
|
691
|
-
|
692
|
-
# @param [BibTeX::Entry]
|
693
|
-
def bibtex_date(item)
|
694
|
-
date.each do |d|
|
695
|
-
case d.type
|
696
|
-
when "published"
|
697
|
-
item.year = d.on :year
|
698
|
-
item.month = d.on :month
|
699
|
-
when "accessed" then item.urldate = d.on.to_s
|
700
|
-
end
|
701
|
-
end
|
702
|
-
end
|
703
|
-
|
704
|
-
# @param [BibTeX::Entry]
|
705
|
-
def bibtex_series(item)
|
706
|
-
series.each do |s|
|
707
|
-
case s.type
|
708
|
-
when "journal"
|
709
|
-
item.journal = s.title.title
|
710
|
-
item.number = s.number if s.number
|
711
|
-
when nil then item.series = s.title.title
|
712
|
-
end
|
713
|
-
end
|
714
|
-
end
|
715
|
-
|
716
|
-
# @param [BibTeX::Entry]
|
717
|
-
def bibtex_classification(item)
|
718
|
-
classification.each do |c|
|
719
|
-
case c.type
|
720
|
-
when "type" then item["type"] = c.value
|
721
|
-
# when "keyword" then item.keywords = c.value
|
722
|
-
when "mendeley" then item["mendeley-tags"] = c.value
|
723
|
-
end
|
724
|
-
end
|
725
|
-
end
|
726
|
-
|
727
|
-
# @param [BibTeX::Entry]
|
728
|
-
def bibtex_docidentifier(item)
|
729
|
-
docidentifier.each do |i|
|
730
|
-
case i.type
|
731
|
-
when "isbn" then item.isbn = i.id
|
732
|
-
when "lccn" then item.lccn = i.id
|
733
|
-
when "issn" then item.issn = i.id
|
734
|
-
end
|
735
|
-
end
|
736
|
-
end
|
737
|
-
|
738
|
-
# @param [BibTeX::Entry]
|
739
|
-
def bibtex_link(item)
|
740
|
-
link.each do |l|
|
741
|
-
case l.type
|
742
|
-
when "doi" then item.doi = l.content
|
743
|
-
when "file" then item.file2 = l.content
|
744
|
-
when "src" then item.url = l.content
|
745
|
-
end
|
746
|
-
end
|
747
|
-
end
|
748
|
-
|
749
591
|
# @param opts [Hash]
|
750
592
|
# @option opts [Nokogiri::XML::Builder] :builder XML builder
|
751
593
|
# @option opts [Boolean] bibdata
|
@@ -811,268 +653,5 @@ module RelatonBib
|
|
811
653
|
xml["schema-version"] = schema unless opts[:embedded]
|
812
654
|
xml
|
813
655
|
end
|
814
|
-
|
815
|
-
#
|
816
|
-
# Render BibXML (RFC, BCP)
|
817
|
-
#
|
818
|
-
# @param [Nokogiri::XML::Builder] builder
|
819
|
-
# @param [Boolean] include_bibdata
|
820
|
-
#
|
821
|
-
def render_bibxml(builder, include_keywords) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
822
|
-
target = link.detect { |l| l.type.casecmp("src").zero? } ||
|
823
|
-
link.detect { |l| l.type.casecmp("doi").zero? }
|
824
|
-
bxml = if docnumber&.match(/^BCP/) || (docidentifier.detect(&:primary)&.id ||
|
825
|
-
docidentifier[0].id).include?("BCP")
|
826
|
-
render_bibxml_refgroup(builder, include_keywords)
|
827
|
-
else
|
828
|
-
render_bibxml_ref(builder, include_keywords)
|
829
|
-
end
|
830
|
-
bxml[:target] = target.content.to_s if target
|
831
|
-
end
|
832
|
-
|
833
|
-
#
|
834
|
-
# Render BibXML (BCP)
|
835
|
-
#
|
836
|
-
# @param [Nokogiri::XML::Builder] builder
|
837
|
-
# @param [Boolean] include_keywords
|
838
|
-
#
|
839
|
-
def render_bibxml_refgroup(builder, include_keywords)
|
840
|
-
builder.referencegroup(**ref_attrs) do |b|
|
841
|
-
relation.each do |r|
|
842
|
-
r.bibitem.to_bibxml(b, include_keywords: include_keywords) if r.type == "includes"
|
843
|
-
end
|
844
|
-
end
|
845
|
-
end
|
846
|
-
|
847
|
-
#
|
848
|
-
# Render BibXML (RFC)
|
849
|
-
#
|
850
|
-
# @param [Nokogiri::XML::Builder] builder
|
851
|
-
# @param [Boolean] include_keywords
|
852
|
-
#
|
853
|
-
def render_bibxml_ref(builder, include_keywords) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
854
|
-
builder.reference(**ref_attrs) do |xml|
|
855
|
-
if title.any? || contributor.any? || date.any? || abstract.any? ||
|
856
|
-
editorialgroup&.technical_committee&.any? ||
|
857
|
-
(include_keywords && keyword.any?)
|
858
|
-
xml.front do
|
859
|
-
xml.title title[0].title.content if title.any?
|
860
|
-
render_authors xml
|
861
|
-
render_date xml
|
862
|
-
render_workgroup xml
|
863
|
-
render_keyword xml if include_keywords
|
864
|
-
render_abstract xml
|
865
|
-
end
|
866
|
-
end
|
867
|
-
render_seriesinfo xml
|
868
|
-
render_format xml
|
869
|
-
end
|
870
|
-
end
|
871
|
-
|
872
|
-
def render_format(builder)
|
873
|
-
link.select { |l| l.type == "TXT" }.each do |l|
|
874
|
-
builder.format type: l.type, target: l.content
|
875
|
-
end
|
876
|
-
end
|
877
|
-
|
878
|
-
#
|
879
|
-
# Create reference attributes
|
880
|
-
#
|
881
|
-
# @return [Hash<Symbol=>String>] attributes
|
882
|
-
#
|
883
|
-
def ref_attrs # rubocop:disable Metrics/AbcSize
|
884
|
-
discopes = %w[anchor docName number]
|
885
|
-
attrs = docidentifier.each_with_object({}) do |di, h|
|
886
|
-
next unless discopes.include?(di.scope)
|
887
|
-
|
888
|
-
h[di.scope.to_sym] = di.id
|
889
|
-
end
|
890
|
-
return attrs if attrs.any?
|
891
|
-
|
892
|
-
docidentifier.first&.tap do |di|
|
893
|
-
anchor = di.type == "IANA" ? di.id.split[1..-1].join(" ").upcase : di.id
|
894
|
-
return { anchor: anchor.gsub(" ", ".") }
|
895
|
-
end
|
896
|
-
end
|
897
|
-
|
898
|
-
#
|
899
|
-
# Render keyword
|
900
|
-
#
|
901
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
902
|
-
#
|
903
|
-
def render_keyword(builder)
|
904
|
-
keyword.each { |kw| builder.keyword kw.content }
|
905
|
-
end
|
906
|
-
|
907
|
-
#
|
908
|
-
# Render workgroup
|
909
|
-
#
|
910
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
911
|
-
#
|
912
|
-
def render_workgroup(builder)
|
913
|
-
editorialgroup&.technical_committee&.each do |tc|
|
914
|
-
builder.workgroup tc.workgroup.name
|
915
|
-
end
|
916
|
-
end
|
917
|
-
|
918
|
-
#
|
919
|
-
# Render abstract
|
920
|
-
#
|
921
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
922
|
-
#
|
923
|
-
def render_abstract(builder)
|
924
|
-
return unless abstract.any?
|
925
|
-
|
926
|
-
builder.abstract { |xml| xml << abstract[0].content.gsub(/(<\/?)p(>)/, '\1t\2') }
|
927
|
-
end
|
928
|
-
|
929
|
-
#
|
930
|
-
# Render date
|
931
|
-
#
|
932
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
933
|
-
#
|
934
|
-
def render_date(builder) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
935
|
-
dt = date.detect { |d| d.type == "published" }
|
936
|
-
return unless dt
|
937
|
-
|
938
|
-
elm = builder.date
|
939
|
-
y = dt.on(:year) || dt.from(:year) || dt.to(:year)
|
940
|
-
elm[:year] = y if y
|
941
|
-
m = dt.on(:month) || dt.from(:month) || dt.to(:month)
|
942
|
-
elm[:month] = Date::MONTHNAMES[m] if m
|
943
|
-
# rfcs = %w[RFC BCP FYI STD]
|
944
|
-
# unless rfcs.include?(doctype) && docidentifier.detect { |di| rfcs.include? di.type }
|
945
|
-
d = dt.on(:day) || dt.from(:day) || dt.to(:day)
|
946
|
-
elm[:day] = d if d
|
947
|
-
# end
|
948
|
-
end
|
949
|
-
|
950
|
-
#
|
951
|
-
# Render seriesinfo
|
952
|
-
#
|
953
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
954
|
-
#
|
955
|
-
def render_seriesinfo(builder) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
956
|
-
docidentifier.each do |di|
|
957
|
-
if BibXMLParser::SERIESINFONAMES.include? di.type
|
958
|
-
builder.seriesInfo(name: di.type, value: di.id)
|
959
|
-
end
|
960
|
-
end
|
961
|
-
# di_types = docidentifier.map(&:type)
|
962
|
-
series.select do |s|
|
963
|
-
s.title && # !di_types.include?(s.title.title.to_s) &&
|
964
|
-
!BibXMLParser::SERIESINFONAMES.include?(s.title.title.to_s)
|
965
|
-
end.uniq { |s| s.title.title.to_s }.each do |s|
|
966
|
-
si = builder.seriesInfo(name: s.title.title.to_s)
|
967
|
-
si[:value] = s.number if s.number
|
968
|
-
end
|
969
|
-
end
|
970
|
-
|
971
|
-
#
|
972
|
-
# Render authors
|
973
|
-
#
|
974
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
975
|
-
#
|
976
|
-
def render_authors(builder) # rubocop:disable Metrics/AbcSize
|
977
|
-
contributor.each do |c|
|
978
|
-
builder.author do |xml|
|
979
|
-
xml.parent[:role] = "editor" if c.role.detect { |r| r.type == "editor" }
|
980
|
-
if c.entity.is_a?(Person) then render_person xml, c.entity
|
981
|
-
else render_organization xml, c.entity, c.role
|
982
|
-
end
|
983
|
-
render_address xml, c
|
984
|
-
end
|
985
|
-
end
|
986
|
-
end
|
987
|
-
|
988
|
-
#
|
989
|
-
# Render address
|
990
|
-
#
|
991
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
992
|
-
# @param [RelatonBib::ContributionInfo] contrib contributor
|
993
|
-
#
|
994
|
-
def render_address(builder, contrib) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
995
|
-
# addr = contrib.entity.contact.reject do |cn|
|
996
|
-
# cn.is_a?(Address) && cn.postcode.nil?
|
997
|
-
# end
|
998
|
-
if contrib.entity.contact.any?
|
999
|
-
builder.address do |xml|
|
1000
|
-
address = contrib.entity.contact.detect { |cn| cn.is_a? Address }
|
1001
|
-
if address
|
1002
|
-
xml.postal do
|
1003
|
-
xml.city address.city if address.city
|
1004
|
-
xml.code address.postcode if address.postcode
|
1005
|
-
xml.country address.country if address.country
|
1006
|
-
xml.region address.state if address.state
|
1007
|
-
xml.street address.street[0] if address.street.any?
|
1008
|
-
end
|
1009
|
-
end
|
1010
|
-
render_contact xml, contrib.entity.contact
|
1011
|
-
end
|
1012
|
-
end
|
1013
|
-
end
|
1014
|
-
|
1015
|
-
#
|
1016
|
-
# Render contact
|
1017
|
-
#
|
1018
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
1019
|
-
# @param [Array<RelatonBib::Address, RelatonBib::Contact>] addr contact
|
1020
|
-
#
|
1021
|
-
def render_contact(builder, addr)
|
1022
|
-
%w[phone email uri].each do |type|
|
1023
|
-
cont = addr.detect { |cn| cn.is_a?(Contact) && cn.type == type }
|
1024
|
-
builder.send type, cont.value if cont
|
1025
|
-
end
|
1026
|
-
end
|
1027
|
-
|
1028
|
-
#
|
1029
|
-
# Render person
|
1030
|
-
#
|
1031
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
1032
|
-
# @param [RelatonBib::Person] person person
|
1033
|
-
#
|
1034
|
-
def render_person(builder, person) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
1035
|
-
render_organization builder, person.affiliation.first&.organization
|
1036
|
-
if person.name.completename
|
1037
|
-
builder.parent[:fullname] = person.name.completename.content
|
1038
|
-
elsif person.name.forename.any?
|
1039
|
-
builder.parent[:fullname] = person.name.forename.map do |n|
|
1040
|
-
n.content || n.initial
|
1041
|
-
end.join " "
|
1042
|
-
end
|
1043
|
-
if person.name.initials
|
1044
|
-
builder.parent[:initials] = person.name.initials.content
|
1045
|
-
elsif person.name.forename.any?
|
1046
|
-
builder.parent[:initials] = person.name.forename.map do |f|
|
1047
|
-
"#{f.initial || f.content[0]}."
|
1048
|
-
end.join
|
1049
|
-
end
|
1050
|
-
if person.name.surname
|
1051
|
-
if !person.name.completename && person.name.forename.any? && person.name.surname
|
1052
|
-
builder.parent[:fullname] += " #{person.name.surname}"
|
1053
|
-
end
|
1054
|
-
builder.parent[:surname] = person.name.surname.content
|
1055
|
-
end
|
1056
|
-
end
|
1057
|
-
|
1058
|
-
#
|
1059
|
-
# Render organization
|
1060
|
-
#
|
1061
|
-
# @param [Nokogiri::XML::Builder] builder xml builder
|
1062
|
-
# @param [RelatonBib::Organization] org organization
|
1063
|
-
#
|
1064
|
-
def render_organization(builder, org, _role = []) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/AbcSize
|
1065
|
-
abbrev = org&.abbreviation&.content
|
1066
|
-
orgname = org&.name&.first&.content
|
1067
|
-
orgname = if BibXMLParser::ORGNAMES.key?(abbrev) then abbrev
|
1068
|
-
else BibXMLParser::ORGNAMES.key(orgname) || orgname || abbrev
|
1069
|
-
end
|
1070
|
-
# if role.detect { |r| r.description.detect { |d| d.content == "BibXML author" } }
|
1071
|
-
# builder.parent[:fullname] = orgname
|
1072
|
-
# else
|
1073
|
-
org = builder.organization orgname
|
1074
|
-
org[:abbrev] = abbrev if abbrev
|
1075
|
-
# end
|
1076
|
-
end
|
1077
656
|
end
|
1078
657
|
end
|
data/lib/relaton_bib/forename.rb
CHANGED
@@ -122,7 +122,7 @@ module RelatonBib
|
|
122
122
|
str.gsub(/(?<=<)\w+:(?=\w+>)/, "").gsub(/(?<=<\/)\w+:(?=\w+>)/, "")
|
123
123
|
.gsub(/<i>/, "<em>").gsub(/<\/i>/, "</em>")
|
124
124
|
.gsub(/<b>/, "<strong>").gsub(/<\/b>/, "</strong>")
|
125
|
-
.gsub(/<(?!\/?(em|strong|stem|sup|sub|tt|br\s?\/|p))[^\s!]\/?.*?>/, "
|
125
|
+
.gsub(/<(?!\/?(em|strong|stem|sup|sub|tt|br\s?\/|p))[^\s!]\/?.*?>/, "")
|
126
126
|
.gsub(/\s+([.,:;!?<])/, "\\1").strip
|
127
127
|
end
|
128
128
|
end
|
@@ -282,7 +282,7 @@ module RelatonBib
|
|
282
282
|
return [] unless person[:affiliation]
|
283
283
|
|
284
284
|
RelatonBib.array(person[:affiliation]).map do |a|
|
285
|
-
a[:description] = RelatonBib.array(a[:description])
|
285
|
+
a[:description] = RelatonBib.array(a[:description]).map do |d|
|
286
286
|
cnt = if d.is_a?(Hash)
|
287
287
|
{ content: d[:content], language: d[:language],
|
288
288
|
script: d[:script], format: d[:format] }
|
@@ -323,7 +323,9 @@ module RelatonBib
|
|
323
323
|
return unless ret[:copyright]
|
324
324
|
|
325
325
|
ret[:copyright] = RelatonBib.array(ret[:copyright]).map do |c|
|
326
|
-
c[:owner] = RelatonBib.array(c[:owner])
|
326
|
+
c[:owner] = RelatonBib.array(c[:owner]).map do |o|
|
327
|
+
org_hash_to_bib(o)
|
328
|
+
end
|
327
329
|
c
|
328
330
|
end
|
329
331
|
end
|
data/lib/relaton_bib/hit.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "weakref"
|
2
|
+
|
1
3
|
module RelatonBib
|
2
4
|
class Hit
|
3
5
|
# @return [RelatonBib::HitCollection]
|
@@ -10,7 +12,7 @@ module RelatonBib
|
|
10
12
|
# @param hit_collection [RelatonBib::HitCollection]
|
11
13
|
def initialize(hit, hit_collection = nil)
|
12
14
|
@hit = hit
|
13
|
-
@hit_collection = hit_collection
|
15
|
+
@hit_collection = WeakRef.new hit_collection if hit_collection
|
14
16
|
end
|
15
17
|
|
16
18
|
# @return [String]
|
data/lib/relaton_bib/medium.rb
CHANGED
@@ -11,7 +11,7 @@ module RelatonBib
|
|
11
11
|
# @param form [String, nil] form of the medium
|
12
12
|
# @param carrier [String, nil] carrier of the medium
|
13
13
|
# @param size [String, nil] size of the medium
|
14
|
-
# @param scale [String, nil]
|
14
|
+
# @param scale [String, nil]
|
15
15
|
#
|
16
16
|
def initialize(**args)
|
17
17
|
@content = args[:content]
|
@@ -0,0 +1,312 @@
|
|
1
|
+
# Monkey patch to fix the issue with month quotes in BibTeX
|
2
|
+
module BibTeX
|
3
|
+
class Value
|
4
|
+
def to_s(options = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
5
|
+
if options.key?(:filter)
|
6
|
+
opts = options.reject { |k,| k == :filter || (k == :quotes && (!atomic? || symbol?)) }
|
7
|
+
return convert(options[:filter]).to_s(opts)
|
8
|
+
end
|
9
|
+
|
10
|
+
return value.to_s unless options.key?(:quotes) && atomic?
|
11
|
+
|
12
|
+
q = Array(options[:quotes])
|
13
|
+
[q[0], value, q[-1]].compact.join
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module RelatonBib
|
19
|
+
# BibTeX builder.
|
20
|
+
module Renderer
|
21
|
+
class BibtexBuilder
|
22
|
+
ATTRS = %i[
|
23
|
+
type id title author editor booktitle series number edition contributor
|
24
|
+
date address note relation extent classification keyword docidentifier
|
25
|
+
timestamp link
|
26
|
+
].freeze
|
27
|
+
|
28
|
+
#
|
29
|
+
# Build BibTeX bibliography.
|
30
|
+
#
|
31
|
+
# @param bib [RelatonBib::BibliographicItem]
|
32
|
+
# @param bibtex [BibTeX::Bibliography, nil] BibTeX bibliography
|
33
|
+
#
|
34
|
+
# @return [BibTeX::Bibliography] BibTeX bibliography
|
35
|
+
#
|
36
|
+
def self.build(bib, bibtex = nil)
|
37
|
+
new(bib).build bibtex
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Initialize BibTeX builder.
|
42
|
+
#
|
43
|
+
# @param bib [RelatonBib::BibliographicItem]
|
44
|
+
def initialize(bib)
|
45
|
+
@bib = bib
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Build BibTeX bibliography.
|
50
|
+
#
|
51
|
+
# @param bibtex [BibTeX::Bibliography, nil] BibTeX bibliography
|
52
|
+
#
|
53
|
+
# @return [BibTeX::Bibliography] BibTeX bibliography
|
54
|
+
#
|
55
|
+
def build(bibtex = nil)
|
56
|
+
@item = BibTeX::Entry.new
|
57
|
+
ATTRS.each { |a| send("add_#{a}") }
|
58
|
+
bibtex ||= BibTeX::Bibliography.new
|
59
|
+
bibtex << @item
|
60
|
+
bibtex
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
#
|
66
|
+
# Add type to BibTeX item
|
67
|
+
#
|
68
|
+
def add_type
|
69
|
+
@item.type = bibtex_type
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [String] BibTeX type
|
73
|
+
def bibtex_type
|
74
|
+
case @bib.type
|
75
|
+
when "standard", nil then "misc"
|
76
|
+
else @bib.type
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Add ID to BibTeX item
|
82
|
+
#
|
83
|
+
def add_id
|
84
|
+
@item.key = @bib.id
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Add title to BibTeX item
|
89
|
+
#
|
90
|
+
def add_title
|
91
|
+
@bib.title.to_bibtex @item
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Add booktitle to BibTeX item
|
96
|
+
#
|
97
|
+
def add_booktitle
|
98
|
+
included_in = @bib.relation.detect { |r| r.type == "includedIn" }
|
99
|
+
return unless included_in
|
100
|
+
|
101
|
+
@item.booktitle = included_in.bibitem.title.first.title
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Add author to BibTeX item
|
106
|
+
#
|
107
|
+
def add_author
|
108
|
+
add_author_editor "author"
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Add editor to BibTeX item
|
113
|
+
#
|
114
|
+
def add_editor
|
115
|
+
add_author_editor "editor"
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Add author or editor to BibTeX item
|
120
|
+
#
|
121
|
+
# @param [String] type "author" or "editor"
|
122
|
+
#
|
123
|
+
def add_author_editor(type)
|
124
|
+
contribs = @bib.contributor.select do |c|
|
125
|
+
c.entity.is_a?(Person) && c.role.any? { |e| e.type == type }
|
126
|
+
end.map &:entity
|
127
|
+
|
128
|
+
return unless contribs.any?
|
129
|
+
|
130
|
+
@item.send "#{type}=", concat_names(contribs)
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Concatenate names of contributors
|
135
|
+
#
|
136
|
+
# @param [Array<RelatonBib::Person>] contribs contributors
|
137
|
+
#
|
138
|
+
# @return [String] concatenated names
|
139
|
+
#
|
140
|
+
def concat_names(contribs)
|
141
|
+
contribs.map do |p|
|
142
|
+
if p.name.surname
|
143
|
+
"#{p.name.surname}, #{p.name.forename.map(&:to_s).join(' ')}"
|
144
|
+
else
|
145
|
+
p.name.completename.to_s
|
146
|
+
end
|
147
|
+
end.join(" and ")
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
# Add series to BibTeX item
|
152
|
+
#
|
153
|
+
def add_series
|
154
|
+
@bib.series.each do |s|
|
155
|
+
case s.type
|
156
|
+
when "journal"
|
157
|
+
@item.journal = s.title.title
|
158
|
+
@item.number = s.number if s.number
|
159
|
+
when nil then @item.series = s.title.title
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# Add number to BibTeX item
|
166
|
+
#
|
167
|
+
def add_number
|
168
|
+
return unless %w[techreport manual].include? @bib.type
|
169
|
+
|
170
|
+
did = @bib.docidentifier.detect { |i| i.primary == true }
|
171
|
+
did ||= @bib.docidentifier.first
|
172
|
+
@item.number = did.id if did
|
173
|
+
end
|
174
|
+
|
175
|
+
#
|
176
|
+
# Add edition to BibTeX item
|
177
|
+
#
|
178
|
+
def add_edition
|
179
|
+
@item.edition = @bib.edition.content if @bib.edition
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# Add contributor to BibTeX item
|
184
|
+
#
|
185
|
+
def add_contributor # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
186
|
+
@bib.contributor.each do |c|
|
187
|
+
rls = c.role.map(&:type)
|
188
|
+
if rls.include?("publisher") then @item.publisher = c.entity.name
|
189
|
+
elsif rls.include?("distributor")
|
190
|
+
case @bib.type
|
191
|
+
when "techreport" then @item.institution = c.entity.name
|
192
|
+
when "inproceedings", "conference", "manual", "proceedings"
|
193
|
+
@item.organization = c.entity.name
|
194
|
+
when "mastersthesis", "phdthesis" then @item.school = c.entity.name
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
#
|
201
|
+
# Add date to BibTeX item
|
202
|
+
#
|
203
|
+
def add_date
|
204
|
+
@bib.date.each do |d|
|
205
|
+
case d.type
|
206
|
+
when "published"
|
207
|
+
@item.year = d.on :year
|
208
|
+
month = d.on :month
|
209
|
+
@item.month = month if month
|
210
|
+
when "accessed" then @item.urldate = d.on.to_s
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
#
|
216
|
+
# Add address to BibTeX item
|
217
|
+
#
|
218
|
+
def add_address # rubocop:disable Metrics/AbcSize
|
219
|
+
return unless @bib.place.any?
|
220
|
+
|
221
|
+
reg = @bib.place[0].region[0].name if @bib.place[0].region.any?
|
222
|
+
addr = [@bib.place[0].name, @bib.place[0].city, reg]
|
223
|
+
@item.address = addr.compact.join(", ")
|
224
|
+
end
|
225
|
+
|
226
|
+
#
|
227
|
+
# Add note to BibTeX item
|
228
|
+
#
|
229
|
+
def add_note # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
230
|
+
@bib.biblionote.each do |n|
|
231
|
+
case n.type
|
232
|
+
when "annote" then @item.annote = n.content
|
233
|
+
when "howpublished" then @item.howpublished = n.content
|
234
|
+
when "comment" then @item.comment = n.content
|
235
|
+
when "tableOfContents" then @item.content = n.content
|
236
|
+
when nil then @item.note = n.content
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
#
|
242
|
+
# Add relation to BibTeX item
|
243
|
+
#
|
244
|
+
def add_relation
|
245
|
+
rel = @bib.relation.detect { |r| r.type == "partOf" }
|
246
|
+
if rel
|
247
|
+
title_main = rel.bibitem.title.detect { |t| t.type == "main" }
|
248
|
+
@item.booktitle = title_main.title.content
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
#
|
253
|
+
# Add extent to BibTeX item
|
254
|
+
#
|
255
|
+
def add_extent
|
256
|
+
@bib.extent.each { |e| e.to_bibtex(@item) }
|
257
|
+
end
|
258
|
+
|
259
|
+
#
|
260
|
+
# Add classification to BibTeX item
|
261
|
+
#
|
262
|
+
def add_classification
|
263
|
+
@bib.classification.each do |c|
|
264
|
+
case c.type
|
265
|
+
when "type" then @item["type"] = c.value
|
266
|
+
when "mendeley" then @item["mendeley-tags"] = c.value
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
#
|
272
|
+
# Add keywords to BibTeX item
|
273
|
+
#
|
274
|
+
def add_keyword
|
275
|
+
@item.keywords = @bib.keyword.map(&:content).join(", ") if @bib.keyword.any?
|
276
|
+
end
|
277
|
+
|
278
|
+
#
|
279
|
+
# Add docidentifier to BibTeX item
|
280
|
+
#
|
281
|
+
def add_docidentifier
|
282
|
+
@bib.docidentifier.each do |i|
|
283
|
+
case i.type
|
284
|
+
when "isbn" then @item.isbn = i.id
|
285
|
+
when "lccn" then @item.lccn = i.id
|
286
|
+
when "issn" then @item.issn = i.id
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
#
|
292
|
+
# Add identifier to BibTeX item
|
293
|
+
#
|
294
|
+
def add_timestamp
|
295
|
+
@item.timestamp = @bib.fetched.to_s if @bib.fetched
|
296
|
+
end
|
297
|
+
|
298
|
+
#
|
299
|
+
# Add link to BibTeX item
|
300
|
+
#
|
301
|
+
def add_link
|
302
|
+
@bib.link.each do |l|
|
303
|
+
case l.type&.downcase
|
304
|
+
when "doi" then @item.doi = l.content
|
305
|
+
when "file" then @item.file2 = l.content
|
306
|
+
when "src" then @item.url = l.content
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
module RelatonBib
|
2
|
+
module Renderer
|
3
|
+
class BibXML
|
4
|
+
def initialize(bib)
|
5
|
+
@bib = bib
|
6
|
+
end
|
7
|
+
|
8
|
+
#
|
9
|
+
# Render BibXML (RFC)
|
10
|
+
#
|
11
|
+
# @param [Nokogiri::XML::Builder, nil] builder
|
12
|
+
# @param [Boolean] include_keywords (false)
|
13
|
+
#
|
14
|
+
# @return [String, Nokogiri::XML::Builder::NodeBuilder] XML
|
15
|
+
#
|
16
|
+
def render(builder: nil, include_keywords: true)
|
17
|
+
if builder
|
18
|
+
render_bibxml builder, include_keywords
|
19
|
+
else
|
20
|
+
Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
21
|
+
render_bibxml xml, include_keywords
|
22
|
+
end.doc.root.to_xml
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Render BibXML (RFC, BCP)
|
28
|
+
#
|
29
|
+
# @param [Nokogiri::XML::Builder] builder
|
30
|
+
# @param [Boolean] include_bibdata
|
31
|
+
#
|
32
|
+
def render_bibxml(builder, include_keywords) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
33
|
+
target = @bib.link.detect { |l| l.type.casecmp("src").zero? } ||
|
34
|
+
@bib.link.detect { |l| l.type.casecmp("doi").zero? }
|
35
|
+
bxml = if @bib.docnumber&.match(/^BCP/) || (@bib.docidentifier.detect(&:primary)&.id ||
|
36
|
+
@bib.docidentifier[0].id).include?("BCP")
|
37
|
+
render_bibxml_refgroup(builder, include_keywords)
|
38
|
+
else
|
39
|
+
render_bibxml_ref(builder, include_keywords)
|
40
|
+
end
|
41
|
+
bxml[:target] = target.content.to_s if target
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Render BibXML (BCP)
|
46
|
+
#
|
47
|
+
# @param [Nokogiri::XML::Builder] builder
|
48
|
+
# @param [Boolean] include_keywords
|
49
|
+
#
|
50
|
+
def render_bibxml_refgroup(builder, include_keywords)
|
51
|
+
builder.referencegroup(**ref_attrs) do |b|
|
52
|
+
@bib.relation.each do |r|
|
53
|
+
r.bibitem.to_bibxml(b, include_keywords: include_keywords) if r.type == "includes"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Render BibXML (RFC)
|
60
|
+
#
|
61
|
+
# @param [Nokogiri::XML::Builder] builder
|
62
|
+
# @param [Boolean] include_keywords
|
63
|
+
#
|
64
|
+
def render_bibxml_ref(builder, include_keywords) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
65
|
+
builder.reference(**ref_attrs) do |xml|
|
66
|
+
if @bib.title.any? || @bib.contributor.any? || @bib.date.any? || @bib.abstract.any? ||
|
67
|
+
@bib.editorialgroup&.technical_committee&.any? ||
|
68
|
+
(include_keywords && @bib.keyword.any?)
|
69
|
+
xml.front do
|
70
|
+
xml.title @bib.title[0].title.content if @bib.title.any?
|
71
|
+
render_authors xml
|
72
|
+
render_date xml
|
73
|
+
render_workgroup xml
|
74
|
+
render_keyword xml if include_keywords
|
75
|
+
render_abstract xml
|
76
|
+
end
|
77
|
+
end
|
78
|
+
render_seriesinfo xml
|
79
|
+
render_format xml
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# Create reference attributes
|
85
|
+
#
|
86
|
+
# @return [Hash<Symbol=>String>] attributes
|
87
|
+
#
|
88
|
+
def ref_attrs # rubocop:disable Metrics/AbcSize
|
89
|
+
discopes = %w[anchor docName number]
|
90
|
+
attrs = @bib.docidentifier.each_with_object({}) do |di, h|
|
91
|
+
next unless discopes.include?(di.scope)
|
92
|
+
|
93
|
+
h[di.scope.to_sym] = di.id
|
94
|
+
end
|
95
|
+
return attrs if attrs.any?
|
96
|
+
|
97
|
+
@bib.docidentifier.first&.tap do |di|
|
98
|
+
anchor = di.type == "IANA" ? di.id.split[1..].join(" ").upcase : di.id
|
99
|
+
return { anchor: anchor.gsub(" ", ".") }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Render authors
|
105
|
+
#
|
106
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
107
|
+
#
|
108
|
+
def render_authors(builder) # rubocop:disable Metrics/AbcSize
|
109
|
+
@bib.contributor.each do |c|
|
110
|
+
builder.author do |xml|
|
111
|
+
xml.parent[:role] = "editor" if c.role.detect { |r| r.type == "editor" }
|
112
|
+
if c.entity.is_a?(Person) then render_person xml, c.entity
|
113
|
+
else render_organization xml, c.entity, c.role
|
114
|
+
end
|
115
|
+
render_address xml, c
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Render address
|
122
|
+
#
|
123
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
124
|
+
# @param [RelatonBib::ContributionInfo] contrib contributor
|
125
|
+
#
|
126
|
+
def render_address(builder, contrib) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
127
|
+
# addr = contrib.entity.contact.reject do |cn|
|
128
|
+
# cn.is_a?(Address) && cn.postcode.nil?
|
129
|
+
# end
|
130
|
+
if contrib.entity.contact.any?
|
131
|
+
builder.address do |xml|
|
132
|
+
address = contrib.entity.contact.detect { |cn| cn.is_a? Address }
|
133
|
+
if address
|
134
|
+
xml.postal do
|
135
|
+
xml.city address.city if address.city
|
136
|
+
xml.code address.postcode if address.postcode
|
137
|
+
xml.country address.country if address.country
|
138
|
+
xml.region address.state if address.state
|
139
|
+
xml.street address.street[0] if address.street.any?
|
140
|
+
end
|
141
|
+
end
|
142
|
+
render_contact xml, contrib.entity.contact
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Render contact
|
149
|
+
#
|
150
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
151
|
+
# @param [Array<RelatonBib::Address, RelatonBib::Contact>] addr contact
|
152
|
+
#
|
153
|
+
def render_contact(builder, addr)
|
154
|
+
%w[phone email uri].each do |type|
|
155
|
+
cont = addr.detect { |cn| cn.is_a?(Contact) && cn.type == type }
|
156
|
+
builder.send type, cont.value if cont
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# Render person
|
162
|
+
#
|
163
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
164
|
+
# @param [RelatonBib::Person] person person
|
165
|
+
#
|
166
|
+
def render_person(builder, person) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
167
|
+
render_organization builder, person.affiliation.first&.organization
|
168
|
+
if person.name.completename
|
169
|
+
builder.parent[:fullname] = person.name.completename.content
|
170
|
+
elsif person.name.forename.any?
|
171
|
+
builder.parent[:fullname] = person.name.forename.map do |n|
|
172
|
+
n.content || n.initial
|
173
|
+
end.join " "
|
174
|
+
end
|
175
|
+
if person.name.initials
|
176
|
+
builder.parent[:initials] = person.name.initials.content
|
177
|
+
elsif person.name.forename.any?
|
178
|
+
builder.parent[:initials] = person.name.forename.map do |f|
|
179
|
+
"#{f.initial || f.content[0]}."
|
180
|
+
end.join
|
181
|
+
end
|
182
|
+
if person.name.surname
|
183
|
+
if !person.name.completename && person.name.forename.any? && person.name.surname
|
184
|
+
builder.parent[:fullname] += " #{person.name.surname}"
|
185
|
+
end
|
186
|
+
builder.parent[:surname] = person.name.surname.content
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Render organization
|
192
|
+
#
|
193
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
194
|
+
# @param [RelatonBib::Organization] org organization
|
195
|
+
#
|
196
|
+
def render_organization(builder, org, _role = []) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/AbcSize
|
197
|
+
abbrev = org&.abbreviation&.content
|
198
|
+
orgname = org&.name&.first&.content
|
199
|
+
orgname = if BibXMLParser::ORGNAMES.key?(abbrev) then abbrev
|
200
|
+
else BibXMLParser::ORGNAMES.key(orgname) || orgname || abbrev
|
201
|
+
end
|
202
|
+
# if role.detect { |r| r.description.detect { |d| d.content == "BibXML author" } }
|
203
|
+
# builder.parent[:fullname] = orgname
|
204
|
+
# else
|
205
|
+
org = builder.organization orgname
|
206
|
+
org[:abbrev] = abbrev if abbrev
|
207
|
+
# end
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Render date
|
212
|
+
#
|
213
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
214
|
+
#
|
215
|
+
def render_date(builder) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
216
|
+
dt = @bib.date.detect { |d| d.type == "published" }
|
217
|
+
return unless dt
|
218
|
+
|
219
|
+
elm = builder.date
|
220
|
+
y = dt.on(:year) || dt.from(:year) || dt.to(:year)
|
221
|
+
elm[:year] = y if y
|
222
|
+
m = dt.on(:month) || dt.from(:month) || dt.to(:month)
|
223
|
+
elm[:month] = Date::MONTHNAMES[m] if m
|
224
|
+
# rfcs = %w[RFC BCP FYI STD]
|
225
|
+
# unless rfcs.include?(doctype) && docidentifier.detect { |di| rfcs.include? di.type }
|
226
|
+
d = dt.on(:day) || dt.from(:day) || dt.to(:day)
|
227
|
+
elm[:day] = d if d
|
228
|
+
# end
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
# Render workgroup
|
233
|
+
#
|
234
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
235
|
+
#
|
236
|
+
def render_workgroup(builder)
|
237
|
+
@bib.editorialgroup&.technical_committee&.each do |tc|
|
238
|
+
builder.workgroup tc.workgroup.name
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
#
|
243
|
+
# Render keyword
|
244
|
+
#
|
245
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
246
|
+
#
|
247
|
+
def render_keyword(builder)
|
248
|
+
@bib.keyword.each { |kw| builder.keyword kw.content }
|
249
|
+
end
|
250
|
+
|
251
|
+
#
|
252
|
+
# Render abstract
|
253
|
+
#
|
254
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
255
|
+
#
|
256
|
+
def render_abstract(builder)
|
257
|
+
return unless @bib.abstract.any?
|
258
|
+
|
259
|
+
builder.abstract { |xml| xml << @bib.abstract[0].content.gsub(/(<\/?)p(>)/, '\1t\2') }
|
260
|
+
end
|
261
|
+
|
262
|
+
#
|
263
|
+
# Render seriesinfo
|
264
|
+
#
|
265
|
+
# @param [Nokogiri::XML::Builder] builder xml builder
|
266
|
+
#
|
267
|
+
def render_seriesinfo(builder) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
268
|
+
@bib.docidentifier.each do |di|
|
269
|
+
if BibXMLParser::SERIESINFONAMES.include?(di.type) && di.scope != "trademark"
|
270
|
+
builder.seriesInfo(name: di.type, value: di.id)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
# di_types = docidentifier.map(&:type)
|
274
|
+
@bib.series.select do |s|
|
275
|
+
s.title && # !di_types.include?(s.title.title.to_s) &&
|
276
|
+
!BibXMLParser::SERIESINFONAMES.include?(s.title.title.to_s)
|
277
|
+
end.uniq { |s| s.title.title.to_s }.each do |s|
|
278
|
+
si = builder.seriesInfo(name: s.title.title.to_s)
|
279
|
+
si[:value] = s.number if s.number
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def render_format(builder)
|
284
|
+
@bib.link.select { |l| l.type == "TXT" }.each do |l|
|
285
|
+
builder.format type: l.type, target: l.content
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
data/lib/relaton_bib/version.rb
CHANGED
data/lib/relaton_bib.rb
CHANGED
@@ -11,6 +11,8 @@ require "relaton_bib/bibliographic_item"
|
|
11
11
|
require "relaton_bib/hit_collection"
|
12
12
|
require "relaton_bib/hit"
|
13
13
|
require "relaton_bib/bibxml_parser"
|
14
|
+
require "relaton_bib/renderer/bibtex_builder"
|
15
|
+
require "relaton_bib/renderer/bibxml"
|
14
16
|
|
15
17
|
module RelatonBib
|
16
18
|
class Error < StandardError; end
|
@@ -66,15 +68,17 @@ module RelatonBib
|
|
66
68
|
# Parse yaml content
|
67
69
|
#
|
68
70
|
# @param [String] yaml content
|
71
|
+
# @param [Array] classes classes to be allowed
|
72
|
+
# @param [Boolean] symbolize_names symbolize names if true (default: false)
|
69
73
|
#
|
70
74
|
# @return [Hash] data
|
71
75
|
#
|
72
|
-
def parse_yaml(yaml, classes = [])
|
76
|
+
def parse_yaml(yaml, classes = [], symbolize_names: false)
|
73
77
|
# Newer versions of Psych uses the `permitted_classes:` parameter
|
74
78
|
if YAML.method(:safe_load).parameters.map(&:last).include? :permitted_classes
|
75
|
-
YAML.safe_load(yaml, permitted_classes: classes)
|
79
|
+
YAML.safe_load(yaml, permitted_classes: classes, symbolize_names: symbolize_names)
|
76
80
|
else
|
77
|
-
YAML.safe_load(yaml, classes)
|
81
|
+
YAML.safe_load(yaml, classes, symbolize_names: symbolize_names)
|
78
82
|
end
|
79
83
|
end
|
80
84
|
end
|
data/relaton-bib.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.bindir = "exe"
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
24
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
25
25
|
|
26
26
|
spec.add_development_dependency "byebug"
|
27
27
|
spec.add_development_dependency "equivalent-xml", "~> 0.6"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relaton-bib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.14.
|
4
|
+
version: 1.14.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -266,6 +266,8 @@ files:
|
|
266
266
|
- lib/relaton_bib/organization.rb
|
267
267
|
- lib/relaton_bib/person.rb
|
268
268
|
- lib/relaton_bib/place.rb
|
269
|
+
- lib/relaton_bib/renderer/bibtex_builder.rb
|
270
|
+
- lib/relaton_bib/renderer/bibxml.rb
|
269
271
|
- lib/relaton_bib/series.rb
|
270
272
|
- lib/relaton_bib/structured_identifier.rb
|
271
273
|
- lib/relaton_bib/technical_committee.rb
|
@@ -289,7 +291,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
289
291
|
requirements:
|
290
292
|
- - ">="
|
291
293
|
- !ruby/object:Gem::Version
|
292
|
-
version: 2.
|
294
|
+
version: 2.7.0
|
293
295
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
294
296
|
requirements:
|
295
297
|
- - ">="
|