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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/inspectionProfiles/Project_Default.xml +3 -0
  3. data/.idea/marc.iml +56 -54
  4. data/.ruby-version +1 -1
  5. data/.yardopts +6 -1
  6. data/CHANGES.md +18 -0
  7. data/LICENSE.md +1 -1
  8. data/berkeley_library-marc.gemspec +2 -1
  9. data/lib/berkeley_library/marc/field_info/var_fields/ind_def.rb +4 -0
  10. data/lib/berkeley_library/marc/field_info/var_fields/ind_val_def.rb +2 -0
  11. data/lib/berkeley_library/marc/field_info/var_fields/instrument_or_voices_code.rb +2 -0
  12. data/lib/berkeley_library/marc/field_info/var_fields/section.rb +12 -0
  13. data/lib/berkeley_library/marc/field_info/var_fields/subfield_def.rb +12 -1
  14. data/lib/berkeley_library/marc/field_info/var_fields/subfield_val.rb +2 -0
  15. data/lib/berkeley_library/marc/field_info/var_fields/var_field_def.rb +3 -0
  16. data/lib/berkeley_library/marc/field_info/var_fields/var_field_list.rb +11 -0
  17. data/lib/berkeley_library/marc/field_info/var_fields/var_field_parser.rb +20 -0
  18. data/lib/berkeley_library/marc/field_info/var_fields/var_field_transform.rb +19 -0
  19. data/lib/berkeley_library/marc/field_info/var_fields.rb +8 -0
  20. data/lib/berkeley_library/marc/field_info.rb +8 -0
  21. data/lib/berkeley_library/marc/module_info.rb +20 -1
  22. data/lib/berkeley_library/marc.rb +5 -0
  23. data/lib/marc_extensions/data_field.rb +16 -3
  24. data/lib/marc_extensions/field_map.rb +19 -14
  25. data/lib/marc_extensions/record.rb +15 -5
  26. data/lib/marc_extensions/subfield.rb +10 -2
  27. data/lib/marc_extensions/xml_reader.rb +62 -2
  28. data/lib/marc_extensions.rb +3 -0
  29. data/spec/data/record-187888.xml +0 -1
  30. data/spec/marc_extensions/record_spec.rb +33 -37
  31. data/spec/marc_extensions/xml_reader_spec.rb +47 -0
  32. data/spec/spec_helper.rb +0 -4
  33. metadata +22 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c479c395bc201b47ebfc171b3ee402e5962a4111f618ee26473aeb6d689011d5
4
- data.tar.gz: 3197dc1cfbc96c65a31f6528351ce1b39dbea33e8142245e7527c55342c98f26
3
+ metadata.gz: 25ed54f0bd91408a2bc16d7d51525e4bfe7086bf9b3a507b2e40a846432fff32
4
+ data.tar.gz: 135562e29c813d72f4830bfd8413a79c6480c2f7c5c396621a14ccdc22732432
5
5
  SHA512:
