Skip to content

Instantly share code, notes, and snippets.

View havenwood's full-sized avatar
:octocat:

Shannon Skipper havenwood

:octocat:
  • Ashland, Oregon
  • 08:58 (UTC -07:00)
View GitHub Profile
@havenwood
havenwood / immutable.rb
Created July 1, 2024 18:46
An example immutable (Dry) and mutable (Active Model) Args interface
require 'dry-struct'
require 'dry-types'
require 'dry-validation'
class WordTally
class Args < Dry::Struct
module Types
include Dry.Types()
end
@havenwood
havenwood / caesar.rb
Last active June 23, 2024 23:21
A Caesar cipher example in Ruby
class Caesar
def initialize(rot: 13, lower: [*'a'..'z'], upper: [*'A'..'Z'])
@rot = rot
@book = book(lower:, upper:)
end
def cipher(message) = message.gsub(/[a-zA-Z]/, @book)
alias_method :call, :cipher
private
@havenwood
havenwood / which.rb
Last active June 23, 2024 17:25
A `which` command for Ruby
module FileUtils
# Returns the full path to an executable command if it exists in the PATH.
#
# FileUtils.which('ruby') # => "/usr/bin/ruby"
# FileUtils.which('matz') # => nil
#
# Keyword arguments:
#
# - <tt>env: 'PATH'</tt> - the PATH environment variable.
# - <tt>separator: File::PATH_SEPARATOR</tt> - the PATH separator.
@havenwood
havenwood / uuid_v7.rb
Last active June 17, 2024 21:33
UUIDv7 in Ruby, using IO::Buffer
def uuid_v7
milliseconds = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
buffer = IO::Buffer.new(16)
buffer.set_string([milliseconds].pack('Q>')[2..], 0)
buffer.set_string(SecureRandom.bytes(10), 6)
buffer.set_value(:U8, 6, buffer.get_value(:U8, 6) & 0x0F | 0x70)
buffer.set_value(:U8, 8, buffer.get_value(:U8, 8) & 0x3F | 0x80)
buffer.get_string.unpack('H8H4H4H4H12').join('-')
end
@havenwood
havenwood / nano_id.rb
Created June 16, 2024 22:54
A simple Nano ID implementation in Ruby
# frozen_string_literal: true
require 'securerandom'
module NanoID
ALPHABET = [*'A'..'Z', *'a'..'z', *'0'..'9', '_', '-'].freeze
module_function
def nano_id(alphabet: ALPHABET, size: 21)
@havenwood
havenwood / coerce.rb
Created May 31, 2024 21:56
An example showing that #coerce can be private.
Value = Data.define(:number) do
def +(other) = with(number: number + other.number)
private
def coerce(number) = [Value.new(number), self]
end
42 + Value.new(42)
#=> #<data Value number=84>
@havenwood
havenwood / build.rb
Created May 29, 2024 19:29 — forked from jedschneider/build.rb
build script for terraform deploys
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'optparse'
require 'fileutils'
require 'open3'
module TerraformExecutor
Config = Struct.new(:parallelism, :init, :vault, :tag, keyword_init: true)
@havenwood
havenwood / delete_archdir_prefix.patch
Last active April 24, 2024 22:20
Minimalist patch for Ruby 3.3.1 [Bug #20450] https://github.com/ruby/ruby/pull/10619
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb
index e756af61ea..555d1d4cd1 100644
--- a/lib/bundled_gems.rb
+++ b/lib/bundled_gems.rb
@@ -98,7 +98,7 @@ def self.warning?(name, specs: nil)
# name can be a feature name or a file path with String or Pathname
feature = File.path(name)
# bootsnap expand `require "csv"` to `require "#{LIBDIR}/csv.rb"`
- name = feature.delete_prefix(LIBDIR).chomp(".rb").tr("/", "-")
+ name = feature.delete_prefix(ARCHDIR).delete_prefix(LIBDIR).tr("/", "-")
@havenwood
havenwood / export.rb
Last active April 17, 2024 22:24
Zip example for #ruby IRC
##
# This is similar to your code to reproduce what it's doing
def export_similar_to_your_code
io = Zip::OutputStream.write_buffer do |stream|
'a'.upto 'z' do |char|
stream.put_next_entry "#{char}.txt"
stream << char * 42
end
ensure
stream.close_buffer
@havenwood
havenwood / attributes.rb
Last active April 8, 2024 00:11
My example showing dynamic top level instance variables with attrs for #ruby IRC
class Attributes < Module
def initialize(**attributes)
self.class.class_eval do
define_method :included do |klass|
klass.class_eval do
attributes.each do |key, value|
instance_variable_set "@#{key}", value
singleton_class.class_eval { attr_accessor key }
end
end