summon 1.0.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.
- data/.specification +58 -0
- data/History.txt +4 -0
- data/Manifest.txt +52 -0
- data/PostInstall.txt +4 -0
- data/README.rdoc +77 -0
- data/Rakefile +25 -0
- data/bin/summon +10 -0
- data/bin/summonh +19 -0
- data/ispec/integration_spec.rb +61 -0
- data/lib/summon.rb +41 -0
- data/lib/summon/cli.rb +136 -0
- data/lib/summon/log.rb +40 -0
- data/lib/summon/schema.rb +109 -0
- data/lib/summon/schema/availability.rb +14 -0
- data/lib/summon/schema/citation.rb +11 -0
- data/lib/summon/schema/date.rb +23 -0
- data/lib/summon/schema/document.rb +84 -0
- data/lib/summon/schema/error.rb +4 -0
- data/lib/summon/schema/facet.rb +51 -0
- data/lib/summon/schema/query.rb +96 -0
- data/lib/summon/schema/range.rb +52 -0
- data/lib/summon/schema/search.rb +37 -0
- data/lib/summon/schema/suggestion.rb +5 -0
- data/lib/summon/service.rb +44 -0
- data/lib/summon/transport.rb +13 -0
- data/lib/summon/transport/canned.json +2327 -0
- data/lib/summon/transport/canned.rb +9 -0
- data/lib/summon/transport/errors.rb +12 -0
- data/lib/summon/transport/headers.rb +55 -0
- data/lib/summon/transport/http.rb +114 -0
- data/lib/summon/transport/qstring.rb +49 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/summon/log_spec.rb +28 -0
- data/spec/summon/schema/availability_spec.rb +31 -0
- data/spec/summon/schema/citation_spec.rb +34 -0
- data/spec/summon/schema/date_spec.rb +12 -0
- data/spec/summon/schema/document_spec.rb +235 -0
- data/spec/summon/schema/facet_spec.rb +115 -0
- data/spec/summon/schema/query_spec.rb +163 -0
- data/spec/summon/schema/range_spec.rb +45 -0
- data/spec/summon/schema/search_spec.rb +62 -0
- data/spec/summon/schema_spec.rb +143 -0
- data/spec/summon/service_spec.rb +18 -0
- data/spec/summon/transport/headers_spec.rb +47 -0
- data/spec/summon/transport/http_spec.rb +29 -0
- data/spec/summon/transport/qstring_spec.rb +24 -0
- data/spec/summon_spec.rb +48 -0
- data/summon.gemspec +41 -0
- metadata +145 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
module Summon::Transport
|
2
|
+
|
3
|
+
class TransportError < StandardError; end
|
4
|
+
|
5
|
+
class AuthorizationError < TransportError; end
|
6
|
+
|
7
|
+
class ServiceError < TransportError; end
|
8
|
+
|
9
|
+
class RequestError < TransportError; end
|
10
|
+
|
11
|
+
class UnknownResponseError < TransportError; end
|
12
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'uri'
|
3
|
+
require 'openssl'
|
4
|
+
require 'sha1'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
module Summon::Transport
|
8
|
+
class Headers < Hash
|
9
|
+
include Qstring
|
10
|
+
def initialize(options = {})
|
11
|
+
@params = options[:params] || {}
|
12
|
+
@url = options[:url]
|
13
|
+
@uri = URI.parse(@url)
|
14
|
+
@access_id = options[:access_id]
|
15
|
+
@client_key = options[:client_key]
|
16
|
+
@secret_key = options[:secret_key]
|
17
|
+
@session_id = options[:session_id]
|
18
|
+
@log = Summon::Log.new(options[:log])
|
19
|
+
@accept = "application/#{options[:accept] || 'json'}"
|
20
|
+
@time = Time.now.httpdate
|
21
|
+
validate!
|
22
|
+
merge!({
|
23
|
+
"Content-Type" => "application/x-www-form-urlencoded; charset=utf8",
|
24
|
+
"Accept" => @accept,
|
25
|
+
"x-summon-date" => @time,
|
26
|
+
"x-summon-session-id" => @session_id,
|
27
|
+
"Authorization" => "Summon #{[@access_id, @client_key, digest].reject {|o| o.nil?}.join(';')}",
|
28
|
+
"Host" => "#{@uri.host}:#{@uri.port}"
|
29
|
+
}).reject! {|k,v| v.nil?}
|
30
|
+
@log.debug {
|
31
|
+
"#{self.class.name}\n#{self.map {|k,v| "#{k}: #{v}"}.join("\n")}"
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def digest
|
36
|
+
id = [@accept, @time, "#{@uri.host}:#{@uri.port}", @uri.path, qstr].join("\n") + "\n"
|
37
|
+
Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, @secret_key, id)).chomp.tap {|digest|
|
38
|
+
# @log.debug {"ID: #{id.inspect}"}
|
39
|
+
# @log.debug {"DIGEST: #{digest}\n"}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def qstr
|
44
|
+
to_query_string(@params, false)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def validate!
|
50
|
+
raise AuthorizationError, "No Access ID specified" if @access_id.nil?
|
51
|
+
raise AuthorizationError, "Secret Key not provided for Access ID: #{@access_id}" if @secret_key.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Summon::Transport
|
5
|
+
class Http
|
6
|
+
include Qstring
|
7
|
+
|
8
|
+
DEFAULTS = {:url => "http://api.summon.serialssolutions.com"}
|
9
|
+
|
10
|
+
def initialize(options = {:url => nil, :access_id => nil, :secret_key => nil, :client_key => nil, :session_id => nil, :log => nil})
|
11
|
+
@options = DEFAULTS.merge options
|
12
|
+
@access_id = @options[:access_id]
|
13
|
+
@secret_key = @options[:secret_key]
|
14
|
+
@client_key = @options[:client_key]
|
15
|
+
@session_id = @options[:session_id] || "SUMMON-SESSION-#{Socket.gethostname}-#{$$}-#{sidalloc}"
|
16
|
+
@url = @options[:url]
|
17
|
+
@log = Summon::Log.new(options[:log])
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(path, params = {})
|
21
|
+
session_id = params["s.session.id"]
|
22
|
+
params.delete "s.session.id"
|
23
|
+
urlget "#{@url}#{path}?#{to_query_string(params, true)}", params, session_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def urlget(url, params = nil, session_id = nil)
|
27
|
+
uri = URI.parse url
|
28
|
+
params ||= from_query_string(uri.query)
|
29
|
+
session_id ||= @session_id
|
30
|
+
headers = Headers.new(
|
31
|
+
:url => url,
|
32
|
+
:params => params,
|
33
|
+
:access_id => @access_id,
|
34
|
+
:secret_key => @secret_key,
|
35
|
+
:client_key => @client_key,
|
36
|
+
:session_id => session_id,
|
37
|
+
:log => @log
|
38
|
+
)
|
39
|
+
|
40
|
+
@log.info("ruby-summon:transport") {
|
41
|
+
"GET: #{url}"
|
42
|
+
}
|
43
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
44
|
+
http.start do
|
45
|
+
get = Net::HTTP::Get.new("#{uri.path}#{'?' + uri.query if uri.query && uri.query != ''}")
|
46
|
+
get.merge! headers
|
47
|
+
http.request(get) do |response|
|
48
|
+
case response
|
49
|
+
when Net::HTTPSuccess
|
50
|
+
return parse(response)
|
51
|
+
when Net::HTTPUnauthorized
|
52
|
+
raise AuthorizationError, status(response)
|
53
|
+
when Net::HTTPClientError
|
54
|
+
raise RequestError, error(response)
|
55
|
+
when Net::HTTPServerError
|
56
|
+
raise ServiceError, error(response)
|
57
|
+
else
|
58
|
+
raise UnknownResponseError, "Unknown response: #{response}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(response)
|
65
|
+
case response.content_type
|
66
|
+
when "application/json"
|
67
|
+
JSON.parse(response.body).tap do |json|
|
68
|
+
@log.debug("ruby-summon::transport") { "JSON RESPONSE: #{json.inspect}" }
|
69
|
+
end
|
70
|
+
|
71
|
+
when "text/plain"
|
72
|
+
response.body.tap do |text|
|
73
|
+
@log.debug("ruby-summon::transport") { "TEXT RESPONSE: #{text.inspect}" }
|
74
|
+
end
|
75
|
+
|
76
|
+
else
|
77
|
+
raise ServiceError, "service returned unexpected #{response.content_type} : #{response.body}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def error(response)
|
82
|
+
case response.content_type
|
83
|
+
when "application/json"
|
84
|
+
JSON.parse(response.body)["errors"].first["message"]
|
85
|
+
else
|
86
|
+
status(response)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def status(response)
|
91
|
+
"#{response.code}: #{response.message}"
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
@sessions = 0
|
97
|
+
|
98
|
+
def sidalloc
|
99
|
+
self.class.instance_eval do
|
100
|
+
@sessions += 1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
module Net::HTTPHeader
|
109
|
+
def merge!(hash)
|
110
|
+
for k, v in hash
|
111
|
+
self[k] = v
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module Summon::Transport
|
5
|
+
module Qstring
|
6
|
+
|
7
|
+
def to_query_string(hash, urlencode = true)
|
8
|
+
hash.reject {|k,v| v.nil? || v == ''}.inject([]) do |qs,pair|
|
9
|
+
qs.tap do
|
10
|
+
k,v = pair
|
11
|
+
if v.is_a?(Array)
|
12
|
+
for el in v
|
13
|
+
qs << encode_param(k, el, urlencode)
|
14
|
+
end
|
15
|
+
else
|
16
|
+
qs << encode_param(k, v, urlencode)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end.reject{|o| o.nil? || o.empty?}.sort.join('&')
|
20
|
+
end
|
21
|
+
|
22
|
+
def urlencode(str)
|
23
|
+
str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def urldecode(str)
|
27
|
+
CGI.unescape(str)
|
28
|
+
end
|
29
|
+
|
30
|
+
def encode_param(k, v, do_urlencode)
|
31
|
+
"#{k.to_s}=#{do_urlencode ? urlencode(v.to_s) : v.to_s}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def from_query_string(qstr)
|
35
|
+
qstr ||= ""
|
36
|
+
{}.tap do |result|
|
37
|
+
for param in qstr.split('&')
|
38
|
+
m,k,v = *param.match(/^(.*?)=(.*?)$/)
|
39
|
+
if current = result[k]
|
40
|
+
result[k] = current.to_a
|
41
|
+
result[k] << urldecode(v)
|
42
|
+
else
|
43
|
+
result[k] = urldecode(v)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion -rubygems"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/summon.rb'}"
|
9
|
+
puts "Loading summon gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/summon')
|
2
|
+
gem 'rspec'
|
3
|
+
require 'spec'
|
4
|
+
|
5
|
+
def pre(text)
|
6
|
+
puts "<pre>" +
|
7
|
+
text.to_s.
|
8
|
+
gsub("&", "&").
|
9
|
+
gsub("<", "<").
|
10
|
+
gsub(">", ">") +
|
11
|
+
"</pre>"
|
12
|
+
end
|
13
|
+
|
14
|
+
class Object
|
15
|
+
def remove_src
|
16
|
+
@src = nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
3
|
+
|
4
|
+
describe Summon::Log do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@logger = stub(:Logger)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "passes through all methods to the underlying logger" do
|
11
|
+
log = Summon::Log.new(@logger)
|
12
|
+
@logger.should_receive(:info).with("foo")
|
13
|
+
log.info("foo")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "creates a stderr logger when no spec is provided" do
|
17
|
+
Logger.should_receive(:new).with($stderr).and_return(@logger)
|
18
|
+
@logger.should_receive(:level=).with(Logger::WARN)
|
19
|
+
log = Summon::Log.new
|
20
|
+
end
|
21
|
+
|
22
|
+
it "creates a logger from an option hash when the spec is a set of options" do
|
23
|
+
out = stub(:OutputStream)
|
24
|
+
Logger.should_receive(:new).with(out).and_return(@logger)
|
25
|
+
@logger.should_receive(:level=).with(Logger::ERROR)
|
26
|
+
log = Summon::Log.new(:level => :error, :initialize => [out])
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Availability do
|
4
|
+
it "should map" do
|
5
|
+
availabilities = Summon::Availability.parse_results("Result"=>{"RecordSummary"=>[
|
6
|
+
{
|
7
|
+
"ID"=>"1038053",
|
8
|
+
"RecordList"=>"http://api.staging.summon.serialssolutions.com:8093/status?key=HD3UV5FG9E&output=application%2Fjson&action=list&token=1038053",
|
9
|
+
"Record"=>{"Status"=>"unknown", "StatusMessage"=>"Available", "Location"=>"Architecture Library", "CallNumber"=>" 720.979 A534"},
|
10
|
+
"RecordCount"=>1},
|
11
|
+
{
|
12
|
+
"ID"=>"1038082",
|
13
|
+
"RecordList"=>"http://api.staging.summon.serialssolutions.com:8093/status?key=HD3UV5FG9E&output=application%2Fjson&action=list&token=1038082",
|
14
|
+
"Record"=>{"Status"=>"unknown", "StatusMessage"=>"Available", "Location"=>"Main Library", "CallNumber"=>" 628.5 B6157"},
|
15
|
+
"RecordCount"=>1}]})
|
16
|
+
|
17
|
+
one, two = availabilities
|
18
|
+
|
19
|
+
one.token.should == "1038053"
|
20
|
+
one.status.should == "unknown"
|
21
|
+
one.status_message.should == "Available"
|
22
|
+
one.location.should == "Architecture Library"
|
23
|
+
one.call_number.should == " 720.979 A534"
|
24
|
+
|
25
|
+
two.token.should == "1038082"
|
26
|
+
two.status.should == "unknown"
|
27
|
+
two.status_message.should == "Available"
|
28
|
+
two.location.should == "Main Library"
|
29
|
+
two.call_number.should == " 628.5 B6157"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Citation do
|
4
|
+
it "should map" do
|
5
|
+
results = {"Results"=>{"Citations"=>{"Citation"=>[
|
6
|
+
{
|
7
|
+
"Name"=>"American Medical Association, 10th Edition",
|
8
|
+
"Text"=>"Morrow BH, Price VB. <span class=\"italic\">Anasazi architecture and American design</span>. 1st ed. ed. Albuquerque: University of New Mexico Press; Wed. www.magnolia.com.",
|
9
|
+
"ShortName"=>"AMA"},
|
10
|
+
{
|
11
|
+
"Label"=>"Chicago 15th Edition (Notes & Bibliography)",
|
12
|
+
"Text"=>"Morrow, Baker H. and V. B. Price. Anasazi Architecture and American Design. 1st ed. ed. Albuquerque: University of New Mexico Press, Wed, (accessed August 5, 2009).",
|
13
|
+
"ShortName"=>"Chicago NB"},
|
14
|
+
{
|
15
|
+
"Label"=>"MLA",
|
16
|
+
"Text"=>"Morrow, Baker H., and V. B. Price. Anasazi Architecture and American Design. 1st ed. ed. Albuquerque: University of New Mexico Press, Wed. . 5 Aug. 2009",
|
17
|
+
"Caption"=>"Modern Language Association, 6th Edition",
|
18
|
+
"ShortName"=>"MLA"},
|
19
|
+
{
|
20
|
+
"Label"=>"Vancouver",
|
21
|
+
"Text"=>"Morrow BH, Price VB. Anasazi architecture and American design. 1st ed. ed. Albuquerque: University of New Mexico Press; Wed.",
|
22
|
+
"ShortName"=>"Vancouver"}
|
23
|
+
]}, "Timing"=>{"ElapsedQueryTime"=>16, "TotalQueryTime"=>14, "TotalExecutionTime"=>1938}}}
|
24
|
+
|
25
|
+
citations = Summon::Citation.parse_results(results)
|
26
|
+
citations[0].name.should == "American Medical Association, 10th Edition"
|
27
|
+
citations[0].text.should == "Morrow BH, Price VB. <span class=\"italic\">Anasazi architecture and American design</span>. 1st ed. ed. Albuquerque: University of New Mexico Press; Wed. www.magnolia.com."
|
28
|
+
citations[0].short_name.should == "AMA"
|
29
|
+
|
30
|
+
citations[2].name.should == nil
|
31
|
+
citations[2].label.should == "MLA"
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Date do
|
4
|
+
it "should do stuff w/ date" do
|
5
|
+
date = Summon::Date.new({"month"=>"01", "text"=>"c2000.", "day"=>"02", "year"=>"2000"})
|
6
|
+
|
7
|
+
date.day.should == 2
|
8
|
+
date.month.should == 1
|
9
|
+
date.year.should == 2000
|
10
|
+
date.text.should == "c2000."
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Summon::Document do
|
4
|
+
it "should map" do
|
5
|
+
doc = Summon::Document.new(JSON.parse(EXAMPLE_DOCUMENT_JSON))
|
6
|
+
doc.remove_src
|
7
|
+
doc.publication_date.remove_src
|
8
|
+
doc.authors.each {|a| a.remove_src }
|
9
|
+
doc.to_yaml.should == EXPECTED_DOCUMENT_YAML
|
10
|
+
end
|
11
|
+
|
12
|
+
EXAMPLE_DOCUMENT_JSON = <<-JSON
|
13
|
+
{
|
14
|
+
"Publisher_xml": [
|
15
|
+
{
|
16
|
+
"name": "Spirulina Records"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"name": "Swingsistersound"
|
20
|
+
}
|
21
|
+
],
|
22
|
+
"Abstract": ["This is the most awesome document ever"],
|
23
|
+
"DOI": [ "10.1109\/CBMS.2008.1"],
|
24
|
+
"ISSN": ["1063-7125", "0000-1111"],
|
25
|
+
"Issue": ["7"],
|
26
|
+
"PublicationTitle": ["Batman Books"],
|
27
|
+
"StartPage": ["pp23"],
|
28
|
+
"SubjectTerms": [
|
29
|
+
"Women's music",
|
30
|
+
"Popular music",
|
31
|
+
"Rock music"
|
32
|
+
],
|
33
|
+
"EndPage": ["i"],
|
34
|
+
"TableOfContents": [
|
35
|
+
"The very thing -- Dark night -- 2 truths & uh lie -- Reckless -- Spin -- Free -- Real of you -- Fire -- Purple hair -- Ghost -- Nuthin' -- Faith."
|
36
|
+
],
|
37
|
+
"XQueryRevision": [
|
38
|
+
"Rev: 6229"
|
39
|
+
],
|
40
|
+
"inHoldings": false,
|
41
|
+
"DBID": [
|
42
|
+
"GXQ"
|
43
|
+
],
|
44
|
+
"Notes": [
|
45
|
+
"Compact disc."
|
46
|
+
],
|
47
|
+
"PublicationDateYear": [
|
48
|
+
"2000"
|
49
|
+
],
|
50
|
+
"hasFullText": false,
|
51
|
+
"timestamp": [
|
52
|
+
"Thu Jul 09 19:44:12 EDT 2009"
|
53
|
+
],
|
54
|
+
"Author": [
|
55
|
+
"Hunter, Lisa"
|
56
|
+
],
|
57
|
+
"PublicationDate": [
|
58
|
+
"c2000."
|
59
|
+
],
|
60
|
+
"Subtitle": [
|
61
|
+
"the life and death of Joey Stefano"
|
62
|
+
],
|
63
|
+
"Title": [
|
64
|
+
"Lisa Hunter -- alive"
|
65
|
+
],
|
66
|
+
"ID": [
|
67
|
+
"gvsu_catalog_b16644323"
|
68
|
+
],
|
69
|
+
"LCCallNum": [
|
70
|
+
"M1630.18 .H95 2000"
|
71
|
+
],
|
72
|
+
"Language": [
|
73
|
+
"English"
|
74
|
+
],
|
75
|
+
"PublicationDateCentury": [
|
76
|
+
"2000"
|
77
|
+
],
|
78
|
+
"PublicationDateDecade": [
|
79
|
+
"2000"
|
80
|
+
],
|
81
|
+
"openUrl": "ctx_ver=Z39.88-2004&rfr_id=info:sid\/summon.serialssolutions.com&rft_val_fmt=info:ofi\/fmt:kev:mtx:dc&rft.title=Lisa+Hunter+--+alive&rft.creator=Hunter%2C+Lisa&rft.date=c200-0.&rft.pub=Spirulina+Records&rft.externalDBID=n%2Fa&rft.externalDocID=b16644323",
|
82
|
+
"Author_xml": [
|
83
|
+
{
|
84
|
+
"fullname": "Hunter, Lisa",
|
85
|
+
"surname": "Hunter",
|
86
|
+
"givenname": "Lisa"
|
87
|
+
}
|
88
|
+
],
|
89
|
+
"Library": [
|
90
|
+
"Women's Center Library"
|
91
|
+
],
|
92
|
+
"PublicationDate_xml": [
|
93
|
+
{
|
94
|
+
"month": "01",
|
95
|
+
"text": "c2000.",
|
96
|
+
"day": "02",
|
97
|
+
"year": "2000"
|
98
|
+
}
|
99
|
+
],
|
100
|
+
"PublicationPlace": [
|
101
|
+
"S.l.",
|
102
|
+
"Ann Arbor, Mich"
|
103
|
+
],
|
104
|
+
"TemporalSubjectTerms": [
|
105
|
+
"1991-2000"
|
106
|
+
],
|
107
|
+
"PublicationPlace_xml": [
|
108
|
+
{
|
109
|
+
"name": "S.l."
|
110
|
+
},
|
111
|
+
{
|
112
|
+
"name": "Ann Arbor, Mich"
|
113
|
+
}
|
114
|
+
],
|
115
|
+
"DocumentTitleAlternate": [
|
116
|
+
"Alive"
|
117
|
+
],
|
118
|
+
"score": [
|
119
|
+
"1.0"
|
120
|
+
],
|
121
|
+
"Snippet": [
|
122
|
+
"This is the snippet"
|
123
|
+
],
|
124
|
+
"availabilityToken": "b16644323",
|
125
|
+
"ContentType": [
|
126
|
+
"Audio Recording"
|
127
|
+
],
|
128
|
+
"Publisher": [
|
129
|
+
"Spirulina Records",
|
130
|
+
"Swingsistersound"
|
131
|
+
],
|
132
|
+
"PageCount": [
|
133
|
+
"xxviii, 140 p."
|
134
|
+
],
|
135
|
+
"Genre": [
|
136
|
+
"Biography",
|
137
|
+
"Congress"
|
138
|
+
],
|
139
|
+
"ISBN": [
|
140
|
+
"0849343763 (v. 1)",
|
141
|
+
"0849343771 (v. 2)"
|
142
|
+
],
|
143
|
+
"PublicationSeriesTitle": [
|
144
|
+
"A Bantam book"
|
145
|
+
],
|
146
|
+
"DissertationAdvisor": [
|
147
|
+
"Claudio Friedmann"
|
148
|
+
],
|
149
|
+
"DissertationCategory": [
|
150
|
+
"Education"
|
151
|
+
],
|
152
|
+
"DissertationDegree": [
|
153
|
+
"M.S.J."
|
154
|
+
],
|
155
|
+
"DissertationDegreeDate": [
|
156
|
+
"2001"
|
157
|
+
],
|
158
|
+
"DissertationDegreeDateCentury": [
|
159
|
+
"2000"
|
160
|
+
],
|
161
|
+
"DissertationDegreeDateDecade":[
|
162
|
+
"2000"
|
163
|
+
],
|
164
|
+
"DissertationDegreeDateYear": [
|
165
|
+
"2001"
|
166
|
+
],
|
167
|
+
"DissertationSchool": [
|
168
|
+
"West Virginia University"
|
169
|
+
]
|
170
|
+
}
|
171
|
+
JSON
|
172
|
+
|
173
|
+
EXPECTED_DOCUMENT_YAML = <<-YAML
|
174
|
+
--- !ruby/object:Summon::Document
|
175
|
+
abstract: This is the most awesome document ever
|
176
|
+
authors:
|
177
|
+
- Hunter, Lisa
|
178
|
+
availability_token: b16644323
|
179
|
+
call_number: M1630.18 .H95 2000
|
180
|
+
content_type: Audio Recording
|
181
|
+
dissertation_advisor: Claudio Friedmann
|
182
|
+
dissertation_category: Education
|
183
|
+
dissertation_degree: M.S.J.
|
184
|
+
dissertation_degree_date: "2001"
|
185
|
+
dissertation_degree_date_century: "2000"
|
186
|
+
dissertation_degree_date_decade: "2000"
|
187
|
+
dissertation_degree_date_year: "2001"
|
188
|
+
dissertation_school: West Virginia University
|
189
|
+
doi: 10.1109\/CBMS.2008.1
|
190
|
+
end_page: i
|
191
|
+
fulltext: false
|
192
|
+
genres:
|
193
|
+
- Biography
|
194
|
+
- Congress
|
195
|
+
id: gvsu_catalog_b16644323
|
196
|
+
isbns:
|
197
|
+
- 0849343763 (v. 1)
|
198
|
+
- 0849343771 (v. 2)
|
199
|
+
issns:
|
200
|
+
- 1063-7125
|
201
|
+
- 0000-1111
|
202
|
+
issue: "7"
|
203
|
+
languages:
|
204
|
+
- English
|
205
|
+
library: Women's Center Library
|
206
|
+
open_url: ctx_ver=Z39.88-2004&rfr_id=info:sid/summon.serialssolutions.com&rft_val_fmt=info:ofi/fmt:kev:mtx:dc&rft.title=Lisa+Hunter+--+alive&rft.creator=Hunter%2C+Lisa&rft.date=c200-0.&rft.pub=Spirulina+Records&rft.externalDBID=n%2Fa&rft.externalDocID=b16644323
|
207
|
+
page_count: xxviii, 140 p.
|
208
|
+
patent_number:
|
209
|
+
publication_date: !ruby/object:Summon::Date
|
210
|
+
day: "02"
|
211
|
+
month: "01"
|
212
|
+
src:
|
213
|
+
text: c2000.
|
214
|
+
year: "2000"
|
215
|
+
publication_series_title: A Bantam book
|
216
|
+
publication_title: Batman Books
|
217
|
+
publishers:
|
218
|
+
- Spirulina Records
|
219
|
+
- Swingsistersound
|
220
|
+
snippet: This is the snippet
|
221
|
+
src:
|
222
|
+
start_page: pp23
|
223
|
+
subject_terms:
|
224
|
+
- Women's music
|
225
|
+
- Popular music
|
226
|
+
- Rock music
|
227
|
+
subtitle: the life and death of Joey Stefano
|
228
|
+
thumbnail_large:
|
229
|
+
thumbnail_medium:
|
230
|
+
thumbnail_small:
|
231
|
+
title: Lisa Hunter -- alive
|
232
|
+
url:
|
233
|
+
volume:
|
234
|
+
YAML
|
235
|
+
end
|