6
- metadata.gz: c6e8adff15efbc36fea120f03481c59cc451831c40447a06c0451733d6660fb0fb2766ca0955a7214b0b941f861421f7d1ccfbacc41d37b6f8a012b67bddea1d
7
- data.tar.gz: 62cb9959145a7b8a490b2cc7fe88657e6ca26233dc9dde6a7f8b9ec146fb5303bb17bdabcc8c96da97ac408aa3d795c46aa9954fd49d757acf049bd7c5829897
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.4" jdkType="RUBY_SDK" />
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="addressable (v2.8.0, RVM: ruby-2.7.4) [gem]" level="application" />
16
- <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, RVM: ruby-2.7.4) [gem]" level="application" />
17
- <orderEntry type="library" scope="PROVIDED" name="builder (v3.2.4, RVM: ruby-2.7.4) [gem]" level="application" />
18
- <orderEntry type="library" scope="PROVIDED" name="bundle-audit (v0.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
19
- <orderEntry type="library" scope="PROVIDED" name="bundler (v2.2.14, RVM: ruby-2.7.4) [gem]" level="application" />
20
- <orderEntry type="library" scope="PROVIDED" name="bundler-audit (v0.9.0.1, RVM: ruby-2.7.4) [gem]" level="application" />
21
- <orderEntry type="library" scope="PROVIDED" name="ci_reporter (v2.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
22
- <orderEntry type="library" scope="PROVIDED" name="ci_reporter_rspec (v1.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
23
- <orderEntry type="library" scope="PROVIDED" name="colorize (v0.8.1, RVM: ruby-2.7.4) [gem]" level="application" />
24
- <orderEntry type="library" scope="PROVIDED" name="crack (v0.4.5, RVM: ruby-2.7.4) [gem]" level="application" />
25
- <orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.4.4, RVM: ruby-2.7.4) [gem]" level="application" />
26
- <orderEntry type="library" scope="PROVIDED" name="docile (v1.4.0, RVM: ruby-2.7.4) [gem]" level="application" />
27
- <orderEntry type="library" scope="PROVIDED" name="dotenv (v2.7.6, RVM: ruby-2.7.4) [gem]" level="application" />
28
- <orderEntry type="library" scope="PROVIDED" name="ffi (v1.15.4, RVM: ruby-2.7.4) [gem]" level="application" />
29
- <orderEntry type="library" scope="PROVIDED" name="hashdiff (v1.0.1, RVM: ruby-2.7.4) [gem]" level="application" />
30
- <orderEntry type="library" scope="PROVIDED" name="listen (v3.1.5, RVM: ruby-2.7.4) [gem]" level="application" />
31
- <orderEntry type="library" scope="PROVIDED" name="marc (v1.1.1, RVM: ruby-2.7.4) [gem]" level="application" />
32
- <orderEntry type="library" scope="PROVIDED" name="parallel (v1.21.0, RVM: ruby-2.7.4) [gem]" level="application" />
33
- <orderEntry type="library" scope="PROVIDED" name="parser (v3.0.2.0, RVM: ruby-2.7.4) [gem]" level="application" />
34
- <orderEntry type="library" scope="PROVIDED" name="parslet (v2.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
35
- <orderEntry type="library" scope="PROVIDED" name="public_suffix (v4.0.6, RVM: ruby-2.7.4) [gem]" level="application" />
36
- <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
37
- <orderEntry type="library" scope="PROVIDED" name="rake (v13.0.6, RVM: ruby-2.7.4) [gem]" level="application" />
38
- <orderEntry type="library" scope="PROVIDED" name="rb-fsevent (v0.11.0, RVM: ruby-2.7.4) [gem]" level="application" />
39
- <orderEntry type="library" scope="PROVIDED" name="rb-inotify (v0.10.1, RVM: ruby-2.7.4) [gem]" level="application" />
40
- <orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.1.1, RVM: ruby-2.7.4) [gem]" level="application" />
41
- <orderEntry type="library" scope="PROVIDED" name="rexml (v3.2.5, RVM: ruby-2.7.4) [gem]" level="application" />
42
- <orderEntry type="library" scope="PROVIDED" name="rspec (v3.10.0, RVM: ruby-2.7.4) [gem]" level="application" />
43
- <orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.10.1, RVM: ruby-2.7.4) [gem]" level="application" />
44
- <orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.10.1, RVM: ruby-2.7.4) [gem]" level="application" />
45
- <orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.10.2, RVM: ruby-2.7.4) [gem]" level="application" />
46
- <orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.10.2, RVM: ruby-2.7.4) [gem]" level="application" />
47
- <orderEntry type="library" scope="PROVIDED" name="rubocop (v1.11.0, RVM: ruby-2.7.4) [gem]" level="application" />
48
- <orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.11.0, RVM: ruby-2.7.4) [gem]" level="application" />
49
- <orderEntry type="library" scope="PROVIDED" name="rubocop-rake (v0.6.0, RVM: ruby-2.7.4) [gem]" level="application" />
50
- <orderEntry type="library" scope="PROVIDED" name="rubocop-rspec (v2.4.0, RVM: ruby-2.7.4) [gem]" level="application" />
51
- <orderEntry type="library" scope="PROVIDED" name="ruby-marc-spec (v0.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
52
- <orderEntry type="library" scope="PROVIDED" name="ruby-prof (v0.17.0, RVM: ruby-2.7.4) [gem]" level="application" />
53
- <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.11.0, RVM: ruby-2.7.4) [gem]" level="application" />
54
- <orderEntry type="library" scope="PROVIDED" name="ruby_dep (v1.5.0, RVM: ruby-2.7.4) [gem]" level="application" />
55
- <orderEntry type="library" scope="PROVIDED" name="scrub_rb (v1.0.1, RVM: ruby-2.7.4) [gem]" level="application" />
56
- <orderEntry type="library" scope="PROVIDED" name="simplecov (v0.21.2, RVM: ruby-2.7.4) [gem]" level="application" />
57
- <orderEntry type="library" scope="PROVIDED" name="simplecov-html (v0.12.3, RVM: ruby-2.7.4) [gem]" level="application" />
58
- <orderEntry type="library" scope="PROVIDED" name="simplecov-rcov (v0.2.3, RVM: ruby-2.7.4) [gem]" level="application" />
59
- <orderEntry type="library" scope="PROVIDED" name="simplecov_json_formatter (v0.1.3, RVM: ruby-2.7.4) [gem]" level="application" />
60
- <orderEntry type="library" scope="PROVIDED" name="thor (v1.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
61
- <orderEntry type="library" scope="PROVIDED" name="typesafe_enum (v0.3.0, RVM: ruby-2.7.4) [gem]" level="application" />
62
- <orderEntry type="library" scope="PROVIDED" name="unf (v0.1.4, RVM: ruby-2.7.4) [gem]" level="application" />
63
- <orderEntry type="library" scope="PROVIDED" name="unf_ext (v0.0.8, RVM: ruby-2.7.4) [gem]" level="application" />
64
- <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v2.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
65
- <orderEntry type="library" scope="PROVIDED" name="webmock (v3.14.0, RVM: ruby-2.7.4) [gem]" level="application" />
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.0.gem" fullCommand="gem" id="gem" />
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
@@ -1 +1,6 @@
1
- --no-private --protected lib/**/*.rb -m markdown
1
+ --no-private
2
+ --protected
3
+ -m markdown
4
+ -o ./artifacts/doc
5
+ --exclude lib/berkeley_library/marc/field_info/var_fields/data
6
+ lib/**/*.rb
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 © 2021 The Regents of the University of California
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 'webmock', '~> 3.12'
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
- # TODO: destructure range codes in some useful way (e.g. 886a-z, 0-9)
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
- VERSION = '0.2.1'.freeze
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
@@ -1,3 +1,8 @@
1
1
  require 'marc_extensions'
