Skip to content

Instantly share code, notes, and snippets.

View kaspth's full-sized avatar

Kasper Timm Hansen kaspth

View GitHub Profile
@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
@kaspth
kaspth / themed_form_with.rb
Last active June 14, 2023 14:21
A pitch to have the ability to go between several form builders in a form, focused on Bullet Train's themed field partials.
# Provide a BulletTrain::Theme::FormBuilder, with extensions to
# go between Rails standard form helpers and BulletTrain's themed versions seamlessly.
# With standard Rails:
# form_with model: Post.new do |form|
# form.themed.text_field # Use BulletTrain theming on just one field
#
# form.themed.fields do # Need a nested section of fields but themed?
# end
# end
@kaspth
kaspth / object_proxy.rb
Created June 10, 2023 14:42
Making Ruby better at object proxying, so we don't need to add `user_name` etc. for Law of Demeter.
class Object::Proxy < SimpleDelegator
def initialize(object, **values)
super(object)
@values = values
end
def method_missing(name, ...)
@values.fetch(name) { super }
end
end
class Developer
has_object :search_scorer, after_save_commit: :rebuild_later # Forward callback onto context object.
end
# From my https://github.com/kaspth/active_record-associated_object gem.
# app/models/developer/search_scorer.rb
class Developer::SearchScorer < ActiveRecord::AssociatedObject
performs :rebuild # Adds `rebuild_later` to automatically generate a job to run the scoring calculation in.
def rebuild
record.update! search_score: new_score
@kaspth
kaspth / a_expositions_from_secondary_service.rb
Last active April 6, 2023 16:56
Let secondary services deliver expositions to a primary service intake which it may process, everything happens on a private network.
class Invoice
delivers_exposition # only: :create ?
# ^ shorthand for this:
after_create_commit -> { Exposition.deliver_later "invoice.create", self }
after_update_commit -> { Exposition.deliver_later "invoice.update", self }
after_destroy_commit -> { Exposition.deliver_later "invoice.destroy", self }
end
class Exposition < Data.define(:service, :event, :gid)
def initialize(service: "invoices", **) = super
@kaspth
kaspth / action_view.rb
Created December 29, 2022 15:03
Very condensed write up of Action View's rendering
# app/views/cards/_card.html.erb
# <%= greeting %>
#
# ^ gets compiled onto ActionView::Base as a Ruby method, when called like this:
#
# render "cards/card", greeting: "Hello"
#
# Here's roughly what the compiled source looks like:
class ActionView::Base
def render_card(local_assigns, output_buffer) # Not the actual method name, and the arguments change if using strict locals
require "tsort"
module Rails
module Initializable
extend ActiveSupport::Concern
def run_initializers(group = :default, *arguments)
@ran ||= true.tap do
Initializer.tsort(initializers).each { instance_exec(*arguments, &_1.block) if _1.in?(group) }
end
@kaspth
kaspth / method_chain.rb
Created December 18, 2022 17:48
A half written-up implementation of progressively enhancing an options hash through method chaining on a context object.
class Method::Chain
def initialize(descriptor, **options)
@descriptor, @options = descriptor, options
end
def self.define(context, *methods, &block)
instance = new Definition.new(&block)
instance.apply context, *methods
instance
end