solo-rails 0.0.1 → 0.0.2
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/README +20 -0
- data/lib/solo-rails/helpers.rb +5 -0
- data/lib/solo-rails/version.rb +1 -1
- data/lib/solo-rails.rb +222 -3
- metadata +9 -7
data/README
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
SoloRails
|
2
|
+
|
3
|
+
This gem provides a Ruby wrapper for the Soutron Solo API.
|
4
|
+
|
5
|
+
It provides two methods, one to search the catalogue and one to fetch a specific record.
|
6
|
+
|
7
|
+
Search method
|
8
|
+
|
9
|
+
@records = Library.search :q => '',
|
10
|
+
:select => 'Title;Authors;Created Date',
|
11
|
+
:search_id => @records[:search_info].fetch(:id),
|
12
|
+
:ctrt => ct,
|
13
|
+
:sort => 'Created Date:d',
|
14
|
+
:material => ct[:content_type],
|
15
|
+
:per_page => 30,
|
16
|
+
:page => 0
|
17
|
+
|
18
|
+
Show
|
19
|
+
|
20
|
+
@record = Librar.search("1234556")
|
data/lib/solo-rails/version.rb
CHANGED
data/lib/solo-rails.rb
CHANGED
@@ -3,12 +3,231 @@ require 'cgi'
|
|
3
3
|
require 'open-uri'
|
4
4
|
require 'chronic'
|
5
5
|
require 'nokogiri'
|
6
|
-
require 'solo-rails/railtie' #if defined?(Rails)
|
7
6
|
|
8
7
|
module SoloRails
|
9
8
|
|
10
|
-
def
|
11
|
-
|
9
|
+
def show(id)
|
10
|
+
Catalogue.new.show(id)
|
12
11
|
end
|
13
12
|
|
13
|
+
def search(*args)
|
14
|
+
Catalogue.new.search(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
class Catalogue
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@site = "http://library.iser.essex.ac.uk/Library/WebServices/SoutronApi.svc/"
|
21
|
+
end
|
22
|
+
|
23
|
+
# returns SoloHash of values for individual catalogue record
|
24
|
+
def show(id)
|
25
|
+
id = id.to_i
|
26
|
+
response = SoloHash.new
|
27
|
+
url = "#{@site}getcatalogue?id=#{id}"
|
28
|
+
begin
|
29
|
+
soutron_data = Nokogiri::XML(open(url, :read_timeout => 180))
|
30
|
+
response[:id] = soutron_data.xpath("/soutron/catalogs_view/ct/cat").attribute("id").text
|
31
|
+
# response[:request_url] = url - removed for security/speed purposes - PG 2011-02-17
|
32
|
+
response[:content_type] = soutron_data.xpath("/soutron/catalogs_view/ct").attribute("name").text
|
33
|
+
response[:record_type] = soutron_data.xpath("/soutron/catalogs_view/ct/cat/rt").attribute("name").text
|
34
|
+
soutron_data.xpath("/soutron/catalogs_view/ct/cat/fs/f").each do |f|
|
35
|
+
if f.xpath("count(./vs/v)") > 0
|
36
|
+
response[uscore(f.attribute("name").text).to_sym] = parse_values(f.attribute("ft").text, f.xpath("./vs/v"))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# related records - PG 2011-03-01
|
40
|
+
if soutron_data.xpath("count(/soutron/catalogs_view/ct/cat/related_catalogs)") > 0
|
41
|
+
@related_records = []
|
42
|
+
soutron_data.xpath("/soutron/catalogs_view/ct/cat/related_catalogs/ct").each do |related_ct|
|
43
|
+
related_record = SoloHash.new
|
44
|
+
related_record.merge!( { "content_type".to_sym => related_ct.attribute("name").text } )
|
45
|
+
related_ct.xpath('ctlgs/cat').each do |r|
|
46
|
+
related_record.merge!( {"cid".to_sym => r.attribute("id").text } )
|
47
|
+
end
|
48
|
+
@related_records << related_record
|
49
|
+
end
|
50
|
+
response[:related_records] = @related_records
|
51
|
+
end
|
52
|
+
rescue
|
53
|
+
response = nil
|
54
|
+
end
|
55
|
+
return response
|
56
|
+
end
|
57
|
+
|
58
|
+
# returns nested hash record for given search - PG 2011-01-21
|
59
|
+
def search(*args)
|
60
|
+
build_query_url(args.pop)
|
61
|
+
begin
|
62
|
+
parse_results(Nokogiri::XML(open(url, :read_timeout => 180)))
|
63
|
+
rescue Exception => e
|
64
|
+
Rails.logger.info("SOLO Error in URL: " + url)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def build_query_url(*options)
|
71
|
+
q, ctrt, select, sort, page, material, search_id, per_page, ignore_is_website_feature = iser_solo_parse_options(options)
|
72
|
+
url = "#{@site}searchcatalogues?"
|
73
|
+
query_string = []
|
74
|
+
# If we have a value of search_id, then should only also pass: search_id, select, sort, page, per_page & material
|
75
|
+
if search_id.present?
|
76
|
+
query_string << "searchid=#{search_id}"
|
77
|
+
else
|
78
|
+
query_string << "q=#{q}"
|
79
|
+
query_string << "ctrt=#{ctrt}" if ctrt.present?
|
80
|
+
end
|
81
|
+
query_string << "page=#{page}" if page.present?
|
82
|
+
query_string << "pageSize=#{per_page}" if per_page.present?
|
83
|
+
query_string << "sort=#{sort}" if sort.present?
|
84
|
+
query_string << "fields=#{select}" if select.present?
|
85
|
+
query_string << "material=#{material}" if material.present?
|
86
|
+
url += query_string.join("&")
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_results(soutron_data)
|
90
|
+
response = SoloHash.new
|
91
|
+
meta = {:id => soutron_data.xpath("/soutron/search_info").attribute("id").text}
|
92
|
+
meta["total_items".to_sym] = soutron_data.xpath("/soutron/search_info").attribute("totalItems").text
|
93
|
+
meta["page".to_sym] = page
|
94
|
+
meta["per_page".to_sym] = per_page
|
95
|
+
meta["select".to_sym] = select
|
96
|
+
if soutron_data.xpath("count(//ct)") > 0
|
97
|
+
unless soutron_data.xpath("/soutron/search_info/catalogs_view/ct[*]").first.nil?
|
98
|
+
meta["active_content_type".to_sym] = soutron_data.xpath("/soutron/search_info/catalogs_view/ct[*]").first.attribute("name").text
|
99
|
+
meta["active_content_type_count".to_sym] = soutron_data.xpath("/soutron/search_info/catalogs_view/ct[*]").first.attribute("count").text
|
100
|
+
end
|
101
|
+
end
|
102
|
+
response.merge!("search_info".to_sym => meta)
|
103
|
+
@content_types = []
|
104
|
+
soutron_data.xpath("/soutron/search_info/catalogs_view/ct").each do |ct|
|
105
|
+
content_type = SoloHash.new
|
106
|
+
content_type.merge!( { "content_type".to_sym => ct.attribute("name").text } )
|
107
|
+
content_type.merge!( { "size".to_sym => ct.attribute("count").text } )
|
108
|
+
@records = []
|
109
|
+
ct.xpath("./ctlgs/cat").each do |cat|
|
110
|
+
record = SoloHash.new
|
111
|
+
record.merge!( {:id => cat.attribute("id").text, :record_type => cat.xpath("./rt").attribute("name").text} )
|
112
|
+
cat.xpath("./fs/f").each do |f|
|
113
|
+
if f.xpath("count(./vs/v)") > 0 # only include field if it has a value
|
114
|
+
record[uscore(f.attribute("name").text).to_sym] = parse_values(f.attribute("ft").text, f.xpath("./vs/v"))
|
115
|
+
end # / if has value
|
116
|
+
end # /f
|
117
|
+
@records << record
|
118
|
+
end # /cat
|
119
|
+
content_type.merge!({"records".to_sym => @records })
|
120
|
+
@content_types << content_type
|
121
|
+
end # /ct
|
122
|
+
response.merge!(:content_types => @content_types)
|
123
|
+
return response
|
124
|
+
end
|
125
|
+
|
126
|
+
# returns array of URL safe variables from options
|
127
|
+
def iser_solo_parse_options(options)
|
128
|
+
q = options[:q]
|
129
|
+
unless options[:ignore_is_website_feature] == true
|
130
|
+
q.nil? ? nil : q << ";Is Website Feature:Y"
|
131
|
+
end
|
132
|
+
ctrt = options[:ctrt]
|
133
|
+
select = options[:select]
|
134
|
+
sort = options[:sort]
|
135
|
+
page = options[:page]
|
136
|
+
material = options[:material]
|
137
|
+
search_id = options[:search_id]
|
138
|
+
per_page = options[:per_page].blank? ? 20 : options[:per_page]
|
139
|
+
url_safe([q, ctrt, select, sort, page, material, search_id, per_page])
|
140
|
+
end
|
141
|
+
|
142
|
+
# CGI escapes 'options' array to make safe URLs
|
143
|
+
def url_safe(options)
|
144
|
+
options.collect! { |option| CGI.escape(option.to_s) }
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns values for a field based on field type, either individual value or array
|
148
|
+
def parse_values(field_type, elements)
|
149
|
+
if elements.size > 1
|
150
|
+
value = elements.collect{|v| parse_value(field_type, v)}
|
151
|
+
else
|
152
|
+
value = parse_value(field_type, elements.first)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# returns value based on field type
|
157
|
+
# @field_types = {
|
158
|
+
# 1 => "Text",
|
159
|
+
# 2 => "Integer",
|
160
|
+
# 3 => "Date",
|
161
|
+
# 4 => "File",
|
162
|
+
# 5 => "Thesaurus",
|
163
|
+
# 6 => "Validation List",
|
164
|
+
# 7 => "URL",
|
165
|
+
# 8 => "Complex Date",
|
166
|
+
# 9 => "Decimal",
|
167
|
+
# 10 => "Image",
|
168
|
+
# 11 => "Rich Text",
|
169
|
+
# 12 => "User"
|
170
|
+
# }
|
171
|
+
def parse_value(field_type, element)
|
172
|
+
field_type = field_type.to_i
|
173
|
+
case field_type
|
174
|
+
when 1, 4, 5, 6, 11, 12 then element.text.to_s
|
175
|
+
when 2 then element.text.to_i
|
176
|
+
when 3 then Date.parse(element.text.to_s)
|
177
|
+
# when 3 then element.text.to_s
|
178
|
+
when 7 then
|
179
|
+
if element.attribute("desc").value.size > 0 && !element.attribute("desc").value.eql?(element.text.to_s)
|
180
|
+
# "#{element.attribute("desc")} - #{ActionController::Base.helpers.auto_link(element.text.to_s)}"
|
181
|
+
"#{element.attribute("desc")} - element.text.to_s)}"
|
182
|
+
else
|
183
|
+
# ActionController::Base.helpers.auto_link(element.text.to_s)
|
184
|
+
element.text.to_s
|
185
|
+
end
|
186
|
+
when 8 then parse_complex_date(element)
|
187
|
+
else field_type
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# attempts to make ruby Date or failsover to string from SOLO complex date field - PG 2011-04-08
|
192
|
+
def parse_complex_date(element)
|
193
|
+
d = element.text.split("-")
|
194
|
+
date = []
|
195
|
+
date << "%02d" % d[2] unless d[2].nil?
|
196
|
+
date << "%02d" % d[1] unless d[1].nil?
|
197
|
+
date << d[0] unless d[0].nil?
|
198
|
+
circa = "circa " if element.attribute("circa").to_s == "1"
|
199
|
+
nodate = "forthcoming " if element.attribute("nodate").to_s == "1"
|
200
|
+
ongoing = "ongoing" if element.attribute("ongoing").to_s == "1"
|
201
|
+
begin
|
202
|
+
ret = Date.parse("#{date[0]}-#{date[1]}-#{date[2]}")
|
203
|
+
rescue
|
204
|
+
ret = "#{circa}#{nodate}#{date.join("-")} #{ongoing}".capitalize.strip
|
205
|
+
end
|
206
|
+
ret
|
207
|
+
end
|
208
|
+
|
209
|
+
# removes spaces from 'str' and then 'borrows' rails underscore method
|
210
|
+
# converts strings like "Publication Date" into "publication_date"
|
211
|
+
def uscore(str)
|
212
|
+
word = str.gsub(/\s*/,"")
|
213
|
+
word = word.to_s.dup
|
214
|
+
word.gsub!(/::/, '/')
|
215
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
216
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
217
|
+
word.tr!("-", "_")
|
218
|
+
word.downcase!
|
219
|
+
word
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
# Allows object.fieldname searches, returning nil rather than exception if key does not exist - PG 2011-01-20
|
227
|
+
class SoloHash < Hash
|
228
|
+
def method_missing(method, *params)
|
229
|
+
method = method.to_sym
|
230
|
+
return self[method] if self.keys.collect(&:to_sym).include?(method)
|
231
|
+
nil
|
232
|
+
end
|
14
233
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solo-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-01-13 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70135075996920 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70135075996920
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: nokogiri
|
27
|
-
requirement: &
|
27
|
+
requirement: &70135075995560 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70135075995560
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: chronic
|
38
|
-
requirement: &
|
38
|
+
requirement: &70135075994020 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70135075994020
|
47
47
|
description: Provides methods to query Soutron Solo catalog from Ruby
|
48
48
|
email:
|
49
49
|
- github@modagoo.co.uk
|
@@ -53,8 +53,10 @@ extra_rdoc_files: []
|
|
53
53
|
files:
|
54
54
|
- .gitignore
|
55
55
|
- Gemfile
|
56
|
+
- README
|
56
57
|
- Rakefile
|
57
58
|
- lib/solo-rails.rb
|
59
|
+
- lib/solo-rails/helpers.rb
|
58
60
|
- lib/solo-rails/version.rb
|
59
61
|
- solo-rails.gemspec
|
60
62
|
homepage: ''
|