wax_tasks 1.0.0.pre.beta → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ module WaxTasks
5
+ #
6
+ class Collection
7
+ #
8
+ module Metadata
9
+ #
10
+ #
11
+ def search_fields=(fields)
12
+ @search_fields.concat(fields).flatten.compact.uniq
13
+ end
14
+
15
+ #
16
+ #
17
+ def records_from_pages
18
+ paths = Dir.glob("#{@page_source}/*.{md, markdown}")
19
+ warn Rainbow("There are no pages in #{@page_source} to index.").orange if paths.empty?
20
+
21
+ paths.map do |path|
22
+ begin
23
+ content = WaxTasks::Utils.content_clean File.read(path)
24
+ Record.new(SafeYAML.load_file(path)).tap do |r|
25
+ r.set 'content', content
26
+ r.set 'permalink', "/#{@name}/#{r.pid}#{@ext}" unless r.permalink?
27
+ end
28
+ rescue StandardError => e
29
+ raise Error::PageLoad, "Cannot load page #{path}\n#{e}"
30
+ end
31
+ end
32
+ end
33
+
34
+ #
35
+ #
36
+ def records_from_metadata
37
+ raise Error::MissingSource, "Cannot find metadata source '#{@metadata_source}'" unless File.exist? @metadata_source
38
+
39
+ metadata = Utils.ingest @metadata_source
40
+ metadata.each_with_index.map do |meta, i|
41
+ Record.new(meta).tap do |r|
42
+ r.set 'order', Utils.padded_int(i, metadata.length) unless r.order?
43
+ r.set 'layout', @config['layout'] if @config.key? 'layout'
44
+ r.set 'collection', @name
45
+ end
46
+ end
47
+ end
48
+
49
+ #
50
+ #
51
+ def update_metadata(update)
52
+ records = consolidate_records records_from_metadata, update
53
+ reformatted = case File.extname @metadata_source
54
+ when '.csv'
55
+ csv_string records
56
+ when '.json'
57
+ json_string records
58
+ when /\.ya?ml/
59
+ yaml_string records
60
+ end
61
+ File.open(@metadata_source, 'w') { |f| f.puts reformatted }
62
+ end
63
+
64
+ #
65
+ #
66
+ def consolidate_records(original, new)
67
+ lost_record_pids = original.map(&:pid) - new.map(&:pid)
68
+ lost_record_pids.each do |pid|
69
+ new << original.find { |r| r.pid == pid }
70
+ end
71
+ new.sort_by(&:order)
72
+ end
73
+
74
+ #
75
+ #
76
+ def csv_string(records)
77
+ keys = records.flat_map(&:keys).uniq
78
+ CSV.generate do |csv|
79
+ csv << keys
80
+ records.each do |r|
81
+ csv << keys.map { |k| r.hash.fetch(k, '') }
82
+ end
83
+ end
84
+ end
85
+
86
+ #
87
+ #
88
+ def json_string(records)
89
+ hashes = records.map(&:hash)
90
+ JSON.pretty_generate hashes
91
+ end
92
+
93
+ #
94
+ #
95
+ def yaml_string(records)
96
+ hashes = records.map(&:hash)
97
+ hashes.to_yaml
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaxTasks
4
+ #
5
+ class Config
6
+ attr_reader :collections
7
+
8
+ def initialize(config)
9
+ @config = config
10
+ @collections = process_collections
11
+ end
12
+
13
+ #
14
+ #
15
+ def source
16
+ @config.dig 'source'
17
+ end
18
+
19
+ #
20
+ #
21
+ def collections_dir
22
+ @config.dig 'collections_dir'
23
+ end
24
+
25
+ #
26
+ # Contructs permalink extension from site `permalink` variable
27
+ #
28
+ # @return [String] the end of the permalink, either '/' or '.html'
29
+ def ext
30
+ case @config.dig 'permalink'
31
+ when 'pretty' || '/'
32
+ '/'
33
+ else
34
+ '.html'
35
+ end
36
+ end
37
+
38
+ #
39
+ #
40
+ def process_collections
41
+ if @config.key? 'collections'
42
+ @config['collections'].map do |k, v|
43
+ WaxTasks::Collection.new(k, v, source, collections_dir, ext)
44
+ end
45
+ else
46
+ []
47
+ end
48
+ end
49
+
50
+ #
51
+ #
52
+ def search(name)
53
+ search_config = @config.dig 'search', name
54
+ raise WaxTasks::Error::InvalidConfig if search_config.nil?
55
+ raise WaxTasks::Error::InvalidConfig unless search_config.dig('collections').is_a? Hash
56
+
57
+ search_config['collections'] = search_config['collections'].map do |k, v|
58
+ fields = v.fetch('fields', [])
59
+ fields << 'content' if v.fetch('content', false)
60
+ find_collection(k).tap { |c| c.search_fields = fields }
61
+ end
62
+
63
+ search_config
64
+ end
65
+
66
+ #
67
+ #
68
+ def find_collection(name)
69
+ collection = @collections.find { |c| c.name == name }
70
+ raise WaxTasks::Error::InvalidCollection, "Cannot find requested collection '#{name}'" if collection.nil?
71
+
72
+ collection
73
+ end
74
+ end
75
+ end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WaxTasks
2
4
  # Custom WaxTasks Errors module
