Last active
August 21, 2025 16:28
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #-------------------------------------------------- | |
| # 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