berkeley_library-marc 0.2.1 → 0.3.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 +4 -4
- data/.idea/inspectionProfiles/Project_Default.xml +3 -0
- data/.idea/marc.iml +56 -54
- data/.ruby-version +1 -1
- data/.yardopts +6 -1
- data/CHANGES.md +18 -0
- data/LICENSE.md +1 -1
- data/berkeley_library-marc.gemspec +2 -1
- data/lib/berkeley_library/marc/field_info/var_fields/ind_def.rb +4 -0
- data/lib/berkeley_library/marc/field_info/var_fields/ind_val_def.rb +2 -0
- data/lib/berkeley_library/marc/field_info/var_fields/instrument_or_voices_code.rb +2 -0
- data/lib/berkeley_library/marc/field_info/var_fields/section.rb +12 -0
- data/lib/berkeley_library/marc/field_info/var_fields/subfield_def.rb +12 -1
- data/lib/berkeley_library/marc/field_info/var_fields/subfield_val.rb +2 -0
- data/lib/berkeley_library/marc/field_info/var_fields/var_field_def.rb +3 -0
- data/lib/berkeley_library/marc/field_info/var_fields/var_field_list.rb +11 -0
- data/lib/berkeley_library/marc/field_info/var_fields/var_field_parser.rb +20 -0
- data/lib/berkeley_library/marc/field_info/var_fields/var_field_transform.rb +19 -0
- data/lib/berkeley_library/marc/field_info/var_fields.rb +8 -0
- data/lib/berkeley_library/marc/field_info.rb +8 -0
- data/lib/berkeley_library/marc/module_info.rb +20 -1
- data/lib/berkeley_library/marc.rb +5 -0
- data/lib/marc_extensions/data_field.rb +16 -3
- data/lib/marc_extensions/field_map.rb +19 -14
- data/lib/marc_extensions/record.rb +15 -5
- data/lib/marc_extensions/subfield.rb +10 -2
- data/lib/marc_extensions/xml_reader.rb +62 -2
- data/lib/marc_extensions.rb +3 -0
- data/spec/data/record-187888.xml +0 -1
- data/spec/marc_extensions/record_spec.rb +33 -37
- data/spec/marc_extensions/xml_reader_spec.rb +47 -0
- data/spec/spec_helper.rb +0 -4
- metadata +22 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 25ed54f0bd91408a2bc16d7d51525e4bfe7086bf9b3a507b2e40a846432fff32
|
|
4
|
+
data.tar.gz: 135562e29c813d72f4830bfd8413a79c6480c2f7c5c396621a14ccdc22732432
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 968f53042e1d9b390c842ecc30f2b531ac58a17b49670ede19d9458a5559d93bb7c689c3665028a5c77d80cd892112468ad20b424aac72b420850b759529d6c1
|
|
7
|
+
data.tar.gz: d454a28e68812c807dcab0908317a566ff7949a3c66e3d22bb2374a457cee4dcb86c2cbb78ea69bcc4cd855cd74cb3b5e27a4cad016faec80276d3eec4860d03
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
11
11
|
<inspection_tool class="Rubocop" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
12
12
|
<inspection_tool class="RubyCaseWithoutElseBlockInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
13
|
+
<inspection_tool class="RubyMismatchedArgumentType" enabled="true" level="WARNING" enabled_by_default="true">
|
|
14
|
+
<option name="myCheckNilability" value="false" />
|
|
15
|
+
</inspection_tool>
|
|
13
16
|
<inspection_tool class="RubyStringKeysInHashInspection" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
|
14
17
|
<inspection_tool class="RubyUnnecessaryReturnStatement" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
15
18
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
data/.idea/marc.iml
CHANGED
|
@@ -6,63 +6,65 @@
|
|
|
6
6
|
<component name="NewModuleRootManager">
|
|
7
7
|
<content url="file://$MODULE_DIR$">
|
|
8
8
|
<sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
|
|
9
|
-
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
|
10
9
|
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
11
10
|
<excludeFolder url="file://$MODULE_DIR$/artifacts" />
|
|
12
11
|
</content>
|
|
13
|
-
<orderEntry type="jdk" jdkName="RVM: ruby-2.7.
|
|
12
|
+
<orderEntry type="jdk" jdkName="RVM: ruby-2.7.5" jdkType="RUBY_SDK" />
|
|
14
13
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
15
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
16
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
17
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
18
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
19
|
-
<orderEntry type="library" scope="PROVIDED" name="bundler (
|
|
20
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
21
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
22
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
23
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
24
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
25
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
26
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
27
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
28
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
29
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
30
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
31
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
32
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
33
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
34
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
35
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
36
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
37
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
38
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
39
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
40
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
41
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
42
|
-
<orderEntry type="library" scope="PROVIDED" name="rspec (v3.10.
|
|
43
|
-
<orderEntry type="library" scope="PROVIDED" name="rspec-
|
|
44
|
-
<orderEntry type="library" scope="PROVIDED" name="rspec-
|
|
45
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
46
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
47
|
-
<orderEntry type="library" scope="PROVIDED" name="rubocop (
|
|
48
|
-
<orderEntry type="library" scope="PROVIDED" name="rubocop-
|
|
49
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
50
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
51
|
-
<orderEntry type="library" scope="PROVIDED" name="ruby-
|
|
52
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
53
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
54
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
55
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
56
|
-
<orderEntry type="library" scope="PROVIDED" name="simplecov (v0.
|
|
57
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
58
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
59
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
60
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
61
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
62
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
63
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
64
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
|
65
|
-
|
|
14
|
+
<orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
15
|
+
<orderEntry type="library" scope="PROVIDED" name="builder (v3.2.4, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
16
|
+
<orderEntry type="library" scope="PROVIDED" name="bundle-audit (v0.1.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
17
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.2.31, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
18
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler-audit (v0.9.0.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
19
|
+
<orderEntry type="library" scope="PROVIDED" name="ci_reporter (v2.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
20
|
+
<orderEntry type="library" scope="PROVIDED" name="ci_reporter_rspec (v1.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
21
|
+
<orderEntry type="library" scope="PROVIDED" name="colorize (v0.8.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
22
|
+
<orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.5.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
23
|
+
<orderEntry type="library" scope="PROVIDED" name="docile (v1.4.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
24
|
+
<orderEntry type="library" scope="PROVIDED" name="dotenv (v2.7.6, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
25
|
+
<orderEntry type="library" scope="PROVIDED" name="ffi (v1.15.4, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
26
|
+
<orderEntry type="library" scope="PROVIDED" name="listen (v3.1.5, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
27
|
+
<orderEntry type="library" scope="PROVIDED" name="marc (v1.1.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
28
|
+
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.13.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
29
|
+
<orderEntry type="library" scope="PROVIDED" name="parallel (v1.21.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
30
|
+
<orderEntry type="library" scope="PROVIDED" name="parser (v3.1.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
31
|
+
<orderEntry type="library" scope="PROVIDED" name="parslet (v2.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
32
|
+
<orderEntry type="library" scope="PROVIDED" name="racc (v1.6.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
33
|
+
<orderEntry type="library" scope="PROVIDED" name="rainbow (v3.0.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
34
|
+
<orderEntry type="library" scope="PROVIDED" name="rake (v13.0.6, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
35
|
+
<orderEntry type="library" scope="PROVIDED" name="rb-fsevent (v0.11.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
36
|
+
<orderEntry type="library" scope="PROVIDED" name="rb-inotify (v0.10.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
37
|
+
<orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.2.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
38
|
+
<orderEntry type="library" scope="PROVIDED" name="rexml (v3.2.5, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
39
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec (v3.10.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
40
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.10.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
41
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.10.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
42
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.10.2, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
43
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.10.3, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
44
|
+
<orderEntry type="library" scope="PROVIDED" name="rubocop (v1.11.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
45
|
+
<orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.15.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
46
|
+
<orderEntry type="library" scope="PROVIDED" name="rubocop-rake (v0.6.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
47
|
+
<orderEntry type="library" scope="PROVIDED" name="rubocop-rspec (v2.4.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
48
|
+
<orderEntry type="library" scope="PROVIDED" name="ruby-marc-spec (v0.1.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
49
|
+
<orderEntry type="library" scope="PROVIDED" name="ruby-prof (v0.17.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
50
|
+
<orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.11.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
51
|
+
<orderEntry type="library" scope="PROVIDED" name="ruby_dep (v1.5.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
52
|
+
<orderEntry type="library" scope="PROVIDED" name="scrub_rb (v1.0.1, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
53
|
+
<orderEntry type="library" scope="PROVIDED" name="simplecov (v0.21.2, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
54
|
+
<orderEntry type="library" scope="PROVIDED" name="simplecov-html (v0.12.3, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
55
|
+
<orderEntry type="library" scope="PROVIDED" name="simplecov-rcov (v0.2.3, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
56
|
+
<orderEntry type="library" scope="PROVIDED" name="simplecov_json_formatter (v0.1.3, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
57
|
+
<orderEntry type="library" scope="PROVIDED" name="thor (v1.1.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
58
|
+
<orderEntry type="library" scope="PROVIDED" name="typesafe_enum (v0.3.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
59
|
+
<orderEntry type="library" scope="PROVIDED" name="unf (v0.1.4, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
60
|
+
<orderEntry type="library" scope="PROVIDED" name="unf_ext (v0.0.8, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
61
|
+
<orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v2.1.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
62
|
+
<orderEntry type="library" scope="PROVIDED" name="webrick (v1.7.0, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
63
|
+
<orderEntry type="library" scope="PROVIDED" name="yard (v0.9.27, RVM: ruby-2.7.5) [gem]" level="application" />
|
|
64
|
+
</component>
|
|
65
|
+
<component name="RModuleSettingsStorage">
|
|
66
|
+
<LOAD_PATH number="2" string0="$MODULE_DIR$/lib" string1="$MODULE_DIR$/spec" />
|
|
67
|
+
<I18N_FOLDERS number="0" />
|
|
66
68
|
</component>
|
|
67
69
|
<component name="RakeTasksCache">
|
|
68
70
|
<option name="myRootTask">
|
|
@@ -75,7 +77,7 @@
|
|
|
75
77
|
</RakeTaskImpl>
|
|
76
78
|
<RakeTaskImpl description="Run all specs in spec directory, with coverage" fullCommand="coverage" id="coverage" />
|
|
77
79
|
<RakeTaskImpl description="Run tests, check test coverage, check code style, check for vulnerabilities, build gem" fullCommand="default" id="default" />
|
|
78
|
-
<RakeTaskImpl description="Build berkeley_library-marc.gemspec as berkeley_library-marc-0.2.
|
|
80
|
+
<RakeTaskImpl description="Build berkeley_library-marc.gemspec as berkeley_library-marc-0.2.2.gem" fullCommand="gem" id="gem" />
|
|
79
81
|
<RakeTaskImpl description="Run RuboCop with auto-correct, and output results to console" fullCommand="ra" id="ra" />
|
|
80
82
|
<RakeTaskImpl description="Run rubocop with HTML output" fullCommand="rubocop" id="rubocop" />
|
|
81
83
|
<RakeTaskImpl id="rubocop">
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.7
|
|
1
|
+
2.7.5
|
data/.yardopts
CHANGED
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
# 0.3.0 (2022-01-25)
|
|
2
|
+
|
|
3
|
+
Fixes:
|
|
4
|
+
|
|
5
|
+
- Methods in `MARCExtensions::RecordExtensions` and `MARCExtensions::FieldMapExtensions`
|
|
6
|
+
now correctly return `Enumerator::Lazy` as documented.
|
|
7
|
+
- Fix issue where `freeze:` option to `MARC::XMLReader#new` or `MARC::XMLReader#read`
|
|
8
|
+
was accepted, but not implemented
|
|
9
|
+
- Test `MARC::XMLReader` extensions with both `MARC::REXMLReader` and `MARC::NokogiriReader`
|
|
10
|
+
- **Note:** the extensions _should_ work with `JREXMLReader`, `JRubyStaxReader`, and
|
|
11
|
+
`LibXMLReader`, but these have not been tested.
|
|
12
|
+
|
|
13
|
+
Possible breaking changes:
|
|
14
|
+
|
|
15
|
+
- The unused constant `MARCExtensions::FieldMapExtensions::VALID_TAGS` has been removed.
|
|
16
|
+
- `MARC::XMLReader#read` now takes an `options` hash instead of a `freeze:` keyword
|
|
17
|
+
parameter for better compatibility with `MARC::XMLReader#new`, esp. in Ruby 2.x.
|
|
18
|
+
|
|
1
19
|
# 0.2.1 (2021-10-16)
|
|
2
20
|
|
|
3
21
|
- Add [MARC::Spec](https://github.com/BerkeleyLibrary/marc-spec)
|
data/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright ©
|
|
3
|
+
Copyright © 2022 The Regents of the University of California
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
6
6
|
copy of this software and associated documentation files (the “Software”),
|
|
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
|
31
31
|
spec.add_development_dependency 'colorize', '~> 0.8'
|
|
32
32
|
spec.add_development_dependency 'dotenv', '~> 2.7'
|
|
33
33
|
spec.add_development_dependency 'listen', '>= 3.0.5', '< 3.2'
|
|
34
|
+
spec.add_development_dependency 'nokogiri', '~> 1.13'
|
|
34
35
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
35
36
|
spec.add_development_dependency 'rspec', '~> 3.10'
|
|
36
37
|
spec.add_development_dependency 'rubocop', '= 1.11'
|
|
@@ -39,5 +40,5 @@ Gem::Specification.new do |spec|
|
|
|
39
40
|
spec.add_development_dependency 'ruby-prof', '~> 0.17.0'
|
|
40
41
|
spec.add_development_dependency 'simplecov', '~> 0.21'
|
|
41
42
|
spec.add_development_dependency 'simplecov-rcov', '~> 0.2'
|
|
42
|
-
spec.add_development_dependency '
|
|
43
|
+
spec.add_development_dependency 'yard', '~> 0.9.27'
|
|
43
44
|
end
|
|
@@ -5,10 +5,12 @@ module BerkeleyLibrary
|
|
|
5
5
|
module Marc
|
|
6
6
|
module FieldInfo
|
|
7
7
|
module VarFields
|
|
8
|
+
# An indicator definition.
|
|
8
9
|
class IndDef
|
|
9
10
|
# TODO: include Comparable
|
|
10
11
|
include Obsolescible
|
|
11
12
|
|
|
13
|
+
# Human-readable position names
|
|
12
14
|
POS_NAMES = { 1 => 'First', 2 => 'Second' }.freeze
|
|
13
15
|
|
|
14
16
|
attr_reader :pos
|
|
@@ -23,10 +25,12 @@ module BerkeleyLibrary
|
|
|
23
25
|
@val_defs = val_defs
|
|
24
26
|
end
|
|
25
27
|
|
|
28
|
+
# @see Obsolescible#reject_obsoletes
|
|
26
29
|
def reject_obsoletes
|
|
27
30
|
IndDef.new(pos: pos, desc: desc, val_defs: _reject_obsolete(val_defs))
|
|
28
31
|
end
|
|
29
32
|
|
|
33
|
+
# see Object#to_s
|
|
30
34
|
def to_s
|
|
31
35
|
lines = ["#{POS_NAMES[pos]} - #{desc}"]
|
|
32
36
|
val_defs.each { |v| lines << " #{v}" }
|
|
@@ -4,6 +4,7 @@ module BerkeleyLibrary
|
|
|
4
4
|
module Marc
|
|
5
5
|
module FieldInfo
|
|
6
6
|
module VarFields
|
|
7
|
+
# An indicator value definition.
|
|
7
8
|
class IndValDef
|
|
8
9
|
# TODO: include Comparable
|
|
9
10
|
include Obsolescible
|
|
@@ -17,6 +18,7 @@ module BerkeleyLibrary
|
|
|
17
18
|
@desc = desc
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
# see Object#to_s
|
|
20
22
|
def to_s
|
|
21
23
|
"#{val} - #{desc}"
|
|
22
24
|
end
|
|
@@ -4,6 +4,7 @@ module BerkeleyLibrary
|
|
|
4
4
|
module Marc
|
|
5
5
|
module FieldInfo
|
|
6
6
|
module VarFields
|
|
7
|
+
# An instrument or voices code.
|
|
7
8
|
class InstrumentOrVoicesCode
|
|
8
9
|
# TODO: include Comparable
|
|
9
10
|
include Obsolescible
|
|
@@ -16,6 +17,7 @@ module BerkeleyLibrary
|
|
|
16
17
|
@desc = desc
|
|
17
18
|
end
|
|
18
19
|
|
|
20
|
+
# see Object#to_s
|
|
19
21
|
def to_s
|
|
20
22
|
"#{val} - #{desc}"
|
|
21
23
|
end
|
|
@@ -5,6 +5,7 @@ module BerkeleyLibrary
|
|
|
5
5
|
module Marc
|
|
6
6
|
module FieldInfo
|
|
7
7
|
module VarFields
|
|
8
|
+
# A section of a MARC field list
|
|
8
9
|
class Section
|
|
9
10
|
include Enumerable
|
|
10
11
|
include Obsolescible
|
|
@@ -17,20 +18,30 @@ module BerkeleyLibrary
|
|
|
17
18
|
@var_fields = var_fields
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
# Each variable field definition in this section.
|
|
22
|
+
# @overload each
|
|
23
|
+
# An enumerator of the fields in this section.
|
|
24
|
+
# @return [Enumerator<VarFieldDef>] the fields
|
|
25
|
+
# @overload each(&block)
|
|
26
|
+
# Yields each field in this section.
|
|
27
|
+
# @yieldparam vf [VarFieldDef] the field.
|
|
20
28
|
def each(&block)
|
|
21
29
|
return to_enum(:each) unless block_given?
|
|
22
30
|
|
|
23
31
|
var_fields.each(&block)
|
|
24
32
|
end
|
|
25
33
|
|
|
34
|
+
# The number of variable fields in this section.
|
|
26
35
|
def size
|
|
27
36
|
var_fields.size
|
|
28
37
|
end
|
|
29
38
|
|
|
39
|
+
# Returns true if this section contains no variable fields.
|
|
30
40
|
def empty?
|
|
31
41
|
var_fields.empty?
|
|
32
42
|
end
|
|
33
43
|
|
|
44
|
+
# @see Obsolescible#reject_obsoletes
|
|
34
45
|
def reject_obsoletes
|
|
35
46
|
Section.new(
|
|
36
47
|
desc: desc,
|
|
@@ -38,6 +49,7 @@ module BerkeleyLibrary
|
|
|
38
49
|
)
|
|
39
50
|
end
|
|
40
51
|
|
|
52
|
+
# see Object#to_s
|
|
41
53
|
def to_s
|
|
42
54
|
blocks = ["--#{desc}--"]
|
|
43
55
|
blocks.concat(var_fields.map(&:to_s))
|
|
@@ -5,8 +5,9 @@ module BerkeleyLibrary
|
|
|
5
5
|
module Marc
|
|
6
6
|
module FieldInfo
|
|
7
7
|
module VarFields
|
|
8
|
-
#
|
|
8
|
+
# A subfield definition.
|
|
9
9
|
class SubfieldDef
|
|
10
|
+
# TODO: destructure range codes in some useful way (e.g. 886a-z, 0-9)
|
|
10
11
|
include Obsolescible
|
|
11
12
|
|
|
12
13
|
attr_reader :code, :desc, :values
|
|
@@ -17,19 +18,29 @@ module BerkeleyLibrary
|
|
|
17
18
|
@values = values
|
|
18
19
|
end
|
|
19
20
|
|
|
21
|
+
# @see Obsolescible#reject_obsoletes
|
|
20
22
|
def reject_obsoletes
|
|
21
23
|
SubfieldDef.new(code: code, desc: desc, values: _reject_obsolete(values))
|
|
22
24
|
end
|
|
23
25
|
|
|
26
|
+
# Each value definition for this subfield.
|
|
27
|
+
# @overload each
|
|
28
|
+
# An enumerator of the value definitions for this subfield.
|
|
29
|
+
# @return [Enumerator<SubfieldVal>] the subfields.
|
|
30
|
+
# @overload each(&block)
|
|
31
|
+
# Yields each value definition for this subfield.
|
|
32
|
+
# @yieldparam v [SubfieldVal] the subfield.
|
|
24
33
|
def each_value(&block)
|
|
25
34
|
return to_enum(:each_value) unless block_given?
|
|
26
35
|
|
|
36
|
+
# noinspection RubyMismatchedReturnType
|
|
27
37
|
values.each(&block)
|
|
28
38
|
end
|
|
29
39
|
|
|
30
40
|
INDENT = ' '.freeze
|
|
31
41
|
private_constant :INDENT
|
|
32
42
|
|
|
43
|
+
# see Object#to_s
|
|
33
44
|
def to_s
|
|
34
45
|
lines = ["$#{code_str} - #{desc}"]
|
|
35
46
|
values.each { |v| lines << INDENT + v.to_s }
|
|
@@ -2,6 +2,7 @@ module BerkeleyLibrary
|
|
|
2
2
|
module Marc
|
|
3
3
|
module FieldInfo
|
|
4
4
|
module VarFields
|
|
5
|
+
# A subfield value definition.
|
|
5
6
|
class SubfieldVal
|
|
6
7
|
# TODO: include Comparable
|
|
7
8
|
include Obsolescible
|
|
@@ -14,6 +15,7 @@ module BerkeleyLibrary
|
|
|
14
15
|
@desc = desc
|
|
15
16
|
end
|
|
16
17
|
|
|
18
|
+
# see Object#to_s
|
|
17
19
|
def to_s
|
|
18
20
|
"#{val} - #{desc}"
|
|
19
21
|
end
|
|
@@ -7,6 +7,7 @@ module BerkeleyLibrary
|
|
|
7
7
|
module Marc
|
|
8
8
|
module FieldInfo
|
|
9
9
|
module VarFields
|
|
10
|
+
# A variable field definition.
|
|
10
11
|
class VarFieldDef
|
|
11
12
|
include Obsolescible
|
|
12
13
|
|
|
@@ -20,6 +21,7 @@ module BerkeleyLibrary
|
|
|
20
21
|
@inst_or_voices_codes = inst_or_voices_codes
|
|
21
22
|
end
|
|
22
23
|
|
|
24
|
+
# see Object#to_s
|
|
23
25
|
def to_s
|
|
24
26
|
blocks = ["#{tag} - #{desc}"]
|
|
25
27
|
|
|
@@ -30,6 +32,7 @@ module BerkeleyLibrary
|
|
|
30
32
|
blocks.join("\n")
|
|
31
33
|
end
|
|
32
34
|
|
|
35
|
+
# @see Obsolescible#reject_obsoletes
|
|
33
36
|
def reject_obsoletes
|
|
34
37
|
VarFieldDef.new(
|
|
35
38
|
tag: tag,
|
|
@@ -5,6 +5,7 @@ module BerkeleyLibrary
|
|
|
5
5
|
module Marc
|
|
6
6
|
module FieldInfo
|
|
7
7
|
module VarFields
|
|
8
|
+
# A list of variable fields grouped into sections.
|
|
8
9
|
class VarFieldList
|
|
9
10
|
include Enumerable
|
|
10
11
|
include Obsolescible
|
|
@@ -16,16 +17,25 @@ module BerkeleyLibrary
|
|
|
16
17
|
@sections = sections
|
|
17
18
|
end
|
|
18
19
|
|
|
20
|
+
# Each section in this list.
|
|
21
|
+
# @overload each
|
|
22
|
+
# An enumerator of the sections in this list.
|
|
23
|
+
# @return [Enumerator<Section>] the sections.
|
|
24
|
+
# @overload each(&block)
|
|
25
|
+
# Yields each section in this list.
|
|
26
|
+
# @yieldparam s [Section] the section.
|
|
19
27
|
def each(&block)
|
|
20
28
|
return to_enum(:each) unless block_given?
|
|
21
29
|
|
|
22
30
|
sections.each { |section| section.each(&block) }
|
|
23
31
|
end
|
|
24
32
|
|
|
33
|
+
# The number of sections in this list.
|
|
25
34
|
def size
|
|
26
35
|
sections.sum(&:size)
|
|
27
36
|
end
|
|
28
37
|
|
|
38
|
+
# @see Obsolescible#reject_obsoletes
|
|
29
39
|
def reject_obsoletes
|
|
30
40
|
VarFieldList.new(
|
|
31
41
|
desc: desc,
|
|
@@ -33,6 +43,7 @@ module BerkeleyLibrary
|
|
|
33
43
|
)
|
|
34
44
|
end
|
|
35
45
|
|
|
46
|
+
# see Object#to_s
|
|
36
47
|
def to_s
|
|
37
48
|
sections.map(&:to_s).join("\n")
|
|
38
49
|
end
|
|
@@ -6,6 +6,9 @@ module BerkeleyLibrary
|
|
|
6
6
|
module VarFields
|
|
7
7
|
|
|
8
8
|
# rubocop:disable Style/BlockDelimiters
|
|
9
|
+
|
|
10
|
+
# Parses MARC documentation in the format used by the
|
|
11
|
+
# Library of Congress [field list](https://www.loc.gov/marc/bibliographic/ecbdlist.html).
|
|
9
12
|
class VarFieldParser < Parslet::Parser
|
|
10
13
|
|
|
11
14
|
# ------------------------------------------------------------
|
|
@@ -122,10 +125,27 @@ module BerkeleyLibrary
|
|
|
122
125
|
# ------------------------------------------------------------
|
|
123
126
|
# Parser
|
|
124
127
|
|
|
128
|
+
# Parses the specified field documentation.
|
|
129
|
+
# Usage:
|
|
130
|
+
#
|
|
131
|
+
# ```ruby
|
|
132
|
+
# parser = VarFieldParser.new
|
|
133
|
+
# parse_tree = parser.parse('docs.txt')
|
|
134
|
+
# xform = VarFieldTransform.new
|
|
135
|
+
# var_field_list = xform.apply(parse_tree)
|
|
136
|
+
# ```
|
|
137
|
+
#
|
|
138
|
+
# @param io [String, Source] input for the parse process
|
|
139
|
+
# @option options [Parslet::ErrorReporter] :reporter error reporter to use,
|
|
140
|
+
# defaults to Parslet::ErrorReporter::Tree
|
|
141
|
+
# @option options [Boolean] :prefix Should a prefix match be accepted?
|
|
142
|
+
# (default: false)
|
|
143
|
+
# @return [Hash] a parse tree suitable for input to {VarFieldTransform}
|
|
125
144
|
def parse(io, options = nil)
|
|
126
145
|
opts = { reporter: Parslet::ErrorReporter::Deepest.new }
|
|
127
146
|
opts.merge!(options) if options
|
|
128
147
|
|
|
148
|
+
# noinspection RubyMismatchedReturnType
|
|
129
149
|
super(io, opts)
|
|
130
150
|
end
|
|
131
151
|
end
|
|
@@ -7,8 +7,21 @@ module BerkeleyLibrary
|
|
|
7
7
|
module VarFields
|
|
8
8
|
# TODO: flag [OBSOLETE], (R), (NR)
|
|
9
9
|
# rubocop:disable Style/BlockDelimiters
|
|
10
|
+
|
|
11
|
+
# Transformer converting {VarFieldParser} output to a {VarFieldList}.
|
|
12
|
+
# Usage:
|
|
13
|
+
#
|
|
14
|
+
# ```ruby
|
|
15
|
+
# parser = VarFieldParser.new
|
|
16
|
+
# parse_tree = parser.parse('docs.txt')
|
|
17
|
+
# xform = VarFieldTransform.new
|
|
18
|
+
# var_field_list = xform.apply(parse_tree)
|
|
19
|
+
# ```
|
|
10
20
|
class VarFieldTransform < Parslet::Transform
|
|
11
21
|
|
|
22
|
+
# Intermediate representation of structures constisting of
|
|
23
|
+
# a `val` and a `desc` (includes {IndValDef}, {SubfieldVal},
|
|
24
|
+
# and {InstrumentOrVoicesCode}).
|
|
12
25
|
class AnyValue
|
|
13
26
|
attr_reader :val, :desc
|
|
14
27
|
|
|
@@ -17,14 +30,20 @@ module BerkeleyLibrary
|
|
|
17
30
|
@desc = desc
|
|
18
31
|
end
|
|
19
32
|
|
|
33
|
+
# Converts this {AnyValue} to an {IndValDef}.
|
|
34
|
+
# @return [IndValDef] the {IndValDef}
|
|
20
35
|
def to_ind_val_def
|
|
21
36
|
IndValDef.new(val: val, desc: desc)
|
|
22
37
|
end
|
|
23
38
|
|
|
39
|
+
# Converts this {AnyValue} to an {SubfieldVal}.
|
|
40
|
+
# @return [SubfieldVal] the {SubfieldVal}
|
|
24
41
|
def to_subfield_val
|
|
25
42
|
SubfieldVal.new(val: val, desc: desc)
|
|
26
43
|
end
|
|
27
44
|
|
|
45
|
+
# Converts this {AnyValue} to an {InstrumentOrVoicesCode}.
|
|
46
|
+
# @return [InstrumentOrVoicesCode] the {InstrumentOrVoicesCode}
|
|
28
47
|
def to_ivc
|
|
29
48
|
InstrumentOrVoicesCode.new(val: val, desc: desc)
|
|
30
49
|
end
|
|
@@ -4,13 +4,19 @@ require 'berkeley_library/marc/field_info/var_fields/data'
|
|
|
4
4
|
module BerkeleyLibrary
|
|
5
5
|
module Marc
|
|
6
6
|
module FieldInfo
|
|
7
|
+
# Parsed documentation for variable fields.
|
|
7
8
|
module VarFields
|
|
8
9
|
|
|
10
|
+
# Path to machine-readable field documentation directory.
|
|
9
11
|
DATA_DIR = File.expand_path('var_fields/data', __dir__)
|
|
12
|
+
|
|
13
|
+
# Path to LOC standard variable field documentation.
|
|
10
14
|
PATH_STANDARD = File.join(DATA_DIR, 'var_fields_standard.txt')
|
|
11
15
|
|
|
12
16
|
class << self
|
|
13
17
|
|
|
18
|
+
# Return information on all LOC standard variable fields.
|
|
19
|
+
# @param obsolete [Boolean] whether to include fields documented as obsolete.
|
|
14
20
|
def standard(obsolete: false)
|
|
15
21
|
@standard_all ||= VarFieldTransform.new.apply(BerkeleyLibrary::Marc::FieldInfo::VarFields::STANDARD_PARSED)
|
|
16
22
|
return @standard_all if obsolete
|
|
@@ -18,6 +24,8 @@ module BerkeleyLibrary
|
|
|
18
24
|
@standard ||= @standard_all.reject_obsoletes
|
|
19
25
|
end
|
|
20
26
|
|
|
27
|
+
# Return information on UC Berkeley special 9xx fields.
|
|
28
|
+
# @param obsolete [Boolean] whether to include fields documented as obsolete.
|
|
21
29
|
def berkeley_9xx(obsolete: false)
|
|
22
30
|
@berkeley_9xx_all ||= VarFieldTransform.new.apply(BerkeleyLibrary::Marc::FieldInfo::VarFields::BERKELEY_9XX_PARSED)
|
|
23
31
|
return @berkeley_9xx_all if obsolete
|
|
@@ -1 +1,9 @@
|
|
|
1
|
+
module BerkeleyLibrary
|
|
2
|
+
module Marc
|
|
3
|
+
# Experimental module for parsing MARC documentation in the format used by the
|
|
4
|
+
# Library of Congress [field list](https://www.loc.gov/marc/bibliographic/ecbdlist.html).
|
|
5
|
+
module FieldInfo; end
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
1
9
|
Dir.glob(File.expand_path('field_info/*.rb', __dir__)).sort.each(&method(:require))
|
|
@@ -1,13 +1,32 @@
|
|
|
1
|
+
# Umbrella module for UC Berkeley Library Ruby code
|
|
1
2
|
module BerkeleyLibrary
|
|
3
|
+
# MARC utilities for the UC Berkeley Library
|
|
2
4
|
module Marc
|
|
5
|
+
# Build information for this module
|
|
3
6
|
class ModuleInfo
|
|
7
|
+
|
|
8
|
+
# The gem name
|
|
4
9
|
NAME = 'berkeley_library-marc'.freeze
|
|
10
|
+
|
|
11
|
+
# The author
|
|
5
12
|
AUTHOR = 'David Moles'.freeze
|
|
13
|
+
|
|
14
|
+
# Author contact email
|
|
6
15
|
AUTHOR_EMAIL = 'dmoles@berkeley.edu'.freeze
|
|
16
|
+
|
|
17
|
+
# Gem summary
|
|
7
18
|
SUMMARY = 'MARC utilities for the UC Berkeley Library'.freeze
|
|
19
|
+
|
|
20
|
+
# Gem description
|
|
8
21
|
DESCRIPTION = 'A gem providing MARC-related utility code and extensions to ruby-marc for the UC Berkeley Library'.freeze
|
|
22
|
+
|
|
23
|
+
# Gem license
|
|
9
24
|
LICENSE = 'MIT'.freeze
|
|
10
|
-
|
|
25
|
+
|
|
26
|
+
# Gem version
|
|
27
|
+
VERSION = '0.3.0'.freeze
|
|
28
|
+
|
|
29
|
+
# Gem homepage
|
|
11
30
|
HOMEPAGE = 'https://github.com/BerkeleyLibrary/marc'.freeze
|
|
12
31
|
end
|
|
13
32
|
end
|
|
@@ -2,26 +2,39 @@ require 'marc'
|
|
|
2
2
|
require 'marc_extensions/subfield'
|
|
3
3
|
|
|
4
4
|
module MARCExtensions
|
|
5
|
+
# Extensions for [MARC::XMLReader](https://rubydoc.info/gems/marc/MARC/DataField).
|
|
5
6
|
module DataFieldExtensions
|
|
7
|
+
# Returns a list of all the subfield codes in this data field.
|
|
8
|
+
# @return [Array] the subfield codes
|
|
6
9
|
def subfield_codes
|
|
7
10
|
subfields.map(&:code)
|
|
8
11
|
end
|
|
9
12
|
|
|
13
|
+
# Whether this datafield and all its tag, indicators, and
|
|
14
|
+
# subfields are frozen.
|
|
15
|
+
#
|
|
16
|
+
# @return [Boolean] true if the field is frozen, false otherwise.
|
|
10
17
|
def frozen?
|
|
11
|
-
[tag, indicator1, indicator2, subfields].all?(&:frozen?)
|
|
12
|
-
|
|
18
|
+
[tag, indicator1, indicator2, subfields].all?(&:frozen?) &&
|
|
19
|
+
subfields.all?(&:frozen?) &&
|
|
20
|
+
super
|
|
13
21
|
end
|
|
14
22
|
|
|
23
|
+
# Recursively freezes this datafield, along with its tag, indicators,
|
|
24
|
+
# and subfields.
|
|
25
|
+
#
|
|
26
|
+
# @return [MARC::DataField] this data field.
|
|
15
27
|
def freeze
|
|
16
28
|
[tag, indicator1, indicator2].each(&:freeze)
|
|
17
29
|
subfields.each(&:freeze)
|
|
18
30
|
subfields.freeze
|
|
19
|
-
|
|
31
|
+
super
|
|
20
32
|
end
|
|
21
33
|
end
|
|
22
34
|
end
|
|
23
35
|
|
|
24
36
|
module MARC
|
|
37
|
+
# Applies the extensions in {MARCExtensions::DataFieldExtensions}
|
|
25
38
|
# @see https://rubydoc.info/gems/marc/MARC/DataField RubyGems documentation
|
|
26
39
|
class DataField
|
|
27
40
|
prepend MARCExtensions::DataFieldExtensions
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require 'marc'
|
|
2
|
+
|
|
2
3
|
module MARCExtensions
|
|
4
|
+
# Extensions to [MARC::FieldMap](https://rubydoc.info/gems/marc/MARC/FieldMap).
|
|
3
5
|
module FieldMapExtensions
|
|
4
6
|
|
|
5
|
-
VALID_TAGS = ('000'..'999').freeze
|
|
6
|
-
|
|
7
7
|
# Gets the specified fields in order by tag.
|
|
8
8
|
#
|
|
9
9
|
# @overload each_sorted_by_tag(tags, &block)
|
|
@@ -23,29 +23,33 @@ module MARCExtensions
|
|
|
23
23
|
def each_sorted_by_tag(tags = nil, &block)
|
|
24
24
|
reindex unless @clean
|
|
25
25
|
|
|
26
|
-
indices_for(tags)
|
|
26
|
+
indices = indices_for(tags)
|
|
27
|
+
fields = indices.map { |i| self[i] }
|
|
28
|
+
# noinspection RubyMismatchedReturnType
|
|
29
|
+
fields.each(&block)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Recursively freezes all fields.
|
|
33
|
+
# @return [MARC::FieldMap] this FieldMap.
|
|
34
|
+
def freeze
|
|
35
|
+
unless frozen?
|
|
36
|
+
reindex unless @clean
|
|
37
|
+
each(&:freeze)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
super
|
|
27
41
|
end
|
|
28
42
|
|
|
29
43
|
private
|
|
30
44
|
|
|
31
45
|
def indices_for(tags)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
sorted_tag_array(tags)
|
|
46
|
+
sorted_tag_array(tags || tag_list)
|
|
35
47
|
.lazy # prevent unnecessary allocations
|
|
36
48
|
.map { |t| @tags[t] } # get indices for each tag
|
|
37
49
|
.reject(&:nil?) # ignoring any tags we don't have fields for
|
|
38
50
|
.flat_map { |x| x } # flatten list of indices -- equiv. Array#flatten
|
|
39
51
|
end
|
|
40
52
|
|
|
41
|
-
def all_indices
|
|
42
|
-
[].tap do |a|
|
|
43
|
-
@tags.keys.sort.map do |t|
|
|
44
|
-
a.concat(@tags[t])
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
53
|
def sorted_tag_array(tags)
|
|
50
54
|
return Array(tags) if tags.is_a?(Range)
|
|
51
55
|
|
|
@@ -56,6 +60,7 @@ module MARCExtensions
|
|
|
56
60
|
end
|
|
57
61
|
|
|
58
62
|
module MARC
|
|
63
|
+
# Applies the extensions in {MARCExtensions::FieldMapExtensions}.
|
|
59
64
|
# @see https://rubydoc.info/gems/marc/MARC/FieldMap RubyGems documentation
|
|
60
65
|
class FieldMap
|
|
61
66
|
prepend MARCExtensions::FieldMapExtensions
|
|
@@ -4,6 +4,7 @@ require 'marc_extensions/field_map'
|
|
|
4
4
|
require 'marc_extensions/data_field'
|
|
5
5
|
|
|
6
6
|
module MARCExtensions
|
|
7
|
+
# Extensions to [MARC::Record](https://rubydoc.info/gems/marc/MARC/Record).
|
|
7
8
|
module RecordExtensions
|
|
8
9
|
|
|
9
10
|
# Gets the specified fields in order by tag.
|
|
@@ -38,6 +39,7 @@ module MARCExtensions
|
|
|
38
39
|
# Yields each control field.
|
|
39
40
|
# @yieldparam field [MARC::ControlField] Each control field.
|
|
40
41
|
def each_control_field(&block)
|
|
42
|
+
# noinspection RubyMismatchedReturnType
|
|
41
43
|
each_sorted_by_tag.take_while { |df| df.tag.to_i <= 10 }.each(&block)
|
|
42
44
|
end
|
|
43
45
|
|
|
@@ -52,6 +54,7 @@ module MARCExtensions
|
|
|
52
54
|
# Yields each data field.
|
|
53
55
|
# @yieldparam field [MARC::DataField] Each data field.
|
|
54
56
|
def each_data_field(&block)
|
|
57
|
+
# noinspection RubyMismatchedReturnType
|
|
55
58
|
each_sorted_by_tag.select { |df| df.tag.to_i > 10 }.each(&block)
|
|
56
59
|
end
|
|
57
60
|
|
|
@@ -72,20 +75,24 @@ module MARCExtensions
|
|
|
72
75
|
data_fields_by_tag.values.flatten
|
|
73
76
|
end
|
|
74
77
|
|
|
75
|
-
#
|
|
78
|
+
# Recursively freezes this record, along with its leader and fields.
|
|
79
|
+
# @return [MARC::Record] this record.
|
|
76
80
|
def freeze
|
|
81
|
+
return if frozen?
|
|
82
|
+
|
|
77
83
|
leader.freeze
|
|
78
|
-
fields.each(&:freeze)
|
|
79
84
|
fields.freeze
|
|
80
|
-
|
|
85
|
+
super
|
|
81
86
|
end
|
|
82
87
|
|
|
88
|
+
# Whether this record, its fields, and leader are all frozen.
|
|
83
89
|
# @return [Boolean] true if the fields and leader are frozen
|
|
84
90
|
def frozen?
|
|
85
|
-
(fields.frozen? && leader.frozen?)
|
|
91
|
+
(fields.frozen? && leader.frozen?) && super
|
|
86
92
|
end
|
|
87
93
|
|
|
88
|
-
#
|
|
94
|
+
# Returns the canonical ID from the 001 control field.
|
|
95
|
+
# @return [String, nil] the 001 control field value, or nil if not present
|
|
89
96
|
def record_id
|
|
90
97
|
cf_001 = self['001']
|
|
91
98
|
return cf_001.value if cf_001
|
|
@@ -102,7 +109,10 @@ module MARCExtensions
|
|
|
102
109
|
end
|
|
103
110
|
end
|
|
104
111
|
|
|
112
|
+
# Extensions to [ruby-marc](https://rubydoc.info/gems/marc/)
|
|
113
|
+
# @see https://rubydoc.info/gems/marc/MARC RubyGems documentation
|
|
105
114
|
module MARC
|
|
115
|
+
# Applies the extensions in {MARCExtensions::RecordExtensions}.
|
|
106
116
|
# @see https://rubydoc.info/gems/marc/MARC/Record RubyGems documentation
|
|
107
117
|
class Record
|
|
108
118
|
prepend MARCExtensions::RecordExtensions
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
require 'marc'
|
|
2
2
|
|
|
3
3
|
module MARCExtensions
|
|
4
|
+
# Extensions to [MARC::Subfield](https://rubydoc.info/gems/marc/MARC/Subfield).
|
|
4
5
|
module SubfieldExtensions
|
|
6
|
+
|
|
7
|
+
# Recursively freezes this subfield, including its code and value.
|
|
8
|
+
#
|
|
9
|
+
# @return [Boolean] true if this subfield is frozen, false otherwise
|
|
5
10
|
def frozen?
|
|
6
|
-
[code, value].all?(&:frozen?)
|
|
11
|
+
[code, value].all?(&:frozen?) && super
|
|
7
12
|
end
|
|
8
13
|
|
|
14
|
+
# Whether this subfield and its code and value are frozen.
|
|
15
|
+
# @return [MARC::Subfield] this subfield.
|
|
9
16
|
def freeze
|
|
10
17
|
[code, value].each(&:freeze)
|
|
11
|
-
|
|
18
|
+
super
|
|
12
19
|
end
|
|
13
20
|
end
|
|
14
21
|
end
|
|
15
22
|
|
|
16
23
|
module MARC
|
|
24
|
+
# Applies the extensions in {MARCExtensions::SubfieldExtensions}.
|
|
17
25
|
# @see https://rubydoc.info/gems/marc/MARC/Subfield RubyGems documentation
|
|
18
26
|
class Subfield
|
|
19
27
|
prepend MARCExtensions::SubfieldExtensions
|
|
@@ -2,16 +2,76 @@ require 'marc'
|
|
|
2
2
|
require 'marc_extensions/record'
|
|
3
3
|
|
|
4
4
|
module MARCExtensions
|
|
5
|
+
# Extends [MARC::XMLReader](https://rubydoc.info/gems/marc/MARC/XMLReader).
|
|
6
|
+
module XMLReaderExtensions
|
|
7
|
+
# Adds a `:freeze` option to [MARC::XMLReader](https://rubydoc.info/gems/marc/MARC/XMLReader)
|
|
8
|
+
# which freezes each record as it's constructed:
|
|
9
|
+
#
|
|
10
|
+
# ```ruby
|
|
11
|
+
# reader = MARC::XMLReader.new('marc.xml', { freeze: true })
|
|
12
|
+
# record = reader.first
|
|
13
|
+
# record.frozen?
|
|
14
|
+
# # => true
|
|
15
|
+
# ```
|
|
16
|
+
#
|
|
17
|
+
# @see MARCExtensions::RecordExtensions#freeze
|
|
18
|
+
def initialize(file, options = {})
|
|
19
|
+
@freeze = options[:freeze]
|
|
20
|
+
super(file, options)
|
|
21
|
+
|
|
22
|
+
# It's surprisingly tricky to get these into the general superclass
|
|
23
|
+
# chain, so instead we just prepend them to the eigenclass
|
|
24
|
+
if respond_to?(:yield_record)
|
|
25
|
+
class << self; prepend(MARCExtensions::YieldFrozenRecord); end
|
|
26
|
+
elsif respond_to?(:build_record, true)
|
|
27
|
+
class << self; prepend(MARCExtensions::BuildFrozenRecord); end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Class extensions for [MARC::XMLReader](https://rubydoc.info/gems/marc/MARC/XMLReader).
|
|
5
33
|
module XMLReaderClassExtensions
|
|
6
|
-
|
|
7
|
-
|
|
34
|
+
# Reads MARC records from the specified file or IO
|
|
35
|
+
#
|
|
36
|
+
# @param file [String, IO] a string file path, or an IO object
|
|
37
|
+
# @return [MARC::XMLReader] a reader for the specified file or IO
|
|
38
|
+
def read(file, options = {})
|
|
39
|
+
new(file, options)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Extends [MARC::GenericPullParser](https://rubydoc.info/gems/marc/MARC/GenericPullParser)
|
|
44
|
+
# to support `:freeze` option
|
|
45
|
+
module YieldFrozenRecord
|
|
46
|
+
# Builds a MARC record, freezing it if the `:freeze` option
|
|
47
|
+
# was passed to the reader.
|
|
48
|
+
# @@yieldparam record [MARC::Record] the record
|
|
49
|
+
def yield_record
|
|
50
|
+
@record[:record].freeze if @freeze
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Extends [MARC::REXMLReader](https://rubydoc.info/gems/marc/MARC/REXMLReader)
|
|
56
|
+
# and [MARC::LibXMLReader](https://rubydoc.info/gems/marc/MARC/LibXMLReader)
|
|
57
|
+
# to support `:freeze` option
|
|
58
|
+
module BuildFrozenRecord
|
|
59
|
+
# Builds a MARC record, freezing it if the `:freeze` option
|
|
60
|
+
# was passed to the reader.
|
|
61
|
+
# @return [MARC::Record] the record
|
|
62
|
+
def build_record
|
|
63
|
+
super.tap { |record| record.freeze if @freeze }
|
|
8
64
|
end
|
|
9
65
|
end
|
|
10
66
|
end
|
|
11
67
|
|
|
12
68
|
module MARC
|
|
69
|
+
# Applies the extensions in {MARCExtensions::XMLReaderExtensions}
|
|
70
|
+
# and {MARCExtensions::XMLReaderClassExtensions}.
|
|
13
71
|
# @see https://rubydoc.info/gems/marc/MARC/XMLReader RubyGems documentation
|
|
14
72
|
class XMLReader
|
|
73
|
+
prepend MARCExtensions::XMLReaderExtensions
|
|
74
|
+
|
|
15
75
|
class << self
|
|
16
76
|
prepend MARCExtensions::XMLReaderClassExtensions
|
|
17
77
|
end
|
data/lib/marc_extensions.rb
CHANGED
data/spec/data/record-187888.xml
CHANGED
|
@@ -36,42 +36,6 @@ describe MARC::Record do
|
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
describe :frozen? do
|
|
40
|
-
it 'returns false neither fields nor leader are frozen' do
|
|
41
|
-
expect(marc_record.leader).not_to be_frozen # just to be sure
|
|
42
|
-
expect(marc_record.fields).not_to be_frozen # just to be sure
|
|
43
|
-
expect(marc_record).not_to be_frozen
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'returns false if only fields are frozen' do
|
|
47
|
-
expect(marc_record.leader).not_to be_frozen # just to be sure
|
|
48
|
-
expect(marc_record.fields).not_to be_frozen # just to be sure
|
|
49
|
-
marc_record.leader.freeze
|
|
50
|
-
expect(marc_record).not_to be_frozen
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it 'returns false if only leader is frozen' do
|
|
54
|
-
expect(marc_record.leader).not_to be_frozen # just to be sure
|
|
55
|
-
expect(marc_record.fields).not_to be_frozen # just to be sure
|
|
56
|
-
marc_record.fields.freeze
|
|
57
|
-
expect(marc_record).not_to be_frozen
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
it 'returns false if neither fields nor leader are frozen' do
|
|
61
|
-
expect(marc_record.leader).not_to be_frozen # just to be sure
|
|
62
|
-
expect(marc_record.fields).not_to be_frozen # just to be sure
|
|
63
|
-
expect(marc_record).not_to be_frozen
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it 'returns true if both fields and leader are frozen' do
|
|
67
|
-
expect(marc_record.leader).not_to be_frozen # just to be sure
|
|
68
|
-
expect(marc_record.fields).not_to be_frozen # just to be sure
|
|
69
|
-
marc_record.fields.freeze
|
|
70
|
-
marc_record.leader.freeze
|
|
71
|
-
expect(marc_record).to be_frozen
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
39
|
describe :data_fields do
|
|
76
40
|
it 'returns only the data fields' do
|
|
77
41
|
expected_tags = %w[024 035 245 336 505 505 505 505 505 505 540 852 856 856 901 902 902 980 982 991]
|
|
@@ -111,7 +75,8 @@ describe MARC::Record do
|
|
|
111
75
|
|
|
112
76
|
describe :each_data_field do
|
|
113
77
|
it 'returns only the data fields, in order' do
|
|
114
|
-
|
|
78
|
+
each_data_field = marc_record.each_data_field
|
|
79
|
+
expect(each_data_field.to_a).to eq(marc_record.data_fields)
|
|
115
80
|
end
|
|
116
81
|
|
|
117
82
|
it 'groups fields by tag even when disordered' do
|
|
@@ -126,6 +91,16 @@ describe MARC::Record do
|
|
|
126
91
|
df_852_ix = dff.find_index { |df| df.tag == '852' }
|
|
127
92
|
expect(dff[df_852_ix, 3]).to eq([df_852, df_856_1, df_856_2])
|
|
128
93
|
end
|
|
94
|
+
|
|
95
|
+
it 'returns a lazy enumerator if not passed a block' do
|
|
96
|
+
en = marc_record.each_data_field
|
|
97
|
+
expect(en).to be_a(Enumerator::Lazy)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'returns nil if passed a block' do
|
|
101
|
+
result = marc_record.each_data_field { |_| next }
|
|
102
|
+
expect(result).to be_nil
|
|
103
|
+
end
|
|
129
104
|
end
|
|
130
105
|
|
|
131
106
|
describe :each_sorted_by_tag do
|
|
@@ -140,6 +115,14 @@ describe MARC::Record do
|
|
|
140
115
|
end
|
|
141
116
|
end
|
|
142
117
|
|
|
118
|
+
it 'returns a lazy enumerator' do
|
|
119
|
+
en = marc_record.each_sorted_by_tag
|
|
120
|
+
expect(en).to be_a(Enumerator::Lazy)
|
|
121
|
+
|
|
122
|
+
en = marc_record.each_sorted_by_tag(tags)
|
|
123
|
+
expect(en).to be_a(Enumerator::Lazy)
|
|
124
|
+
end
|
|
125
|
+
|
|
143
126
|
it 'returns only fields with the specified tags, sorted, in original order' do
|
|
144
127
|
result = []
|
|
145
128
|
marc_record.each_sorted_by_tag(tags) { |f| result << f }
|
|
@@ -149,6 +132,9 @@ describe MARC::Record do
|
|
|
149
132
|
it 'returns nil if passed a block' do
|
|
150
133
|
result = marc_record.each_sorted_by_tag(tags) { |_| next }
|
|
151
134
|
expect(result).to be_nil
|
|
135
|
+
|
|
136
|
+
result = marc_record.each_sorted_by_tag { |_| next }
|
|
137
|
+
expect(result).to be_nil
|
|
152
138
|
end
|
|
153
139
|
|
|
154
140
|
it 'returns an enum if not passed a block' do
|
|
@@ -207,6 +193,16 @@ describe MARC::Record do
|
|
|
207
193
|
expect(cff.size).to eq(expected_tags.size)
|
|
208
194
|
expect(cff.map(&:tag)).to eq(expected_tags)
|
|
209
195
|
end
|
|
196
|
+
|
|
197
|
+
it 'returns nil if passed a block' do
|
|
198
|
+
result = marc_record.each_control_field { |_| next }
|
|
199
|
+
expect(result).to be_nil
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it 'returns a lazy enumerator if not passed a block' do
|
|
203
|
+
en = marc_record.each_control_field
|
|
204
|
+
expect(en).to be_a(Enumerator::Lazy)
|
|
205
|
+
end
|
|
210
206
|
end
|
|
211
207
|
|
|
212
208
|
describe :spec do
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module MARC
|
|
4
|
+
describe XMLReader do
|
|
5
|
+
let(:infile_path) { 'spec/data/record-187888.xml' }
|
|
6
|
+
describe :new do
|
|
7
|
+
# not our first choice, but it's the ruby-marc default behavior
|
|
8
|
+
it 'returns a REXMLParser by default' do
|
|
9
|
+
reader = XMLReader.new(infile_path)
|
|
10
|
+
expect(reader).to be_a(REXMLReader)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'works with Nokogiri' do
|
|
14
|
+
reader = XMLReader.new(infile_path, { parser: 'nokogiri' })
|
|
15
|
+
expect(reader).to be_a(NokogiriReader)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe :read do
|
|
20
|
+
it 'reads a file' do
|
|
21
|
+
reader = XMLReader.read(infile_path)
|
|
22
|
+
expect(reader).to be_a(MARC::XMLReader)
|
|
23
|
+
record = reader.first
|
|
24
|
+
expect(record).to be_a(MARC::Record)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe 'freeze: true' do
|
|
28
|
+
it 'works with REXML' do
|
|
29
|
+
reader = XMLReader.read(infile_path, { parser: 'rexml', freeze: true })
|
|
30
|
+
expect(reader).to be_a(MARC::REXMLReader)
|
|
31
|
+
record = reader.first
|
|
32
|
+
expect(record).to be_a(MARC::Record)
|
|
33
|
+
expect(record).to be_frozen
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'works with Nokogiri' do
|
|
37
|
+
reader = XMLReader.read(infile_path, { parser: 'nokogiri', freeze: true })
|
|
38
|
+
expect(reader).to be_a(MARC::NokogiriReader)
|
|
39
|
+
record = reader.first
|
|
40
|
+
expect(record).to be_a(MARC::Record)
|
|
41
|
+
expect(record).to be_frozen
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -7,14 +7,10 @@ require 'simplecov' if ENV['COVERAGE']
|
|
|
7
7
|
# ------------------------------------------------------------
|
|
8
8
|
# RSpec
|
|
9
9
|
|
|
10
|
-
require 'webmock/rspec'
|
|
11
|
-
|
|
12
10
|
RSpec.configure do |config|
|
|
13
11
|
config.color = true
|
|
14
12
|
config.tty = true
|
|
15
13
|
config.formatter = :documentation
|
|
16
|
-
config.before(:each) { WebMock.disable_net_connect!(allow_localhost: true) }
|
|
17
|
-
config.after(:each) { WebMock.allow_net_connect! }
|
|
18
14
|
config.mock_with :rspec do |mocks|
|
|
19
15
|
mocks.verify_partial_doubles = true
|
|
20
16
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: berkeley_library-marc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Moles
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-01-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: marc
|
|
@@ -128,6 +128,20 @@ dependencies:
|
|
|
128
128
|
- - "<"
|
|
129
129
|
- !ruby/object:Gem::Version
|
|
130
130
|
version: '3.2'
|
|
131
|
+
- !ruby/object:Gem::Dependency
|
|
132
|
+
name: nokogiri
|
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - "~>"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '1.13'
|
|
138
|
+
type: :development
|
|
139
|
+
prerelease: false
|
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - "~>"
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '1.13'
|
|
131
145
|
- !ruby/object:Gem::Dependency
|
|
132
146
|
name: rake
|
|
133
147
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -241,19 +255,19 @@ dependencies:
|
|
|
241
255
|
- !ruby/object:Gem::Version
|
|
242
256
|
version: '0.2'
|
|
243
257
|
- !ruby/object:Gem::Dependency
|
|
244
|
-
name:
|
|
258
|
+
name: yard
|
|
245
259
|
requirement: !ruby/object:Gem::Requirement
|
|
246
260
|
requirements:
|
|
247
261
|
- - "~>"
|
|
248
262
|
- !ruby/object:Gem::Version
|
|
249
|
-
version:
|
|
263
|
+
version: 0.9.27
|
|
250
264
|
type: :development
|
|
251
265
|
prerelease: false
|
|
252
266
|
version_requirements: !ruby/object:Gem::Requirement
|
|
253
267
|
requirements:
|
|
254
268
|
- - "~>"
|
|
255
269
|
- !ruby/object:Gem::Version
|
|
256
|
-
version:
|
|
270
|
+
version: 0.9.27
|
|
257
271
|
description: A gem providing MARC-related utility code and extensions to ruby-marc
|
|
258
272
|
for the UC Berkeley Library
|
|
259
273
|
email: dmoles@berkeley.edu
|
|
@@ -330,6 +344,7 @@ files:
|
|
|
330
344
|
- spec/data/record-187888.xml
|
|
331
345
|
- spec/marc_extensions/data_field_spec.rb
|
|
332
346
|
- spec/marc_extensions/record_spec.rb
|
|
347
|
+
- spec/marc_extensions/xml_reader_spec.rb
|
|
333
348
|
- spec/spec_helper.rb
|
|
334
349
|
homepage: https://github.com/BerkeleyLibrary/marc
|
|
335
350
|
licenses:
|
|
@@ -350,7 +365,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
350
365
|
- !ruby/object:Gem::Version
|
|
351
366
|
version: '0'
|
|
352
367
|
requirements: []
|
|
353
|
-
rubygems_version: 3.1.
|
|
368
|
+
rubygems_version: 3.1.6
|
|
354
369
|
signing_key:
|
|
355
370
|
specification_version: 4
|
|
356
371
|
summary: MARC utilities for the UC Berkeley Library
|
|
@@ -365,4 +380,5 @@ test_files:
|
|
|
365
380
|
- spec/data/record-187888.xml
|
|
366
381
|
- spec/marc_extensions/data_field_spec.rb
|
|
367
382
|
- spec/marc_extensions/record_spec.rb
|
|
383
|
+
- spec/marc_extensions/xml_reader_spec.rb
|
|
368
384
|
- spec/spec_helper.rb
|