3
5
  module Error
4
6
  # Custom WaxTasks Error class with magenta console output
5
7
  class WaxTasksError < StandardError
6
8
  def initialize(msg = '')
7
- super(msg.magenta)
9
+ super(Rainbow(msg).magenta)
8
10
  end
9
11
  end
10
12
 
@@ -13,8 +15,8 @@ module WaxTasks
13
15
  class MissingArguments < WaxTasksError; end
14
16
 
15
17
  # Custom Error:
16
- # Site config cannot be found / parsed
17
- class InvalidSiteConfig < WaxTasksError; end
18
+ # Site config cannot be found / parsed for the task at hand
19
+ class InvalidConfig < WaxTasksError; end
18
20
 
19
21
  # Custom Error:
20
22
  # Collection specified cannot be found / parsed in site config
@@ -22,58 +24,42 @@ module WaxTasks
22
24
 
23
25
  # Custom Error:
24
26
  # Collection data source type is not allowed or is an invalid file
25
- class InvalidSource < WaxTasksError; end
27
+ class InvalidSource < WaxTasksError; end
26
28
 
27
29
  # Custom Error:
28
30
  # Data source file could not be found
29
- class MissingSource < WaxTasksError; end
30
-
31
- # Custom Error:
32
- # While loading markdown pages to index, one could not be read
33
- class LunrPageLoad < WaxTasksError; end
34
-
35
- # Custom Error:
36
- # Lunr collection does not have fields specified to index
37
- class MissingFields < WaxTasksError; end
31
+ class MissingSource < WaxTasksError; end
38
32
 
39
33
  # Custom Error:
40
- # Page layout was not specified for a pagemaster collection
41
- class MissingLayout < WaxTasksError; end
34
+ # Could not load collection page(s)
35
+ class PageLoad < WaxTasksError; end
42
36
 
43
37
  # Custom Error:
44
38
  # Collection item does not have a required pid value
45
- class MissingPid < WaxTasksError; end
39
+ class MissingPid < WaxTasksError; end
46
40
 
47
41
  # Custom Error:
48
42
  # Collection item has a non-unique pud value
49
- class NonUniquePid < WaxTasksError; end
43
+ class NonUniquePid < WaxTasksError; end
50
44
 
51
45
  # Custom Error:
52
46
  # Collection page item could not be generated
53
- class PageFailure < WaxTasksError; end
47
+ class PageFailure < WaxTasksError; end
54
48
 
55
49
  # Custom Error:
56
50
  # CSV file failed to lint + could not be loaded
57
- class InvalidCSV < WaxTasksError; end
51
+ class InvalidCSV < WaxTasksError; end
58
52
 
59
53
  # Custom Error:
60
54
  # JSON file failed to lint + could not be loaded
61
- class InvalidJSON < WaxTasksError; end
55
+ class InvalidJSON < WaxTasksError; end
62
56
 
63
57
  # Custom Error:
64
58
  # YAML file failed to lint + could not be loaded
65
- class InvalidYAML < WaxTasksError; end
66
-
67
- # Custom Error:
68
- # No collections in site config have lunr_index parameters
69
- class NoLunrCollections < WaxTasksError; end
70
-
71
- # Custom Error:
72
- # Cannot find _site directory to push to GitHub
73
- class MissingSite < WaxTasksError; end
59
+ class InvalidYAML < WaxTasksError; end
74
60
 
75
61
  # Custom Error:
76
- # Cannot find IIIF source image files
77
- class MissingIiifSrc < WaxTasksError; end
62
+ # Search index in site config has no valid collections to index
63
+ class NoSearchCollections < WaxTasksError; end
78
64
  end
