cirneco 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b25496604d7050477dbcd531561118874f76705
4
- data.tar.gz: f3e38823524d96cd5382a5a54d3838daaf8c3b42
3
+ metadata.gz: cd780244d65b7e0dfac84a9e8a7e1e4355cd6afc
4
+ data.tar.gz: 434b17d7508b897ada24bfeca7a1173a047ae684
5
5
  SHA512:
6
- metadata.gz: 8b521bfb2aceebdb52d8248dccd6de030976413720d392748358620e7527c33398224a4a33aea7d7a4dca234c8506da408aceb00f5ac1a47e82177e034392c70
7
- data.tar.gz: ada9b59941a9c2f3182736cb3ba54b2c44d3b16226a20abc51be56dc0a5b6f0e6949311c6b5ca9a20e396fe624fd872c2d152abe6fd99f823d0f164d27f46b1c
6
+ metadata.gz: 9234bb25ca4ab3639f0c55f348cd603216034859f9a714f6423761d3f1a0dda8f9b1781b4919918d9447dd534a356452aef11814909061a78d8cc2ead5ca6b6c
7
+ data.tar.gz: 0c0ed870ae4cf051d80a798799946a2d5b25600df3dd438b975dc394adbd20c97fa370d21ad6e380feef8e31b616c2b1b7c2888fa210bca39263b25dba3b265d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cirneco (0.8.1)
4
+ cirneco (0.8.2)
5
5
  activesupport (~> 4.2, >= 4.2.5)
6
6
  base32-crockford-checksum (~> 0.2.2)
7
7
  bergamasco (~> 0.3)
@@ -22,7 +22,7 @@ GEM
22
22
  tzinfo (~> 1.1)
23
23
  addressable (2.3.8)
24
24
  base32-crockford-checksum (0.2.3)
25
- bergamasco (0.3.5)
25
+ bergamasco (0.3.6)
26
26
  activesupport (~> 4.2, >= 4.2.5)
27
27
  addressable (~> 2.3.8)
28
28
  builder (~> 3.2, >= 3.2.2)
data/lib/cirneco/doi.rb CHANGED
@@ -85,6 +85,22 @@ module Cirneco
85
85
  end
86
86
  end
87
87
 
88
+ desc "name DOCUMENT", "name document"
89
+ method_option :length, :type => :numeric
90
+ method_option :lower_limit, :type => :numeric
91
+ method_option :split, :type => :numeric, :default => 4
92
+ method_option :namespace, :default => 'MS-'
93
+ method_option :opt_in, :type => :boolean
94
+ def name(filepath)
95
+ if File.directory?(filepath)
96
+ response = update_all_accession_numbers(filepath, options)
97
+ else
98
+ response = update_accession_number(filepath, options)
99
+ end
100
+
101
+ puts response
102
+ end
103
+
88
104
  desc "mint DOCUMENT", "mint document"
89
105
  method_option :sitepath, :default => ENV['SITE_SITEPATH']
90
106
  method_option :authorpath, :default => ENV['SITE_AUTHORPATH']
@@ -95,12 +111,12 @@ module Cirneco
95
111
  method_option :password, :default => ENV['MDS_PASSWORD']
96
112
  method_option :prefix, :default => ENV['PREFIX']
97
113
  method_option :sandbox, :type => :boolean, :force => false
98
- def mint(filepath)
114
+ def mint(url)
99
115
 
100
- if filepath.is_a?(Array)
101
- response = mint_dois_for_all_urls(filepath, options)
116
+ if url.is_a?(Array)
117
+ response = mint_dois_for_all_urls(url, options)
102
118
  else
103
- response = mint_doi_for_url(filepath, options)
119
+ response = mint_doi_for_url(url, options)
104
120
  end
105
121
 
106
122
  puts response
@@ -116,12 +132,12 @@ module Cirneco
116
132
  method_option :password, :default => ENV['MDS_PASSWORD']
117
133
  method_option :prefix, :default => ENV['PREFIX']
118
134
  method_option :sandbox, :type => :boolean, :force => false
119
- def mint_and_hide(filepath)
135
+ def mint_and_hide(url)
120
136
 
