ruby-marc-spec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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