marcspec 1.5.0 → 1.6.1
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.
- data/CHANGES +32 -0
- data/Rakefile +21 -11
- data/VERSION +1 -1
- data/lib/marcspec.rb +9 -7
- data/lib/marcspec/constantspec.rb +16 -1
- data/lib/marcspec/controlfieldspec.rb +22 -1
- data/lib/marcspec/customspec.rb +37 -1
- data/lib/marcspec/dsl.rb +20 -5
- data/lib/marcspec/map.rb +8 -7
- data/lib/marcspec/multivaluemap.rb +1 -1
- data/lib/marcspec/solrfieldspec.rb +66 -2
- data/lib/marcspec/specset.rb +79 -11
- data/lib/marcspec/variablefieldspec.rb +52 -4
- data/spec/cachespot_spec.rb +1 -1
- data/spec/controlfieldspec_spec.rb +4 -4
- data/spec/dsl_spec.rb +52 -30
- data/spec/leaderspec_spec.rb +2 -2
- data/spec/maps_spec.rb +42 -42
- data/spec/marcfieldspecs_spec.rb +22 -22
- data/spec/solrfieldspec_spec.rb +24 -24
- data/spec/spec.opts +7 -0
- data/spec/spec_helper.rb +3 -6
- data/spec/specset_spec.rb +20 -19
- data/spec/variablefieldspec_spec.rb +9 -9
- metadata +156 -144
data/CHANGES
CHANGED
@@ -1,45 +1,77 @@
|
|
1
|
+
1.6.1
|
2
|
+
* Change VariableField#asDSLString to reflect compact declaration of spec with subs
|
3
|
+
|
4
|
+
1.6.0
|
5
|
+
* Allow specs like spec('245ac'), with or without a block as well.
|
6
|
+
|
7
|
+
1.5.3
|
8
|
+
* Changed to use Logback::Simple
|
9
|
+
|
10
|
+
1.5.2
|
11
|
+
* Added more docs
|
12
|
+
* Put in actual @deprecated strings in YARD docs
|
13
|
+
|
14
|
+
1.5.1
|
15
|
+
* Fixed lots of DSL bugs
|
16
|
+
* Moved testing to RSpec in anticipation of using Hudson
|
17
|
+
|
1
18
|
1.5.0
|
2
19
|
* Added DSL; making it the preferred way to operate. Totally deprecating the aray-of-hashes stuff.
|
20
|
+
|
3
21
|
1.1.1
|
4
22
|
* Fixed bug with :noMapKeyDefault => :passthrough for MVMap
|
23
|
+
|
5
24
|
1.1.0
|
6
25
|
* Added support for Proc objects as the value in a MVMap
|
26
|
+
|
7
27
|
1.0.0
|
8
28
|
* Added constant specs (:constantValue=>'val' or :constantValue=>['array', 'of', 'values'])
|
9
29
|
* Arbitrarily decided this is version 1.0
|
30
|
+
|
10
31
|
0.9.0
|
11
32
|
* Added ability to benchmark by calling ss.doc_from_marc(r, true) instead of just ss.doc_from_marc(r)
|
33
|
+
|
12
34
|
0.8.1
|
13
35
|
* Added some specs, squashed some bugs. In particular, make sure the Range passed to a ControlField
|
14
36
|
makes sense (x..y, where x<=y and x > 0)
|
37
|
+
|
15
38
|
0.8.0
|
16
39
|
* Changed the syntax for a variable field from ['245', '*', '*', 'ab'] to just ['245', 'ab']. We'll worry
|
17
40
|
about indicators when that bridge gets crossed.
|
41
|
+
|
18
42
|
0.7.3
|
19
43
|
* Squashed a bug where I forgot to deal with escaping in java .properties files. Now I'm just using
|
20
44
|
a real Java Properties object so I don't have to worry about it.
|
45
|
+
|
21
46
|
0.7.2
|
22
47
|
* Also change methodArgs to functionArgs
|
48
|
+
|
23
49
|
0.7.1
|
24
50
|
* Forgot to update this CHANGES file.
|
51
|
+
|
25
52
|
0.7.0
|
26
53
|
* Change configuration for custom functions to use :functionSymbol instead of :methodSymbol. Because, you know, they're
|
27
54
|
module functions, not class methods.
|
28
55
|
* Split out marcspec stuff into multiple files (leader/control/variable fields).
|
56
|
+
|
29
57
|
0.6.0
|
30
58
|
* Allow custom functions to return values for multiple solr fields at once; should help avoid duplication of work.
|
59
|
+
|
31
60
|
0.5.0
|
32
61
|
* Allow solr field names to repeat in a spec set. This allows you to cumulatively add to a solr field based on "regular"
|
33
62
|
and custom (or, say, two custom) specs.
|
63
|
+
|
34
64
|
0.4.0
|
35
65
|
* MAJOR BACKWARD-INCOMPATIBLE CHANGE!! The signature for custom routines is now def function(doc, record, my, args), where
|
36
66
|
"doc" is a hashlike (usually a SolrDocument) that contains all the work that has happened up to this point. The idea is that you
|
37
67
|
can use previously-computed values to determine values for different fields. Use sparingly.
|
68
|
+
|
38
69
|
0.3.0
|
39
70
|
* Changed behavior with respect to repeated subfields. A spec such as '260 ac' returns the values of the 'a' and
|
40
71
|
'c' subfields concatenated together. A request for '631 z' would, similarly, return the values *of all the subfield
|
41
72
|
z's* concatenated together. I'm now treating this as a special case. If the request is for a single subfield code,
|
42
73
|
multiple values are returned separate from each other.
|
43
74
|
|
75
|
+
|
44
76
|
0.2.0
|
45
77
|
* First public release
|
data/Rakefile
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
gem 'ci_reporter'
|
4
|
+
require 'ci/reporter/rake/rspec'
|
3
5
|
|
4
6
|
begin
|
5
7
|
require 'jeweler'
|
@@ -10,11 +12,12 @@ begin
|
|
10
12
|
gem.email = "bill@dueber.com"
|
11
13
|
gem.homepage = "http://github.com/billdueber/marcspec"
|
12
14
|
gem.authors = ["BillDueber"]
|
13
|
-
gem.add_development_dependency "
|
15
|
+
gem.add_development_dependency "rspec"
|
14
16
|
gem.add_development_dependency "yard", ">= 0"
|
15
|
-
|
16
|
-
gem.add_dependency 'marc4j4r', '>=
|
17
|
-
gem.add_dependency '
|
17
|
+
gem.add_development_dependency 'ci_reporter'
|
18
|
+
gem.add_dependency 'marc4j4r', '>=1.1.0'
|
19
|
+
gem.add_dependency 'logback-simple'
|
20
|
+
gem.add_dependency 'jruby_streaming_update_solr_server', '>=0.5.0'
|
18
21
|
|
19
22
|
|
20
23
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
@@ -24,13 +27,20 @@ rescue LoadError
|
|
24
27
|
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
28
|
end
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
|
31
|
+
require 'spec/rake/spectask'
|
32
|
+
desc "Run rspec specs"
|
33
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
34
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Run Rspec tests with CI output in spec/reports"
|
38
|
+
Spec::Rake::SpecTask.new('cispec') do |t|
|
39
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
32
40
|
end
|
33
41
|
|
42
|
+
|
43
|
+
|
34
44
|
begin
|
35
45
|
require 'rcov/rcovtask'
|
36
46
|
Rcov::RcovTask.new do |spec|
|
@@ -40,12 +50,12 @@ begin
|
|
40
50
|
end
|
41
51
|
rescue LoadError
|
42
52
|
task :rcov do
|
43
|
-
abort "RCov is not available. In order to run rcov, you must:
|
53
|
+
abort "RCov is not available. In order to run rcov, you must: jgem install rcov-java"
|
44
54
|
end
|
45
55
|
end
|
46
56
|
|
47
57
|
task :spec => :check_dependencies
|
48
|
-
|
58
|
+
task :cispec => :"ci:setup:rspec"
|
49
59
|
task :default => :spec
|
50
60
|
|
51
61
|
begin
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.6.1
|
data/lib/marcspec.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
require 'logger'
|
2
1
|
require 'marc4j4r'
|
2
|
+
require "logback-simple"
|
3
|
+
|
3
4
|
|
4
|
-
$LOG = Logger.new(STDOUT)
|
5
|
-
$LOG.level = Logger::WARN
|
6
5
|
|
7
6
|
require "marcspec/customspec"
|
8
7
|
require "marcspec/solrfieldspec"
|
@@ -13,11 +12,14 @@ require "marcspec/specset"
|
|
13
12
|
require "marcspec/marcfieldspec"
|
14
13
|
require "marcspec/dsl"
|
15
14
|
|
16
|
-
# Build up a little module to include in MARC4J4R::Record that
|
17
|
-
# gives us a way to cache computed values within the record itself
|
18
|
-
# It's just a hash.
|
19
|
-
|
20
15
|
module CacheSpot
|
16
|
+
# Build up a little module to include in MARC4J4R::Record that
|
17
|
+
# gives us a way to cache computed values within the record itself
|
18
|
+
# It's just a hash.
|
19
|
+
#
|
20
|
+
# Pretty sure this belongs somewhere else; not sure where.
|
21
|
+
#
|
22
|
+
# @return [Hash] the cachespot hash
|
21
23
|
def cachespot
|
22
24
|
@_cachespot ||= {}
|
23
25
|
return @_cachespot
|
@@ -2,10 +2,11 @@ require 'marcspec/solrfieldspec'
|
|
2
2
|
|
3
3
|
|
4
4
|
module MARCSpec
|
5
|
+
|
6
|
+
# A ConstantSolrSpec always returns the same value(s) no matter what's in the record.
|
5
7
|
class ConstantSolrSpec < SolrFieldSpec
|
6
8
|
attr_accessor :constantValue
|
7
9
|
|
8
|
-
#attr_accessor :solrField, :first, :map, :noMapKeyDefault, :marcfieldspecs, :default, :arity
|
9
10
|
|
10
11
|
def initialize opts = {}
|
11
12
|
@solrField = opts[:solrField]
|
@@ -20,18 +21,32 @@ module MARCSpec
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
24
|
+
# Return the constant value associated with this spec
|
25
|
+
# @param [MARC4J4R::Record] r The record. IGNORED. It's a constant ;-)
|
26
|
+
# @param [Hash, SolrInputDocument] doc The hash-like object that contains previously-generated content. IGNORED
|
27
|
+
# @return [String, Array] The constant value(s) associated with this object.
|
28
|
+
|
23
29
|
def marc_values r, doc = {}
|
24
30
|
return @constantValue
|
25
31
|
end
|
26
32
|
|
33
|
+
# Basic equality
|
27
34
|
def == other
|
28
35
|
return @constantValue == other.constantValue
|
29
36
|
end
|
30
37
|
|
38
|
+
# Build up from a ruby hash
|
39
|
+
# @deprecated Use the DSL
|
31
40
|
def self.fromHash h
|
32
41
|
return self.new(h)
|
33
42
|
end
|
34
43
|
|
44
|
+
def asDSLString
|
45
|
+
return "constant('#{@solrField}') do\n value #{@constantValue.inspect}\nend"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Used to round-trip to/from hash syntax
|
49
|
+
# @deprecated Use the DSL
|
35
50
|
def asPPString
|
36
51
|
s = StringIO.new
|
37
52
|
s.print "{\n :solrField=> "
|
@@ -17,6 +17,8 @@ module MARCSpec
|
|
17
17
|
# substrings are specified.
|
18
18
|
|
19
19
|
class ControlFieldSpec
|
20
|
+
include Logback::Simple
|
21
|
+
|
20
22
|
attr_accessor :tag, :range, :rangehistory
|
21
23
|
|
22
24
|
def initialize (tag, range=nil)
|
@@ -33,7 +35,8 @@ module MARCSpec
|
|
33
35
|
(self.range == other.range))
|
34
36
|
end
|
35
37
|
|
36
|
-
|
38
|
+
# Set the range of characters to use (nil for all)
|
39
|
+
#
|
37
40
|
# Always force a real range, since in Ruby 1.9 a string subscript with a single fixnum
|
38
41
|
# will return the character code of that character (e.g., "Bill"[0] => 66, wherease
|
39
42
|
# "Bill"[0..0] gives the expected 'B'
|
@@ -76,10 +79,25 @@ module MARCSpec
|
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
82
|
+
# Print it out has a ruby hash
|
83
|
+
# @deprecated Use the DSL
|
84
|
+
|
79
85
|
def pretty_print pp
|
80
86
|
pp.pp eval(self.asPPString)
|
81
87
|
end
|
82
88
|
|
89
|
+
# Print out as a DSL segment
|
90
|
+
def asDSLString
|
91
|
+
if (@range)
|
92
|
+
return "spec('#{@tag}') {chars #{@range}}"
|
93
|
+
else
|
94
|
+
return "spec('#{@tag}')"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Print out as a ruby hash.
|
99
|
+
# @deprecated Use the DSL
|
100
|
+
|
83
101
|
def asPPString
|
84
102
|
s = StringIO.new
|
85
103
|
if @range
|
@@ -90,6 +108,9 @@ module MARCSpec
|
|
90
108
|
return s.string
|
91
109
|
end
|
92
110
|
|
111
|
+
# Recreate from an asPPString call
|
112
|
+
# @deprecated Use the DSL
|
113
|
+
|
93
114
|
def self.fromPPString str
|
94
115
|
a = eval(str)
|
95
116
|
return self.new(*a)
|
data/lib/marcspec/customspec.rb
CHANGED
@@ -47,6 +47,8 @@ module MARCSpec
|
|
47
47
|
# no key in the map that matches the value.
|
48
48
|
#
|
49
49
|
# Note that the last four options don't make sense if multiple :solrFields are given, and are illegal in that case.
|
50
|
+
#
|
51
|
+
# Also note that using the DSL to produce these is easier from config file.
|
50
52
|
|
51
53
|
def initialize(opts)
|
52
54
|
@solrField = opts[:solrField]
|
@@ -85,11 +87,45 @@ module MARCSpec
|
|
85
87
|
end
|
86
88
|
|
87
89
|
|
90
|
+
# Produce one from the results of eval'ing a asPPString string
|
91
|
+
# @deprecated Use the DSL
|
92
|
+
|
88
93
|
def self.fromHash h
|
89
94
|
return self.new(h)
|
90
95
|
end
|
91
96
|
|
92
|
-
|
97
|
+
# Produce DSL code that will reproduce this object
|
98
|
+
def asDSLString
|
99
|
+
s = StringIO.new
|
100
|
+
s.puts "custom('#{@solrField}') do"
|
101
|
+
s.puts " firstOnly" if @first
|
102
|
+
if @defaultValue
|
103
|
+
s.puts " default " +
|
104
|
+
PP.singleline_pp(@defaultValue + "\n", s)
|
105
|
+
end
|
106
|
+
if @map
|
107
|
+
s.print " mapname "
|
108
|
+
PP.pp(@map.mapname, s)
|
109
|
+
end
|
110
|
+
if @noMapKeyDefault
|
111
|
+
s.print(" mapMissDefault ")
|
112
|
+
PP.singleline_pp(@noMapKeyDefault, s)
|
113
|
+
s.print("\n ")
|
114
|
+
end
|
115
|
+
|
116
|
+
s.puts(" function(:#{@functionSymbol}) {")
|
117
|
+
s.puts(" mod #{@module}")
|
118
|
+
if @functionArgs and @functionArgs.size > 0
|
119
|
+
args = @functionArgs.map{|a| a.inspect}.join(', ')
|
120
|
+
s.puts " args #{args}"
|
121
|
+
end
|
122
|
+
s.puts " }"
|
123
|
+
s.puts "end"
|
124
|
+
return s.string
|
125
|
+
end
|
126
|
+
|
127
|
+
# Print out as a ruby hash.
|
128
|
+
# @deprecated Use the DSL
|
93
129
|
def asPPString
|
94
130
|
s = StringIO.new
|
95
131
|
s.print "{\n :solrField=> "
|
data/lib/marcspec/dsl.rb
CHANGED
@@ -9,11 +9,11 @@ module MARCSpec
|
|
9
9
|
|
10
10
|
# Re-open SpecSet to add the necessary methods
|
11
11
|
|
12
|
-
class SpecSet
|
12
|
+
class SpecSet
|
13
13
|
|
14
14
|
# create a normal field
|
15
15
|
def field(name, &blk)
|
16
|
-
|
16
|
+
log.debug "Creating regular field #{name}"
|
17
17
|
sfs = SolrFieldSpec.new(:solrField=>name)
|
18
18
|
sfs.instance_eval(&blk)
|
19
19
|
self << sfs
|
@@ -22,7 +22,7 @@ module MARCSpec
|
|
22
22
|
|
23
23
|
# Create a constant field
|
24
24
|
def constant(name, &blk)
|
25
|
-
|
25
|
+
log.debug "Creating constant field #{name}"
|
26
26
|
|
27
27
|
constant = ConstantSolrSpec.new(:solrField=>name)
|
28
28
|
constant.instance_eval(&blk)
|
@@ -31,7 +31,7 @@ module MARCSpec
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def custom(name, &blk)
|
34
|
-
|
34
|
+
log.debug "Creating custom field #{name}"
|
35
35
|
custom = CustomSolrSpec.new(:solrField=>name)
|
36
36
|
custom.instance_eval(&blk)
|
37
37
|
|
@@ -45,17 +45,32 @@ module MARCSpec
|
|
45
45
|
|
46
46
|
class SolrFieldSpec
|
47
47
|
def spec(tag, &blk)
|
48
|
+
|
49
|
+
subs = nil
|
50
|
+
if tag =~ /^(...)(.+)$/
|
51
|
+
tag = $1
|
52
|
+
subs = $2
|
53
|
+
end
|
54
|
+
|
48
55
|
if tag.to_i == tag
|
49
56
|
tag = '%03d' % tag
|
50
57
|
end
|
51
58
|
|
52
59
|
marcfieldspec = nil
|
53
|
-
|
60
|
+
|
61
|
+
if tag == 'LDR'
|
62
|
+
marcfieldspec = MARCSpec::LeaderSpec.new('LDR')
|
63
|
+
elsif MARC4J4R::ControlField.control_tag? tag
|
54
64
|
marcfieldspec = MARCSpec::ControlFieldSpec.new(tag)
|
55
65
|
else
|
56
66
|
marcfieldspec = MARCSpec::VariableFieldSpec.new(tag)
|
57
67
|
end
|
58
68
|
|
69
|
+
# Did we get subs? If so, add them now.
|
70
|
+
if subs
|
71
|
+
marcfieldspec.codes = subs
|
72
|
+
end
|
73
|
+
|
59
74
|
marcfieldspec.instance_eval(&blk) if block_given?
|
60
75
|
|
61
76
|
# If we had multiple sub calls, get them from the codehistory
|
data/lib/marcspec/map.rb
CHANGED
@@ -10,14 +10,15 @@ module MARCSpec
|
|
10
10
|
# NOTE: THIS IS AN ABSTRACT SUPERCLASS. DO NOT INSTANTIATE IT DIRECTLY
|
11
11
|
|
12
12
|
class Map
|
13
|
+
include Logback::Simple
|
14
|
+
|
13
15
|
attr_accessor :mapname, :map
|
14
16
|
|
15
|
-
# Create a new map. The passed map is either
|
16
|
-
#
|
17
|
+
# Create a new map. The passed map is either a standard hash (KVMap) or a list of duples
|
18
|
+
# (for a MultiValueMap)
|
17
19
|
#
|
18
20
|
# @param [String] mapname The name of this map; can be used to find it later on.
|
19
|
-
# @param [Hash, Array
|
20
|
-
# array of duples (2-value arrays) for a MultiValueMap.
|
21
|
+
# @param [Hash, Array] map Either a normal key-value hash (for a KV Map) or an array of duples (2-value arrays) for a MultiValueMap.
|
21
22
|
def initialize(mapname, map)
|
22
23
|
@mapname = mapname
|
23
24
|
@map = map
|
@@ -34,14 +35,14 @@ module MARCSpec
|
|
34
35
|
begin
|
35
36
|
str = File.open(filename).read
|
36
37
|
rescue Exception => e
|
37
|
-
|
38
|
+
log.fatal "Problem opening #{filename}: #{e.message}"
|
38
39
|
raise e
|
39
40
|
end
|
40
41
|
|
41
42
|
begin
|
42
43
|
rawmap = eval(str)
|
43
44
|
rescue Exception => e
|
44
|
-
|
45
|
+
log.fatal "Problem evaluating (with 'eval') file #{filename}: #{e.message}"
|
45
46
|
raise e
|
46
47
|
end
|
47
48
|
|
@@ -58,7 +59,7 @@ module MARCSpec
|
|
58
59
|
when :multi
|
59
60
|
return MultiValueMap.new(rawmap[:mapname], rawmap[:map])
|
60
61
|
else
|
61
|
-
|
62
|
+
log.fatal "Map file #{filename} doesn't seem to be either a KV map or a MuliValueMap according to :maptype (#{rawmap[:maptype]})"
|
62
63
|
raise ArgumentError, "File #{filename} doesn't evaluate to a valid map"
|
63
64
|
end
|
64
65
|
|
@@ -91,7 +91,7 @@ module MARCSpec
|
|
91
91
|
prop.load(f.to_inputstream)
|
92
92
|
prop.each do |patstring,kv|
|
93
93
|
unless patstring =~ /^pattern/ and kv =~ /.+=>.+/
|
94
|
-
|
94
|
+
log.warn "MultiValueMap import skipping weird line in #{filename}\n #{l}"
|
95
95
|
next
|
96
96
|
end
|
97
97
|
match = /^\s*(.+?)\s*=>\s*(.+?)\s*$/.match(kv)
|