Skip to content

Instantly share code, notes, and snippets.

@diogotito
Last active August 21, 2025 16:28
Show Gist options
  • Select an option

  • Save diogotito/892b9c1bff71b93480108510e0afa671 to your computer and use it in GitHub Desktop.

Select an option

Save diogotito/892b9c1bff71b93480108510e0afa671 to your computer and use it in GitHub Desktop.
Crake - Cursed Ruby make. Demonstrates why class variables aren't recommended, I guess
#--------------------------------------------------
# fake Rake
#--------------------------------------------------
module TaskRunner
Task = Data.define *%i| name reqs recipes | do
@@tasks = {}
def run
reqs.each { @@tasks[it]&.run }
recipes.each { |recipe| recipe.call(self) }
@@tasks.delete(name) # Don't repeat this Task
end
end
END {
(@@tasks[ARGV[1]] || @@tasks.each_value.first)&.run
}
private module_function def task(arg, &recipe)
case arg
when Hash
name, reqs = arg.first
when String, Symbol
name = arg
end
@@tasks[name] ||= Task[name:, reqs: Array(reqs), recipes: Array(recipe)]
end
def self.[](...) = @@tasks.[](...)
end
# Bring the above "DSL" to the top-level
# (I could use `include` but that would polute the class vars of everything)
extend TaskRunner
#------------------------------------------------------------------------------
# Logging tasks
# - - -
# 1. Prepending a module -- the modern way to monkey patch.
# Also notice how `super` is super awesome!
#
module LoggingTaskOverride
def task(...)
super do |t|
puts "--- Running #{t.name} ---"
yield t
puts
end
end
end
TaskRunner.prepend LoggingTaskOverride
# - - -
# 2. Intercepting Tasks' "recipes" Array's #each
# to yield a phantom first action
#
module LoggingTaskTrappingArrayEach
module PrependHack
def each
yield -> t { puts ">>> Running \e[36m#{t.name}\e[0m's actions <<<" }
super
end
alias_method(:save_each, :each)
end
def run
recipes.extend(PrependHack)
PrependHack.remove_method(:each)
super
end
end
TaskRunner::Task.prepend LoggingTaskTrappingArrayEach
#------------------------------------------------------------------------------
# fake tasks
#
task 'three' => ['one', 'two'] do |t|
puts "I run after one and two!"
end
task 'one' => ['before_one'] do |t|
puts "One!"
end
task 'two' do |t|
puts "Two!"
end
task 'before_one' do |t|
puts "Let's go!"
end
__END__
puts "\e[32m---"
# pp((123).task('kek') { puts 'lol' })
cvar_tasks = -> o { o.class_variable_get(:@@tasks) }
p cvar_tasks[singleton_class] rescue puts "not in singleton_class"
p cvar_tasks[TaskRunner] rescue puts "not in TaskRunner"
p cvar_tasks[TaskRunner::Task] rescue puts "not in TaskRunner::Task"
p cvar_tasks[Integer] rescue puts "not in Integer"
p cvar_tasks[Object] rescue puts "not in Object"
puts "---\e[0m"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment