ddr-models 2.0.1 → 2.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -17
  3. data/app/models/collection.rb +1 -35
  4. data/ddr-models.gemspec +2 -1
  5. data/lib/ddr/actions.rb +1 -0
  6. data/lib/ddr/actions/virus_check.rb +28 -0
  7. data/lib/ddr/auth.rb +4 -0
  8. data/lib/ddr/auth/ability_definitions/datastream_ability_definitions.rb +7 -5
  9. data/lib/ddr/auth/grouper_gateway.rb +9 -1
  10. data/lib/ddr/auth/permissions.rb +2 -1
  11. data/lib/ddr/auth/role_based_access_controls_enforcement.rb +5 -5
  12. data/lib/ddr/auth/roles/role_types.rb +2 -1
  13. data/lib/ddr/datastreams.rb +2 -2
  14. data/lib/ddr/datastreams/administrative_metadata_datastream.rb +27 -14
  15. data/lib/ddr/datastreams/datastream_behavior.rb +13 -0
  16. data/lib/ddr/datastreams/fits_datastream.rb +88 -0
  17. data/lib/ddr/derivatives/png_generator.rb +2 -0
  18. data/lib/ddr/derivatives/ptif_generator.rb +2 -0
  19. data/lib/ddr/events/fixity_check_event.rb +2 -2
  20. data/lib/ddr/events/virus_check_event.rb +2 -14
  21. data/lib/ddr/index.rb +29 -0
  22. data/lib/ddr/index/abstract_query_result.rb +23 -0
  23. data/lib/ddr/index/connection.rb +17 -0
  24. data/lib/ddr/index/csv_query_result.rb +61 -0
  25. data/lib/ddr/index/document_builder.rb +9 -0
  26. data/lib/ddr/index/field.rb +23 -0
  27. data/lib/ddr/index/fields.rb +83 -0
  28. data/lib/ddr/index/filter.rb +48 -0
  29. data/lib/ddr/index/filters.rb +19 -0
  30. data/lib/ddr/index/legacy_license_fields.rb +14 -0
  31. data/lib/ddr/index/query.rb +35 -0
  32. data/lib/ddr/index/query_builder.rb +74 -0
  33. data/lib/ddr/index/query_clause.rb +52 -0
  34. data/lib/ddr/index/query_result.rb +70 -0
  35. data/lib/ddr/index/query_value.rb +16 -0
  36. data/lib/ddr/index/response.rb +13 -0
  37. data/lib/ddr/index/unique_key_field.rb +12 -0
  38. data/lib/ddr/index_fields.rb +7 -53
  39. data/lib/ddr/jobs.rb +1 -1
  40. data/lib/ddr/jobs/fits_file_characterization.rb +51 -0
  41. data/lib/ddr/managers.rb +1 -0
  42. data/lib/ddr/managers/technical_metadata_manager.rb +104 -0
  43. data/lib/ddr/models.rb +39 -23
  44. data/lib/ddr/models/base.rb +0 -2
  45. data/lib/ddr/models/describable.rb +1 -1
  46. data/lib/ddr/models/effective_license.rb +9 -0
  47. data/lib/ddr/models/engine.rb +13 -0
  48. data/lib/ddr/models/file_management.rb +157 -160
  49. data/lib/ddr/models/governable.rb +0 -4
  50. data/lib/ddr/models/has_admin_metadata.rb +80 -72
  51. data/lib/ddr/models/has_children.rb +1 -1
  52. data/lib/ddr/models/has_content.rb +18 -0
  53. data/lib/ddr/models/has_struct_metadata.rb +5 -1
  54. data/lib/ddr/models/indexing.rb +32 -20
  55. data/lib/ddr/models/inherited_license.rb +13 -0
  56. data/lib/ddr/models/license.rb +38 -0
  57. data/lib/ddr/models/solr_document.rb +195 -211
  58. data/lib/ddr/models/version.rb +1 -1
  59. data/lib/ddr/models/year_facet.rb +154 -0
  60. data/lib/ddr/utils.rb +13 -1
  61. data/lib/ddr/vocab/roles.rb +0 -10
  62. data/spec/controllers/including_role_based_access_controls_enforcement_spec.rb +4 -4
  63. data/spec/datastreams/fits_datastream_spec.rb +84 -0
  64. data/spec/fixtures/fits/document.xml +65 -0
  65. data/spec/fixtures/fits/image.xml +59 -0
  66. data/spec/index/filter_spec.rb +47 -0
  67. data/spec/index/filters_spec.rb +17 -0
  68. data/spec/index/query_spec.rb +19 -0
  69. data/spec/jobs/fits_file_characterization_spec.rb +52 -0
  70. data/spec/managers/technical_metadata_manager_spec.rb +140 -0
  71. data/spec/models/active_fedora_datastream_spec.rb +44 -0
  72. data/spec/models/collection_spec.rb +7 -12
  73. data/spec/models/component_spec.rb +3 -6
  74. data/spec/models/effective_license_spec.rb +49 -0
  75. data/spec/models/has_admin_metadata_spec.rb +143 -194
  76. data/spec/models/has_struct_metadata_spec.rb +2 -2
  77. data/spec/models/indexing_spec.rb +40 -0
  78. data/spec/models/solr_document_spec.rb +96 -37
  79. data/spec/models/year_facet_spec.rb +65 -0
  80. data/spec/spec_helper.rb +1 -7
  81. data/spec/support/shared_examples_for_ddr_models.rb +0 -2
  82. data/spec/support/shared_examples_for_has_content.rb +37 -3
  83. metadata +79 -32
  84. data/lib/ddr/datastreams/properties_datastream.rb +0 -25
  85. data/lib/ddr/jobs/migrate_legacy_authorization.rb +0 -23
  86. data/lib/ddr/models/has_properties.rb +0 -15
  87. data/lib/ddr/models/licensable.rb +0 -28
  88. data/spec/auth/legacy_authorization_spec.rb +0 -94
  89. data/spec/auth/legacy_roles_spec.rb +0 -32
  90. data/spec/jobs/migrate_legacy_authorization_spec.rb +0 -43
  91. data/spec/support/shared_examples_for_has_properties.rb +0 -5
  92. data/spec/support/shared_examples_for_licensable.rb +0 -15
