require 'hashie' require 'concurrent' class Traject::Indexer # A Hash of settings for a Traject::Indexer, which also ends up passed along # to other objects Traject::Indexer interacts with. # # Enhanced with a few features from Hashie, to make it for # instance string/symbol indifferent # # method #provide(key, value) is added, to do like settings[key] ||= value, # set only if not already set (but unlike ||=, nil or false can count as already set) # # Also has an interesting 'defaults' system, meant to play along # with configuration file 'provide' statements. There is a built-in hash of # defaults, which will be lazily filled in if accessed and not yet # set. (nil can count as set, though!). If they haven't been lazily # set yet, then #provide will still fill them in. But you can also call # fill_in_defaults! to fill all defaults in, if you know configuration # files have all been loaded, and want to fill them in for inspection. class Settings < Hash include Hashie::Extensions::MergeInitializer # can init with hash include Hashie::Extensions::IndifferentAccess def initialize(*args) super self.default_proc = lambda do |hash, key| if self.class.defaults.has_key?(key) return hash[key] = self.class.defaults[key] else return nil end end end # a cautious store, which only saves key=value if # there was not already a value for #key. Can be used # to set settings that can be overridden on command line, # or general first-set-wins settings. def provide(key, value) unless has_key? key store(key, value) end end # reverse_merge copied from ActiveSupport, pretty straightforward, # modified to make sure we return a Settings def reverse_merge(other_hash) self.class.new(other_hash).merge(self) end def reverse_merge!(other_hash) replace(reverse_merge(other_hash)) end def fill_in_defaults! self.reverse_merge!(self.class.defaults) end def self.mri_defaults { "reader_class_name" => "Traject::MarcReader", "writer_class_name" => "Traject::SolrJsonWriter", "marc_source.type" => "binary", "solrj_writer.batch_size" => 200, "solrj_writer.thread_pool" => 1, "processing_thread_pool" => self.default_processing_thread_pool, "log.batch_size.severity" => "info" } end def self.jruby_defaults { 'reader_class_name' => "Traject::Marc4JReader", 'marc4j_reader.permissive' => true } end def self.defaults return @@defaults if defined? @@defaults default_settings = self.mri_defaults if defined? JRUBY_VERSION default_settings.merge! self.jruby_defaults end @@defaults = default_settings end def inspect # Keep any key ending in password out of the inspect self.inject({}) do |hash, (key, value)| hash[key] = (key =~ /password\Z/) ? "[hidden]" : value hash end.inspect end protected def self.default_processing_thread_pool if ["jruby", "rbx"].include? ENV["RUBY_ENGINE"] [1, Concurrent.processor_count - 1].max else 1 end end end end