cff 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 330c0177c6b7fed7915ddeddbc8ba68a9eb9f9e3
4
- data.tar.gz: '089cd1ad45d23af25bc1ccbac3b0ffffceedb570'
2
+ SHA256:
3
+ metadata.gz: 32661be9e23147731575824f34df12b82dfb6f0560af3fd4d8081958f633cac6
4
+ data.tar.gz: 5b525849ff1e6ff1829d70e657852377c88bf0b6e83dffff96dd6cd660fc029b
5
5
  SHA512:
6
- metadata.gz: 290ee6b5066a2f5d016ceff0416faf00f8f12df42c72e62b4642efa2a4d5afa64b32fc1a8e7843d3aec8a4165359445e7a2fd940e523a069a6f6509b181797d3
7
- data.tar.gz: 0a99851ff3c46441be5fc86d3317bb2bc1828c5f4e5d15dbb8e507541feb9a73e4ff751a7fbd9355a8097ae42db3ac9bfb38428bd28aa5b981b8cb42a74b4cb9
6
+ metadata.gz: c1df6fd36b30cdd828d9d80ae183795f9eea5a3691684ed0769bbe75b8bca026ed540611f671341bca8880352f396c727931ceb55865086b8613c016af5a7769
7
+ data.tar.gz: 0f3afd7def478528b073c4a9454c804731fe6c50cde9acbcdafa0fdc0d6bfba577ca812fcc34fe0b36732f5b1dafebde2b90940f81c6ddf882ac22754b01b419
data/CHANGES.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changes log for the Ruby CFF Library
2
2
 
3
+ ## Version 0.4.0
4
+
5
+ * Remove unused Util#expand_field method.
6
+ * Changed Model#keywords to be a field type.
7
+ * Model is now a subclass of ModelPart.
8
+ * Document ModelPart and Util just enough.
9
+ * Add Util::normalize_modelpart_array! method.
10
+ * Tighten up checking for empty collections in model.
11
+ * Move the references into the Model fields.
12
+ * Add an in-place actor collection builder method.
13
+ * Move authors and contact to Model fields.
14
+ * Refactor Reference so the actor lists are fields.
15
+ * Remove unused method: Util::build_actor_collection.
16
+ * Remove unused method: Util::expand_array_field.
17
+ * Add rubocop to the development dependencies.
18
+ * Add rubocop configuration files.
19
+ * Add rubocop rake tasks.
20
+ * Many rubocop fixes.
21
+ * Compact ALLOWED_FIELDS lists for consistency.
22
+ * Allow creation of a Reference without a type.
23
+ * Remove unused method: Util.delete_from_hash.
24
+ * Refactor duplicated code into Util.fields_to_hash.
25
+ * Add File#write (instance method).
26
+ * Ensure a model always returns '' for missing fields.
27
+ * Test reading short and minimal CFF files.
28
+ * Cleanup duplicated tests.
29
+ * Don't store dotfiles in the gemfile.
30
+ * Add a CITATION.cff file!
31
+
3
32
  ## Version 0.3.0
4
33
 
5
34
  * Update badges for new repo location.
@@ -0,0 +1,21 @@
1
+ cff-version: 1.0.3
2
+ message: If you use ruby-cff in your work, please cite it using the following metadata
3
+ title: Ruby CFF Library
4
+ abstract: This library provides a Ruby interface to manipulate CITATION.cff files
5
+ authors:
6
+ - family-names: Haines
7
+ given-names: Robert
8
+ orcid: https://orcid.org/0000-0002-9538-7919
9
+ affiliation: The University of Manchester, UK
10
+ keywords:
11
+ - ruby
12
+ - credit
13
+ - citation
14
+ - metadata
15
+ - cff
16
+ version: 0.4.0
17
+ doi: 10.5281/zenodo.1184077
18
+ date-released: 2018-07-29
19
+ license: Apache-2.0
20
+ repository-artifact: https://rubygems.org/gems/cff
21
+ repository-code: https://github.com/citation-file-format/ruby-cff
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/Rakefile CHANGED
@@ -12,22 +12,25 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require "bundler/gem_tasks"
16
- require "rake/testtask"
17
- require "rdoc/task"
15
+ require 'bundler/gem_tasks'
16
+ require 'rake/testtask'
17
+ require 'rdoc/task'
18
+ require 'rubocop/rake_task'
18
19
 
19
- task :default => :test
20
+ task default: :test
20
21
 
