139139#
140140# Special thanks to Jose Hales-Garcia for this solution.
141141#
142+ # ### Leverage the Provider instance
143+ #
144+ # The traditional implementation of the OAI::Provider would pass the OAI::Provider
145+ # class to the different resposnes. This made it hard to inject context into a
146+ # common provider. Consider that we might have different request headers that
147+ # change the scope of the OAI::Provider queries.
148+ #
149+ # ```ruby
150+ # class InstanceProvider
151+ # def initialize(options = {})
152+ # super({ :provider_context => :instance_based })
153+ # @controller = options.fetch(:controller)
154+ # end
155+ # attr_reader :controller
156+ # end
157+ #
158+ # class OaiController < ApplicationController
159+ # def index
160+ # provider = InstanceProvider.new({ :controller => self })
161+ # request_body = provider.process_request(oai_params.to_h)
162+ # render :body => request_body, :content_type => 'text/xml'
163+ # end
164+ # ```
165+ #
166+ # In the above example, the underlying response object will now receive an
167+ # instance of the InstanceProvider. Without the `super({ :provider_context => :instance_based })`
168+ # the response objects would have received the class InstanceProvider as the
169+ # given provider.
170+ #
142171# ## Supporting custom metadata formats
143172#
144173# See {OAI::MetadataFormat} for details.
@@ -292,39 +321,132 @@ def inherited(klass)
292321
293322 Base . register_format ( OAI ::Provider ::Metadata ::DublinCore . instance )
294323
324+ PROVIDER_CONTEXTS = {
325+ :class_based => :class_based ,
326+ :instance_based => :instance_based
327+ }
328+
329+ def initialize ( options = { } )
330+ provider_context = options . fetch ( :provider_context ) { :class_based }
331+ @provider_context = PROVIDER_CONTEXTS . fetch ( provider_context )
332+ end
333+
334+ # @note These are the accessor methods on the class. If you need to overwrite
335+ # them on the instance level you can do that. However, an instance of this
336+ # class won't be used unless you initialize with:
337+ # { :provider_context => :instance_based }
338+ attr_writer :name , :url , :prefix , :email , :delete_support , :granularity , :model , :identifier , :description
339+
340+ # The traditional interaction of a Provider has been to:
341+ #
342+ # 1) Assign attributes to the Provider class
343+ # 2) Instantiate the Provider class
344+ # 3) Call response instance methods for theProvider which pass
345+ # the Provider class and not the instance.
346+ #
347+ # The above behavior continues unless you initialize the Provider with
348+ # { :provider_context => :instance_based }. If you do that, then the
349+ # Provider behavior will be:
350+ #
351+ # 1) Assign attributes to Provider class
352+ # 2) Instantiate the Provider class
353+ # 3) Call response instance methods for theProvider which pass an
354+ # instance of the Provider to those response objects.
355+ # a) The instance will mirror all of the assigned Provider class
356+ # attributes, but allows for overriding and extending on a
357+ # case by case basis.
358+ # (Dear reader, please note the second behavior is something most
359+ # of us would've assumed to be the case, but for historic now lost
360+ # reasons is not the case.)
361+ def provider_context
362+ if @provider_context == :instance_based
363+ self
364+ else
365+ self . class
366+ end
367+ end
368+
369+ def format_supported? ( *args )
370+ self . class . format_supported? ( *args )
371+ end
372+
373+ def format ( *args )
374+ self . class . format ( *args )
375+ end
376+
377+ def formats
378+ self . class . formats
379+ end
380+
381+ def name
382+ @name || self . class . name
383+ end
384+
385+ def url
386+ @url || self . class . url
387+ end
388+
389+ def prefix
390+ @prefix || self . class . prefix
391+ end
392+
393+ def email
394+ @email || self . class . email
395+ end
396+
397+ def delete_support
398+ @delete_support || self . class . delete_support
399+ end
400+
401+ def granularity
402+ @granularity || self . class . granularity
403+ end
404+
405+ def model
406+ @model || self . class . model
407+ end
408+
409+ def identifier
410+ @identifier || self . class . identifier
411+ end
412+
413+ def description
414+ @description || self . class . description
415+ end
416+
295417 # Equivalent to '&verb=Identify', returns information about the repository
296418 def identify ( options = { } )
297- Response ::Identify . new ( self . class , options ) . to_xml
419+ Response ::Identify . new ( provider_context , options ) . to_xml
298420 end
299421
300422 # Equivalent to '&verb=ListSets', returns a list of sets that are supported
301423 # by the repository or an error if sets are not supported.
302424 def list_sets ( options = { } )
303- Response ::ListSets . new ( self . class , options ) . to_xml
425+ Response ::ListSets . new ( provider_context , options ) . to_xml
304426 end
305427
306428 # Equivalent to '&verb=ListMetadataFormats', returns a list of metadata formats
307429 # supported by the repository.
308430 def list_metadata_formats ( options = { } )
309- Response ::ListMetadataFormats . new ( self . class , options ) . to_xml
431+ Response ::ListMetadataFormats . new ( provider_context , options ) . to_xml
310432 end
311433
312434 # Equivalent to '&verb=ListIdentifiers', returns a list of record headers that
313435 # meet the supplied criteria.
314436 def list_identifiers ( options = { } )
315- Response ::ListIdentifiers . new ( self . class , options ) . to_xml
437+ Response ::ListIdentifiers . new ( provider_context , options ) . to_xml
316438 end
317439
318440 # Equivalent to '&verb=ListRecords', returns a list of records that meet the
319441 # supplied criteria.
320442 def list_records ( options = { } )
321- Response ::ListRecords . new ( self . class , options ) . to_xml
443+ Response ::ListRecords . new ( provider_context , options ) . to_xml
322444 end
323445
324446 # Equivalent to '&verb=GetRecord', returns a record matching the required
325447 # :identifier option
326448 def get_record ( options = { } )
327- Response ::GetRecord . new ( self . class , options ) . to_xml
449+ Response ::GetRecord . new ( provider_context , options ) . to_xml
328450 end
329451
330452 # xml_response = process_verb('ListRecords', :from => 'October 1, 2005',
@@ -336,7 +458,7 @@ def process_request(params = {})
336458 begin
337459
338460 # Allow the request to pass in a url
339- self . class . url = params [ 'url' ] ? params . delete ( 'url' ) : self . class . url
461+ provider_context . url = params [ 'url' ] ? params . delete ( 'url' ) : self . url
340462
341463 verb = params . delete ( 'verb' ) || params . delete ( :verb )
342464
0 commit comments