2
2
 
3
+ module BerkeleyLibrary
4
+ # Umbrella module for UC Berkeley Library MARC code.
5
+ module Marc; end
6
+ end
7
+
3
8
  Dir.glob(File.expand_path('marc/*.rb', __dir__)).sort.each(&method(:require))
@@ -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
- subfields.all?(&:frozen?)
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
- self
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).map { |i| self[i] }.each(&block)
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
- return all_indices unless tags
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
- # Freezes the leader and fields.
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
- self
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
- # TODO: use info from parsed documentation? or move to TIND-specific extension
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
- self
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
- def read(file, freeze: false)
7
- new(file, freeze: freeze)
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
@@ -1 +1,4 @@
1
+ # Extensions to [ruby-marc](https://rubydoc.info/gems/marc/)
2
+ module MARCExtensions; end
3
+
1
4
  Dir.glob(File.expand_path('marc_extensions/*.rb', __dir__)).sort.each(&method(:require))
@@ -1,4 +1,3 @@
1
-
2
1
  <?xml version="1.0" encoding="UTF-8"?>
3
2
  <collection xmlns="http://www.loc.gov/MARC21/slim">
4
3
  <record>
@@ -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
- expect(marc_record.each_data_field.to_a).to eq(marc_record.data_fields)
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.2.1
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: 2021-10-16 00:00:00.000000000 Z
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: webmock
258
+ name: yard
245
259
  requirement: !ruby/object:Gem::Requirement
246
260
  requirements:
247
261
  - - "~>"
248
262
  - !ruby/object:Gem::Version
249
- version: '3.12'
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: '3.12'
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.4
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