79
65
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaxTasks
4
+ #
5
+ class Index
6
+ attr_reader :path, :collections
7
+
8
+ def initialize(config)
9
+ @config = config
10
+ @collections = config.dig 'collections'
11
+ @path = config.dig 'index'
12
+
13
+ raise WaxTasks::Error::NoSearchCollections if @collections.nil?
14
+ raise WaxTasks::Error::InvalidConfig if @path.nil?
15
+
16
+ @records = records
17
+ end
18
+
19
+ #
20
+ #
21
+ def records
22
+ lunr_id = 0
23
+ @collections.flat_map do |collection|
24
+ collection.records_from_pages.each.flat_map do |r|
25
+ r.keep_only collection.search_fields
26
+ r.set 'lunr_id', lunr_id
27
+ r.lunr_normalize_values
28
+ lunr_id += 1
29
+ r
30
+ end
31
+ end
32
+ end
33
+
34
+ #
35
+ #
36
+ def write_to(dir)
37
+ file_path = WaxTasks::Utils.safe_join Dir.pwd, dir, path
38
+ FileUtils.mkdir_p File.dirname(file_path)
39
+ File.open(file_path, 'w') do |f|
40
+ f.puts "---\nlayout: none\n---\n"
41
+ f.puts JSON.pretty_generate(@records.map(&:hash))
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaxTasks
4
+ #
5
+ class Item
6
+ attr_accessor :record, :iiif_config
7
+ attr_reader :pid
8
+
9
+ #
10
+ #
11
+ #
12
+ def initialize(path, variants)
13
+ @path = path
14
+ @variants = variants
15
+ @type = type
16
+ @pid = File.basename @path, '.*'
17
+ @assets = assets
18
+ end
19
+
20
+ #
21
+ #
22
+ def accepted_image_formats
23
+ %w[.png .jpg .jpeg .tiff]
24
+ end
25
+
26
+ #
27
+ #
28
+ def type
29
+ Dir.exist?(@path) ? 'dir' : File.extname(@path)
30
+ end
31
+
32
+ #
33
+ #
34
+ def valid?
35
+ accepted_image_formats.include?(@type) || @type == 'dir'
36
+ end
37
+
38
+ #
39
+ #
40
+ def record?
41
+ @record.is_a? Record
42
+ end
43
+
44
+ #
45
+ #
46
+ def assets
47
+ if accepted_image_formats.include? @type
48
+ [Asset.new(@path, @pid, @variants)]
49
+ elsif @type == 'dir'
50
+ paths = Dir.glob("#{@path}/*{#{accepted_image_formats.join(',')}}")
51
+ paths.map { |p| Asset.new(p, @pid, @variants) }
52
+ else
53
+ []
54
+ end
55
+ end
56
+
57
+ #
58
+ #
59
+ def simple_derivatives
60
+ @assets.map(&:simple_derivatives).flatten
61
+ end
62
+
63
+ #
64
+ #
65
+ def logo
66
+ logo_uri = @iiif_config&.dig 'logo'
67
+ "{{ '#{logo_uri}' | absolute_url }}" if logo_uri
68
+ end
69
+
70
+ def label
71
+ label_key = @iiif_config&.dig 'label'
72
+ if @record && label_key
73
+ @record.hash.dig label_key
74
+ else
75
+ @pid
76
+ end
77
+ end
78
+
79
+ #
80
+ #
81
+ def description
82
+ description_key = @iiif_config&.dig 'description'
83
+ @record.hash.dig description_key if description_key && @record
84
+ end
85
+
86
+ #
87
+ #
88
+ def attribution
89
+ attribution_key = @iiif_config.dig 'attribution'
90
+ @record.hash.dig attribution_key if attribution_key && @record
91
+ end
92
+
93
+ #
94
+ #
95
+ def iiif_image_records
96
+ opts = base_opts.clone
97
+ is_only = @assets.length == 1
98
+
99
+ @assets.map.with_index do |asset, i|
100
+ asset.to_iiif_image_record(is_only, i, opts)
101
+ end
102
+ end
103
+
104
+ #
105
+ #
106
+ def base_opts
107
+ opts = { label: label }
108
+ return opts unless @iiif_config
109
+
110
+ opts[:logo] = logo if logo
111
+ opts[:description] = description.to_s if description
112
+ opts[:attribution] = attribution.to_s if attribution
113
+ opts
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WaxTasks
4
+ #
5
+ class Record
6
+ attr_reader :pid, :hash, :order
7
+
8
+ def initialize(hash)
9
+ @hash = hash
10
+ @pid = @hash.dig 'pid'
11
+ @order = @hash.dig 'order'
12
+ end
13
+
14
+ #
15
+ #
16
+ def lunr_normalize_values
17
+ @hash.transform_values { |v| Utils.lunr_normalize v }
18
+ end
19
+
20
+ #
21
+ #
22
+ def keys
23
+ @hash.keys
24
+ end
25
+
26
+ #
27
+ #
28
+ def set(key, value)
29
+ @hash[key] = value
30
+ end
31
+
32
+ #
33
+ #
34
+ def permalink?
35
+ @hash.key? 'permalink'
36
+ end
37
+
38
+ #
39
+ #
40
+ def order?
41
+ @order.is_a? String
42
+ end
43
+
44
+ #
45
+ #
46
+ def keep_only(fields)
47
+ @hash.select! { |k, _v| fields.include? k }
48
+ end
49
+
50
+ #
51
+ #
52
+ def write_to_page(dir)
53
+ raise Error::MissingPid if @pid.nil?
54
+
55
+ path = "#{dir}/#{Utils.slug(@pid)}.md"
56
+ if File.exist? path
57
+ 0
58
+ else
59
+ FileUtils.mkdir_p File.dirname(path)
60
+ File.open(path, 'w') { |f| f.puts "#{@hash.to_yaml}---" }
61
+ 1
62
+ end
63
+ end
64
+ end
65
+ end