@@ -0,0 +1,52 @@
1
+ module Ddr::Index
2
+ class QueryClause
3
+
4
+ PRESENT = "[* TO *]"
5
+ TERM = "{!term f=%s}%s"
6
+ BEFORE_DAYS = "[* TO NOW-%sDAYS]"
7
+
8
+ class << self
9
+ # Standard Solr query, no escaping applied
10
+ def build(field, value)
11
+ [field, value].join(":")
12
+ end
13
+
14
+ def unique_key(value)
15
+ term(UniqueKeyField.instance, value)
16
+ end
17
+ alias_method :id, :unique_key
18
+ alias_method :pid, :unique_key
19
+
20
+ def negative(field, value)
21
+ build "-#{field}", value
22
+ end
23
+
24
+ def present(field)
25
+ build field, PRESENT
26
+ end
27
+
28
+ def absent(field)
29
+ negative field, PRESENT
30
+ end
31
+
32
+ def or_values(field, *values)
33
+ build field, QueryValue.or_values(*values)
34
+ end
35
+
36
+ def before(field, date_time)
37
+ value = "[* TO %s]" % Ddr::Utils.solr_date(date_time)
38
+ build field, value
39
+ end
40
+
41
+ def before_days(field, days)
42
+ value = BEFORE_DAYS % days.to_i
43
+ build field, value
44
+ end
45
+
46
+ def term(field, value)
47
+ TERM % [field, value.gsub(/"/, '\"')]
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,70 @@
1
+ module Ddr::Index
2
+ class QueryResult < AbstractQueryResult
3
+
4
+ PAGE_SIZE = 1000
5
+
6
+ delegate :csv, to: :query
7
+
8
+ def each(&block)
9
+ if params[:rows]
10
+ each_unpaginated(&block)
11
+ else
12
+ each_paginated(&block)
13
+ end
14
+ end
15
+
16
+ def each_unpaginated(&block)
17
+ conn.select(params).docs.each(&block)
18
+ end
19
+
20
+ def each_paginated(&block)
21
+ pages.each { |pg| pg.each(&block) }
22
+ end
23
+
24
+ def pids
25
+ Enumerator.new do |e|
26
+ each do |doc|
27
+ e << doc[Fields::PID]
28
+ end
29
+ end
30
+ end
31
+
32
+ def each_pid(&block)
33
+ pids.each(&block)
34
+ end
35
+
36
+ def docs
37
+ Enumerator.new do |e|
38
+ each do |doc|
39
+ e << DocumentBuilder.build(doc)
40
+ end
41
+ end
42
+ end
43
+
44
+ def all
45
+ to_a
46
+ end
47
+
48
+ def pages
49
+ num = 1
50
+ Enumerator.new do |e|
51
+ loop do
52
+ pg = page(num)
53
+ e << pg
54
+ unless pg.has_next?
55
+ break
56
+ end
57
+ num += 1
58
+ end
59
+ end
60
+ end
61
+
62
+ def page(num)
63
+ page_params = params.dup
64
+ page_size = page_params.delete(:rows) || PAGE_SIZE
65
+ response = conn.page num, page_size, "select", params: page_params
66
+ response.docs
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,16 @@
1
+ module Ddr::Index
2
+ class QueryValue
3
+
4
+ class << self
5
+ def build(value)
6
+ RSolr.solr_escape(value)
7
+ end
8
+
9
+ def or_values(*values)
10
+ value = values.map { |v| build(v) }.join(" OR ")
11
+ "(#{value})"
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module Ddr::Index
2
+ class Response < SimpleDelegator
3
+
4
+ def docs
5
+ self["response"]["docs"]
6
+ end
7
+
8
+ def num_found
9
+ self["response"]["numFound"].to_i
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'singleton'
2
+
3
+ module Ddr::Index
4
+ class UniqueKeyField < Field
5
+ include Singleton
6
+
7
+ def initialize
8
+ super SOLR_DOCUMENT_ID
9
+ end
10
+
11
+ end
12
+ end
@@ -1,60 +1,14 @@
1
1
  module Ddr
2
2
  module IndexFields
3
3
 
4
- def self.solr_name(*args)
5
- ActiveFedora::SolrService.solr_name(*args)
6
- end
4
+ warn "[DEPRECATION] `Ddr::IndexFields` is deprecated and will be removed in ddr-models 3.0." \
5
+ " Use `Ddr::Index::Fields` instead."
6
+
7
+ include Ddr::Index::Fields
7
8
 
8
- ACCESS_ROLE = solr_name :access_role, :stored_sortable
9
- ACTIVE_FEDORA_MODEL = solr_name :active_fedora_model, :stored_sortable
10
- ADMIN_SET = solr_name :admin_set, :stored_sortable
11
- ADMIN_SET_FACET = solr_name :admin_set_facet, :facetable
12
- COLLECTION_FACET = solr_name :collection_facet, :facetable
13
- COLLECTION_URI = solr_name :collection_uri, :symbol
14
- CONTENT_CONTROL_GROUP = solr_name :content_control_group, :searchable, type: :string
15
- CONTENT_SIZE = solr_name :content_size, :stored_sortable, type: :integer
16
- CONTENT_SIZE_HUMAN = solr_name :content_size_human, :symbol
17
- CREATOR_FACET = solr_name :creator_facet, :facetable
18
- DATE_FACET = solr_name :date_facet, :facetable
19
- DATE_SORT = solr_name :date_sort, :sortable
20
- DEFAULT_LICENSE_DESCRIPTION = solr_name :default_license_description, type: :string
21
- DEFAULT_LICENSE_TITLE = solr_name :default_license_title, type: :string
22
- DEFAULT_LICENSE_URL = solr_name :default_license_url, type: :string
23
- DISPLAY_FORMAT = solr_name :display_format, :stored_sortable
24
- EXTRACTED_TEXT = solr_name :extracted_text, :searchable, type: :text
25
- HAS_MODEL = solr_name :has_model, :symbol
26
- IDENTIFIER_ALL = solr_name :identifier_all, :symbol
27
- INTERNAL_URI = solr_name :internal_uri, :stored_sortable
28
- IS_ATTACHED_TO = solr_name :is_attached_to, :symbol
29
- IS_EXTERNAL_TARGET_FOR = solr_name :is_external_target_for, :symbol
30
- IS_GOVERNED_BY = solr_name :is_governed_by, :symbol
31
- IS_MEMBER_OF = solr_name :is_member_of, :symbol
32
- IS_MEMBER_OF_COLLECTION = solr_name :is_member_of_collection, :symbol
33
- IS_PART_OF = solr_name :is_part_of, :symbol
34
- LAST_FIXITY_CHECK_ON = solr_name :last_fixity_check_on, :stored_sortable, type: :date
35
- LAST_FIXITY_CHECK_OUTCOME = solr_name :last_fixity_check_outcome, :symbol
36
- LAST_VIRUS_CHECK_ON = solr_name :last_virus_check_on, :stored_sortable, type: :date
37
- LAST_VIRUS_CHECK_OUTCOME = solr_name :last_virus_check_outcome, :symbol
38
- LICENSE_DESCRIPTION = solr_name :license_description, type: :string
39
- LICENSE_TITLE = solr_name :license_title, type: :string
40
- LICENSE_URL = solr_name :license_url, type: :string
41
- LOCAL_ID = solr_name :local_id, :stored_sortable
42
- MEDIA_SUB_TYPE = solr_name :content_media_sub_type, :facetable
43
- MEDIA_MAJOR_TYPE = solr_name :content_media_major_type, :facetable
44
- MEDIA_TYPE = solr_name :content_media_type, :symbol
45
- MULTIRES_IMAGE_FILE_PATH = solr_name :multires_image_file_path, :stored_sortable
46
- OBJECT_PROFILE = solr_name :object_profile, :displayable
47
- OBJECT_STATE = solr_name :object_state, :stored_sortable
48
- OBJECT_CREATE_DATE = solr_name :system_create, :stored_sortable, type: :date
49
- OBJECT_MODIFIED_DATE = solr_name :system_modified, :stored_sortable, type: :date
50
- PERMANENT_ID = solr_name :permanent_id, :stored_sortable, type: :string
51
- PERMANENT_URL = solr_name :permanent_url, :stored_sortable, type: :string
52
- POLICY_ROLE = solr_name :policy_role, :symbol
53
- RESEARCH_HELP_CONTACT = solr_name :research_help_contact, :stored_sortable
54
- RESOURCE_ROLE = solr_name :resource_role, :symbol
55
- STRUCT_MAPS = solr_name :struct_maps, :stored_sortable
56
- TITLE = solr_name :title, :stored_sortable
57
- WORKFLOW_STATE = solr_name :workflow_state, :stored_sortable
9
+ def self.get(name)
10
+ Ddr::Index::Fields.get(name)
11
+ end
58
12
 
59
13
  end
60
14
  end
@@ -3,7 +3,7 @@ module Ddr
3
3
  extend ActiveSupport::Autoload
4
4
 
5
5
  autoload :PermanentId
6
- autoload :MigrateLegacyAuthorization
6
+ autoload :FitsFileCharacterization
7
7
 
8
8
  autoload_at 'ddr/jobs/permanent_id' do
9
9
  autoload :MakeUnavailable
@@ -0,0 +1,51 @@
1
+ require 'open3'
2
+
3
+ module Ddr::Jobs
4
+ class FitsFileCharacterization
5
+
6
+ @queue = :file_characterization
7
+
8
+ EVENT_SUMMARY = 'FITS characterization of content file'.freeze
9
+
10
+ def self.perform(pid)
11
+ obj = ActiveFedora::Base.find(pid)
12
+ tmp_filename = Ddr::Utils::sanitize_filename(obj.original_filename) || obj.content.default_file_name
13
+ Dir.mktmpdir do |dir|
14
+ infile = create_temp_infile(dir, tmp_filename, obj.content.content)
15
+ fits_output, err, status = Open3.capture3(fits_command, '-i', infile)
16
+ if status.success? && fits_output.present?
17
+ obj.reload
18
+ obj.fits.content = fits_output
19
+ obj.save!
20
+ end
21
+ notify_event(pid, err, status)
22
+ end
23
+ end
24
+
25
+ def self.fits_command
26
+ File.join(Ddr::Models.fits_home, 'fits.sh')
27
+ end
28
+
29
+ def self.fits_version
30
+ `#{fits_command} -v`.strip
31
+ end
32
+
33
+ private
34
+
35
+ def self.create_temp_infile(dir, tmp_filename, content)
36
+ temp_infile = File.join(dir, tmp_filename)
37
+ File.open(temp_infile, 'wb') do |f|
38
+ f.write content
39
+ end
40
+ temp_infile
41
+ end
42
+
43
+ def self.notify_event(pid, err, status)
44
+ details = status.success? ? nil : err
45
+ event_args = { pid: pid, summary: EVENT_SUMMARY, software: "fits #{fits_version}", detail: details }
46
+ event_args[:outcome] = status.success? ? Ddr::Events::Event::SUCCESS : Ddr::Events::Event::FAILURE
47
+ Ddr::Notifications.notify_event(:update, event_args)
48
+ end
49
+
50
+ end
51
+ end
@@ -5,6 +5,7 @@ module Ddr
5
5
  autoload :Manager
6
6
  autoload :DerivativesManager
7
7
  autoload :PermanentIdManager
8
+ autoload :TechnicalMetadataManager
8
9
  autoload :WorkflowManager
9
10
 
10
11
  end
@@ -0,0 +1,104 @@
1
+ module Ddr::Managers
2
+ class TechnicalMetadataManager < Manager
3
+
4
+ FITS_TIMESTAMP_FORMAT = "%D %l:%M %p" # Ex. 7/3/15 8:29 PM
5
+
6
+ delegate :content, :fits, to: :object
7
+
8
+ delegate :valid, :well_formed,
9
+ :media_type, :format_label, :format_version, :pronom_identifier,
10
+ :created, :modified, :creating_application, :extent,
11
+ :image_width, :image_height, :color_space,
12
+ to: :fits
13
+
14
+ alias_method :file_size, :extent
15
+ alias_method :last_modified, :modified
16
+
17
+ def fits?
18
+ !fits_version.nil?
19
+ end
20
+
21
+ def fits_version
22
+ fits.version.first
23
+ end
24
+
25
+ def fits_datetime
26
+ if fits_timestamp = fits.timestamp.first
27
+ no_zone = DateTime.strptime(fits_timestamp, FITS_TIMESTAMP_FORMAT)
28
+ no_zone.change(offset: no_zone.to_time.zone)
29
+ end
30
+ end
31
+
32
+ def file_size
33
+ extent.map(&:to_i)
34
+ end
35
+
36
+ def file_human_size
37
+ file_size.map do |fs|
38
+ "%s (%s bytes)" % [ ActiveSupport::NumberHelper.number_to_human_size(fs),
39
+ ActiveSupport::NumberHelper.number_to_delimited(fs) ]
40
+ end
41
+ end
42
+
43
+ def checksum_digest
44
+ content.checksumType
45
+ end
46
+
47
+ def checksum_value
48
+ content.checksum
49
+ end
50
+
51
+ def invalid?
52
+ valid.any? { |v| v == "false" }
53
+ end
54
+
55
+ def valid?
56
+ !invalid?
57
+ end
58
+
59
+ def ill_formed?
60
+ well_formed.any? { |v| v == "false" }
61
+ end
62
+
63
+ def well_formed?
64
+ !ill_formed?
65
+ end
66
+
67
+ def creation_time
68
+ created.map { |datestr| coerce_to_time(datestr) }.compact
69
+ end
70
+
71
+ def modification_time
72
+ modified.map { |datestr| coerce_to_time(datestr) }.compact
73
+ end
74
+
75
+ def index_fields
76
+ { Ddr::Index::Fields::TECHMD_FITS_VERSION => fits_version,
77
+ Ddr::Index::Fields::TECHMD_FITS_DATETIME => Ddr::Utils.solr_date(fits_datetime),
78
+ Ddr::Index::Fields::TECHMD_CREATION_TIME => Ddr::Utils.solr_dates(creation_time),
79
+ Ddr::Index::Fields::TECHMD_MODIFICATION_TIME => Ddr::Utils.solr_dates(modification_time),
80
+ Ddr::Index::Fields::TECHMD_COLOR_SPACE => color_space,
81
+ Ddr::Index::Fields::TECHMD_CREATING_APPLICATION => creating_application,
82
+ Ddr::Index::Fields::TECHMD_FILE_SIZE => file_size,
83
+ Ddr::Index::Fields::TECHMD_FORMAT_LABEL => format_label,
84
+ Ddr::Index::Fields::TECHMD_FORMAT_VERSION => format_version,
85
+ Ddr::Index::Fields::TECHMD_IMAGE_HEIGHT => image_height,
86
+ Ddr::Index::Fields::TECHMD_IMAGE_WIDTH => image_width,
87
+ Ddr::Index::Fields::TECHMD_MEDIA_TYPE => media_type,
88
+ Ddr::Index::Fields::TECHMD_PRONOM_IDENTIFIER => pronom_identifier,
89
+ Ddr::Index::Fields::TECHMD_VALID => valid,
90
+ Ddr::Index::Fields::TECHMD_WELL_FORMED => well_formed,
91
+ }
92
+ end
93
+
94
+ private
95
+
96
+ def coerce_to_time(datestr)
97
+ datestr.sub! /\A(\d+):(\d+):(\d+)/, '\1-\2-\3'
98
+ DateTime.parse(datestr).to_time
99
+ rescue ArgumentError
100
+ nil
101
+ end
102
+
103
+ end
104
+ end
@@ -9,32 +9,37 @@ require 'active_record'
9
9
  require 'hydra-core'
10
10
  require 'hydra/validations'
11
11
 
12
- require 'ddr/actions'
13
- require 'ddr/auth'
14
- require 'ddr/contacts'
15
- require 'ddr/datastreams'
16
- require 'ddr/derivatives'
17
- require 'ddr/events'
18
- require 'ddr/index_fields'
19
- require 'ddr/jobs'
20
- require 'ddr/managers'
21
- require 'ddr/metadata'
22
- require 'ddr/notifications'
23
- require 'ddr/utils'
24
- require 'ddr/vocab'
25
-
26
12
  module Ddr
13
+ extend ActiveSupport::Autoload
14
+
15
+ autoload :Actions
16
+ autoload :Auth
17
+ autoload :Contacts
18
+ autoload :Datastreams
19
+ autoload :Derivatives
20
+ autoload :Events
21
+ autoload :Index
22
+ autoload :IndexFields
23
+ autoload :Jobs
24
+ autoload :Managers
25
+ autoload :Metadata
26
+ autoload :Notifications
27
+ autoload :Utils
28
+ autoload :Vocab
29
+
27
30
  module Models
28
31
  extend ActiveSupport::Autoload
29
32
 
30
- autoload :Base
31
33
  autoload :AccessControllable
32
- autoload :Describable
33
- autoload :EventLoggable
34
- autoload :Error
34
+ autoload :Base
35
35
  autoload :ChecksumInvalid, 'ddr/models/error'
36
- autoload :DerivativeGenerationFailure, 'ddr/models/error'
37
36
  autoload :ContentModelError, 'ddr/models/error'
37
+ autoload :DerivativeGenerationFailure, 'ddr/models/error'
38
+ autoload :Describable
39
+ autoload :EffectiveLicense
40
+ autoload :Error
41
+ autoload :EventLoggable
42
+ autoload :FileManagement
38
43
  autoload :FixityCheckable
39
44
  autoload :Governable
40
45
  autoload :HasAdminMetadata
@@ -42,15 +47,15 @@ module Ddr
42
47
  autoload :HasChildren
43
48
  autoload :HasContent
44
49
  autoload :HasMultiresImage
45
- autoload :HasProperties
46
50
  autoload :HasStructMetadata
47
51
  autoload :HasThumbnail
48
52
  autoload :Indexing
49
- autoload :FileManagement
50
- autoload :Licensable
53
+ autoload :InheritedLicense
54
+ autoload :License
51
55
  autoload :SolrDocument
52
- autoload :Structure
53
56
  autoload :StructDiv
57
+ autoload :Structure
58
+ autoload :YearFacet
54
59
 
55
60
  # Base directory of default external file store
56
61
  mattr_accessor :external_file_store
@@ -71,6 +76,17 @@ module Ddr
71
76
  "https://repository.lib.duke.edu/id/"
72
77
  end
73
78
 
79
+ # Home directory for FITS
80
+ mattr_accessor :fits_home
81
+
82
+ # Run file characterization or not?
83
+ mattr_accessor :characterize_files do
84
+ false
85
+ end
86
+ class << self
87
+ alias :characterize_files? :characterize_files
88
+ end
89
+
74
90
  # Yields an object with module configuration accessors
75
91
  def self.configure
76
92
  yield self