Skip to content

Instantly share code, notes, and snippets.

View kaspth's full-sized avatar

Kasper Timm Hansen kaspth

View GitHub Profile
@kaspth
kaspth / concern.rb
Created June 4, 2024 20:37
Writing Concerns without the `extend`/`included`/`class_methods` boilerplate.
# Maybe there's a way to support ActiveSupport::Concern's dependencies too?
# Although this doesn't use the module hierarchy, so `prepend` can't work.
class Concern < Module
def initialize(&block) = @block = block
def included(klass) = klass.class_eval(&@block)
end
module Kernel
def Concern(...) = Concern.new(...)
end
require "bundler/inline"
gemfile do
gem "rails"
gem "sqlite3"
end
require "active_record"
require "action_controller"
require "rails"
class ActiveRecord::Relation::Loaded < Data.define(:records)
def where(**conditions)
records = @records.dup
conditions.each do |key, value|
records.select! { |record| record.send(key) == value }
end
with(records:)
end
# Not sure how to maintain the order of the passed in keys?
@kaspth
kaspth / tapper.rb
Created March 18, 2024 13:52
For multiple chains of mutating methods, most likely on Enumerables.
class Tapper < BasicObject
def initialize(object) = @object = object
def method_missing(meth)
@object.tap(&meth)
self
end
end
class Object
# Spotify Mix Playlists: Assuming we have a history of played songs for a user,
# we have song recommendations via nearest neighbor search,
# and we have categorizations (genre, mood, era, instrumental/vocal, cultural/regional, theme),
# let system admins create mix templates based on music categorizations
# and then generate refreshable custom playlists for each user.
class User
has_many :playlists
has_one :history
end
# Here's the problem statement we worked on:
# 1. Spam post detection: Run a forum post through a series of configurable checks to give it a spam score,
# and flag the post when it crosses the threshold, with details on what led to the score.
# We had a Gemfile with `gem "rails"` and `gem "sqlite3"` in it, but that was it.
require "bundler/setup"
require "active_record"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
@kaspth
kaspth / stowaway.rb
Last active January 19, 2024 19:40
A Rails modeling implementation of https://brandur.org/soft-deletion
create_table :stowaway_records do |t|
t.string :record_type, null: false
t.jsonb :record_attributes, null: false, default: {}
t.timestamps
t.index :record_type
end
class Stowaway::Record < ActiveRecord::Base
def self.preserve(record)
create! record_type: record.class, record_attributes: record.attributes
@kaspth
kaspth / db-seeds-accounts-kaspers_donuts.rb
Last active November 1, 2023 02:58
A showcase of oaken, using data from its test suite. Early Access at: https://kaspthrb.gumroad.com/l/open-source-retreat-summer-2023
donuts = accounts.create :kaspers_donuts, name: "Kasper's Donuts"
kasper = users.create :kasper, name: "Kasper", accounts: [donuts]
coworker = users.create :coworker, name: "Coworker", accounts: [donuts]
menu = menus.create account: donuts
plain_donut = menu_items.create menu: menu, name: "Plain", price_cents: 10_00
sprinkled_donut = menu_items.create menu: menu, name: "Sprinkled", price_cents: 10_10
supporter = users.create name: "Super Supporter"

Here's the second weekly recap!

In last weeks recap, I shared where we were at in code and it looked like this:

# test_helper.rb
Oaken::Data.load_from "test/seeds"

# test/seeds/users.rb
User = Struct.new(:name, keyword_init: true)
@kaspth
kaspth / form_builder.rb
Created June 15, 2023 16:53
Trying to play around ideas with different FormBuilders for Rails.
class FormBuilder
def text_field(method, **options)
tag.input type: :text, **options_for(__method__, method, **options)
end
def options_for(type, method, index: @index, namespace: @options[:namespace], multiple: false, **options)
Options.new(self, type, method, index:, namespace:, multiple:, **options)
end
class Options