21
22
  Rake::TestTask.new(:test) do |t|
22
- t.libs << "test"
23
- t.libs << "lib"
24
- t.test_files = FileList["test/**/*_test.rb"]
23
+ t.libs << 'test'
24
+ t.libs << 'lib'
25
+ t.test_files = FileList['test/**/*_test.rb']
25
26
  end
26
27
 
27
28
  RDoc::Task.new do |r|
28
- r.main = "README.md"
29
- r.rdoc_files.include("README.md", "LICENCE", "CHANGES.md", "lib/**/*.rb")
30
- r.options << "--markup=markdown"
31
- r.options << "--tab-width=2"
29
+ r.main = 'README.md'
30
+ r.rdoc_files.include('README.md', 'LICENCE', 'CHANGES.md', 'lib/**/*.rb')
31
+ r.options << '--markup=markdown'
32
+ r.options << '--tab-width=2'
32
33
  r.options << "-t Ruby CFF Library version #{::CFF::VERSION}"
33
34
  end
35
+
36
+ RuboCop::RakeTask.new
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "cff"
3
+ require 'bundler/setup'
4
+ require 'cff'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "cff"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start(__FILE__)
@@ -12,37 +12,39 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- lib = File.expand_path("../lib", __FILE__)
15
+ lib = File.expand_path('lib', __dir__)
16
16
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
17
- require "cff/version"
17
+ require 'cff/version'
18
18
 
19
19
  Gem::Specification.new do |spec|
20
- spec.name = "cff"
20
+ spec.name = 'cff'
21
21
  spec.version = CFF::VERSION
22
- spec.authors = ["Robert Haines"]
23
- spec.email = ["robert.haines@manchester.ac.uk"]
22
+ spec.authors = ['Robert Haines']
23
+ spec.email = ['robert.haines@manchester.ac.uk']
24
24
 
25
- spec.summary = "A Ruby library for manipulating CITATION.cff files."
26
- spec.description = "See https://citation-file-format.github.io/ for more info."
27
- spec.homepage = "https://github.com/citation-file-format/ruby-cff"
28
- spec.license = "Apache-2.0"
25
+ spec.summary = 'A Ruby library for manipulating CITATION.cff files.'
26
+ spec.description = 'See https://citation-file-format.github.io/ ' \
27
+ 'for more info.'
28
+ spec.homepage = 'https://github.com/citation-file-format/ruby-cff'
29
+ spec.license = 'Apache-2.0'
29
30
 
30
31
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
31
- f.match(%r{^(test|spec|features)/})
32
+ f.match(%r{^((test|spec|features)/|\.)})
32
33
  end
33
- spec.bindir = "exe"
34
+ spec.bindir = 'exe'
34
35
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
- spec.require_paths = ["lib"]
36
+ spec.require_paths = ['lib']
36
37
 
37
- spec.required_ruby_version = ">= 2.2.0"
38
+ spec.required_ruby_version = '>= 2.2.0'
38
39
 
39
- spec.add_runtime_dependency "language_list", "~> 1.2"
40
- spec.add_runtime_dependency "spdx-licenses", "~> 1.1"
40
+ spec.add_runtime_dependency 'language_list', '~> 1.2'
41
+ spec.add_runtime_dependency 'spdx-licenses', '~> 1.1'
41
42
 
42
- spec.add_development_dependency "bundler", "~> 1.16"
43
- spec.add_development_dependency "rake", "~> 10.0"
44
- spec.add_development_dependency "minitest", "~> 5.0"
45
- spec.add_development_dependency "coveralls", "~> 0.8"
46
- spec.add_development_dependency "test_construct", "~> 2.0"
47
- spec.add_development_dependency "rdoc", "~> 6.0"
43
+ spec.add_development_dependency 'bundler', '~> 1.16'
44
+ spec.add_development_dependency 'coveralls', '~> 0.8'
45
+ spec.add_development_dependency 'minitest', '~> 5.0'
46
+ spec.add_development_dependency 'rake', '~> 10.0'
47
+ spec.add_development_dependency 'rdoc', '~> 6.0'
48
+ spec.add_development_dependency 'rubocop', '~> 0.54'
49
+ spec.add_development_dependency 'test_construct', '~> 2.0'
48
50
  end
