ruby-marc-spec 0.1.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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +18 -0
  3. data/.gitignore +388 -0
  4. data/.gitmodules +3 -0
  5. data/.idea/codeStyles/codeStyleConfig.xml +5 -0
  6. data/.idea/go.imports.xml +6 -0
  7. data/.idea/inspectionProfiles/Project_Default.xml +23 -0
  8. data/.idea/marc_spec.iml +102 -0
  9. data/.idea/misc.xml +6 -0
  10. data/.idea/modules.xml +8 -0
  11. data/.idea/templateLanguages.xml +6 -0
  12. data/.idea/vcs.xml +7 -0
  13. data/.rubocop.yml +269 -0
  14. data/.ruby-version +1 -0
  15. data/.simplecov +8 -0
  16. data/CHANGES.md +3 -0
  17. data/Gemfile +6 -0
  18. data/LICENSE.md +21 -0
  19. data/README.md +172 -0
  20. data/Rakefile +20 -0
  21. data/lib/.rubocop.yml +5 -0
  22. data/lib/marc/spec/module_info.rb +14 -0
  23. data/lib/marc/spec/parsing/closed_int_range.rb +28 -0
  24. data/lib/marc/spec/parsing/closed_lc_alpha_range.rb +28 -0
  25. data/lib/marc/spec/parsing/parser.rb +213 -0
  26. data/lib/marc/spec/parsing.rb +1 -0
  27. data/lib/marc/spec/queries/al_num_range.rb +105 -0
  28. data/lib/marc/spec/queries/applicable.rb +18 -0
  29. data/lib/marc/spec/queries/character_spec.rb +81 -0
  30. data/lib/marc/spec/queries/comparison_string.rb +45 -0
  31. data/lib/marc/spec/queries/condition.rb +133 -0
  32. data/lib/marc/spec/queries/condition_context.rb +49 -0
  33. data/lib/marc/spec/queries/dsl.rb +80 -0
  34. data/lib/marc/spec/queries/indicator_value.rb +77 -0
  35. data/lib/marc/spec/queries/operator.rb +129 -0
  36. data/lib/marc/spec/queries/part.rb +63 -0
  37. data/lib/marc/spec/queries/position.rb +59 -0
  38. data/lib/marc/spec/queries/position_or_range.rb +27 -0
  39. data/lib/marc/spec/queries/query.rb +94 -0
  40. data/lib/marc/spec/queries/query_executor.rb +52 -0
  41. data/lib/marc/spec/queries/selector.rb +12 -0
  42. data/lib/marc/spec/queries/subfield.rb +88 -0
  43. data/lib/marc/spec/queries/subfield_value.rb +63 -0
  44. data/lib/marc/spec/queries/tag.rb +107 -0
  45. data/lib/marc/spec/queries/transform.rb +154 -0
  46. data/lib/marc/spec/queries.rb +1 -0
  47. data/lib/marc/spec.rb +32 -0
  48. data/rakelib/.rubocop.yml +19 -0
  49. data/rakelib/bundle.rake +8 -0
  50. data/rakelib/coverage.rake +11 -0
  51. data/rakelib/gem.rake +54 -0
  52. data/rakelib/parser_specs/formatter.rb +31 -0
  53. data/rakelib/parser_specs/parser_specs.rb.txt.erb +35 -0
  54. data/rakelib/parser_specs/rule.rb +95 -0
  55. data/rakelib/parser_specs/suite.rb +91 -0
  56. data/rakelib/parser_specs/test.rb +97 -0
  57. data/rakelib/parser_specs.rb +1 -0
  58. data/rakelib/rubocop.rake +18 -0
  59. data/rakelib/spec.rake +27 -0
  60. data/ruby-marc-spec.gemspec +42 -0
  61. data/spec/.rubocop.yml +46 -0
  62. data/spec/README.md +16 -0
  63. data/spec/data/b23161018-sru.xml +182 -0
  64. data/spec/data/sandburg.xml +82 -0
  65. data/spec/generated/char_indicator_spec.rb +174 -0
  66. data/spec/generated/char_spec.rb +113 -0
  67. data/spec/generated/comparison_string_spec.rb +74 -0
  68. data/spec/generated/field_tag_spec.rb +156 -0
  69. data/spec/generated/index_char_spec.rb +669 -0
  70. data/spec/generated/index_indicator_spec.rb +174 -0
  71. data/spec/generated/index_spec.rb +113 -0
  72. data/spec/generated/index_sub_spec_spec.rb +1087 -0
  73. data/spec/generated/indicators_spec.rb +75 -0
  74. data/spec/generated/position_or_range_spec.rb +110 -0
  75. data/spec/generated/sub_spec_spec.rb +208 -0
  76. data/spec/generated/sub_spec_sub_spec_spec.rb +1829 -0
  77. data/spec/generated/subfield_char_spec.rb +405 -0
  78. data/spec/generated/subfield_range_range_spec.rb +48 -0
  79. data/spec/generated/subfield_range_spec.rb +87 -0
  80. data/spec/generated/subfield_range_sub_spec_spec.rb +214 -0
  81. data/spec/generated/subfield_tag_range_spec.rb +477 -0
  82. data/spec/generated/subfield_tag_sub_spec_spec.rb +3216 -0
  83. data/spec/generated/subfield_tag_tag_spec.rb +5592 -0
  84. data/spec/marc/spec/parsing/closed_int_range_spec.rb +49 -0
  85. data/spec/marc/spec/parsing/closed_lc_alpha_range_spec.rb +49 -0
  86. data/spec/marc/spec/parsing/parser_spec.rb +545 -0
  87. data/spec/marc/spec/queries/al_num_range_spec.rb +114 -0
  88. data/spec/marc/spec/queries/character_spec_spec.rb +28 -0
  89. data/spec/marc/spec/queries/comparison_string_spec.rb +28 -0
  90. data/spec/marc/spec/queries/indicator_value_spec.rb +28 -0
  91. data/spec/marc/spec/queries/query_spec.rb +200 -0
  92. data/spec/marc/spec/queries/subfield_spec.rb +92 -0
  93. data/spec/marc/spec/queries/subfield_value_spec.rb +31 -0
  94. data/spec/marc/spec/queries/tag_spec.rb +144 -0
  95. data/spec/marc/spec/queries/transform_spec.rb +459 -0
  96. data/spec/marc_spec_spec.rb +247 -0
  97. data/spec/scratch_spec.rb +112 -0
  98. data/spec/spec_helper.rb +23 -0
  99. metadata +341 -0
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe AlNumRange do
6
+ describe 'closed, alphabetical' do
7
+ it 'handles string arguments' do
8
+ r = AlNumRange.new('j', 'q')
9
+ expect(r.from).to eq('j')
10
+ expect(r.to).to eq('q')
11
+ expect(r.to_s).to eq('j-q')
12
+
13
+ %w[j m q].each { |i| expect(r).to include(i) }
14
+ %w[i r].each { |i| expect(r).not_to include(i) }
15
+
16
+ expect(r.select_from('nequaquam vacuum')).to eq('nqqmm')
17
+ end
18
+
19
+ it 'handles Parslet::Slice arguments' do
20
+ r = AlNumRange.new(
21
+ Parslet::Slice.new(1, 'j'),
22
+ Parslet::Slice.new(3, 'q')
23
+ )
24
+ expect(r.from).to eq('j')
25
+ expect(r.to).to eq('q')
26
+ expect(r.to_s).to eq('j-q')
27
+
28
+ %w[j m q].each { |i| expect(r).to include(i) }
29
+ %w[i r].each { |i| expect(r).not_to include(i) }
30
+
31
+ expect(r.select_from('nequaquam vacuum')).to eq('nqqmm')
32
+ end
33
+ end
34
+
35
+ describe 'closed, numeric' do
36
+ it 'handles int arguments' do
37
+ r = AlNumRange.new(3, 5)
38
+ expect(r.from).to eq(3)
39
+ expect(r.to).to eq(5)
40
+ expect(r.to_s).to eq('3-5')
41
+
42
+ [3, 4, 5].each { |i| expect(r).to include(i) }
43
+ [2, 6].each { |i| expect(r).not_to include(i) }
44
+
45
+ expect(r.select_from([3, 1, 4, 1, 5, 9, 2, 6, 5])).to eq([1, 5, 9])
46
+ end
47
+
48
+ it 'handles string arguments' do
49
+ r = AlNumRange.new('3', '5')
50
+ expect(r.from).to eq(3)
51
+ expect(r.to).to eq(5)
52
+ expect(r.to_s).to eq('3-5')
53
+
54
+ [3, 4, 5].each { |i| expect(r).to include(i) }
55
+ [2, 6].each { |i| expect(r).not_to include(i) }
56
+
57
+ expect(r.select_from([3, 1, 4, 1, 5, 9, 2, 6, 5])).to eq([1, 5, 9])
58
+ end
59
+ end
60
+
61
+ describe 'left open, numeric' do
62
+ it 'handles int arguments' do
63
+ r = AlNumRange.new(nil, 5)
64
+ expect(r.from).to be_nil
65
+ expect(r.to).to eq(5)
66
+ expect(r.to_s).to eq('#-5')
67
+
68
+ [-5, -4, -3].each { |i| expect(r).to include(i) }
69
+ [1, 2, -6, -7].each { |i| expect(r).not_to include(i) }
70
+
71
+ expect(r.select_from([3, 1, 4, 1, 5, 9, 2, 6, 5])).to eq([1, 5, 9, 2, 6, 5])
72
+ end
73
+
74
+ it 'handles string arguments' do
75
+ r = AlNumRange.new('#', '5')
76
+ expect(r.from).to be_nil
77
+ expect(r.to).to eq(5)
78
+ expect(r.to_s).to eq('#-5')
79
+
80
+ [-5, -4, -3].each { |i| expect(r).to include(i) }
81
+ [1, 2, -6, -7].each { |i| expect(r).not_to include(i) }
82
+
83
+ expect(r.select_from([3, 1, 4, 1, 5, 9, 2, 6, 5])).to eq([1, 5, 9, 2, 6, 5])
84
+ end
85
+ end
86
+
87
+ describe 'right open, numeric' do
88
+ it 'handles int arguments' do
89
+ r = AlNumRange.new(4, nil)
90
+ expect(r.from).to eq(4)
91
+ expect(r.to).to be_nil
92
+ expect(r.to_s).to eq('4-#')
93
+
94
+ [4, 5].each { |i| expect(r).to include(i) }
95
+ [1, 2].each { |i| expect(r).not_to include(i) }
96
+
97
+ expect(r.select_from([3, 1, 4, 1, 5, 9, 2, 6, 5])).to eq([5, 9, 2, 6, 5])
98
+ end
99
+
100
+ it 'handles string arguments' do
101
+ r = AlNumRange.new('4', '#')
102
+ expect(r.from).to eq(4)
103
+ expect(r.to).to be_nil
104
+ expect(r.to_s).to eq('4-#')
105
+
106
+ [4, 5].each { |i| expect(r).to include(i) }
107
+ [1, 2].each { |i| expect(r).not_to include(i) }
108
+
109
+ expect(r.select_from([3, 1, 4, 1, 5, 9, 2, 6, 5])).to eq([5, 9, 2, 6, 5])
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe CharacterSpec do
6
+ it 'accepts a position' do
7
+ pos = Position.new(3)
8
+ # noinspection RubyArgCount
9
+ v = CharacterSpec.new(pos)
10
+ expect(v.character_spec).to eq(pos)
11
+ expect(v.to_s).to eq('/3')
12
+ end
13
+
14
+ it 'accepts a range' do
15
+ range = AlNumRange.new(3, 5)
16
+ # noinspection RubyArgCount
17
+ v = CharacterSpec.new(range)
18
+ expect(v.character_spec).to eq(range)
19
+ expect(v.to_s).to eq('/3-5')
20
+ end
21
+
22
+ it 'rejects an invalid characterspec' do
23
+ # noinspection RubyArgCount
24
+ expect { CharacterSpec.new(/([a-z]+)/) }.to raise_error(ArgumentError)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe ComparisonString do
6
+ describe :str_exact do
7
+ it 'decodes escapes' do
8
+ expecteds = {
9
+ 'value' => 'value',
10
+ '!value' => '!value',
11
+ '\\!value' => '!value',
12
+ '\\svalue' => ' value',
13
+ 'value\\!' => 'value!',
14
+ 'a\\{b\\}\\$1\\\\23\\=\\~\\|\\?' => 'a{b}$1\\\\23=~|?',
15
+ 'help\\sI\\sam\\strapped\\sin\\sa\\sunit\\stest\\!\\sso\\sam\\sI' =>
16
+ 'help I am trapped in a unit test! so am I'
17
+ }
18
+ aggregate_failures do
19
+ expecteds.each do |str_raw, expected|
20
+ cstr = ComparisonString.new(str_raw)
21
+ expect(cstr.str_exact).to eq(expected)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe IndicatorValue do
6
+ it 'accepts an int indicator' do
7
+ v = IndicatorValue.new(1)
8
+ expect(v.ind).to eq(1)
9
+ expect(v.to_s).to eq('^1')
10
+ end
11
+
12
+ it 'accepts a string indicator' do
13
+ v = IndicatorValue.new('1')
14
+ expect(v.ind).to eq(1)
15
+ expect(v.to_s).to eq('^1')
16
+ end
17
+
18
+ it 'rejects a nil indicator' do
19
+ expect { IndicatorValue.new(nil) }.to raise_error(ArgumentError)
20
+ end
21
+
22
+ it 'rejects an invalid indicator' do
23
+ expect { IndicatorValue.new(3) }.to raise_error(ArgumentError)
24
+ expect { IndicatorValue.new('3') }.to raise_error(ArgumentError)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,200 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe Query do
6
+ attr_reader :parser
7
+ attr_reader :xform
8
+ attr_reader :marc_record
9
+
10
+ before(:each) do
11
+ @parser = Parsing::Parser.new
12
+ @xform = Transform.new
13
+ end
14
+
15
+ def subfield_codes(df)
16
+ df.subfields.map(&:code)
17
+ end
18
+
19
+ def subfields(df, code)
20
+ codes = Array(code)
21
+ df.subfields.select { |sf| codes.include?(sf.code) }
22
+ end
23
+
24
+ def verify_all(examples)
25
+ aggregate_failures { examples.each { |query_str, expected| verify_result(query_str, expected) } }
26
+ end
27
+
28
+ def query_from(query_str)
29
+ parse_tree = parser.parse(query_str)
30
+ xform.apply(parse_tree)
31
+ end
32
+
33
+ def verify_result(query_str, expected)
34
+ query = query_from(query_str)
35
+ executor = QueryExecutor.new(marc_record, query)
36
+ actual = executor.execute
37
+
38
+ expect(actual).to eq(expected), -> { failure_msg_for(query_str, query, actual, expected) }
39
+ end
40
+
41
+ def failure_msg_for(input_str, query, actual, expected)
42
+ expected_str = expected.respond_to?(:map) ? expected.map(&:to_s) : expected.to_s
43
+ actual_str = actual.respond_to?(:map) ? actual.map(&:to_s) : actual.to_s
44
+ [
45
+ input_str.inspect,
46
+ "query: \t#{query.inspect}",
47
+ "expected: \t#{expected_str}",
48
+ " \t#{expected.inspect}",
49
+ "actual: \t#{actual_str}",
50
+ " \t#{actual.inspect}"
51
+ ].join("\n\t")
52
+ end
53
+
54
+ describe :to_s do
55
+ it 'includes all elements' do
56
+ # noinspection RubyLiteralArrayInspection
57
+ [
58
+ '245$a',
59
+ '245$a/1-5',
60
+ '245^1',
61
+ '245$a$b',
62
+ '245^1{=\\0}',
63
+ '245$a{$b=\\t}$c$d'
64
+ ].each do |query_str|
65
+ query = query_from(query_str)
66
+ str = query.to_s
67
+ expect(str).not_to include('nil')
68
+ all_elements = ([query.tag, query.selector] + query.subqueries).compact
69
+ all_elements.each do |elem|
70
+ expect(str).to include(elem.to_s)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ describe :to_s_inspect do
77
+ it 'includes all elements' do
78
+ # noinspection RubyLiteralArrayInspection
79
+ [
80
+ '245$a',
81
+ '245$a/1-5',
82
+ '245^1',
83
+ '245$a$b',
84
+ '245^1{=\\0}',
85
+ '245$a{$b=\\t}$c$d'
86
+ ].each do |query_str|
87
+ query = query_from(query_str)
88
+ inspect_str = query.inspect
89
+ expect(inspect_str).not_to include('nil')
90
+ all_elements = ([query.tag, query.selector] + query.subqueries).compact
91
+ all_elements.each do |elem|
92
+ expect(inspect_str).to include(elem.inspect)
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ describe 'non-repeated subfields' do
99
+ before(:each) do
100
+ @marc_record = MARC::XMLReader.new('spec/data/sandburg.xml').first
101
+ end
102
+
103
+ context 'leader' do
104
+ it 'finds the leader' do
105
+ leader = marc_record.leader
106
+ examples = {
107
+ 'LDR' => [leader],
108
+ 'LDR/11' => [leader[11]],
109
+ 'LDR/3-12' => [leader[3..12]]
110
+ }
111
+
112
+ verify_all(examples)
113
+ end
114
+ end
115
+
116
+ context 'fields' do
117
+ it 'finds fields' do
118
+ examples = {
119
+ '035' => marc_record.fields('035'),
120
+ '040' => [marc_record['040']],
121
+ '0..' => marc_record.fields.select { |f| f.tag =~ /^0..$/ }
122
+ }
123
+ verify_all(examples)
124
+ end
125
+ end
126
+
127
+ context 'controlfield data' do
128
+ it 'extracts controlfield data' do
129
+ cf005 = marc_record['005']
130
+ cf005_value = cf005.value
131
+ examples = {
132
+ '005/#' => [cf005_value[-1]],
133
+ '005/1-#' => [cf005_value[1..]]
134
+ }
135
+ verify_all(examples)
136
+ end
137
+ end
138
+
139
+ context 'subfields' do
140
+ it 'finds subfields' do
141
+ df245 = marc_record['245']
142
+ df245a = subfields(df245, 'a').first
143
+ df245c = subfields(df245, 'c').first
144
+ df245ac = subfields(df245, %w[a c])
145
+
146
+ all_sf_a_or_c = marc_record.fields.each_with_object([]) do |df, sff|
147
+ next unless df.respond_to?(:subfields)
148
+
149
+ sff.concat(subfields(df, %w[a c]))
150
+ end
151
+
152
+ examples = {
153
+ '245$a' => [df245a],
154
+ '245$a$c' => df245ac,
155
+ '245$a-c' => df245ac,
156
+ '...$a$c' => all_sf_a_or_c,
157
+ '245$a/#-6' => [df245a.value[-7..]],
158
+ '245$a$c/0-4' => [df245a, df245c.value[0..4]],
159
+ '245$a/0-4$c/0-4' => df245ac.map { |sf| sf.value[0..4] }
160
+ }
161
+
162
+ verify_all(examples)
163
+ end
164
+ end
165
+
166
+ context 'subspecs' do
167
+ it 'can check for the existence of subfields' do
168
+ df245 = marc_record['245']
169
+ df245a = df245.subfields.find { |sf| sf.code == 'a' }
170
+
171
+ _650s = marc_record.fields('650')
172
+ _650s_with_x = _650s.select { |df| subfield_codes(df).include?('x') }
173
+
174
+ examples = {
175
+ '245$a{?245$c}' => [df245a], # left subterm is implicit, and unused
176
+ '245$a{245$a?245$c}' => [df245a], # left subterm is explicit, but unused
177
+ '245$a{!245$c}' => [],
178
+ '245$a{245$a!245$c}' => [],
179
+ # 650 subfield a if that 650 also has a subfield x
180
+ '650$a{?$x}' => _650s_with_x.flat_map { |df| subfields(df, 'a') },
181
+ # all 650 subfields a if any 650 has a subfield x
182
+ '650$a{?650$x}' => _650s.flat_map { |df| subfields(df, 'a') }
183
+ }
184
+ verify_all(examples)
185
+ end
186
+
187
+ it 'can compare subfield values' do
188
+ df040 = marc_record['040']
189
+ examples = {
190
+ '040{$a=$c}' => [df040],
191
+ '040{040$a=040$c}' => [df040]
192
+ }
193
+ verify_all(examples)
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ end
200
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe Subfield do
6
+ describe :new do
7
+ it 'accepts a plain code' do
8
+ sf = Subfield.new('u')
9
+ expect(sf.code).to eq('u')
10
+ expect(sf.to_s).to eq('$u')
11
+ end
12
+
13
+ it 'accepts a numeric code range' do
14
+ code_range = AlNumRange.new(3, 5)
15
+ sf = Subfield.new(code_range)
16
+ expect(sf.code).to eq(code_range)
17
+ expect(sf.to_s).to eq('$3-5')
18
+ end
19
+
20
+ it 'accepts an alphabetic code range' do
21
+ code_range = AlNumRange.new('k', 'q')
22
+ sf = Subfield.new(code_range)
23
+ expect(sf.code).to eq(code_range)
24
+ expect(sf.to_s).to eq('$k-q')
25
+ end
26
+ end
27
+ end
28
+
29
+ describe :apply do
30
+ attr_reader :marc_record
31
+
32
+ describe 'non-repeated subfields' do
33
+ before(:each) do
34
+ @marc_record = MARC::XMLReader.new('spec/data/sandburg.xml').first
35
+ end
36
+
37
+ it 'finds a subfield' do
38
+ df245 = marc_record['245']
39
+ result = Subfield.new('a').apply(df245)
40
+ expect(result).to be_an(Array)
41
+ expect(result.size).to eq(1)
42
+
43
+ sf245a = result.first
44
+ expect(sf245a).to be_a(MARC::Subfield)
45
+
46
+ expected = df245.subfields.find { |sf| sf.code == 'a' }
47
+ expect(sf245a).to eq(expected)
48
+ end
49
+
50
+ it 'finds a range of subfields' do
51
+ df260 = marc_record['260']
52
+ range = AlNumRange.new('b', 'c')
53
+ result = Subfield.new(range).apply(df260)
54
+ expect(result).to be_an(Array)
55
+ expect(result.size).to eq(2)
56
+
57
+ expected = df260.subfields.select { |sf| %w[b c].include?(sf.code) }
58
+ expect(result).to eq(expected)
59
+ end
60
+
61
+ end
62
+
63
+ describe 'repeated subfields' do
64
+ attr_reader :df998
65
+
66
+ before(:each) do
67
+ @marc_record = MARC::XMLReader.new('spec/data/b23161018-sru.xml').first
68
+ @df998 = marc_record['998']
69
+ end
70
+
71
+ it 'finds repeated subfields' do
72
+ result = Subfield.new('g').apply(df998)
73
+ expect(result.size).to eq(20)
74
+
75
+ expected = df998.subfields.select { |sf| sf.code == 'g' }
76
+ expect(result).to eq(expected)
77
+ end
78
+
79
+ it 'finds repeated subfields by index' do
80
+ marc_record = MARC::XMLReader.new('spec/data/b23161018-sru.xml').first
81
+ df998 = marc_record['998']
82
+ result = Subfield.new('g', index: AlNumRange.new(3, 5)).apply(df998)
83
+ expect(result.size).to eq(3)
84
+
85
+ all_sf998g = df998.subfields.select { |sf| sf.code == 'g' }
86
+ expected = all_sf998g[3..5]
87
+ expect(result).to eq(expected)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe SubfieldValue do
6
+ describe :apply do
7
+ attr_reader :marc_record
8
+ attr_reader :df998
9
+
10
+ before(:each) do
11
+ @marc_record = MARC::XMLReader.new('spec/data/b23161018-sru.xml').first
12
+ @df998 = marc_record['998']
13
+ end
14
+
15
+ it 'extracts substrings from values' do
16
+ subfield = Subfield.new('g', index: AlNumRange.new(3, 5))
17
+ # noinspection RubyArgCount
18
+ subfield_value = SubfieldValue.new(subfield, CharacterSpec.new(AlNumRange.new(0, 9)))
19
+
20
+ result = subfield_value.apply(df998)
21
+ expect(result.size).to eq(3)
22
+
23
+ all_sf998g = df998.subfields.select { |sf| sf.code == 'g' }
24
+ selected = all_sf998g[3..5]
25
+ expected = selected.map { |sf| sf.value[0..9] }
26
+ expect(result).to eq(expected)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+
3
+ module MARC::Spec
4
+ module Queries
5
+ describe Tag do
6
+ describe :new do
7
+ it 'accepts a plain tag' do
8
+ tag = Tag.new('856')
9
+ expect(tag.tag_exact).to eq('856')
10
+ expect(tag.tag_re).to be_nil
11
+ expect(tag.to_s).to eq('856')
12
+ expect(tag.inspect).to eq('Tag<856>')
13
+ end
14
+
15
+ it 'accepts a wildcard' do
16
+ tag = Tag.new('.56')
17
+ expect(tag.tag_exact).to be_nil
18
+ expect(tag.tag_re).to eq(/^.56$/)
19
+ expect(tag.to_s).to eq('.56')
20
+ expect(tag.inspect).to eq 'Tag</^.56$/>'
21
+ end
22
+
23
+ it 'accepts a regexp' do
24
+ tag = Tag.new(/.56/)
25
+ expect(tag.tag_exact).to be_nil
26
+ expect(tag.tag_re).to eq(/.56/)
27
+ expect(tag.to_s).to eq('.56')
28
+ expect(tag.inspect).to eq 'Tag</.56/>'
29
+ end
30
+
31
+ it 'accepts a position index' do
32
+ index = Position.new(2)
33
+ tag = Tag.new('650', index)
34
+ expect(tag.index).to eq(index)
35
+ end
36
+
37
+ it 'accepts a range index' do
38
+ index = AlNumRange.new(3, nil)
39
+ tag = Tag.new('650', index)
40
+ expect(tag.index).to eq(index)
41
+ end
42
+ end
43
+
44
+ describe :apply do
45
+ attr_reader :marc_record
46
+
47
+ before(:each) do
48
+ @marc_record = MARC::XMLReader.new('spec/data/sandburg.xml').first
49
+ end
50
+
51
+ it 'finds the leader' do
52
+ result = Tag.new('LDR').apply(marc_record)
53
+ expect(result).to be_an(Array)
54
+ expect(result.size).to eq(1)
55
+
56
+ leader = result.first
57
+ expect(leader).to eq(marc_record.leader)
58
+ end
59
+
60
+ it 'finds a control field' do
61
+ result = Tag.new('003').apply(marc_record)
62
+ expect(result).to be_an(Array)
63
+ expect(result.size).to eq(1)
64
+
65
+ cf003 = result.first
66
+ expect(cf003).to be_a(MARC::ControlField)
67
+ expect(cf003.tag).to eq('003')
68
+ end
69
+
70
+ it 'finds a data field' do
71
+ result = Tag.new('245').apply(marc_record)
72
+ expect(result).to be_an(Array)
73
+ expect(result.size).to eq(1)
74
+
75
+ df245 = result.first
76
+ expect(df245).to eq(marc_record['245'])
77
+ end
78
+
79
+ it 'finds a repeated data field' do
80
+ result = Tag.new('650').apply(marc_record)
81
+ expect(result).to be_an(Array)
82
+ expect(result.size).to eq(5)
83
+
84
+ expected = marc_record.fields('650')
85
+ expect(result).to eq(expected)
86
+ end
87
+
88
+ it 'finds some repeated data fields by position index' do
89
+ result = Tag.new('650', Position.new(2)).apply(marc_record)
90
+ expect(result).to be_an(Array)
91
+ expect(result.size).to eq(1)
92
+
93
+ df650s = marc_record.fields('650')
94
+ expect(result.first).to eq(df650s[2])
95
+ end
96
+
97
+ it 'finds some repeated data fields by range index' do
98
+ result = Tag.new('650', AlNumRange.new(1, 3)).apply(marc_record)
99
+ expect(result).to be_an(Array)
100
+ expect(result.size).to eq(3)
101
+
102
+ df650s = marc_record.fields('650')
103
+ expected = [1, 2, 3].map { |i| df650s[i] }
104
+ expect(result).to eq(expected)
105
+ end
106
+
107
+ describe 'wildcards' do
108
+ it 'finds a control field' do
109
+ result = Tag.new('0.3').apply(marc_record)
110
+ expect(result).to be_an(Array)
111
+ expect(result.size).to eq(1)
112
+
113
+ cf003 = result.first
114
+ expect(cf003).to be_a(MARC::ControlField)
115
+ expect(cf003.tag).to eq('003')
116
+ end
117
+
118
+ it 'finds a mix of control and data fields' do
119
+ result = Tag.new('..5').apply(marc_record)
120
+ expect(result).to be_an(Array)
121
+ expect(result.size).to eq(2)
122
+
123
+ cf005 = result.first
124
+ expect(cf005).to be_a(MARC::ControlField)
125
+ expect(cf005.tag).to eq('005')
126
+
127
+ df245 = result.last
128
+ expect(df245).to be_a(MARC::DataField)
129
+ expect(df245.tag).to eq('245')
130
+ end
131
+
132
+ it 'finds fields by index' do
133
+ result = Tag.new('2..', Position.new(1)).apply(marc_record)
134
+ expect(result).to be_an(Array)
135
+ expect(result.size).to eq(1)
136
+
137
+ df250 = result.first
138
+ expect(df250).to eq(marc_record['250'])
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end