marcspec 1.5.0 → 1.6.1

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