Class: Jekyll::Plugins::PaginateV3::Support::FrontmatterPath

Inherits:
Object
  • Object
show all
Defined in:
lib/jekyll-paginate-v3/support/frontmatter_path.rb

Overview

Traverses frontmatter-style nested hashes using configurable path, array, and equivalent-key rules.

Use one instance per syntax configuration, then call with for scoped variations such as template-level separator overrides.

Constant Summary collapse

DEFAULT_SEPARATOR =
'.'
DEFAULT_ARRAYS =
:expand
UNSET =
Object.new.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(separator: DEFAULT_SEPARATOR, arrays: DEFAULT_ARRAYS, equivalents: nil, equivalent_lookup: UNSET) ⇒ FrontmatterPath

Builds a frontmatter-path helper for one default configuration.



86
87
88
89
90
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 86

def initialize(separator: DEFAULT_SEPARATOR, arrays: DEFAULT_ARRAYS, equivalents: nil, equivalent_lookup: UNSET)
	@separator = normalise_separator(separator)
	@arrays = normalise_array_mode(arrays)
	@equivalent_lookup = equivalent_lookup.equal?(UNSET) ? self.class.build_equivalent_lookup(equivalents) : normalise_equivalent_lookup(equivalent_lookup)
end

Instance Attribute Details

#arraysObject (readonly)

Returns the value of attribute arrays.



20
21
22
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 20

def arrays
  @arrays
end

#equivalent_lookupObject (readonly)

Returns the value of attribute equivalent_lookup.



20
21
22
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 20

def equivalent_lookup
  @equivalent_lookup
end

#separatorObject (readonly)

Returns the value of attribute separator.



20
21
22
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 20

def separator
  @separator
end

Class Method Details

.build_equivalent_lookup(raw_equivalents, split_delimiter: StringArray::DEFAULT_DELIMITER) ⇒ Object

Normalises equivalent-key definitions into a path-aware lookup table.

Keys are stored against their full requested path so aliases can be scoped to one nested level only.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 31

def self.build_equivalent_lookup(raw_equivalents, split_delimiter: StringArray::DEFAULT_DELIMITER)
	return {} if raw_equivalents == false || raw_equivalents.nil?

	string_array = Jekyll::Plugins::PaginateV3::Support::StringArray.new(delimiter: split_delimiter)
	lookup = {}
	groups = raw_equivalents.is_a?(Array) ? raw_equivalents : [raw_equivalents]

	groups.each do |group|
		keys = if group.is_a?(Array)
							group.flat_map { |entry| string_array.interpret(entry, split: -1, flatten: true) }
						else
							string_array.interpret(group, split: -1, flatten: true)
						end
		keys = keys.map { |entry| entry.to_s.strip }.reject(&:empty?).uniq
		next if keys.length < 2

		keys.each { |key| lookup[key] = keys }
	end

	lookup
end

.read_hash(hash, key) ⇒ Object

Reads a hash entry using exact, string, or symbol lookup.



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 54

def self.read_hash(hash, key)
	return hash[key] if hash.key?(key)

	string_key = key.to_s
	return hash[string_key] if hash.key?(string_key)

	symbol_key = string_key.to_sym
	return hash[symbol_key] if hash.key?(symbol_key)

	nil
end

.resolve_hash_key(hash, requested_key_path, equivalent_lookup, separator: DEFAULT_SEPARATOR) ⇒ Object

Resolves the effective key present in one hash for the requested path-so-far.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 68

def self.resolve_hash_key(hash, requested_key_path, equivalent_lookup, separator: DEFAULT_SEPARATOR)
	string_key_path = requested_key_path.to_s.strip
	return nil if string_key_path.empty?

	group = equivalent_lookup[string_key_path] || [string_key_path]
	candidate_segments = group.map { |candidate_path| split_path(candidate_path, separator).last }.reject(&:empty?).uniq

	candidate_segments.reverse_each do |candidate|
		return candidate if hash.key?(candidate)

		symbol_candidate = candidate.to_sym
		return symbol_candidate if hash.key?(symbol_candidate)
	end

	nil
end

.split_path(path, separator = DEFAULT_SEPARATOR) ⇒ Object

Splits one configured path into non-blank segments.



23
24
25
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 23

def self.split_path(path, separator = DEFAULT_SEPARATOR)
	path.to_s.split(separator.to_s).map(&:strip).reject(&:empty?)
end

Instance Method Details

#traverse(data, path, separator: UNSET, arrays: UNSET, equivalents: UNSET, equivalent_lookup: UNSET) ⇒ Object

Traverses one data structure and returns:

  • nil when the path is missing
  • one raw terminal value when one match is found
  • an array of raw terminal values when many matches are found


124
125
126
127
128
129
130
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 124

def traverse(data, path, separator: UNSET, arrays: UNSET, equivalents: UNSET, equivalent_lookup: UNSET)
	active_separator = separator.equal?(UNSET) ? @separator : normalise_separator(separator)
	active_arrays = arrays.equal?(UNSET) ? @arrays : normalise_array_mode(arrays)
	active_lookup = resolve_lookup(equivalents, equivalent_lookup)

	traverse_internal(data, path, separator: active_separator, arrays: active_arrays, equivalent_lookup: active_lookup)
end

#with(separator: UNSET, arrays: UNSET, equivalents: UNSET, equivalent_lookup: UNSET) ⇒ Object

Builds a clone with selected configuration overrides.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/jekyll-paginate-v3/support/frontmatter_path.rb', line 93

def with(separator: UNSET, arrays: UNSET, equivalents: UNSET, equivalent_lookup: UNSET)
	resolved_separator = separator.equal?(UNSET) ? @separator : separator
	resolved_arrays = arrays.equal?(UNSET) ? @arrays : arrays

	if !equivalent_lookup.equal?(UNSET)
		return self.class.new(
			separator: resolved_separator,
			arrays: resolved_arrays,
			equivalent_lookup: equivalent_lookup
		)
	end

	if !equivalents.equal?(UNSET)
		return self.class.new(
			separator: resolved_separator,
			arrays: resolved_arrays,
			equivalents: equivalents
		)
	end

	self.class.new(
		separator: resolved_separator,
		arrays: resolved_arrays,
		equivalent_lookup: @equivalent_lookup
	)
end