121
- if filepath.is_a?(Array)
122
- response = mint_and_hide_dois_for_all_urls(filepath, options)
137
+ if url.is_a?(Array)
138
+ response = mint_and_hide_dois_for_all_urls(url, options)
123
139
  else
124
- response = mint_and_hide_doi_for_url(filepath, options)
140
+ response = mint_and_hide_doi_for_url(url, options)
125
141
  end
126
142
 
127
143
  puts response
@@ -136,12 +152,12 @@ module Cirneco
136
152
  method_option :username, :default => ENV['MDS_USERNAME']
137
153
  method_option :password, :default => ENV['MDS_PASSWORD']
138
154
  method_option :sandbox, :type => :boolean, :force => false
139
- def hide(filepath)
155
+ def hide(url)
140
156
 
141
- if filepath.is_a?(Array)
142
- response = hide_dois_for_all_urls(filepath, options)
157
+ if url.is_a?(Array)
158
+ response = hide_dois_for_all_urls(url, options)
143
159
  else
144
- response = hide_doi_for_url(filepath, options)
160
+ response = hide_doi_for_url(url, options)
145
161
  end
146
162
 
147
163
  puts response
data/lib/cirneco/utils.rb CHANGED
@@ -65,16 +65,20 @@ module Cirneco
65
65
  end
66
66
 
67
67
  def get_all_accession_numbers(folderpath)
68
- Dir.glob("#{folderpath}/*.md").map do |filepath|
68
+ Dir.glob("#{folderpath}/*.md").sort.map do |filepath|
69
69
  get_accession_number(filepath)
70
70
  end.select { |a| a > 0 }.sort
71
71
  end
72
72
 
73
73
  def update_accession_number(filepath, options={})
74
74
  filename = File.basename(filepath)
75
- return "File #{filename} ignored: not a markdown file" unless File.extname(filepath) == ".md"
75
+ return "File #{filename} ignored: not a markdown or html file" unless %w(.md .html).include?(File.extname(filepath))
76
76
 
77
77
  old_metadata = Bergamasco::Markdown.read_yaml_for_doi_metadata(filepath)
78
+ return "File #{filename} ignored: no yaml front matter" unless old_metadata.present?
79
+
80
+ return "File #{filename} ignored: no empty accession_number" if options[:opt_in] && !old_metadata.key?("accession_number")
81
+
78
82
  return "Accession number #{old_metadata["accession_number"]} not changed for #{filename}" if old_metadata["accession_number"]
79
83
 
80
84
  if old_metadata["doi"].present?
@@ -91,9 +95,9 @@ module Cirneco
91
95
  "Accession number #{new_metadata["accession_number"]} generated for #{filename}"
92
96
  end
93
97
 
94
- def update_all_accession_numbers(folderpath)
95
- Dir.glob("#{folderpath}/*.md").map do |filepath|
96
- update_accession_number(filepath)
98
+ def update_all_accession_numbers(folderpath, options={})
99
+ Dir.glob("#{folderpath}/*.md").sort.map do |filepath|
100
+ update_accession_number(filepath, options)
97
101
  end
98
102
  end
99
103
 
@@ -1,3 +1,3 @@
1
1
  module Cirneco
2
- VERSION = "0.8.1"
2
+ VERSION = "0.8.2"
3
3
  end
data/spec/doi_spec.rb CHANGED
@@ -50,6 +50,15 @@ describe Cirneco::Doi do
50
50
  subject.options = { number: number }
51
51
  expect { subject.accession_number }.to output("MS-123\n").to_stdout
52
52
  end
53
+
54
+ it 'updates accession_number for file' do
55
+ expect { subject.name fixture_path + 'cool-dois.html.md' }.to output("Accession number MS-123 not changed for cool-dois.html.md\n").to_stdout
56
+ end
57
+
58
+ it 'updates accession_number for all files with opt-in' do
59
+ subject.options = { opt_in: true }
60
+ expect { subject.name fixture_path }.to output("Accession number MS-124 not changed for cool-dois-minted.html.md\nFile cool-dois-no-accession-number.html.md ignored: no empty accession_number\nAccession number MS-123 not changed for cool-dois.html.md\n").to_stdout
61
+ end
53
62
  end
