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 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 "bacon", ">= 0"
15
+ gem.add_development_dependency "rspec"
14
16
  gem.add_development_dependency "yard", ">= 0"
15
-
16
- gem.add_dependency 'marc4j4r', '>=0.9.0'
17
- gem.add_dependency 'jruby_streaming_update_solr_server', '>=0.3.1'
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
- require 'rake/testtask'
28
- Rake::TestTask.new(:spec) do |spec|
29
- spec.libs << 'lib' << 'spec'
30
- spec.pattern = 'spec/**/*_spec.rb'
31
- spec.verbose = true
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: sudo gem install spicycode-rcov"
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.5.0
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)
@@ -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
- $LOG.debug "Creating regular field #{name}"
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
- $LOG.debug "Creating constant field #{name}"
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
- $LOG.debug "Creating custom field #{name}"
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
- if MARC4J4R::ControlField.control_tag? tag
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
- # a standard hash or a list of duples
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<2-value-arrays>] map Either a normal key-value hash (for a KV Map) or an
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
- $LOG.error "Problem opening #{filename}: #{e.message}"
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
- $LOG.error "Problem evaluating (with 'eval') file #{filename}: #{e.message}"
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
- $LOG.error "Map file #{filename} doesn't seem to be either a KV map or a MuliValueMap according to :maptype (#{rawmap[:maptype]})"
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
- $LOG.warn "MultiValueMap import skipping weird line in #{filename}\n #{l}"
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)