data/lib/cff.rb CHANGED
@@ -12,19 +12,19 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require "date"
16
- require "yaml"
17
- require "language_list"
18
- require "spdx-licenses"
15
+ require 'date'
16
+ require 'yaml'
17
+ require 'language_list'
18
+ require 'spdx-licenses'
19
19
 
20
- require "cff/version"
21
- require "cff/util"
22
- require "cff/model-part"
23
- require "cff/person"
24
- require "cff/entity"
25
- require "cff/reference"
26
- require "cff/model"
27
- require "cff/file"
20
+ require 'cff/version'
21
+ require 'cff/util'
22
+ require 'cff/model_part'
23
+ require 'cff/person'
24
+ require 'cff/entity'
25
+ require 'cff/reference'
26
+ require 'cff/model'
27
+ require 'cff/file'
28
28
 
29
29
  # This library provides a Ruby interface to manipulate CITATION.cff files. The
30
30
  # primary entry points are Model and File.
@@ -32,5 +32,4 @@ require "cff/file"
32
32
  # See the [CITATION.cff documentation](https://citation-file-format.github.io/)
33
33
  # for more details.
34
34
  module CFF
35
-
36
35
  end
@@ -12,7 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- #
15
+ ##
16
16
  module CFF
17
17
 
18
18
  # An Entity can represent different types of entities, e.g., a publishing
@@ -21,20 +21,8 @@ module CFF
21
21
  class Entity < ModelPart
22
22
 
23
23
  ALLOWED_FIELDS = [
24
- 'address',
25
- 'city',
26
- 'country',
27
- 'email',
28
- 'date-end',
29
- 'date-start',
30
- 'fax',
31
- 'location',
32
- 'name',
33
- 'orcid',
34
- 'post-code',
35
- 'region',
36
- 'tel',
37
- 'website'
24
+ 'address', 'city', 'country', 'email', 'date-end', 'date-start', 'fax',
25
+ 'location', 'name', 'orcid', 'post-code', 'region', 'tel', 'website'
38
26
  ].freeze # :nodoc:
39
27
 
40
28
  # :call-seq:
@@ -42,7 +30,7 @@ module CFF
42
30
  #
43
31
  # Create a new Entity with the supplied name.
44
32
  def initialize(param)
45
- if Hash === param
33
+ if param.is_a?(Hash)
46
34
  @fields = param
47
35
  else
48
36
  @fields = Hash.new('')
@@ -56,9 +44,7 @@ module CFF
56
44
  # Set the `date-end` field. If a non-Date object is passed in it will
57
45
  # be parsed into a Date.
58
46
  def date_end=(date)
59
- unless Date === date
60
- date = Date.parse(date)
61
- end
47
+ date = Date.parse(date) unless date.is_a?(Date)
62
48
 
63
49
  @fields['date-end'] = date
64
50
  end
@@ -69,12 +55,9 @@ module CFF
69
55
  # Set the `date-start` field. If a non-Date object is passed in it will
70
56
  # be parsed into a Date.
71
57
  def date_start=(date)
72
- unless Date === date
73
- date = Date.parse(date)
74
- end
58
+ date = Date.parse(date) unless date.is_a?(Date)
75
59
 
76
60
  @fields['date-start'] = date
77
61
  end
78
-
79
62
  end
80
63
  end
@@ -12,14 +12,14 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- #
15
+ ##
16
16
  module CFF
17
17
 
18
18
  # File provides direct access to a CFF Model, with the addition of some
19
19
  # filesystem utilities.
20
20
  class File
21
21
 
22
- YAML_HEADER = "---\n" # :nodoc:
22
+ YAML_HEADER = "---\n".freeze # :nodoc:
23
23
 
24
24
  # :call-seq:
25
25
  # new(title) -> File
@@ -31,9 +31,7 @@ module CFF
31
31
  # All methods provided by Model are also available directly on File
32
32
  # objects.
33
33
  def initialize(param)
34
- unless Model === param
35
- param = Model.new(param)
36
- end
34
+ param = Model.new(param) unless param.is_a?(Model)
37
35
 
38
36
  @model = param
39
37
  end
@@ -43,7 +41,7 @@ module CFF
43
41
  #
44
42
  # Read a file and parse it for subsequent manipulation.
45
43
  def self.read(file)
46
- new(YAML::load_file(file))
44
+ new(YAML.load_file(file))
47
45
  end
48
46
 
49
47
  # :call-seq:
@@ -52,16 +50,25 @@ module CFF
52
50
  #
53
51
  # Write the supplied model or yaml string to `file`.