54
63
 
55
64
  context "base32" do
@@ -0,0 +1,97 @@
1
+ ---
2
+ layout: post
3
+ title: Cool DOI's
4
+ author: mfenner
5
+ date: 2016-12-15
6
+ tags:
7
+ - doi
8
+ - featured
9
+ image: https://blog.datacite.org/images/2016/12/cool-dois.png
10
+ ---
11
+ In 1998 Tim Berners-Lee coined the term cool URIs [-@https://www.w3.org/Provider/Style/URI], that is URIs that don’t change. We know that URLs referenced in the scholarly literature are often not cool, leading to link rot [@https://doi.org/10.1371/journal.pone.0115253] and making it hard or impossible to find the referenced resource.READMORE
12
+
13
+ Cool URIs are, of course, a fundamental principle behind DOIs, with the two important concepts [*resolution*](https://www.doi.org/doi_handbook/3_Resolution.html) (it is very hard to maintain a URL directly pointing at a resource) and [*policies*](https://www.doi.org/doi_handbook/6_Policies.html) (that all DOI registration agencies and organizations minting DOIs agree to maintain the redirection). The third essential element for DOIs, their [*data model*](https://www.doi.org/doi_handbook/4_Data_Model.html), is not directly about persistent linking, but about the discoverability of the linked resources via standard metadata in a central index.
14
+
15
+ All DOIs, expressed as HTTP URI, are therefore cool URIs. So what is a cool DOI? And, furthermore, how to create and use them? To understand what a cool DOI is, we have to explain the three parts that make up a DOI:
16
+
17
+ ![](/images/2016/12/doi-parts.png)
18
+
19
+ ### Proxy
20
+
21
+ The proxy is not part of the DOI specification, but almost all scholarly DOIs that users encounter today will be expressed as HTTP URLs. DataCite recommends that all DOIs are displayed as permanent URLs, consistent with the recommendations of other DOI registration agencies, e.g. the [Crossref DOI display guidelines](http://www.crossref.org/02publishers/doi_display_guidelines.html). When the DOI system was originally designed, it was thought that the DOI protocol would become widely used, but that clearly has not happened and displaying DOIs as **doi:10.5281/ZENODO.31780** is therefore not recommended.
22
+
23
+ The DOI proxy enables the functionality of expressing DOIs as HTTP URIs. Users should also be aware of two these two recommendations:
24
+
25
+ * Use [doi.org](https://www.doi.org/doi_proxy/proxy_policies.html) instead of dx.doi.org as DNS name
26
+ * Use the HTTPS protocol instead of HTTP protocol
27
+
28
+ Ed Pentz from Crossref makes the case for HTTPS in a [September blog post](http://blog.crossref.org/2016/09/new-crossref-doi-display-guidelines.html). The web, and therefore also the scholarly web, is moving to HTTPS as the default. It is important that the DOI proxy redirects to HTTPS URLs, and it will take some time until all DataCite data centers use HTTPS for the landing pages their DOIs redirects to.
29
+
30
+ What many users don’t know is that doi.org is not the only proxy server for DOIs. DOIs use the handle system and any handle server will resolve a DOI, just as doi.org will resolve any handle. This means that [https://hdl.handle.net/10.5281/ZENODO.31780](https://hdl.handle.net/10.5281/ZENODO.31780) will resolve to the landing page for that DOI and that [http://doi.org/10273/BGRB5054RX05201](http://doi.org/10273/BGRB5054RX05201) is a handle (for a [IGSN](http://www.igsn.org/)) and not a DOI.
31
+
32
+ ### Prefix
33
+
34
+ The DOI prefix is used as a namespace so that DOIs are globally unique without requiring global coordination for every new identifier. Prefixes in the handle system and therefore for DOIs are numbers without any semantic meaning. One lesson learned with persistent identifiers is that adding meaning to the identifier (e.g. by using a prefix with the name of the data repository) is always dangerous, because – despite best intentions – all names can change over time.
35
+
36
+ Since the DOI prefix is a namespace to keep DOIs globally unique, there is usually no need for multiple prefixes for one organization managing DOI assignment. The tricky part is that these responsibilities can change, e.g. when an organization manages multiple repositories and one of them is migrated to another organization. It therefore makes sense to assign one prefix per list of resources that always stays together, e.g. one repository. It is possible that one prefix is managed by multiple organizations (as long as they use the same DOI registration agency), but that makes DOI management more complex.
37
+
38
+ ### Suffix
39
+
40
+ The suffix for a DOI can be (almost) any string. Which is both a feature and a curse. It is a feature because it gives maximal flexibility, for example when migrating existing identifiers to the DOI system. And it is a curse because it not always works well in the web context, as the list of characters allowed in a URL is limited. A good example of this are SICIs ([Serial Item and Contribution Identifier](https://en.wikipedia.org/wiki/Serial_Item_and_Contribution_Identifier)), they were defined in 1996 before the DOI system was implemented, and could then be migrated to DOIs. Unfortunately they can contain many characters that are problematic in a URL or make it difficult to validate the DOI, as in [https://doi.org/10.1002/(sici)1099-1409(199908/10)3:6/7<672::aid-jpp192>3.0.co;2-8](https://doi.org/10.1002/(sici)1099-1409(199908/10)3:6/7<672::aid-jpp192>3.0.co;2-8). A Crossref [blog post](http://blog.crossref.org/2015/08/doi-regular-expressions.html) by Andrew Gilmartin gives a good overview about the characters found in DOIs and suggests the following regular expression to check for valid DOIs:
41
+
42
+ ```
43
+ /^10.\d{4,9}/[-._;()/:A-Z0-9]+$/i
44
+ ```
45
+
46
+ SICIs demonstrate two other pitfalls:
47
+
48
+ * they contain semantic information (ISSN, volume, number, etc.) that may change over time, and
49
+ * they are long, difficult to transcribe, with characters not allowed in URLs, and not very human-readable.
50
+
51
+ Semantic information might also lead users to expect certain functionalities. A common pattern that we see at DataCite is to include information about the version or parent in the suffix, e.g. [https://doi.org/10.6084/M9.FIGSHARE.3501629.V1](https://doi.org/10.6084/M9.FIGSHARE.3501629.V1) or [https://doi.org/10.5061/DRYAD.0SN63/7](https://doi.org/10.5061/DRYAD.0SN63/7). While the decision on what to put into the suffix is up to each data center, we should make sure users don't think that these are functionalities of the DOI system (e.g. that adding **.V2** to any DOI name will resolve to version 2 of that resource).
52
+
53
+ Another issue to keep in mind when assigning suffixes is that DOIs – in contrast to HTTP URIs – are case-insensitive, [https://doi.org/10.5281/ZENODO.31780](https://doi.org/10.5281/ZENODO.31780) and [https://doi.org/10.5281/zenodo.31780](https://doi.org/10.5281/zenodo.31780) are the same DOI. All DOIs are [converted to upper case](https://www.doi.org/doi_handbook/2_Numbering.html#2.4) upon registration and DOI resolution, but DOIs are not consistently displayed in such a way.
54
+
55
+ ### Generating cool DOIs
56
+
57
+ With all that, what should the ideal DOI look like? Its suffix should be:
58
+
59
+ * opaque without semantic information
60
+ * work well in a web environment, avoiding characters problematic in URLs
61
+ * short and human-readable
62
+ * Resistant to transcription errors
63
+ * easy to generate
64
+
65
+ On Tuesday DataCite released a tool that helps generating such a suffix, an open source command line tool called [cirneco](https://github.com/datacite/cirneco) (a lot of our open source software uses Italian dog breed names). Cirneco is a Ruby gem that can be installed via
66
+
67
+ ```
68
+ gem install cirneco
69
+ ```
70
+
71
+ Cirneco uses base32 encoding, as [described](http://www.crockford.com/wrmg/base32.html) by Douglas Crockford. The encoding starts with a randomly generated number to guarantee uniqueness of the identifier, and then encodes the number into a string that uses all numbers and uppercase letters. It avoids the letters I, O and L as they can be confused with the letter 1 and 0, using 32 characters (and 5 checksum characters) in total. The last character is a checksum. The resulting string from cirneco always has a length of 8 characters, in groups of 4 separated by a hyphen to help with readability. The advantage of base32 encoding over using only numbers (as for example ORCID is doing) is that the resulting string becomes much more compact, the available 7 characters (plus one for the checksum) can encode 34,359,738,367 strings, compared to 10 million when only using numbers. This number is large enough that the resulting suffix will not only be unique for a given prefix, but also unique for all DOIs (there is a very small chance to get the same random number twice, but this will be rejected when trying to register the DOI).
72
+
73
+ Another common way to generate random strings would have been universally unique identifiers ([UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier)), but they are long and not very human-readable, e.g. [https://doi.org/10.4233/UUID:6D192FE2-DE18-4556-873A-D3CD56AB96A6](https://doi.org/10.4233/UUID:6D192FE2-DE18-4556-873A-D3CD56AB96A6).
74
+
75
+ An example DOI generated by cirneco would be
76
+
77
+ ```
78
+ cirneco doi generate --prefix 10.5555
79
+ 10.5555/KVTD-VPWM
80
+ ```
81
+
82
+ The generated DOI is short enough that it should work well in places where space is limited, providing an alternative to the [ShortDOI](http://shortdoi.org/) service which shortens existing DOIs, but does this by adding another layer on top of the DOI proxy.
83
+
84
+ Another cirneco command checks that this is a valid bas32 string using the checksum
85
+
86
+ ```
87
+ cirneco doi check 10.5555/KVTD-VPWM
88
+ Checksum for 10.5555/KVTD-VPWM is valid
89
+ ```
90
+
91
+ This can be used to quickly verify a DOI, e.g. in a web form or API. The Ruby base32 encoding library used by cirneco is open source ([https://github.com/datacite/base32](https://github.com/datacite/base32). I added the checksum to the existing library), and implementations of the Crockford base32 encoding pattern are available in many other languages, including [Python](https://github.com/jbittel/base32-crockford), [PHP](https://github.com/dflydev/dflydev-base32-crockford), [Javascript](https://www.npmjs.com/package/base32-crockford), [Java](http://stackoverflow.com/questions/22385467/crockford-base32-encoding-for-large-number-java-implementation), [Go](https://github.com/richardlehane/crock32) and [.NET](https://crockfordbase32.codeplex.com/).
92
+
93
+ To answer the question raised at the beginning: a cool DOI is a DOI expressed as HTTPS URI using the doi.org proxy and using a base32-encoded suffix, for example **https://doi.org/10.5555/KVTD-VPWM**. This DOI works well in a web environment, is human readable, easy to parse and detect (e.g. in text mining), and can be generated using an algorithm that is well understood and supported.
94
+
95
+ ![](/images/2016/12/cool-dois.png)
96
+
97
+ ### References
data/spec/utils_spec.rb CHANGED
@@ -102,8 +102,8 @@ describe Cirneco::DataCenter, vcr: true, :order => :defined do
102
102
  end
103
103
 
104
104
  it 'should update for all files' do
105
- response = subject.update_all_accession_numbers(fixture_path)
106
- expect(response).to eq(["Accession number MS-123 not changed for cool-dois.html.md", "Accession number MS-124 not changed for cool-dois-minted.html.md"])
105
+ response = subject.update_all_accession_numbers(fixture_path, opt_in: true)
106
+ expect(response).to eq(["Accession number MS-124 not changed for cool-dois-minted.html.md", "File cool-dois-no-accession-number.html.md ignored: no empty accession_number", "Accession number MS-123 not changed for cool-dois.html.md"])
107
107
  end
108
108
  end
109
109
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cirneco
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Fenner
@@ -350,6 +350,7 @@ files:
350
350
  - spec/fixtures/cool-dois-minted.html
351
351
  - spec/fixtures/cool-dois-minted.html.md
352
352
  - spec/fixtures/cool-dois-missing-metadata.html
353
+ - spec/fixtures/cool-dois-no-accession-number.html.md
353
354
  - spec/fixtures/cool-dois-no-json-ld.html
354
355
  - spec/fixtures/cool-dois.html
355
356
  - spec/fixtures/cool-dois.html.md