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)
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)
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 |
# 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 |
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 |
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 |
# 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 |
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 |