blacklight 3.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.gitmodules +6 -0
- data/.yardopts +4 -0
- data/Gemfile +4 -0
- data/LICENSE +14 -0
- data/README.rdoc +168 -0
- data/Rakefile +9 -0
- data/app/controllers/bookmarks_controller.rb +98 -0
- data/app/controllers/feedback_controller.rb +37 -0
- data/app/controllers/folder_controller.rb +49 -0
- data/app/controllers/saved_searches_controller.rb +45 -0
- data/app/controllers/search_history_controller.rb +25 -0
- data/app/helpers/blacklight_helper.rb +606 -0
- data/app/helpers/bookmarks_helper.rb +3 -0
- data/app/helpers/catalog_helper.rb +65 -0
- data/app/helpers/feedback_helper.rb +2 -0
- data/app/helpers/hash_as_hidden_fields.rb +57 -0
- data/app/helpers/render_constraints_helper.rb +120 -0
- data/app/helpers/saved_searches_helper.rb +2 -0
- data/app/helpers/search_history_helper.rb +2 -0
- data/app/models/bookmark.rb +6 -0
- data/app/models/record_mailer.rb +43 -0
- data/app/models/search.rb +19 -0
- data/app/views/_flash_msg.html.erb +6 -0
- data/app/views/_user_util_links.html.erb +13 -0
- data/app/views/bookmarks/index.html.erb +33 -0
- data/app/views/catalog/_bookmark_control.html.erb +25 -0
- data/app/views/catalog/_bookmark_form.html.erb +8 -0
- data/app/views/catalog/_citation.html.erb +15 -0
- data/app/views/catalog/_constraints.html.erb +7 -0
- data/app/views/catalog/_constraints_element.html.erb +33 -0
- data/app/views/catalog/_did_you_mean.html.erb +10 -0
- data/app/views/catalog/_document_list.html.erb +30 -0
- data/app/views/catalog/_email_form.html.erb +11 -0
- data/app/views/catalog/_facet_limit.html.erb +33 -0
- data/app/views/catalog/_facet_pagination.html.erb +28 -0
- data/app/views/catalog/_facets.html.erb +9 -0
- data/app/views/catalog/_folder_control.html.erb +12 -0
- data/app/views/catalog/_home.html.erb +6 -0
- data/app/views/catalog/_home_text.html.erb +6 -0
- data/app/views/catalog/_index_partials/_default.erb +11 -0
- data/app/views/catalog/_marc_view.html.erb +33 -0
- data/app/views/catalog/_opensearch_response_metadata.html.erb +3 -0
- data/app/views/catalog/_previous_next_doc.html.erb +6 -0
- data/app/views/catalog/_refworks_form.html.erb +7 -0
- data/app/views/catalog/_results_pagination.html.erb +11 -0
- data/app/views/catalog/_search_form.html.erb +14 -0
- data/app/views/catalog/_show_partials/_default.html.erb +9 -0
- data/app/views/catalog/_show_sidebar.html.erb +1 -0
- data/app/views/catalog/_show_tools.html.erb +46 -0
- data/app/views/catalog/_sms_form.html.erb +23 -0
- data/app/views/catalog/_solr_request.html.erb +5 -0
- data/app/views/catalog/_sort_and_per_page.html.erb +20 -0
- data/app/views/catalog/_unapi_microformat.html.erb +1 -0
- data/app/views/catalog/citation.html.erb +1 -0
- data/app/views/catalog/email.erb +1 -0
- data/app/views/catalog/endnote.endnote.erb +1 -0
- data/app/views/catalog/facet.html.erb +28 -0
- data/app/views/catalog/index.atom.builder +108 -0
- data/app/views/catalog/index.html.erb +37 -0
- data/app/views/catalog/index.rss.builder +19 -0
- data/app/views/catalog/librarian_view.html.erb +3 -0
- data/app/views/catalog/opensearch.json.erb +0 -0
- data/app/views/catalog/opensearch.xml.erb +11 -0
- data/app/views/catalog/send_email_record.erb +0 -0
- data/app/views/catalog/show.endnote.erb +1 -0
- data/app/views/catalog/show.html.erb +42 -0
- data/app/views/catalog/show.refworks.erb +1 -0
- data/app/views/catalog/sms.erb +1 -0
- data/app/views/catalog/unapi.xml.builder +6 -0
- data/app/views/feedback/complete.html.erb +3 -0
- data/app/views/feedback/show.html.erb +20 -0
- data/app/views/folder/_tools.html.erb +23 -0
- data/app/views/folder/index.html.erb +44 -0
- data/app/views/layouts/blacklight.html.erb +49 -0
- data/app/views/record_mailer/email_record.erb +6 -0
- data/app/views/record_mailer/sms_record.erb +4 -0
- data/app/views/saved_searches/index.html.erb +27 -0
- data/app/views/search_history/index.html.erb +23 -0
- data/blacklight.gemspec +50 -0
- data/config.ru +4 -0
- data/config/routes.rb +54 -0
- data/db/seeds.rb +7 -0
- data/features/generators.feature +77 -0
- data/features/support/aruba.rb +9 -0
- data/install.rb +0 -0
- data/install/solr.yml +8 -0
- data/lib/blacklight.rb +121 -0
- data/lib/blacklight/catalog.rb +311 -0
- data/lib/blacklight/comma_link_renderer.rb +27 -0
- data/lib/blacklight/configurable.rb +46 -0
- data/lib/blacklight/controller.rb +121 -0
- data/lib/blacklight/engine.rb +32 -0
- data/lib/blacklight/exceptions.rb +13 -0
- data/lib/blacklight/marc.rb +46 -0
- data/lib/blacklight/marc/citation.rb +251 -0
- data/lib/blacklight/search_fields.rb +107 -0
- data/lib/blacklight/solr.rb +7 -0
- data/lib/blacklight/solr/document.rb +239 -0
- data/lib/blacklight/solr/document/dublin_core.rb +40 -0
- data/lib/blacklight/solr/document/email.rb +15 -0
- data/lib/blacklight/solr/document/marc.rb +84 -0
- data/lib/blacklight/solr/document/marc_export.rb +430 -0
- data/lib/blacklight/solr/document/sms.rb +13 -0
- data/lib/blacklight/solr/facet_paginator.rb +93 -0
- data/lib/blacklight/solr_helper.rb +413 -0
- data/lib/blacklight/user.rb +55 -0
- data/lib/blacklight/version.rb +3 -0
- data/lib/colorize.rb +196 -0
- data/lib/generators/blacklight/blacklight_generator.rb +134 -0
- data/lib/generators/blacklight/templates/SolrMarc.jar +0 -0
- data/lib/generators/blacklight/templates/catalog_controller.rb +8 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/config-test.properties +37 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/config.properties +37 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/index.properties +97 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/index_scripts/dewey.bsh +47 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/index_scripts/format.bsh +126 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/translation_maps/README_MAPS +1 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/translation_maps/callnumber_map.properties +407 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/translation_maps/composition_era_map.properties +56 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/translation_maps/country_map.properties +379 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/translation_maps/format_map.properties +50 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/translation_maps/instrument_map.properties +101 -0
- data/lib/generators/blacklight/templates/config/SolrMarc/translation_maps/language_map.properties +490 -0
- data/lib/generators/blacklight/templates/config/blacklight_config.rb +245 -0
- data/lib/generators/blacklight/templates/config/solr.yml +6 -0
- data/lib/generators/blacklight/templates/migrations/add_user_types_to_bookmarks_searches.rb +11 -0
- data/lib/generators/blacklight/templates/migrations/create_bookmarks.rb +17 -0
- data/lib/generators/blacklight/templates/migrations/create_searches.rb +15 -0
- data/lib/generators/blacklight/templates/migrations/remove_editable_fields_from_bookmarks.rb +11 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/bg.png +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/border.png +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/bul_sq_gry.gif +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/checkmark.gif +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/logo.png +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/magnifying_glass.gif +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/remove.gif +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/separator.gif +0 -0
- data/lib/generators/blacklight/templates/public/images/blacklight/start_over.gif +0 -0
- data/lib/generators/blacklight/templates/public/javascripts/blacklight.js +485 -0
- data/lib/generators/blacklight/templates/public/javascripts/jquery-1.4.2.min.js +154 -0
- data/lib/generators/blacklight/templates/public/javascripts/jquery-ui-1.8.1.custom.min.js +756 -0
- data/lib/generators/blacklight/templates/public/stylesheets/blacklight.css +487 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_gloss-wave_35_558fd0_500x100.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-icons_2e4f81_256x240.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/generators/blacklight/templates/public/stylesheets/jquery/ui-lightness/jquery-ui-1.8.1.custom.css +486 -0
- data/lib/generators/blacklight/templates/public/stylesheets/yui.css +31 -0
- data/lib/generators/blacklight/templates/solr_document.rb +30 -0
- data/lib/railties/blacklight.rake +66 -0
- data/lib/railties/cucumber.rake +53 -0
- data/lib/railties/rspec.rake +188 -0
- data/lib/railties/solr_marc.rake +148 -0
- data/lib/railties/test_solr_server.rb +130 -0
- data/spec/helpers/catalog_helper_spec.rb +111 -0
- data/spec/views/catalog/_sms_form.html.erb_spec.rb +19 -0
- data/tasks/blacklight_tasks.rake +4 -0
- data/uninstall.rb +1 -0
- metadata +431 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
##
|
2
|
+
# Module to deal with accessing (and setting some defaults) in an array of
|
3
|
+
# hashes that describe Blacklight search fields. Requires the base class this
|
4
|
+
# module is added to implements a #config method that returns a hash, where
|
5
|
+
# config[:search_fields] will be an array of hashes describing search fields.
|
6
|
+
#
|
7
|
+
# = Search Field Configuration Hash =
|
8
|
+
# [:key]
|
9
|
+
# "title", required, unique key used in search URLs to specify search_field
|
10
|
+
# [:display_label]
|
11
|
+
# "Title", # user-displayable label, optional, if not supplied :key.titlecase will be used
|
12
|
+
# [:qt]
|
13
|
+
# "search", # Solr qt param, request handler, usually can be left blank; defaults to Blacklight.config[:default_solr_params][:qt] if not specified.
|
14
|
+
# [:solr_parameters]
|
15
|
+
# {:qf => "something"} # optional hash of additional parameters to pass to solr for searches on this field.
|
16
|
+
# [:solr_local_parameters]
|
17
|
+
# {:qf => "$something"} # optional hash of additional parameters that will be passed using Solr LocalParams syntax, that can use dollar sign to reference other solr variables.
|
18
|
+
# [:include_in_simple_select]
|
19
|
+
# false. Defaults to true, but you can set to false to have a search field defined for deep-links or BL extensions, but not actually included in the HTML select for simple search choice.
|
20
|
+
#
|
21
|
+
# Optionally you can supply a :key, which is what Blacklight will use
|
22
|
+
# to identify this search field in HTTP query params. If no :key is
|
23
|
+
# supplied, one will be computed from the :display_label. If that will
|
24
|
+
# result in a collision of keys, you should supply one explicitly.
|
25
|
+
#
|
26
|
+
##
|
27
|
+
module Blacklight::SearchFields
|
28
|
+
extend ActiveSupport::Memoizable
|
29
|
+
|
30
|
+
# Looks up search field config list from config[:search_fields], and
|
31
|
+
# 'normalizes' all field config hashes using normalize_config method.
|
32
|
+
# Memoized for efficiency of normalization.
|
33
|
+
def search_field_list
|
34
|
+
normalized = config[:search_fields].collect {|obj| normalize_config(obj)}
|
35
|
+
|
36
|
+
if (duplicates = normalized.collect{|h| h[:key]}.uniq!)
|
37
|
+
raise "Duplicate keys found in search_field config: #{duplicates.inspect}"
|
38
|
+
end
|
39
|
+
|
40
|
+
normalized
|
41
|
+
end
|
42
|
+
memoize :search_field_list
|
43
|
+
|
44
|
+
# Returns suitable argument to options_for_select method, to create
|
45
|
+
# an html select based on #search_field_list. Skips search_fields
|
46
|
+
# marked :include_in_simple_select => false
|
47
|
+
def search_field_options_for_select
|
48
|
+
search_field_list.collect do |field_def|
|
49
|
+
[field_def[:display_label], field_def[:key]] unless field_def[:include_in_simple_select] == false
|
50
|
+
end.compact
|
51
|
+
end
|
52
|
+
|
53
|
+
# Looks up a search field config hash from search_field_list having
|
54
|
+
# a certain supplied :key.
|
55
|
+
def search_field_def_for_key(key)
|
56
|
+
return nil if key.blank?
|
57
|
+
search_field_list.find {|c| c[:key] == key}
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns default search field, used for simpler display in history, etc.
|
61
|
+
# if not set in config, defaults to first field listed in #search_field_list
|
62
|
+
def default_search_field
|
63
|
+
config[:default_search_field] || search_field_list[0]
|
64
|
+
end
|
65
|
+
memoize :default_search_field
|
66
|
+
|
67
|
+
# Shortcut for commonly needed operation, look up display
|
68
|
+
# label for the key specified. Returns "Keyword" if a label
|
69
|
+
# can't be found.
|
70
|
+
def label_for_search_field(key)
|
71
|
+
field_def = search_field_def_for_key(key)
|
72
|
+
if field_def && field_def[:display_label]
|
73
|
+
field_def[:display_label]
|
74
|
+
else
|
75
|
+
"Keyword"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
# Fill in missing default values in a search_field config hash.
|
81
|
+
def normalize_config(field_hash)
|
82
|
+
|
83
|
+
|
84
|
+
# Accept legacy two-element array, if it's not a Hash, assume it's legacy.
|
85
|
+
# No great way to 'duck type' here.
|
86
|
+
unless ( field_hash.kind_of?(Hash))
|
87
|
+
# Consistent with legacy behavior where two fields can have the same label,
|
88
|
+
# as long as they have different qt's, we base the unique :key on :qt.
|
89
|
+
field_hash = {:display_label => field_hash[0], :key => field_hash[1], :qt => field_hash[1]}
|
90
|
+
else
|
91
|
+
# Make a copy of passed in Hash so we don't alter original.
|
92
|
+
field_hash = field_hash.clone
|
93
|
+
end
|
94
|
+
|
95
|
+
raise Exception.new("Search field config is missing ':key' => #{field_hash.inspect}") unless field_hash[:key]
|
96
|
+
|
97
|
+
# If no display_label was provided, turn the :key into one.
|
98
|
+
field_hash[:display_label] ||= field_hash[:key].titlecase
|
99
|
+
|
100
|
+
# If no :qt was provided, take from config default
|
101
|
+
field_hash[:qt] ||= config[:default_solr_params][:qt] if config[:default_solr_params]
|
102
|
+
|
103
|
+
field_hash
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'rsolr'
|
2
|
+
require 'rsolr-ext'
|
3
|
+
##
|
4
|
+
##
|
5
|
+
# = Introduction
|
6
|
+
# Blacklight::Solr::Document is the module with logic for a class representing
|
7
|
+
# an individual document returned from Solr results. It can be added in to any
|
8
|
+
# local class you want, but in default Blacklight a SolrDocument class is
|
9
|
+
# provided for you which is pretty much a blank class "include"ing
|
10
|
+
# Blacklight::Solr::Document.
|
11
|
+
#
|
12
|
+
# Blacklight::Solr::Document mixes in Rsolr::Ext::Model to the calling class.
|
13
|
+
# It also provides some DefaultFinders.
|
14
|
+
#
|
15
|
+
# It also provides support for Document Extensions, which advertise supported
|
16
|
+
# transformation formats.
|
17
|
+
#
|
18
|
+
# = Document Extensions
|
19
|
+
# An Blacklight::Solr::Document extension is simply a ruby module which is mixed
|
20
|
+
# in to individual Document instances. The intended use case is for documents
|
21
|
+
# containing some particular format of source material, such as Marc. An
|
22
|
+
# extension can be registered with your document class, along with a block
|
23
|
+
# containing custom logic for which documents to apply the extension to.
|
24
|
+
#
|
25
|
+
# SolrDocument.use_extension(MyExtension) {|document| my_logic_on_document(document}
|
26
|
+
#
|
27
|
+
# MyExtension will be mixed-in (using ruby 'extend') only to those documents
|
28
|
+
# where the block results in true.
|
29
|
+
#
|
30
|
+
# == Transformation conventions
|
31
|
+
# The main use case for extensions is for transforming a Document to another
|
32
|
+
# format. Either to another type of Ruby object, or to an exportable string in
|
33
|
+
# a certain format.
|
34
|
+
#
|
35
|
+
# The convention for methods contained in extensions that transform to a ruby
|
36
|
+
# object is "to_*". For instance, "to_marc" would return a Ruby Marc object.
|
37
|
+
#
|
38
|
+
# The convention for methods contained in extensions that transform to an
|
39
|
+
# exportable file of some kind is "export_as_*". For instance,
|
40
|
+
# "export_as_marc21" would return a String object containing valid marc21, and
|
41
|
+
# "export_as_marcxml" would return a String object containing valid marcxml.
|
42
|
+
#
|
43
|
+
# The tokens used after "export_as" should normally be the format names as
|
44
|
+
# registered with Rails Mime::Type.
|
45
|
+
#
|
46
|
+
# == Advertising export formats
|
47
|
+
#
|
48
|
+
# If an extension advertises what export formats it can provide, than those
|
49
|
+
# formats will automatically be delivered by the Blacklight catalog/show
|
50
|
+
# controller, and potentially automatically advertised in various places
|
51
|
+
# that advertise available formats. (UnAPI; HTML link rel=alternate; Atom
|
52
|
+
# link rel=alterate; etc).
|
53
|
+
#
|
54
|
+
# Export formats are 'registered' by calling the #will_export_as method
|
55
|
+
# on a Document instance. An extension would usually do this in a
|
56
|
+
# self.extended method, so it can be called on Documents that have
|
57
|
+
# the given extension added to them. For instance:
|
58
|
+
#
|
59
|
+
# module DemoMarcExtension
|
60
|
+
# def self.extended(document)
|
61
|
+
# document.will_export_as(:marc21, "application/marc")
|
62
|
+
# document.will_export_as(:marcxml, "application/marcxml+xml")
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# def export_as_marc21 ; something ; end
|
66
|
+
# def export_as_marcxml ; something ; end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# == Extension Parameters
|
70
|
+
# Every class that includes Blacklight::Solr::Document gets a
|
71
|
+
# #extension_parameters method for saving arbitrary parameters on class-wide
|
72
|
+
# level that can be retrieved by extensions. These are arbitrary, just
|
73
|
+
# conventions with a given extension. For instance:
|
74
|
+
# SolrDocument.extension_parameters[:marc_source_field] = "solr_stored_field_name"
|
75
|
+
#
|
76
|
+
module Blacklight::Solr::Document
|
77
|
+
autoload :Marc, 'blacklight/solr/document/marc'
|
78
|
+
autoload :MarcExport, 'blacklight/solr/document/marc_export'
|
79
|
+
autoload :DublinCore, 'blacklight/solr/document/dublin_core'
|
80
|
+
autoload :Email, 'blacklight/solr/document/email'
|
81
|
+
autoload :Sms, 'blacklight/solr/document/sms'
|
82
|
+
|
83
|
+
def self.included(base)
|
84
|
+
base.send :include, RSolr::Ext::Model
|
85
|
+
base.send :extend, ClassMethods
|
86
|
+
|
87
|
+
# after_initialize hook comes from RSolr::Ext::Model, I think.
|
88
|
+
# We need to make sure all extensions get applied.
|
89
|
+
base.after_initialize do
|
90
|
+
apply_extensions
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Needs to be called in initializer of class including this module, to
|
96
|
+
# apply all registered extensions on a per-document basis
|
97
|
+
def apply_extensions
|
98
|
+
self.class.registered_extensions.each do | registration|
|
99
|
+
self.extend( registration[:module_obj] ) if registration[:condition_proc].nil? || registration[:condition_proc].call( self )
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Register exportable formats supported by the individual document.
|
105
|
+
# Usually called by an extension in it's self.extended method, to
|
106
|
+
# register the formats that extension can export.
|
107
|
+
#
|
108
|
+
# some_document.will_export_as(:some_format, "application/type") means
|
109
|
+
# that the document (usually via an extension) has a method
|
110
|
+
# "export_as_some_format" which returns a String of content that
|
111
|
+
# is described by the mime content_type given.
|
112
|
+
#
|
113
|
+
# The format name should ideally _already_ be registered with
|
114
|
+
# Rails Mime::Type, in your application initializer, representing
|
115
|
+
# the content type given. However, this method will attempt to
|
116
|
+
# register it using Mime::Type.register_alias if it's not previously
|
117
|
+
# registered. This is a bit sketchy though.
|
118
|
+
def will_export_as(short_name, content_type = nil)
|
119
|
+
#Lookup in Rails Mime::Type, register if needed, otherwise take
|
120
|
+
# content-type from registration if needed. This uses
|
121
|
+
# some 'api' to Mime::Type that may or may not be entirely
|
122
|
+
# public, the fact that a Mime::CONST is registered for every
|
123
|
+
# type. But that's the only way to do the kind of check we need, sorry.
|
124
|
+
begin
|
125
|
+
mime_type = "Mime::#{short_name.to_s.upcase}".constantize
|
126
|
+
content_type = mime_type.to_s unless content_type
|
127
|
+
rescue NameError
|
128
|
+
# not registered, we need to register. Use register_alias to be least
|
129
|
+
# likely to interfere with host app.
|
130
|
+
Mime::Type.register_alias(content_type, short_name)
|
131
|
+
end
|
132
|
+
|
133
|
+
# if content_type is nil, look it up from Rails Mime::Type
|
134
|
+
if content_type.nil?
|
135
|
+
# Accurate lookup in Rails Mime::Type is kind of pain, it doesn't
|
136
|
+
# really provide the right API.
|
137
|
+
if defined?(type_const_name)
|
138
|
+
content_type = type_const_name.constantize.to_s
|
139
|
+
end
|
140
|
+
end
|
141
|
+
export_formats[short_name] = {:content_type => content_type}
|
142
|
+
end
|
143
|
+
|
144
|
+
# Collects formats that this doc can export as.
|
145
|
+
# Returns a hash, keys are format short-names that can
|
146
|
+
# be exported. Hash includes:
|
147
|
+
# :content-type => mime-content-type
|
148
|
+
# maybe more later
|
149
|
+
# To see if a given export format is supported by this document,
|
150
|
+
# simply call document.export_formats.keys.include?(:my_format)
|
151
|
+
# Then call #export_as! to do the export.
|
152
|
+
def export_formats
|
153
|
+
@export_formats ||= {}
|
154
|
+
end
|
155
|
+
|
156
|
+
# Call with a format shortname, export_as(:marc), simply returns
|
157
|
+
# #export_as_marc . Later we may expand the design to allow you
|
158
|
+
# to register an arbitrary method name instead of insisting
|
159
|
+
# on the convention, so clients should call this method so
|
160
|
+
# they'll still keep working if we do that.
|
161
|
+
def export_as(short_name)
|
162
|
+
send("export_as_#{short_name.to_s}")
|
163
|
+
end
|
164
|
+
|
165
|
+
# Returns a hash keyed by semantic tokens (see ExtendableClassMethods#semantic_fields), value is an array of
|
166
|
+
# strings. (Array to handle multi-value fields). If no value(s)
|
167
|
+
# available, empty array is returned.
|
168
|
+
#
|
169
|
+
# Default implementation here uses ExtendableClassMethods#semantic_fields
|
170
|
+
# to just take values from Solr stored fields.
|
171
|
+
# Extensions can over-ride this method to provide better/different lookup,
|
172
|
+
# but extensions should call super and modify hash returned, to avoid
|
173
|
+
# unintentionally erasing values provided by other extensions.
|
174
|
+
def to_semantic_values
|
175
|
+
unless @semantic_value_hash
|
176
|
+
@semantic_value_hash = Hash.new([]) # default to empty array
|
177
|
+
self.class.field_semantics.each_pair do |key, solr_field|
|
178
|
+
value = self[solr_field]
|
179
|
+
# Make single and multi-values all arrays, so clients
|
180
|
+
# don't have to know.
|
181
|
+
unless value.nil?
|
182
|
+
value = [value] unless value.kind_of?(Array)
|
183
|
+
@semantic_value_hash[key] = value
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
return @semantic_value_hash
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
# Certain class-level methods needed for the document-specific
|
192
|
+
# extendability architecture
|
193
|
+
module ClassMethods
|
194
|
+
attr_writer :registered_extensions
|
195
|
+
|
196
|
+
# Returns array of hashes of registered extensions. Each hash
|
197
|
+
# has a :module_obj key and a :condition_proc key. Usually this
|
198
|
+
# method is only used internally in #apply_extensions, but if you
|
199
|
+
# want to zero out all previously registered extensions you can call:
|
200
|
+
# SolrDocument.registered_extensions = nil
|
201
|
+
def registered_extensions
|
202
|
+
@registered_extensions ||= []
|
203
|
+
end
|
204
|
+
|
205
|
+
def extension_parameters
|
206
|
+
@extension_parameters ||= {}
|
207
|
+
end
|
208
|
+
|
209
|
+
# Register an extension module with the class. A block taking one
|
210
|
+
# parameter can be supplied; the block will be passed an instance of
|
211
|
+
# a Document, and the extension will be applied only if the block
|
212
|
+
# evaluates as true. If no condition is given, the extension will
|
213
|
+
# be applied to every instance of the class.
|
214
|
+
#
|
215
|
+
# SolrDocument.use_extension( SomeExtensionModule ) { | document | should_apply_some_extension?(document) }
|
216
|
+
# SolrDocument.use_extension( SomeExtensionModule) # will be applied to all docs
|
217
|
+
def use_extension( module_obj, &condition )
|
218
|
+
registered_extensions << {:module_obj => module_obj, :condition_proc => condition}
|
219
|
+
end
|
220
|
+
|
221
|
+
# Class-level method for accessing/setting semantic mappings
|
222
|
+
# for solr stored fields. Can be set by local app, key is
|
223
|
+
# a symbol for a semantic, value is a solr _stored_ field.
|
224
|
+
#
|
225
|
+
# Stored field can be single or multi-value. In some cases
|
226
|
+
# clients may only use the first value from a multi-value field.
|
227
|
+
#
|
228
|
+
# Currently documented semantic tokens, not all may be
|
229
|
+
# used by core BL, but some may be used by plugins present
|
230
|
+
# or future.
|
231
|
+
# :title, :author, :year, :language => User-presentable strings.
|
232
|
+
def field_semantics
|
233
|
+
@field_semantics ||= {}
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
|
239
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
# This module provide Dublin Core export based on the document's semantic values
|
4
|
+
module Blacklight::Solr::Document::DublinCore
|
5
|
+
def self.extended(document)
|
6
|
+
# Register our exportable formats
|
7
|
+
Blacklight::Solr::Document::DublinCore.register_export_formats( document )
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.register_export_formats(document)
|
11
|
+
document.will_export_as(:xml)
|
12
|
+
document.will_export_as(:dc_xml, "text/xml")
|
13
|
+
document.will_export_as(:oai_dc_xml, "text/xml")
|
14
|
+
end
|
15
|
+
|
16
|
+
def dublin_core_field_names
|
17
|
+
[:contributor, :coverage, :creator, :date, :description, :format, :identifier, :language, :publisher, :relation, :rights, :source, :subject, :title, :type]
|
18
|
+
end
|
19
|
+
|
20
|
+
# dublin core elements are mapped against the #dublin_core_field_names whitelist.
|
21
|
+
def export_as_oai_dc_xml
|
22
|
+
xml = Builder::XmlMarkup.new
|
23
|
+
xml.tag!("oai_dc:dc",
|
24
|
+
'xmlns:oai_dc' => "http://www.openarchives.org/OAI/2.0/oai_dc/",
|
25
|
+
'xmlns:dc' => "http://purl.org/dc/elements/1.1/",
|
26
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
27
|
+
'xsi:schemaLocation' => %{http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd}) do
|
28
|
+
self.to_semantic_values.select { |field, values| dublin_core_field_names.include? field.to_sym }.each do |field,values|
|
29
|
+
values.each do |v|
|
30
|
+
xml.tag! 'dc:' + field.to_s, v
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
xml.target!
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :export_as_xml, :export_as_oai_dc_xml
|
38
|
+
alias_method :export_as_dc_xml, :export_as_oai_dc_xml
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# This module provides the body of an email export based on the document's semantic values
|
2
|
+
module Blacklight::Solr::Document::Email
|
3
|
+
|
4
|
+
# Return a text string that will be the body of the email
|
5
|
+
def to_email_text
|
6
|
+
semantics = self.to_semantic_values
|
7
|
+
body = ""
|
8
|
+
body << "Title: #{semantics[:title].join(" ")}\n" unless semantics[:title].blank?
|
9
|
+
body << "Author: #{semantics[:author].join(" ")}\n" unless semantics[:author].blank?
|
10
|
+
body << "Format: #{semantics[:format].join(" ")}\n" unless semantics[:format].blank?
|
11
|
+
body << "Language: #{semantics[:language].join(" ")}" unless semantics[:language].blank?
|
12
|
+
return body unless body.blank?
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
|
2
|
+
# This is a document extension meant to be mixed into a
|
3
|
+
# Blacklight::Solr::Document class, such as SolrDocument. It provides support
|
4
|
+
# for restoration of MARC data (xml or binary) from a Solr stored field, and
|
5
|
+
# then provides various transformations/exports of that Marc via the included
|
6
|
+
# Blacklight::Solr::Document::MarcExport module.
|
7
|
+
#
|
8
|
+
# This extension would normally be registered using
|
9
|
+
# Blacklight::Solr::Document#use_extension. eg:
|
10
|
+
#
|
11
|
+
# SolrDocument.use_extension( Blacklight::Solr::Document::Marc ) { |document| my_logic_for_document_has_marc?( document ) }
|
12
|
+
#
|
13
|
+
# This extension also expects a :marc_source_field and :marc_format_type to
|
14
|
+
# be registered with the hosting classes extension_parameters. In an initializer
|
15
|
+
# or other startup code:
|
16
|
+
# SolrDocument.extension_paramters[:marc_source_field] = "name_of_solr_stored_field"
|
17
|
+
# SolrDocument.extension_parameters[:marc_format_type] = :marc21 # or :marcxml
|
18
|
+
module Blacklight::Solr::Document::Marc
|
19
|
+
|
20
|
+
include Blacklight::Solr::Document::MarcExport # All our export_as stuff based on to_marc.
|
21
|
+
|
22
|
+
class UnsupportedMarcFormatType < RuntimeError; end
|
23
|
+
|
24
|
+
def self.extended(document)
|
25
|
+
# Register our exportable formats, we inherit these from MarcExport
|
26
|
+
Blacklight::Solr::Document::MarcExport.register_export_formats( document )
|
27
|
+
end
|
28
|
+
|
29
|
+
# DEPRECATED. Here for legacy purposes, but use to_marc instead. Or
|
30
|
+
# internally, use the protected _marc_helper method to get the
|
31
|
+
# (somewhat confusingly named) Blacklight::Marc::Document helper object.
|
32
|
+
#
|
33
|
+
# This method gets attached to a SolrDocument.
|
34
|
+
# it uses the marc_source_field and marc_format_type
|
35
|
+
# class attributes to create the Blacklight::Marc::Document instance.
|
36
|
+
# Only returns a Blacklight::Marc::Document instance if
|
37
|
+
# the self.class.marc_source_field key exists.
|
38
|
+
def marc
|
39
|
+
warn "[DEPRECATION] aDocument.marc is deprecated. Please use aDocument.respond_to?(:to_marc) / aDocument.respond_to?(:marc), or aDocument.exports_as.keys.include?(:some_format) / aDocument.export_as(:some_format) instead."
|
40
|
+
|
41
|
+
_marc_helper
|
42
|
+
end
|
43
|
+
|
44
|
+
# ruby-marc object
|
45
|
+
def to_marc
|
46
|
+
@_ruby_marc_obj ||= load_marc
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
protected
|
51
|
+
def marc_source
|
52
|
+
@_marc_source ||= fetch(_marc_source_field)
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_marc
|
56
|
+
case _marc_format_type.to_s
|
57
|
+
when 'marcxml'
|
58
|
+
records = MARC::XMLReader.new(StringIO.new( fetch(_marc_source_field) )).to_a
|
59
|
+
return records[0]
|
60
|
+
when 'marc21'
|
61
|
+
return MARC::Record.new_from_marc( fetch(_marc_source_field) )
|
62
|
+
else
|
63
|
+
|
64
|
+
raise UnsupportedMarcFormatType.new("Only marcxml and marc21 are supported, this documents format is #{_marc_format_type} and the current extension parameters are #{self.class.extension_parameters.inspect}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
def _marc_helper
|
71
|
+
@_marc_helper ||= (
|
72
|
+
Blacklight::Marc::Document.new fetch(_marc_source_field), _marc_format_type )
|
73
|
+
end
|
74
|
+
|
75
|
+
def _marc_source_field
|
76
|
+
self.class.extension_parameters[:marc_source_field]
|
77
|
+
end
|
78
|
+
|
79
|
+
def _marc_format_type
|
80
|
+
#TODO: Raise if not present
|
81
|
+
self.class.extension_parameters[:marc_format_type]
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|