jekyll_plugin_support 1.1.0 → 3.1.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +38 -3
- data/CHANGELOG.md +30 -6
- data/README.md +474 -4
- data/jekyll_plugin_support.gemspec +3 -1
- data/lib/block/jekyll_plugin_support_block.rb +5 -6
- data/lib/block/jekyll_plugin_support_block_noarg.rb +1 -3
- data/lib/error/jekyll_custom_error.rb +6 -5
- data/lib/generator/jekyll_plugin_support_generator.rb +1 -7
- data/lib/helper/jekyll_plugin_helper.rb +5 -5
- data/lib/helper/jekyll_plugin_helper_class.rb +2 -2
- data/lib/hooks/a_page.rb +203 -0
- data/lib/hooks/all_collections_hooks.rb +61 -0
- data/lib/hooks/all_files.rb +48 -0
- data/lib/hooks/class_methods.rb +38 -0
- data/lib/jekyll_all_collections/all_collections_tag.rb +174 -0
- data/lib/jekyll_plugin_support/jekyll_plugin_support_class.rb +6 -7
- data/lib/jekyll_plugin_support/jekyll_plugin_support_spec_support.rb +1 -3
- data/lib/jekyll_plugin_support/version.rb +1 -1
- data/lib/jekyll_plugin_support.rb +27 -12
- data/lib/tag/jekyll_plugin_support_tag.rb +1 -4
- data/lib/tag/jekyll_plugin_support_tag_noarg.rb +0 -2
- data/lib/util/mslinn_binary_search.rb +152 -0
- data/lib/util/send_chain.rb +56 -0
- data/spec/all_collections_tag/all_collections_tag_sort_spec.rb +184 -0
- data/spec/bsearch_spec.rb +50 -0
- data/spec/custom_error_spec.rb +12 -10
- data/spec/date_sort_spec.rb +84 -0
- data/spec/jekyll_plugin_helper_options_spec.rb +9 -3
- data/spec/liquid_variable_parsing_spec.rb +7 -6
- data/spec/mslinn_binary_search_spec.rb +47 -0
- data/spec/send_chain_spec.rb +72 -0
- data/spec/send_spec.rb +28 -0
- data/spec/sorted_lru_files_spec.rb +82 -0
- data/spec/spec_helper.rb +15 -3
- data/spec/status_persistence.txt +4 -7
- data/spec/testable_spec.rb +38 -0
- metadata +56 -5
@@ -1,8 +1,7 @@
|
|
1
|
-
require_relative '../error/jekyll_custom_error'
|
2
|
-
|
3
1
|
# Monkey patch StandardError so a new method called shorten_backtrace is added.
|
4
2
|
class StandardError
|
5
|
-
def shorten_backtrace(backtrace_element_count =
|
3
|
+
def shorten_backtrace(backtrace_element_count = 5)
|
4
|
+
set_backtrace backtrace[0..backtrace_element_count]
|
6
5
|
# self.backtrace = backtrace[0..backtrace_element_count].map do |x|
|
7
6
|
# raise JekyllPluginSupportError, "backtrace contains a #{x.class} with value '#{x}'." unless x.instance_of? String
|
8
7
|
|
@@ -12,21 +11,21 @@ class StandardError
|
|
12
11
|
end
|
13
12
|
|
14
13
|
module JekyllSupport
|
15
|
-
DISPLAYED_CALLS = 8
|
14
|
+
DISPLAYED_CALLS = 8 unless defined?(DISPLAYED_CALLS)
|
16
15
|
|
17
16
|
def self.error_short_trace(logger, error)
|
18
17
|
error.set_backtrace error.backtrace[0..DISPLAYED_CALLS]
|
19
|
-
logger.error { error }
|
18
|
+
logger.error { error.full_message } # Are error and logger.error defined?
|
20
19
|
error
|
21
20
|
end
|
22
21
|
|
23
22
|
# @return a new StandardError subclass containing the shorten_backtrace method
|
24
23
|
def define_error
|
25
|
-
Class.new JekyllSupport::CustomError
|
24
|
+
Class.new ::JekyllSupport::CustomError
|
26
25
|
end
|
27
26
|
module_function :define_error
|
28
27
|
|
29
|
-
JekyllPluginSupportError = define_error
|
28
|
+
JekyllPluginSupportError = define_error unless defined?(JekyllPluginSupportError)
|
30
29
|
|
31
30
|
def self.dump_vars(_logger, liquid_context)
|
32
31
|
page = liquid_context.registers[:page]
|
@@ -1,13 +1,26 @@
|
|
1
|
-
require 'colorator'
|
2
|
-
require 'jekyll'
|
3
|
-
require 'jekyll_plugin_logger'
|
4
|
-
|
5
1
|
def require_directory(dir)
|
6
2
|
Dir[File.join(dir, '*.rb')]&.sort&.each do |file|
|
7
3
|
require file unless file == __FILE__
|
8
4
|
end
|
9
5
|
end
|
10
6
|
|
7
|
+
require 'colorator'
|
8
|
+
require 'jekyll'
|
9
|
+
require 'jekyll_plugin_logger'
|
10
|
+
require 'pry'
|
11
|
+
require 'sorted_set'
|
12
|
+
|
13
|
+
# require_directory __dir__
|
14
|
+
require_directory "#{__dir__}/util"
|
15
|
+
require_directory "#{__dir__}/error"
|
16
|
+
require_directory "#{__dir__}/block"
|
17
|
+
require_directory "#{__dir__}/generator"
|
18
|
+
require_directory "#{__dir__}/helper"
|
19
|
+
require_directory "#{__dir__}/jekyll_plugin_support"
|
20
|
+
require_directory "#{__dir__}/tag"
|
21
|
+
require_directory "#{__dir__}/jekyll_all_collections"
|
22
|
+
require_directory "#{__dir__}/hooks"
|
23
|
+
|
11
24
|
module JekyllSupport
|
12
25
|
def self.redef_without_warning(const, value)
|
13
26
|
send(:remove_const, const) if const_defined?(const)
|
@@ -15,34 +28,36 @@ module JekyllSupport
|
|
15
28
|
end
|
16
29
|
end
|
17
30
|
|
31
|
+
module ToString
|
32
|
+
def to_s
|
33
|
+
"#{self}.class.name"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
18
37
|
module NoArgParsing
|
19
38
|
attr_accessor :no_arg_parsing
|
20
39
|
|
21
40
|
@no_arg_parsing = true
|
22
41
|
end
|
23
42
|
|
24
|
-
require_directory __dir__
|
25
|
-
require_directory "#{__dir__}/block"
|
26
|
-
require_directory "#{__dir__}/error"
|
27
|
-
require_directory "#{__dir__}/generator"
|
28
|
-
require_directory "#{__dir__}/helper"
|
29
|
-
require_directory "#{__dir__}/jekyll_plugin_support"
|
30
|
-
require_directory "#{__dir__}/tag"
|
31
|
-
|
32
43
|
module JekyllSupport
|
33
44
|
class JekyllTag
|
34
45
|
include JekyllSupportError
|
46
|
+
include ToString
|
35
47
|
end
|
36
48
|
|
37
49
|
class JekyllTagNoArgParsing
|
38
50
|
include JekyllSupportError
|
51
|
+
include ToString
|
39
52
|
end
|
40
53
|
|
41
54
|
class JekyllBlock
|
42
55
|
include JekyllSupportError
|
56
|
+
include ToString
|
43
57
|
end
|
44
58
|
|
45
59
|
class JekyllBlockNoArgParsing
|
46
60
|
include JekyllSupportError
|
61
|
+
include ToString
|
47
62
|
end
|
48
63
|
end
|
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'pry'
|
2
|
-
require_relative '../error/jekyll_plugin_error_handling'
|
3
|
-
|
4
1
|
module JekyllSupport
|
5
2
|
# Base class for Jekyll tags
|
6
3
|
class JekyllTag < Liquid::Tag
|
@@ -36,7 +33,7 @@ module JekyllSupport
|
|
36
33
|
@helper = JekyllPluginHelper.new(tag_name, @argument_string, @logger, respond_to?(:no_arg_parsing))
|
37
34
|
|
38
35
|
@error_name = "#{tag_name.camelcase(:upper)}Error"
|
39
|
-
JekyllSupport::CustomError.factory @error_name
|
36
|
+
::JekyllSupport::CustomError.factory @error_name
|
40
37
|
end
|
41
38
|
|
42
39
|
# Method prescribed by the Jekyll plugin lifecycle.
|
@@ -0,0 +1,152 @@
|
|
1
|
+
unless defined?(MSlinnBinarySearchError)
|
2
|
+
class MSlinnBinarySearchError < StandardError
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
# Ruby's binary search is unsuitable because the value to be searched for changes the required ordering for String compares
|
7
|
+
class MSlinnBinarySearch
|
8
|
+
attr_reader :accessor_chain, :array # For testing only
|
9
|
+
|
10
|
+
def initialize(accessor_chain)
|
11
|
+
@array = SortedSet.new # [LruFile] Ordered highest to lowest
|
12
|
+
@accessor_chain = accessor_chain
|
13
|
+
end
|
14
|
+
|
15
|
+
# Convert the SortedSet to an Array
|
16
|
+
def enable_search
|
17
|
+
@array = @array.to_a
|
18
|
+
end
|
19
|
+
|
20
|
+
# A match is found when the Array[LruFile] has an href which starts with the given stem
|
21
|
+
# @param stem [String]
|
22
|
+
# @return first item from @array.url that matches, or nil if no match
|
23
|
+
def find(stem)
|
24
|
+
raise MSlinnBinarySearchError, 'Invalid find because stem to search for is nil.' if stem.nil?
|
25
|
+
|
26
|
+
index = find_index(stem)
|
27
|
+
return nil if index.nil?
|
28
|
+
|
29
|
+
@array[index]
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param stem [String]
|
33
|
+
# @return index of first matching stem, or nil if @array is empty, or 0 if no stem specified
|
34
|
+
def find_index(stem)
|
35
|
+
return nil if @array.empty?
|
36
|
+
return 0 if stem.nil? || stem.empty?
|
37
|
+
|
38
|
+
mets = stem.reverse
|
39
|
+
return nil if @array[0].url[0...mets.size] > mets # TODO: use chain eval for item
|
40
|
+
return nil if @array[0].url[0] != mets[0]
|
41
|
+
|
42
|
+
_find_index(mets, 0, @array.length - 1)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param stem [String]
|
46
|
+
# @return [index] of matching values, or [] if @array is empty, or entire array if no stem specified
|
47
|
+
def find_indices(stem)
|
48
|
+
return [] if @array.empty?
|
49
|
+
return @array if stem.nil? || stem.empty?
|
50
|
+
|
51
|
+
first_index = _find_index(stem, 0, @array.length - 1)
|
52
|
+
last_index = first_index
|
53
|
+
last_index += 1 while @array[last_index].url.start_with? stem
|
54
|
+
[first_index..last_index]
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param item [LruFile]
|
58
|
+
# @return [int] index of matching LruFile in @array, or nil if not found
|
59
|
+
def index_of(lru_file)
|
60
|
+
raise MSlinnBinarySearchError, 'Invalid index_of lru_file (nil).' if lru_file.nil?
|
61
|
+
|
62
|
+
find_index lru_file.url
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [LruFile] item at given index in @array
|
66
|
+
def item_at(index)
|
67
|
+
if index > @array.length - 1
|
68
|
+
raise MSlinnBinarySearchError,
|
69
|
+
"Invalid item_at index (#{index}) is greater than maximum stem (#{@array.length - 1})."
|
70
|
+
end
|
71
|
+
raise MSlinnBinarySearchError, "Invalid item_at index (#{index}) is less than zero." if index.negative?
|
72
|
+
|
73
|
+
@array[index]
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param lru_file [LruFile]
|
77
|
+
def insert(lru_file)
|
78
|
+
raise MSlinnBinarySearchError, 'Invalid insert because new item is nil.' if lru_file.nil?
|
79
|
+
raise MSlinnBinarySearchError, "Invalid insert because new item has no chain (#{lru_file})" if lru_file.chain.nil?
|
80
|
+
|
81
|
+
@array.add lru_file
|
82
|
+
end
|
83
|
+
|
84
|
+
# TODO: Cache this method
|
85
|
+
# @param suffix [String] to use stem search on
|
86
|
+
# @return nil if @array is empty
|
87
|
+
# @return the first item in @array if suffix is nil or an empty string
|
88
|
+
def prefix_search(suffix)
|
89
|
+
return nil if @array.empty?
|
90
|
+
return @array[0] if suffix.empty? || suffix.nil?
|
91
|
+
|
92
|
+
low = search_index { |x| x.evaluate_with suffix }
|
93
|
+
return [] if low.nil?
|
94
|
+
|
95
|
+
high = low
|
96
|
+
high += 1 while high < @array.length &&
|
97
|
+
@array[high].evaluate_with(suffix)
|
98
|
+
@array[low..high]
|
99
|
+
end
|
100
|
+
|
101
|
+
# @param stem [String]
|
102
|
+
# @return [APage] matching APages, or [] if @array is empty, or entire array if no stem specified
|
103
|
+
def select_pages(stem)
|
104
|
+
first_index = find_index stem
|
105
|
+
return [] if first_index.nil?
|
106
|
+
|
107
|
+
last_index = first_index
|
108
|
+
while last_index < @array.length - 1
|
109
|
+
# LruFile.url is reversed, bug LruFile.page is not
|
110
|
+
break unless @array[last_index + 1].url.start_with?(stem.reverse)
|
111
|
+
|
112
|
+
last_index += 1
|
113
|
+
end
|
114
|
+
Range.new(first_index, last_index).map { |i| @array[i].page }
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
# A match is found when the Array[LruFile] has an href which starts with the given stem
|
120
|
+
# @param stem [String]
|
121
|
+
# @return [int] first index in @array that matches, or nil if no match
|
122
|
+
def _find_index(mets, min_index, max_index)
|
123
|
+
raise MSlinnBinarySearchError, "_find_index min_index(#{min_index})<0" if min_index.negative?
|
124
|
+
raise MSlinnBinarySearchError, "_find_index min_index(#{min_index})>max_index(#{max_index})" if min_index > max_index
|
125
|
+
raise MSlinnBinarySearchError, "_find_index max_index(#{max_index})>=@array.length(#{@array.length})" if max_index >= @array.length
|
126
|
+
|
127
|
+
return min_index if (min_index == max_index) && @array[min_index].url.start_with?(mets)
|
128
|
+
|
129
|
+
while min_index < max_index
|
130
|
+
mid_index = (min_index + max_index) / 2
|
131
|
+
mid_value = @array[mid_index].url[0...(mets.size)] # TODO: use chain eval for item
|
132
|
+
|
133
|
+
if mid_value == mets # back up until the first match is found
|
134
|
+
index = mid_index
|
135
|
+
loop do
|
136
|
+
return 0 if index.zero?
|
137
|
+
|
138
|
+
return index unless @array[index - 1].url.start_with?(mets)
|
139
|
+
|
140
|
+
index -= 1
|
141
|
+
end
|
142
|
+
elsif mid_value > mets
|
143
|
+
max_index = mid_index - 1
|
144
|
+
return _find_index(mets, min_index, max_index)
|
145
|
+
else
|
146
|
+
min_index = mid_index + 1
|
147
|
+
return _find_index(mets, min_index, max_index)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Supports one chain at a time
|
2
|
+
module SendChain
|
3
|
+
# See https://stackoverflow.com/a/79333706/553865
|
4
|
+
# This method can be called directly if no methods in the chain require arguments
|
5
|
+
# Does not use any external state
|
6
|
+
def send_chain(chain)
|
7
|
+
Array(chain).inject(self) { |o, a| o.send(*a) }
|
8
|
+
end
|
9
|
+
|
10
|
+
# Saves @chain structure containing :placeholders for arguments to be supplied later
|
11
|
+
# Call when a different chain with :placeholders is desired
|
12
|
+
def new_chain(chain)
|
13
|
+
abort "new_chain error: chain must be an array ('#{chain}' was an #{chain.class.name})" \
|
14
|
+
unless chain.instance_of?(Array)
|
15
|
+
@chain = chain
|
16
|
+
end
|
17
|
+
|
18
|
+
# Call after new_chain, to evaluate @chain with values
|
19
|
+
def substitute_and_send_chain_with(values)
|
20
|
+
send_chain substitute_chain_with values
|
21
|
+
end
|
22
|
+
|
23
|
+
alias evaluate_with substitute_and_send_chain_with
|
24
|
+
|
25
|
+
# Call this method after calling new_chain to perform error checking and replace :placeholders with values.
|
26
|
+
# @chain is not modified.
|
27
|
+
# @return [Array] Modified chain
|
28
|
+
def substitute_chain_with(values)
|
29
|
+
values = [values] unless values.instance_of?(Array)
|
30
|
+
|
31
|
+
placeholder_count = @chain.flatten.count { |x| x == :placeholder }
|
32
|
+
if values.length != placeholder_count
|
33
|
+
abort "with_values error: number of values (#{values.length}) does not match the number of placeholders (#{placeholder_count})"
|
34
|
+
end
|
35
|
+
|
36
|
+
eval_chain @chain, values
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Replaces :placeholders with values
|
42
|
+
# Does not use any external state
|
43
|
+
# @return modified chain
|
44
|
+
def eval_chain(chain, values)
|
45
|
+
chain.map do |c|
|
46
|
+
case c
|
47
|
+
when :placeholder
|
48
|
+
values.shift
|
49
|
+
when Array
|
50
|
+
eval_chain c, values
|
51
|
+
else
|
52
|
+
c
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/hooks/a_page'
|
3
|
+
|
4
|
+
class NullBinding < BasicObject
|
5
|
+
include ::Kernel
|
6
|
+
|
7
|
+
# Avoid error message "warning: undefining `object_id' may cause serious problems"
|
8
|
+
# https://stackoverflow.com/a/17791631/553865
|
9
|
+
(
|
10
|
+
::Kernel.instance_methods(false) +
|
11
|
+
::Kernel.private_instance_methods(false) -
|
12
|
+
[:binding]
|
13
|
+
).each { |x| undef_method(x) unless x == :object_id }
|
14
|
+
|
15
|
+
def min_binding
|
16
|
+
binding
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def show_dates(label, array)
|
21
|
+
puts " #{label} actual: #{array.map(&:title).join(', ')} <==> expected: #{expected.map(&:title).join(', ')}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def show(label, lambda_string, actual, expected)
|
25
|
+
puts "#{label} - For lambda_string: #{lambda_string}"
|
26
|
+
puts " actual: #{actual.map(&:title).join(', ')}"
|
27
|
+
puts "expected: #{expected.map(&:title).join(', ')}"
|
28
|
+
actual_array = actual.map do |x|
|
29
|
+
[
|
30
|
+
(x.date.strftime '%Y-%m-%d' + '/' + x.title), (x.last_modified.strftime '%Y-%m-%d' + '/' + x.title)
|
31
|
+
].join('/')
|
32
|
+
end
|
33
|
+
expected_array = expected.map do |x|
|
34
|
+
[
|
35
|
+
(x.date.strftime '%Y-%m-%d' + '/' + x.title), (x.last_modified.strftime '%Y-%m-%d' + '/' + x.title)
|
36
|
+
].join('/')
|
37
|
+
end
|
38
|
+
puts ' actual date/last_modified: ' + actual_array.join(', ')
|
39
|
+
puts 'expected date/last_modified: ' + expected_array.join(', ')
|
40
|
+
end
|
41
|
+
|
42
|
+
logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
|
43
|
+
|
44
|
+
# See https://stackoverflow.com/a/75388137/553865
|
45
|
+
RSpec.describe(JekyllSupport) do
|
46
|
+
let(:o1) do
|
47
|
+
described_class.apage_from(
|
48
|
+
collection_name: '_posts',
|
49
|
+
date: '2020-01-20',
|
50
|
+
last_modified: '2020-01-20',
|
51
|
+
logger: logger,
|
52
|
+
title: 'a_A (o1)'
|
53
|
+
)
|
54
|
+
end
|
55
|
+
let(:o2) do
|
56
|
+
described_class.apage_from(
|
57
|
+
collection_name: '_posts',
|
58
|
+
date: '2021-01-21',
|
59
|
+
last_modified: '2021-01-21',
|
60
|
+
logger: logger,
|
61
|
+
title: 'b_B (o2)'
|
62
|
+
)
|
63
|
+
end
|
64
|
+
let(:o3) do
|
65
|
+
described_class.apage_from(
|
66
|
+
collection_name: '_posts',
|
67
|
+
date: '2021-01-21',
|
68
|
+
last_modified: '2022-01-22',
|
69
|
+
logger: logger,
|
70
|
+
title: 'b_C (o3)'
|
71
|
+
)
|
72
|
+
end
|
73
|
+
let(:o4) do
|
74
|
+
described_class.apage_from(
|
75
|
+
collection_name: '_posts',
|
76
|
+
date: '2022-01-22',
|
77
|
+
last_modified: '2022-01-22',
|
78
|
+
logger: logger,
|
79
|
+
title: 'c_C (o4)'
|
80
|
+
)
|
81
|
+
end
|
82
|
+
let(:objs) { [o1, o2, o3, o4] }
|
83
|
+
|
84
|
+
it '(1) defines sort_by lambda with last_modified (ascending)' do
|
85
|
+
sort_lambda = ->(a, b) { [a.last_modified] <=> [b.last_modified] }
|
86
|
+
actual = objs.sort(&sort_lambda)
|
87
|
+
expected = [o1, o2, o3, o4]
|
88
|
+
show('(1)', '[a.last_modified] <=> [b.last_modified]', actual, expected)
|
89
|
+
expect(actual).to eq(expected)
|
90
|
+
end
|
91
|
+
|
92
|
+
it '(2) makes sort_by lambdas from stringified comparison of last_modified (ascending)' do
|
93
|
+
sort_lambda_string = '->(a, b) { a.last_modified <=> b.last_modified }'
|
94
|
+
sort_lambda = eval sort_lambda_string, NullBinding.new.min_binding, __FILE__, __LINE__ - 1
|
95
|
+
actual = objs.sort(&sort_lambda)
|
96
|
+
expected = [o1, o2, o3, o4]
|
97
|
+
show('(2)', sort_lambda_string, actual, expected)
|
98
|
+
expect(actual).to eq(expected)
|
99
|
+
end
|
100
|
+
|
101
|
+
it '(3) makes sort_by lambda from stringified array of last_modified (ascending)' do
|
102
|
+
sort_lambda_string = '->(a, b) { [a.last_modified] <=> [b.last_modified] }'
|
103
|
+
sort_lambda = eval sort_lambda_string, NullBinding.new.min_binding, __FILE__, __LINE__ - 1
|
104
|
+
actual = objs.sort(&sort_lambda)
|
105
|
+
expected = [o1, o2, o3, o4]
|
106
|
+
show('(3)', sort_lambda_string, actual, expected)
|
107
|
+
expect(actual).to eq(expected)
|
108
|
+
end
|
109
|
+
|
110
|
+
it '(4) makes sort_by lambda with last_modified (descending) from stringified array' do
|
111
|
+
sort_lambda_string = '->(a, b) { [b.last_modified] <=> [a.last_modified] }'
|
112
|
+
sort_lambda = eval sort_lambda_string, NullBinding.new.min_binding, __FILE__, __LINE__ - 1
|
113
|
+
actual = objs.sort(&sort_lambda)
|
114
|
+
expected = [o4, o3, o2, o1]
|
115
|
+
show('(4)', sort_lambda_string, actual, expected)
|
116
|
+
expect([o3, o4]).to include(actual[0]) # The sort might yield o3 or o4 in this position
|
117
|
+
expect([o3, o4]).to include(actual[1]) # The sort might yield o3 or o4 in this position
|
118
|
+
expect(o2).to eq(actual[2])
|
119
|
+
expect(o1).to eq(actual[3])
|
120
|
+
end
|
121
|
+
|
122
|
+
it '(5) create_lambda with date (descending)' do
|
123
|
+
lambda_string = JekyllAllCollections::AllCollectionsTag.create_lambda_string('-last_modified')
|
124
|
+
expect(lambda_string).to eq('->(a, b) { [b.last_modified] <=> [a.last_modified] }')
|
125
|
+
sort_lambda = self.eval lambda_string, binding
|
126
|
+
actual = objs.sort(&sort_lambda)
|
127
|
+
expected = [o4, o3, o2, o1]
|
128
|
+
show('(5)', lambda_string, actual, expected)
|
129
|
+
expect([o3, o4]).to include(actual[0]) # The sort might yield o3 or o4 in this position
|
130
|
+
expect([o3, o4]).to include(actual[1]) # The sort might yield o3 or o4 in this position
|
131
|
+
expect(o2).to eq(actual[2])
|
132
|
+
expect(o1).to eq(actual[3])
|
133
|
+
end
|
134
|
+
|
135
|
+
it '(6) create_lambda with date (ascending)' do
|
136
|
+
lambda_string = JekyllAllCollections::AllCollectionsTag.create_lambda_string('date')
|
137
|
+
expect(lambda_string).to eq('->(a, b) { [a.date] <=> [b.date] }')
|
138
|
+
sort_lambda = self.eval lambda_string, binding
|
139
|
+
actual = objs.sort(&sort_lambda)
|
140
|
+
expected = [o1, o2, o3, o4]
|
141
|
+
show('(1)', lambda_string, actual, expected)
|
142
|
+
expect(actual).to eq(expected)
|
143
|
+
end
|
144
|
+
|
145
|
+
it '(7) create_lambda with date (ascending) and last_modified (ascending)' do
|
146
|
+
lambda_string = JekyllAllCollections::AllCollectionsTag.create_lambda_string(%w[date last_modified])
|
147
|
+
expect(lambda_string).to eq('->(a, b) { [a.date, a.last_modified] <=> [b.date, b.last_modified] }')
|
148
|
+
sort_lambda = self.eval lambda_string, binding
|
149
|
+
actual = objs.sort(&sort_lambda)
|
150
|
+
expected = [o1, o2, o3, o4]
|
151
|
+
show('(7)', lambda_string, actual, expected)
|
152
|
+
expect(actual).to eq(expected)
|
153
|
+
end
|
154
|
+
|
155
|
+
it '(8) create_lambda with date (descending) and last_modified (descending)' do
|
156
|
+
lambda_string = JekyllAllCollections::AllCollectionsTag.create_lambda_string(['-date', '-last_modified'])
|
157
|
+
expect(lambda_string).to eq('->(a, b) { [b.date, b.last_modified] <=> [a.date, a.last_modified] }')
|
158
|
+
sort_lambda = self.eval lambda_string, binding
|
159
|
+
actual = objs.sort(&sort_lambda)
|
160
|
+
expected = [o4, o3, o2, o1]
|
161
|
+
show('(8)', lambda_string, actual, expected)
|
162
|
+
expect(actual).to eq(expected)
|
163
|
+
end
|
164
|
+
|
165
|
+
it '(9) create_lambda with date (descending) and last_modified (ascending)' do
|
166
|
+
lambda_string = JekyllAllCollections::AllCollectionsTag.create_lambda_string(['-date', 'last_modified'])
|
167
|
+
expect(lambda_string).to eq('->(a, b) { [b.date, a.last_modified] <=> [a.date, b.last_modified] }')
|
168
|
+
sort_lambda = self.eval lambda_string, binding
|
169
|
+
actual = objs.sort(&sort_lambda)
|
170
|
+
expected = [o4, o2, o3, o1]
|
171
|
+
show('(9)', lambda_string, actual, expected)
|
172
|
+
expect(actual).to eq(expected)
|
173
|
+
end
|
174
|
+
|
175
|
+
it '(10) create_lambda with date (ascending) and last_modified (descending)' do
|
176
|
+
lambda_string = JekyllAllCollections::AllCollectionsTag.create_lambda_string(['date', '-last_modified'])
|
177
|
+
expect(lambda_string).to eq('->(a, b) { [a.date, b.last_modified] <=> [b.date, a.last_modified] }')
|
178
|
+
sort_lambda = self.eval lambda_string, binding
|
179
|
+
actual = objs.sort(&sort_lambda)
|
180
|
+
expected = [o1, o3, o2, o4]
|
181
|
+
show('(10)', lambda_string, actual, expected)
|
182
|
+
expect(actual).to eq(expected)
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Ruby's binary search is unsuitable because ordering requirements are not stable.
|
4
|
+
# the value to be searched for changes the required ordering
|
5
|
+
|
6
|
+
RSpec.describe(Array) do
|
7
|
+
before { skip('Never gonna give you up/Never gonna let you down') }
|
8
|
+
|
9
|
+
sorted_ints = [0, 4, 7, 10, 12]
|
10
|
+
sorted_strings = %w[aaa aab aac bbb bbc bbd ccc ccd cce].sort.reverse
|
11
|
+
|
12
|
+
it 'returns index of first int match' do
|
13
|
+
actual = sorted_ints.bsearch_index { |x| x >= 4 }
|
14
|
+
expect(actual).to eq(1)
|
15
|
+
|
16
|
+
actual = sorted_ints.bsearch_index { |x| x >= 6 }
|
17
|
+
expect(actual).to eq(2)
|
18
|
+
|
19
|
+
actual = sorted_ints.bsearch_index { |x| x >= -1 }
|
20
|
+
expect(actual).to eq(0)
|
21
|
+
|
22
|
+
actual = sorted_ints.bsearch_index { |x| x >= 100 }
|
23
|
+
expect(actual).to be_nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# See https://stackoverflow.com/q/79333097/553865
|
27
|
+
it 'returns index of first string match' do
|
28
|
+
puts(sorted_strings.map { |x| x.start_with? 'a' })
|
29
|
+
index = sorted_strings.bsearch_index { |x| x.start_with? 'a' }
|
30
|
+
expect(sorted_strings[index]).to eq('aac')
|
31
|
+
|
32
|
+
index = sorted_strings.bsearch_index { |x| x.start_with? 'aa' }
|
33
|
+
expect(sorted_strings[index]).to eq('aac')
|
34
|
+
|
35
|
+
index = sorted_strings.bsearch_index { |x| x.start_with? 'aaa' }
|
36
|
+
expect(sorted_strings[index]).to eq('aaa')
|
37
|
+
|
38
|
+
index = sorted_strings.bsearch_index { |x| x.start_with? 'b' }
|
39
|
+
expect(sorted_strings[index]).to eq('bbd')
|
40
|
+
|
41
|
+
index = sorted_strings.bsearch_index { |x| x.start_with? 'bb' }
|
42
|
+
expect(sorted_strings[index]).to eq('bbd')
|
43
|
+
|
44
|
+
index = sorted_strings.bsearch_index { |x| x.start_with? 'bbc' }
|
45
|
+
expect(sorted_strings[index]).to eq('bbc')
|
46
|
+
|
47
|
+
index = sorted_strings.bsearch_index { |x| x.start_with? 'cc' }
|
48
|
+
expect(sorted_strings[index]).to eq('cce')
|
49
|
+
end
|
50
|
+
end
|
data/spec/custom_error_spec.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
require_relative '../lib/
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/error/jekyll_custom_error'
|
3
|
+
require_relative '../lib/jekyll_plugin_support/jekyll_plugin_support_class'
|
4
|
+
require_relative '../lib/helper/jekyll_plugin_helper'
|
3
5
|
|
4
6
|
class Dummy
|
5
7
|
def just_for_testing; end
|
@@ -8,30 +10,30 @@ end
|
|
8
10
|
class CustomErrorSpec
|
9
11
|
tag_name = 'test_tag'
|
10
12
|
argument_string = 'This is the argument string'
|
11
|
-
AnError = JekyllSupport.define_error
|
13
|
+
AnError = ::JekyllSupport.define_error
|
12
14
|
AnError.class_variable_set(:@@tag_name, tag_name)
|
13
15
|
AnError.class_variable_set(:@@argument_string, argument_string)
|
14
16
|
|
15
17
|
puts "AnError is a #{AnError.class}; StandardError is a #{StandardError.class}"
|
16
18
|
begin
|
17
|
-
raise AnError, '
|
19
|
+
raise AnError, 'This error is expected'
|
18
20
|
rescue AnError => e
|
19
21
|
puts "Caught AnError: #{e.message}"
|
20
|
-
rescue JekyllSupport::CustomError => e
|
22
|
+
rescue ::JekyllSupport::CustomError => e
|
21
23
|
puts "Caught CustomError: #{e.message}"
|
22
24
|
end
|
23
25
|
|
24
|
-
RSpec.describe JekyllPluginHelper do
|
26
|
+
RSpec.describe ::JekyllSupport::JekyllPluginHelper do
|
25
27
|
it 'generates messages' do
|
26
28
|
msg = described_class.generate_message(Dummy, tag_name, '0.1.0')
|
27
29
|
puts msg
|
28
|
-
expect(msg).to include(
|
29
|
-
expect(msg).to include(
|
30
|
-
expect(msg).to include(
|
30
|
+
expect(msg).to include('Error class: DummyError')
|
31
|
+
expect(msg).to include('CSS class for error messages: dummy_error')
|
32
|
+
expect(msg).to include('die_on_dummy_error: false')
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
|
-
RSpec.describe JekyllSupport::CustomError do
|
36
|
+
RSpec.describe ::JekyllSupport::CustomError do
|
35
37
|
it 'can create custom errors' do
|
36
38
|
expect { raise AnError, 'Oops' }.to raise_error(AnError)
|
37
39
|
end
|