Class: BorrowDirect::GenerateQuery

Inherits:
Object
  • Object
show all
Defined in:
lib/borrow_direct/generate_query.rb

Overview

Generate a “deep link” to query results in BD’s native HTML interface.

Constant Summary collapse

@@fields =

Hash from our own API argument to BD field code

{
  :keyword  => "term",
  :title    => "ti",
  :author   => "au",
  :subject  => "su",
  :isbn     => "isbn",
  :issn     => "issn"
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url_base = nil) ⇒ GenerateQuery

Returns a new instance of GenerateQuery.



19
20
21
# File 'lib/borrow_direct/generate_query.rb', line 19

def initialize(url_base = nil)
  self.url_base = (url_base || BorrowDirect::Defaults.html_base_url)
end

Instance Attribute Details

#url_baseObject

Returns the value of attribute url_base.



7
8
9
# File 'lib/borrow_direct/generate_query.rb', line 7

def url_base
  @url_base
end

Class Method Details

.escape(str) ⇒ Object

Escape a query value. We don’t really know how to escape, for now we just remove double quotes and parens, and replace with spaces. those seem to cause problems, and that seems to work.



151
152
153
# File 'lib/borrow_direct/generate_query.rb', line 151

def self.escape(str)
  str.gsub(/[")()]/, ' ')
end

Instance Method Details

#add_query_param(uri, key, value) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/borrow_direct/generate_query.rb', line 159

def add_query_param(uri, key, value)
  uri = URI.parse(uri) unless uri.kind_of? URI

  query_param = "#{CGI.escape key}=#{CGI.escape value}"

  if uri.query
    uri.query += "&" + query_param
  else
    uri.query = query_param
  end
  
  return uri
end

#build_query_with(options) ⇒ Object

build_query_with(:title => “one two”, :author => “three four”) valid keys are those supported by BD HTML interface:

:title, :author, :isbn, :subject, :keyword, :isbn, :issn

For now, the value is always searched as a phrase, and multiple fields are always ‘and’d. We may enhance/expand later.

Returns an un-escaped query, still needs to be put into a URL



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/borrow_direct/generate_query.rb', line 31

def build_query_with(options)
  clauses = []

  options.each_pair do |field, value|
    next if value.nil?

    code = @@fields[field]

    raise ArgumentError.new("Don't recognize field code `#{field}`") unless code

    clauses << %Q{#{code}="#{escape value}"}
  end

  return clauses.join(" and ")
end

#escape(str) ⇒ Object

Instance method version for convenience.



155
156
157
# File 'lib/borrow_direct/generate_query.rb', line 155

def escape(str)
  self.class.escape(str)
end

#normalized_author(author) ⇒ Object

Lowercase, and try to get just the last name out of something that looks like a cataloging authorized heading.



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/borrow_direct/generate_query.rb', line 133

def normalized_author(author)
  return "" if author.nil? || author.empty?

  author = author.downcase
  # Just take everything before the comma if we have one
  if author =~ /\A(.*),/
    author = $1
  end

  return author
end

#normalized_author_title_params(options) ⇒ Object

Give it a :title and optionally an :author, we’ll normalize them to our suggestion for a good BD author-title keyword search. Returns a hash suitable for passing to #query_url_with

Additional option :max_title_words, default 5.

Raises:

  • (ArgumentError)


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/borrow_direct/generate_query.rb', line 60

def normalized_author_title_params(options)
  raise ArgumentError.new("Need a Hash argument, got #{options.inspect}") unless options.kind_of?(Hash)

  # Symbolize keys please
  #options = options.inject({}){ |h, (k, v)| hash.merge( (k.respond_to?(:to_sym) ? k.to_sym : k) => v )  }

  title           = options[:title].dup  if options[:title]
  author          = options[:author].dup if options[:author]

  
  title  = normalized_title(title, :max_title_words => options[:max_title_words])
  author = normalized_author(author)

  results = {}
  results[:title] = title if title && ! title.empty?
  results[:author] = author if author && ! author.empty?
  
  return results
end

#normalized_author_title_query(options) ⇒ Object

:title, :author and optionally :max_title_words.

Returns a query with a suggested normalized author and title for best BD search. May return just BD base URL if no author/title given.



85
86
87
# File 'lib/borrow_direct/generate_query.rb', line 85

def normalized_author_title_query(options)
  return self.query_url_with self.normalized_author_title_params(options)
end

#normalized_title(title, args = {}) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/borrow_direct/generate_query.rb', line 89

def normalized_title(title, args = {})
  return "" if title.nil? || title.empty?

  max_title_words = args[:max_title_words] || 5
 
  # Remove all things in parens at the END of the title, they tend
  # to be weird addendums. 
  title.gsub!(/\([^)]*\)\s*$/, '')

  # Strip the subtitle or other weird titles, just keep the text
  # before the first colon OR semi-colon
  title.sub!(/[\:\;](.*)$/, '')


  # We want to remove anything that isn't a letter, number, or apostrophe.
  # Other punctuation and weird chars don't help our query.
  # We want to do it in a way that's unicode-aware.
  #
  # This is harder than expected, as ruby regex unicode-aware character
  # classes don't seem to handle combining diacritics well.
  #
  # This crazy way does it, replace anything that matches unicode
  # space (may include more than just ascii ' ') or punct class, unless 
  # it's an apostrophe or an ampersand, which are allowed --
  # and replaces them with plain ascii space.
  title.gsub!(/[[:space:][:punct:]&&[^\'\&]]/, ' ')

  # compress any remaining whitespace
  title.strip!
  title.gsub!(/\s+/, ' ')

  # downcase
  title.downcase!

  # Limit to only first N words
  if max_title_words && title.index(/((.+?[ ,.:\;]+){#{max_title_words}})/)
    title = title.slice(0, $1.length).gsub(/[ ,.:\;]+$/, '')
  end

  return title
end

#query_url_with(arg) ⇒ Object



49
50
51
52
53
# File 'lib/borrow_direct/generate_query.rb', line 49

def query_url_with(arg)
  query = arg.kind_of?(Hash) ? build_query_with(arg) : arg.to_s
  
  return add_query_param(self.url_base, "query", query).to_s
end