Last active
July 1, 2020 20:24
-
-
Save danhodge/5f01fe4739a7d5a22f8739242d79b193 to your computer and use it in GitHub Desktop.
Ruby Tricks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Define a method as both an instance & class method | |
class Foo | |
def self.bar | |
end | |
# Note: this requires Rails/Active Support - not sure if it can be done with Forwardable | |
delegate :bar, to: "self.class" | |
end | |
# Named parameter string substitution | |
template = "Hello, %{name}. The time is now %{time}" | |
str = template % { name: "Ruby", time: Time.now } | |
# Define a custom exception matcher | |
# Needs to be a class or module with a self.=== method that takes an exception instance and returns true or false on match | |
# Sample implementation - handler class | |
class Handler | |
attr_reader :bad_request_exceptions | |
def initialize(bad_request_exceptions: []) | |
@bad_request_exceptions = bad_request_exceptions | |
end | |
def on_bad_request(ex) | |
puts "Bad Request: #{ex.message}" | |
end | |
end | |
# Matcher "factory" | |
module Matcher | |
def self.bad_request(handler) | |
matcher = Module.new | |
matcher.define_singleton_method(:===) do |ex| | |
handler.bad_request_exceptions.any? { |type| type === ex } | |
end | |
matcher | |
end | |
end | |
# Error handler | |
def with_error_handler(handler) | |
yield | |
rescue Matcher.bad_request(handler) => ex | |
handler.on_bad_request(ex) | |
rescue => ex | |
puts "Unexpected Error" | |
end | |
# Usage | |
with_error_handler(Handler.new(bad_request_exceptions: [Excon::Error::BadRequest])) do | |
do_it | |
end | |
# Give an anonymous class a name | |
klass = Class.new do | |
def self.name | |
"NoName" | |
end | |
end | |
klass.new.class.name # => "NoName" | |
# Manually set or override cause on a new exception | |
raise ExceptionClass, cause: ex | |
# Introspect the keyword arguments for a method | |
class SomeClass | |
def some_method(arg1:, arg2: 3, arg3: nil) | |
end | |
end | |
SomeClass.instance_method(:some_method).parameters # => [[:keyreq, :arg1], [:key, :arg2], [:key, :arg3]] | |
# Lazily select the first n unique elements from a collection | |
uniques = Set.new | |
collection.lazy.select { |item| uniques.add?(item) }.take(n) | |
# Set the system timezone to UTC | |
TZ=UTC ruby ... | |
# Inter-process communication | |
# Use the Open3.capture methods for all "one-shot" commands (the popen methods are prone to deadlocks) | |
# The following can be used to run a command the accepts input from stdin and writes output to stdout & stderr | |
stdout, stderr, status = Open3.capture3('cmd', 'arg1', 'arg2', stdin_data: "some input") | |
# To "prepend" class methods, you need to prepend the module into the eigenclass | |
module Other | |
def do_something | |
puts "About to do something" | |
super | |
puts "Just did something" | |
end | |
end | |
class Something | |
singleton_class.prepend Other | |
def self.do_something | |
puts "Doing something" | |
end | |
end | |
# To prepend instance & class methods, the prepended hook can be used | |
module Other2 | |
def self.prepended(base) | |
base.singleton_class.prepend(ClassMethods) | |
end | |
def do_something_else | |
end | |
module ClassMethods | |
def do_something | |
end | |
end | |
end | |
class Something2 | |
prepend Other2 | |
def self.do_something | |
end | |
def do_something_else | |
end | |
end | |
# When prepending multiple modules, the last one is first | |
module Bar | |
def doit(x) | |
puts "Bar: #{x}" | |
super(x + 1) | |
end | |
end | |
module Baz | |
def doit(x) | |
puts "Baz: #{x}" | |
super(x - 3) | |
end | |
end | |
class Foo | |
prepend Bar | |
prepend Baz | |
def doit(x) | |
puts "Foo: #{x}" | |
x * 2 | |
end | |
end | |
> Foo.new.doit(5) | |
Baz: 5 | |
Bar: 2 | |
Foo: 3 | |
# => 6 | |
# Use Enumerable#chunk to break a list of items into approximately equally-sized chunks | |
total_length = 0 | |
chunks = array_of_strings.chunk do |str| | |
total_length += str.length | |
total_length / 100 | |
end | |
chunks.map(&:last) #=> an Array of Arrays of Strings, the combined length of each sub-Array roughly equal to 100 | |
# Unicode code points with more than 4 hex digits (many emojis) need to be enclosed in {} | |
"\u{1f601}" #=> "😁" | |
"\u{1f601 1f602}" #=> "😁😂" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment