Skip to content

Instantly share code, notes, and snippets.

View jaynetics's full-sized avatar

Janosch Müller jaynetics

View GitHub Profile
@jaynetics
jaynetics / script.rb
Created June 27, 2023 17:50
download all comments of a youtube video
#!/usr/bin/env ruby
# usage: script.rb <video_id> <api_key>
require 'json'
require 'net/http'
video_id = ARGV[0].tap { |s| s&.length&.<(13) || fail('pass video id as first argument') }
key = ARGV[1].tap { |s| s&.length&.>(13) || fail('pass api key as second argument') }
url = "https://youtube.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId=#{video_id}&key=#{key}"
@jaynetics
jaynetics / access_db_matcher.rb
Created June 26, 2023 19:25
test in rspec that a block of code does / does not access the DB
RSpec::Matchers.define :access_db do
match do |actual|
# track db access via ActiveRecord instrumentation
sql_callback = ->(*, event) do
# ignore automatic schema queries and transactions, though
@db_event = event unless event[:sql] =~ / a\.|max_ident|SAVEPOINT/
end
ActiveSupport::Notifications.subscribed(sql_callback, 'sql.active_record') do
actual.call
@jaynetics
jaynetics / regexp_properties_by_ruby_version.rb
Created June 14, 2023 19:15
Show when each regexp unicode property was added to Ruby
require 'regexp_parser'
map = Regexp::Syntax.specified_versions.to_h do |ver|
[ver, Regexp::Syntax.const_get(ver).added_features[:property].to_a]
end
Regexp::Syntax::CURRENT.features[:property].to_h do |prop|
[prop, map.keys.find { |v| map[v]additions.include?(prop) }]
end
@jaynetics
jaynetics / struct2.rb
Created May 30, 2023 18:32
Attempt at overriding Struct subclass ::new in Ruby for better kwargs performance
Struct2 = Class.new(Struct)
Struct2.singleton_class.prepend Module.new {
def new(...)
st = super
st.instance_eval <<~RUBY
alias __orig_new__ new
ARG_NOT_GIVEN = Object.new.freeze
def new(#{st.members[0]} = ARG_NOT_GIVEN, *, **)
@jaynetics
jaynetics / benchmarks.rb
Last active May 25, 2023 12:00
Performance overhead of Ruby TracePoint API
######
# Simplest case - one method that does nothing, with and without TP
######
require 'benchmark/ips'
def noop; end
Benchmark.ips { |x| x.report('basic', 'noop') }; 1
@jaynetics
jaynetics / find_unused_modules.rb
Created May 4, 2023 17:37
find possibly unused modules in a rails app
code = Dir['{app,config,lib}/**/*.{rb,slim,erb,rake}'].map { File.read _1 }.join; 1
defs = code.scan(/(?:class|module) \K[A-Z][\w:]+(?=\n)/); 1
refs = code.scan(/(?<!class |module )\b#{Regexp.union(defs + defs.map { |d| d.split('::').last })}\b/); 1
unused = defs.uniq.sort.select { |d| refs.count(d) == 0 && refs.count(d.split('::').last) == 0 }
@jaynetics
jaynetics / hash_new_vs_dup.rb
Created February 27, 2023 10:52
Ruby benchmark for making empty, compare_by_identity Hash with new / literal vs dup
# results on ruby 3.2:
#
# Warming up --------------------------------------
# new 277.194k i/100ms
# dup 394.839k i/100ms
# Calculating -------------------------------------
# new 2.754M (± 1.9%) i/s - 13.860M in 5.034959s
# dup 4.006M (± 0.8%) i/s - 20.137M in 5.026561s
#
# Comparison:
@jaynetics
jaynetics / case_vs_hash.rb
Created February 22, 2023 14:24
Ruby benchmark of symbol lookup in case statement vs Hash
# results on Ruby 3.2:
#
# Warming up --------------------------------------
# hash 1.910M i/100ms
# case 1.297M i/100ms
# Calculating -------------------------------------
# hash 19.029M (± 1.5%) i/s - 95.507M in 5.020123s
# case 12.604M (± 0.4%) i/s - 63.534M in 5.040776s
#
# Comparison:
@jaynetics
jaynetics / weak_ref_registry.rb
Created January 15, 2023 10:27
A self-cleaning weak-ref registry to retrieve object instances by their object_id in Ruby
# This allows doing
#
# Foo.prepend(WeakRefRegistry)
#
# foo = Foo.new # => #<Foo:0x1>
# foo_id = foo.object_id # => 1234
# Foo.registry.fetch(foo_id) # => #<Foo:0x1>
#
# I.e. retrieve Foo instances by their object_id,
# without affecting garbage collection.
@jaynetics
jaynetics / case_vs_equal.rb
Created December 30, 2022 09:22
Benchmark for Ruby case statement vs ==, eql?, equal?
# results on ruby 3.2:
#
# case 7.890M (± 0.9%) i/s - 40.048M in 5.076164s
# == 3.403M (± 0.7%) i/s - 17.121M in 5.031140s
# eql? 1.776M (± 1.2%) i/s - 9.001M in 5.070102s
# equal? 1.791M (± 0.3%) i/s - 8.968M in 5.007507s
require 'benchmark/ips'
def with_case(arg)