54
52
  def self.write(file, cff)
55
- unless String === cff
56
- cff = cff.to_yaml
57
- end
53
+ cff = cff.to_yaml unless cff.is_a?(String)
58
54
 
59
55
  ::File.write(file, cff[YAML_HEADER.length...-1])
60
56
  end
61
57
 
58
+ # :call-seq:
59
+ # write(file)
60
+ #
61
+ # Write this CFF File to `file`.
62
+ def write(file)
63
+ File.write(file, @model)
64
+ end
65
+
62
66
  def method_missing(name, *args) # :nodoc:
63
- @model.send name, *args
67
+ @model.respond_to?(name) ? @model.send(name, *args) : super
64
68
  end
65
69
 
70
+ def respond_to_missing?(name, *all) # :nodoc:
71
+ @model.respond_to?(name, *all)
72
+ end
66
73
  end
67
74
  end
@@ -12,55 +12,94 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- #
15
+ ##
16
16
  module CFF
17
17
 
18
18
  # Model is the core data structure for a CITATION.cff file. It can be
19
19
  # accessed direcly, or via File.
20
- class Model
21
-
22
- include Util
20
+ class Model < ModelPart
23
21
 
24
22
  ALLOWED_FIELDS = [
25
- 'abstract',
26
- 'cff-version',
27
- 'commit',
28
- 'date-released',
29
- 'doi',
30
- 'license',
31
- 'license-url',
32
- 'message',
33
- 'repository',
34
- 'repository-artifact',
35
- 'repository-code',
36
- 'title',
37
- 'url',
38
- 'version'
39
- ].freeze # :nodoc:
23
+ 'abstract', 'authors', 'cff-version', 'contact', 'commit',
24
+ 'date-released', 'doi', 'keywords', 'license', 'license-url', 'message',
25
+ 'references', 'repository', 'repository-artifact', 'repository-code',
26
+ 'title', 'url', 'version'
27
+ ].freeze # :nodoc:
40
28
 
41
29
  # The default message to use if none is explicitly set.
42
- DEFAULT_MESSAGE = "If you use this software in your work, please cite it using the following metadata"
30
+ DEFAULT_MESSAGE = 'If you use this software in your work, please cite ' \
31
+ 'it using the following metadata'.freeze
43
32
 
44
33
  # :call-seq:
45
34
  # new(title) -> Model
46
35
  #
47
36
  # Initialize a new Model with the supplied title.
48
37
  def initialize(param)
49
- @authors = []
50
- @contact = []
51
- @keywords = []
52
- @references = []
53
-
54
- if Hash === param
55
- build_model(param)
38
+ if param.is_a?(Hash)
39
+ @fields = build_model(param)
40
+ @fields.default = ''
56
41
  else
57
42
  @fields = Hash.new('')
58
43
  @fields['cff-version'] = DEFAULT_SPEC_VERSION
59
44
  @fields['message'] = DEFAULT_MESSAGE
60
45
  @fields['title'] = param
61
46
  end
47
+
48
+ %w[authors contact keywords references].each do |field|
49
+ @fields[field] = [] if @fields[field].empty?
50
+ end
62
51
  end
63
52
 
53
+ # :call-seq:
54
+ # date_released = date
55
+ #
56
+ # Set the `date-released` field. If a non-Date object is passed in it will
57
+ # be parsed into a Date.
58
+ def date_released=(date)
59
+ date = Date.parse(date) unless date.is_a?(Date)
60
+
61
+ @fields['date-released'] = date
62
+ end
63
+
64
+ # :call-seq:
65
+ # version = version
66
+ #
67
+ # Set the `version` field.
68
+ def version=(version)
69
+ @fields['version'] = version.to_s
70
+ end
71
+
72
+ def to_yaml # :nodoc:
73
+ YAML.dump fields, line_width: -1, indentation: 2
74
+ end
75
+
76
+ private
77
+
78
+ def fields
79
+ %w[authors contact references].each do |field|
80
+ normalize_modelpart_array!(@fields[field])
81
+ end
82
+
83
+ fields_to_hash(@fields)
84
+ end
85
+
86
+ def build_model(fields)
87
+ build_actor_collection!(fields['authors'] || [])
88
+ build_actor_collection!(fields['contact'] || [])
89
+ (fields['references'] || []).map! do |r|
90
+ Reference.new(r)
91
+ end
92
+
93
+ fields
94
+ end
95
+
96
+ public
97
+
98
+ # Some documentation of "hidden" methods is provided here, out of the
99
+ # way of the main class code.
100
+
101
+ ##
102
+ # :method: authors
64
103
  # :call-seq:
65
104
  # authors -> Array
66
105
  #
@@ -72,10 +111,18 @@ module CFF
72
111
  # ```
73
112
  #
74
113
  # Authors can be a Person or Entity.
75
- def authors
76
- @authors
77
- end
78
114
 
115
+ ##
116
+ # :method: authors=
117
+ # :call-seq:
118
+ # authors = array_of_authors -> Array
119
+ #
120
+ # Replace the list of authors for this citation.
121
+ #
122
+ # Authors can be a Person or Entity.
123
+
124
+ ##
125
+ # :method: contact
79
126
  # :call-seq:
80
127
  # contact -> Array
81
128
  #
@@ -87,23 +134,18 @@ module CFF
87
134
  # ```
88
135
  #
89
136
  # Contacts can be a Person or Entity.
90
- def contact
91
- @contact
92
- end
93
137
 
138
+ ##
139
+ # :method: contact=
94
140
  # :call-seq:
95
- # date_released = date
141
+ # contact = array_of_contacts -> Array
96
142
  #
97
- # Set the `date-released` field. If a non-Date object is passed in it will
98
- # be parsed into a Date.
99
- def date_released=(date)
100
- unless Date === date
101
- date = Date.parse(date)
102
- end
103
-
104
- @fields['date-released'] = date
105
- end
143
+ # Replace the list of contacts for this citation.
144
+ #
145
+ # Contacts can be a Person or Entity.
106
146
 
147
+ ##
148
+ # :method: keywords
107
149
  # :call-seq:
108
150
  # keywords -> Array
109
151
  #
@@ -114,11 +156,19 @@ module CFF
114
156
  # model.keywords << keyword
115
157
  # ```
116
158
  #
117
- # Keywords will be converted to Strings on output to a CFF file.
118
- def keywords
119
- @keywords
120
- end
159
+ # Keywords will be converted to Strings on output.
160
+
161
+ ##
162
+ # :method: keywords=
163
+ # :call-seq:
164
+ # keywords = array_of_keywords -> Array
165
+ #
166
+ # Replace the list of keywords for this citation.
167
+ #
168
+ # Keywords will be converted to Strings on output.
121
169
 
170
+ ##
171
+ # :method: references
122
172
  # :call-seq:
123
173
  # references -> Array
124
174
  #
@@ -128,59 +178,12 @@ module CFF
128
178
  # ```
129
179
  # model.references << reference
130
180
  # ```
131
- def references
132
- @references
133
- end
134
181
 
182
+ ##
183
+ # :method: references=
135
184
  # :call-seq:
136
- # version = version
185
+ # references = array_of_references -> Array
137
186
  #
138
- # Set the `version` field.
139
- def version=(version)
140
- @fields['version'] = version.to_s
141
- end
142
-
143
- def to_yaml # :nodoc:
144
- YAML.dump fields, :line_width => -1, :indentation => 2
145
- end
146
-
147
- def method_missing(name, *args) # :nodoc:
148
- n = method_to_field(name.id2name)
149
- super unless ALLOWED_FIELDS.include?(n.chomp('='))
150
-
151
- if n.end_with?('=')
152
- @fields[n.chomp('=')] = args[0] || ''
153
- else
154
- @fields[n]
155
- end
156
- end
157
-
158
- private
159
-
160
- def fields
161
- model = @fields.dup
162
- [
163
- ['authors', @authors],
164
- ['contact', @contact],
165
- ['references', @references]
166
- ].each do |field, var|
167
- model[field] = expand_array_field(var) unless var.empty?
168
- end
169
- model['keywords'] = @keywords.map { |k| k.to_s } unless @keywords.empty?
170
-
171
- model
172
- end
173
-
174
- def build_model(fields)
175
- build_actor_collection(@authors, fields['authors'])
176
- build_actor_collection(@contact, fields['contact'])
177
- @keywords = fields['keywords']
178
- fields['references'].each do |r|
179
- @references << Reference.new(r)
180
- end
181
-
182
- @fields = delete_from_hash(fields, 'authors', 'contact', 'keywords', 'references')
183
- end
184
-
187
+ # Replace the list of references for this citation.
185
188
  end
186
189
  end