Add bin and edit workflow
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s

This commit is contained in:
2026-09-16 13:11:16 -06:00
parent c8ac4fcae5
commit 4cee170d66
17576 changed files with 895740 additions and 2 deletions
@@ -0,0 +1,112 @@
require 'spec_helper'
require_relative '../../lib/jekyll_all_collections'
class APageStub
attr_reader :date, :last_modified, :label
def initialize(date, last_modified, label = '')
@date = Date.parse date
@last_modified = Date.parse last_modified
@label = label
end
def to_s
@label
end
end
def show(lambda_string, result, expected)
p "For lambda_string: #{lambda_string}"
p " result: #{result.map(&:label).join(', ')} <==> expected: #{expected.map(&:label).join(', ')}"
end
# See https://stackoverflow.com/a/75388137/553865
RSpec.describe(AllCollectionsTag::AllCollectionsTag) do
let(:o1) { APageStub.new('2020-01-01', '2020-01-01', 'a_A') }
let(:o2) { APageStub.new('2021-01-01', '2020-01-01', 'b_A') }
let(:o3) { APageStub.new('2021-01-01', '2023-01-01', 'b_B') }
let(:o4) { APageStub.new('2022-01-01', '2023-01-01', 'c_B') }
let(:objs) { [o1, o2, o3, o4] }
it 'defines sort_by lambda with last_modified' do
sort_lambda = ->(a, b) { [a.last_modified] <=> [b.last_modified] }
result = objs.sort(&sort_lambda)
expect(result).to eq([o1, o2, o3, o4])
end
it 'makes sort_by lambdas from stringified date' do
sort_lambda = eval '->(a, b) { a.last_modified <=> b.last_modified }',
NullBinding.new.min_binding, __FILE__, __LINE__ - 1
result = objs.sort(&sort_lambda)
expect(result).to eq([o1, o2, o3, o4])
end
it 'makes sort_by lambdas from stringified array of last_modified' do
sort_lambda = eval '->(a, b) { [a.last_modified] <=> [b.last_modified] }',
NullBinding.new.min_binding, __FILE__, __LINE__ - 1
result = objs.sort(&sort_lambda)
expect(result).to eq([o1, o2, o3, o4])
end
it 'makes sort_by lambdas with descending keys from stringified array of last_modified' do
sort_lambda = eval '->(a, b) { [b.last_modified] <=> [a.last_modified] }',
NullBinding.new.min_binding, __FILE__, __LINE__ - 1
result = objs.sort(&sort_lambda)
expected = [o3, o4, o1, o2]
expect(result).to eq(expected)
end
it 'create_lambda with 1 date key, descending' do
lambda_string = described_class.create_lambda_string('-last_modified')
sort_lambda = described_class.evaluate(lambda_string)
result = objs.sort(&sort_lambda)
expected = [o3, o4, o1, o2]
# show(lambda_string, result, expected)
expect(result).to eq(expected)
end
it 'create_lambda with 1 date key, ascending' do
lambda_string = described_class.create_lambda_string('date')
sort_lambda = described_class.evaluate(lambda_string)
result = objs.sort(&sort_lambda)
expected = [o1, o2, o3, o4]
# show(lambda_string, result, expected)
expect(result).to eq(expected)
end
it 'create_lambda with 2 date keys, both ascending' do
lambda_string = described_class.create_lambda_string(%w[date last_modified])
sort_lambda = described_class.evaluate(lambda_string)
result = objs.sort(&sort_lambda)
expected = [o1, o2, o3, o4]
# show(lambda_string, result, expected)
expect(result).to eq(expected)
end
it 'create_lambda with 2 date keys, both descending' do
lambda_string = described_class.create_lambda_string(['-date', '-last_modified'])
sort_lambda = described_class.evaluate(lambda_string)
result = objs.sort(&sort_lambda)
expected = [o4, o3, o2, o1]
# show(lambda_string, result, expected)
expect(result).to eq(expected)
end
it 'create_lambda with 2 date keys, first descending and second ascending' do
lambda_string = described_class.create_lambda_string(['-date', 'last_modified'])
sort_lambda = described_class.evaluate(lambda_string)
result = objs.sort(&sort_lambda)
expected = [o4, o2, o3, o1]
# show(lambda_string, result, expected)
expect(result).to eq(expected)
end
it 'create_lambda with 2 date keys, first ascending and second descending' do
lambda_string = described_class.create_lambda_string(['date', '-last_modified'])
sort_lambda = described_class.evaluate(lambda_string)
result = objs.sort(&sort_lambda)
expected = [o1, o3, o2, o4]
# show(lambda_string, result, expected)
expect(result).to eq(expected)
end
end
@@ -0,0 +1,50 @@
require 'spec_helper'
# Ruby's binary search is unsuitable because ordering requirements are not stable.
# the value to be searched for changes the required ordering
RSpec.describe(Array) do
before { skip('Never gonna give you up/Never gonna let you down') }
sorted_ints = [0, 4, 7, 10, 12]
sorted_strings = %w[aaa aab aac bbb bbc bbd ccc ccd cce].sort.reverse
it 'returns index of first int match' do
actual = sorted_ints.bsearch_index { |x| x >= 4 }
expect(actual).to eq(1)
actual = sorted_ints.bsearch_index { |x| x >= 6 }
expect(actual).to eq(2)
actual = sorted_ints.bsearch_index { |x| x >= -1 }
expect(actual).to eq(0)
actual = sorted_ints.bsearch_index { |x| x >= 100 }
expect(actual).to be_nil
end
# See https://stackoverflow.com/q/79333097/553865
it 'returns index of first string match' do
puts(sorted_strings.map { |x| x.start_with? 'a' })
index = sorted_strings.bsearch_index { |x| x.start_with? 'a' }
expect(sorted_strings[index]).to eq('aac')
index = sorted_strings.bsearch_index { |x| x.start_with? 'aa' }
expect(sorted_strings[index]).to eq('aac')
index = sorted_strings.bsearch_index { |x| x.start_with? 'aaa' }
expect(sorted_strings[index]).to eq('aaa')
index = sorted_strings.bsearch_index { |x| x.start_with? 'b' }
expect(sorted_strings[index]).to eq('bbd')
index = sorted_strings.bsearch_index { |x| x.start_with? 'bb' }
expect(sorted_strings[index]).to eq('bbd')
index = sorted_strings.bsearch_index { |x| x.start_with? 'bbc' }
expect(sorted_strings[index]).to eq('bbc')
index = sorted_strings.bsearch_index { |x| x.start_with? 'cc' }
expect(sorted_strings[index]).to eq('cce')
end
end
@@ -0,0 +1,39 @@
require_relative '../lib/error/jekyll_custom_error'
require_relative '../lib/jekyll_plugin_support/jekyll_plugin_support_class'
class Dummy
def just_for_testing; end
end
class CustomErrorSpec
tag_name = 'test_tag'
argument_string = 'This is the argument string'
AnError = ::JekyllSupport.define_error
AnError.class_variable_set(:@@tag_name, tag_name)
AnError.class_variable_set(:@@argument_string, argument_string)
puts "AnError is a #{AnError.class}; StandardError is a #{StandardError.class}"
begin
raise AnError, 'Oops'
rescue AnError => e
puts "Caught AnError: #{e.message}"
rescue ::JekyllSupport::CustomError => e
puts "Caught CustomError: #{e.message}"
end
RSpec.describe JekyllSupport::JekyllPluginHelper do
it 'generates messages' do
msg = described_class.generate_message(Dummy, tag_name, '0.1.0')
puts msg
expect(msg).to include('Error class: DummyError')
expect(msg).to include('CSS class for error messages: dummy_error')
expect(msg).to include('die_on_dummy_error: false')
end
end
RSpec.describe ::JekyllSupport::CustomError do
it 'can create custom errors' do
expect { raise AnError, 'Oops' }.to raise_error(AnError)
end
end
end
@@ -0,0 +1,84 @@
require 'spec_helper'
require_relative '../lib/jekyll_plugin_support'
# Verifies how data comparisons work
class Obj
# `last_modified` is primary sort key
# `date` (when specified) is secondary sort key
attr_reader :date, :last_modified
def initialize(param1, param2)
@last_modified = Date.parse(param1)
@date = Date.parse(param2)
end
end
RSpec.describe(Obj) do
let(:o1) { described_class.new('2000-01-01', '2001-01-01') }
let(:o2) { described_class.new('2010-01-01', '2001-01-01') }
let(:o3) { described_class.new('2010-01-01', '2011-01-01') }
let(:o4) { described_class.new('2020-01-01', '2011-01-01') }
let(:objs) { [o1, o2, o3, o4] }
# See https://ruby-doc.org/3.2.0/Comparable.html
it 'compares one key with ascending dates' do
expect([o1.last_modified] <=> [o2.last_modified]).to eq(-1)
expect([o2.last_modified] <=> [o3.last_modified]).to eq(0)
expect([o3.last_modified] <=> [o4.last_modified]).to eq(-1)
end
it 'compares two keys with ascending dates' do
expect([o1.last_modified, o1.date] <=> [o2.last_modified, o2.date]).to eq(-1)
expect([o2.last_modified, o2.date] <=> [o3.last_modified, o3.date]).to eq(-1)
expect([o3.last_modified, o3.date] <=> [o4.last_modified, o4.date]).to eq(-1)
end
it 'compares one key with descending dates' do
expect([o1.last_modified] <=> [o2.last_modified]).to eq(-1)
expect([o2.last_modified] <=> [o3.last_modified]).to eq(0)
end
it 'compares two keys with descending dates' do
expect([o2.last_modified, o2.date] <=> [o1.last_modified, o1.date]).to eq(1)
expect([o3.last_modified, o3.date] <=> [o2.last_modified, o2.date]).to eq(1)
expect([o4.last_modified, o4.date] <=> [o3.last_modified, o3.date]).to eq(1)
end
# See https://ruby-doc.org/3.2.0/Enumerable.html#method-i-sort
it 'sort with one key ascending' do
sort_lambda = ->(a, b) { [a.last_modified] <=> [b.last_modified] }
result = objs.sort(&sort_lambda)
expect(result).to eq([o1, o2, o3, o4])
end
it 'sort with one key descending' do
sort_lambda = ->(a, b) { [b.last_modified] <=> [a.last_modified] }
result = objs.sort(&sort_lambda)
expect(result).to eq([o4, o2, o3, o1])
end
it 'sort with two keys ascending' do
sort_lambda = ->(a, b) { [a.last_modified, a.date] <=> [b.last_modified, b.date] }
result = objs.sort(&sort_lambda)
expect(result).to eq([o1, o2, o3, o4])
end
it 'sort with both keys descending' do
sort_lambda = ->(a, b) { [b.last_modified, b.date] <=> [a.last_modified, a.date] }
result = objs.sort(&sort_lambda)
expect(result).to eq([o4, o3, o2, o1])
end
it 'sort with last_modified descending and date ascending' do
sort_lambda = ->(a, b) { [b.last_modified, a.date] <=> [a.last_modified, b.date] }
result = objs.sort(&sort_lambda)
expect(result).to eq([o4, o2, o3, o1])
end
it 'sort with last_modified ascending and date descending' do
sort_lambda = ->(a, b) { [a.last_modified, b.date] <=> [b.last_modified, a.date] }
result = objs.sort(&sort_lambda)
expect(result).to eq([o1, o3, o2, o4])
end
end
@@ -0,0 +1,64 @@
require 'jekyll_plugin_logger'
# require 'rspec/match_ignoring_whitespace'
require_relative '../lib/jekyll_plugin_support'
require_relative '../lib/jekyll_plugin_support/jekyll_plugin_support_spec_support'
class JekyllPluginHelperOptionsTest
RSpec.describe ::JekyllSupport::JekyllPluginHelper do
logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
it 'parses quoted string options' do
helper = described_class.new('my_tag', "colors='blue or green' blah ick", logger, false)
helper.reinitialize helper.markup
expect(helper.keys_values.keys).to eq(%w[colors blah ick])
colors = helper.parameter_specified? 'colors'
expect(colors).to eq('blue or green')
expect(helper.keys_values.keys).to eq(%w[blah ick])
end
it 'parses unquoted string options' do
helper = described_class.new('my_tag', 'color=blue blah ick', logger, false)
helper.reinitialize helper.markup
expect(helper.keys_values.keys).to eq(%w[color blah ick])
color = helper.parameter_specified? 'color'
expect(color).to eq('blue')
expect(helper.keys_values.keys).to eq(%w[blah ick])
end
it 'parses quoted booleans' do
helper = described_class.new('my_tag', "bool1='true' bool2='false' blah ick", logger, false)
helper.reinitialize helper.markup
expect(helper.keys_values.keys).to eq(%w[bool1 bool2 blah ick])
bool1 = helper.parameter_specified? 'bool1'
expect(bool1).to be true
bool2 = helper.parameter_specified? 'bool2'
expect(bool2).to be false
expect(helper.keys_values.keys).to eq(%w[blah ick])
expect(helper.remaining_markup).to eq('blah ick')
end
it 'parses unquoted booleans' do
helper = described_class.new('my_tag', 'bool1=true bool2=false blah ick', logger, false)
helper.reinitialize helper.markup
expect(helper.keys_values.keys).to eq(%w[bool1 bool2 blah ick])
bool1 = helper.parameter_specified? 'bool1'
expect(bool1).to be true
bool2 = helper.parameter_specified? 'bool2'
expect(bool2).to be false
expect(helper.keys_values.keys).to eq(%w[blah ick])
expect(helper.remaining_markup).to eq('blah ick')
end
end
end
@@ -0,0 +1,34 @@
require 'jekyll_plugin_logger'
# require 'rspec/match_ignoring_whitespace'
require_relative '../lib/jekyll_plugin_support'
require_relative '../lib/jekyll_plugin_support/jekyll_plugin_support_spec_support'
class LiquidVariableParsing
# @return copy of str with references to defined variables replaced by the values of the variables
def self.variable_replace(str, scopes)
result = str.clone
match_data_list = str.to_enum(:scan, /{{[a-z_][a-zA-Z_0-9]*}}/).map { Regexp.last_match }.reverse
match_data_list&.each do |md|
from = md.begin(0)
to = md.end(0) - 1
ref = str[from..to]
name = ref[2..-3]
scopes&.each do |scope|
value = scope.key?(name) ? scope[name] : ref
# puts "str=#{str}; from=#{from}; to=#{to}; name=#{name} value=#{value}"
result[from..to] = value
end
end
result
end
RSpec.describe ::JekyllSupport::JekyllPluginHelper do
it 'substitutes variable references for values without recursion' do
scopes = [{ 'a' => '{{', 'b' => 'asdf', 'c' => '}}' }]
str = '{{a}}{{b}}{{c}} This should be unchanged: {{d}}'
new_str = LiquidVariableParsing.variable_replace(str, scopes)
expect(str).to start_with('{{a}}')
expect(new_str).to eq('{{asdf}} This should be unchanged: {{d}}')
end
end
end
@@ -0,0 +1,47 @@
require 'spec_helper'
require_relative '../lib/hooks/all_files'
def build_msbs(sorted_strings)
sorted_strings.each do |string|
$msbs.insert LruFile.new(string.reverse, "Page #{string}") # { |x| x.url.start_with? string }
end
$msbs.enable_search
end
RSpec.describe(MSlinnBinarySearch) do
$msbs = described_class.new [:url, %i[start_with? placeholder]]
build_msbs %w[aaa.html baa.html caa.html bbb.html cbb.html dbb.html ccc.html ccd.html cce.html]
it 'handles an empty search string by returning the index of the first item (0)' do
index = $msbs.find_index '' # { |x| x.url.start_with? '' }
expect(index).to be_zero
end
it 'returns the index of the first partial match' do
index = $msbs.find_index 'a.html' # { |x| x.url.start_with? 'a.html' }
expect(index).to eq(0)
index = $msbs.find_index 'baa.html' # { |x| x.url.start_with? 'baa.html' }
expect(index).to eq(1)
index = $msbs.find_index 'c.html' # { |x| x.url.start_with? 'c.html' }
expect(index).to eq(6)
index = $msbs.find_index 'cce.html' # { |x| x.url.start_with? 'cce.html' }
expect(index).to eq(8)
end
it 'returns the item of the first match' do
item = $msbs.find 'a.html' # { |x| x.url.start_with? 'a.html' }
expect(item.url.reverse).to eq('aaa.html')
item = $msbs.find 'baa.html' # { |x| x.url.start_with? 'baa.html' }
expect(item.url.reverse).to eq('baa.html')
item = $msbs.find 'c.html' # { |x| x.url.start_with? 'c.html' }
expect(item.url.reverse).to eq('ccc.html')
item = $msbs.find 'cce.html' # { |x| x.url.start_with? 'cce.html' }
expect(item.url.reverse).to eq('cce.html')
end
end
@@ -0,0 +1,72 @@
require 'spec_helper'
require_relative '../lib/util/send_chain'
unless defined? LruFile
LruFile = Struct.new(:url, :page) do
include SendChain
end
end
RSpec.describe(LruFile) do
lru_file = described_class.new 'abc', 'def'
it 'can perform a simple call if no arguments are required' do
# Equivalent to: lru_file.url.reverse
actual = lru_file.send_chain %i[url reverse]
expect(actual).to eq('cba')
end
it 'can accept a scalar argument in stages' do
lru_file.new_chain [:url, %i[end_with? placeholder]]
# Equivalent to: lru_file.url.end_with?('bc')
substituted_chain = lru_file.substitute_chain_with 'bc'
actual = lru_file.send_chain substituted_chain
expect(actual).to be true
end
it 'can accept a vector argument in stages' do
lru_file.new_chain [:url, %i[end_with? placeholder]]
# Next 2 lines are equivalent to: lru_file.url.end_with?('bc')
substituted_chain = lru_file.substitute_chain_with ['bc']
actual = lru_file.send_chain substituted_chain
expect(actual).to be true
end
it 'can accept a scalar argument in one stage' do
lru_file.new_chain [:url, %i[end_with? placeholder]]
# Equivalent to: lru_file.url.end_with?('bc')
actual = lru_file.substitute_and_send_chain_with 'bc'
expect(actual).to be true
end
it 'can accept an array argument in one stage' do
lru_file.new_chain [:url, %i[end_with? placeholder]]
# Equivalent to: lru_file.url.end_with?('bc')
actual = lru_file.substitute_and_send_chain_with ['bc']
expect(actual).to be true
end
it 'can use the evaluate_with alias' do
lru_file.new_chain [:url, %i[end_with? placeholder]]
# Equivalent to: lru_file.url.end_with?('bc')
actual = lru_file.evaluate_with ['bc']
expect(actual).to be true
end
it 'can reuse the chain with different values' do
lru_file.new_chain [:url, %i[end_with? placeholder]]
# Equivalent to: lru_file.url.end_with?('bc')
actual = lru_file.substitute_and_send_chain_with 'bc'
expect(actual).to be true
# Equivalent to: lru_file.url.end_with?('abc')
substituted_chain = lru_file.substitute_chain_with ['abc']
actual = lru_file.send_chain substituted_chain
expect(actual).to be true
# Equivalent to: lru_file.url.end_with?('de')
actual = lru_file.substitute_and_send_chain_with 'de'
expect(actual).to be false
end
end
@@ -0,0 +1,28 @@
require 'spec_helper'
# Exploring how to set date attributes in an object
class Obj
# `last_modified` is primary sort key
# `date` (when specified) is secondary sort key
attr_reader :date, :last_modified
def initialize(param1, param2)
@last_modified = Date.parse(param1)
@date = Date.parse(param2)
end
end
RSpec.describe(Obj) do
let(:obj) { described_class.new('2000-01-01', '2001-01-01') }
it 'can send date' do
date = obj.send :date
expect(obj.date).to eq(date)
end
it 'can send last_modified' do
last_modified = obj.send :last_modified
expect(obj.last_modified).to eq(last_modified)
end
end
@@ -0,0 +1,82 @@
require 'spec_helper'
require_relative '../lib/hooks/all_files'
RSpec.describe(SortedLruFiles) do
expected1 = 'first-page.html'
expected2 = 'second-page.html'
expected3 = 'third-page.html'
it 'can read back an inserted item' do
sorted_files = described_class.new
sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1
sorted_files.enable_search
actual = sorted_files.select expected1
expect(actual.length).to eq(1)
expect(actual.first&.reverse&.start_with?(expected1.reverse)).to be true
actual = sorted_files.select expected1[5..]
expect(actual.length).to eq(1)
expect(actual.first&.reverse&.start_with?(expected1[5..].reverse)).to be true
actual = sorted_files.select 'should_not_match'
expect(actual).to be_empty
end
it 'works with 2 items and one match' do
sorted_files = described_class.new
sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1
sorted_files.insert(expected2, "https://mslinn.com/#{expected2}")
sorted_files.enable_search
expect(sorted_files.msbs.array[0].url).to be <= sorted_files.msbs.array[1].url
actual = sorted_files.select expected1
expect(actual.length).to eq(1)
expect(actual.first&.end_with?(expected1)).to be true
actual = sorted_files.select expected2
expect(actual.length).to eq(1)
expect(actual.first&.end_with?(expected2)).to be true
end
it 'handles multiple matches' do
sorted_files = described_class.new
sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1
sorted_files.insert(expected2, "https://mslinn.com/#{expected2}")
sorted_files.enable_search
expected = '.html'
actual = sorted_files.select expected
expect(actual.length).to eq(2)
expect(actual.first&.end_with?(expected)).to be true
end
it 'works with 3 items' do
sorted_files = described_class.new
sorted_files.insert(expected1, "https://mslinn.com/#{expected1}") # insert reverses expected1
sorted_files.insert(expected2, "https://mslinn.com/#{expected2}")
sorted_files.insert(expected3, "https://mslinn.com/#{expected3}")
sorted_files.enable_search
expect(sorted_files.msbs.array[0].url).to be <= sorted_files.msbs.array[1].url
expect(sorted_files.msbs.array[1].url).to be <= sorted_files.msbs.array[2].url
actual = sorted_files.select expected1
expect(actual.length).to eq(1)
expect(actual.first&.end_with?(expected1)).to be true
actual = sorted_files.select expected2
expect(actual.length).to eq(1)
expect(actual.first&.end_with?(expected2)).to be true
actual = sorted_files.select expected3
expect(actual.length).to eq(1)
expect(actual.first&.end_with?(expected3)).to be true
expected = '.html'
actual = sorted_files.select expected
expect(actual.length).to eq(3)
expect(actual.first&.end_with?(expected)).to be true
end
end
@@ -0,0 +1,12 @@
require 'jekyll'
require_relative '../lib/jekyll_plugin_support'
Jekyll.logger.log_level = :info
RSpec.configure do |config|
config.filter_run_when_matching focus: true
# config.order = 'random'
# See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures
config.example_status_persistence_file_path = 'spec/status_persistence.txt'
end
@@ -0,0 +1,3 @@
example_id | status | run_time |
----------------------------------------------- | ------ | --------------- |
./spec/jekyll_block_plugin_support_spec.rb[1:1] | passed | 0.00062 seconds |
@@ -0,0 +1,38 @@
require 'spec_helper'
# Exploring how to invoke methods from classes and modules
# See https://mslinn.com/jekyll/10700-designing-for-testability.html
module TestModule
def a_method
'a_method says Hi!'
end
end
class TestClass
extend TestModule # Defines class methods
def initialize(param1, param2)
super()
@param1 = param1
@param2 = param2
end
end
RSpec.describe(TestModule) do
extend described_class
it 'Invokes a_method from module' do
result = self.class.a_method
expect(result).to eq('a_method says Hi!')
end
end
RSpec.describe(TestClass) do
let(:o1) { described_class.new('value1', 'value2') }
it 'Invokes a_method from class' do
result = o1.class.a_method
expect(result).to eq('a_method says Hi!')
end
end