Skip to content

Instantly share code, notes, and snippets.

@watzon
Last active March 9, 2024 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save watzon/acd7ac39be86a86ed5ea1c3340432c8d to your computer and use it in GitHub Desktop.
Save watzon/acd7ac39be86a86ed5ea1c3340432c8d to your computer and use it in GitHub Desktop.
Crystal language snippets
# Creates a `#==` method for a class or module.
# Parameters:
# args [Array(Tuple(Symbol, Symbol))] A list of properties to
# use for comparison. The first will be for a method/variable
# in the current class or module, the second will apply to the
# other.
# other_class [Class] The class to compare this one with
# strict [Bool] Set to false to compare with parent classes too
macro equalize(*args, other_class = nil, strict = true)
{{ other_class = other_class ? other_class.id : @type.id }}
def ==(other : {{ other_class }})
{% if strict %}
return false unless other.class == {{ other_class }}
{% end %}
{% for arg in args %}
return false unless {{ arg.first.id }} == other.{{ arg.last.id }}
{% end %}
true
end
end
class Hash(K, V)
# Extracts the nested value specified by the sequence of key
# objects by calling dig at each step, returning nil
# if any intermediate step is nil.
#
# ```
# hash = {"a" => {"b" => {"c" => "c"}}}
# hash.dig("a", "b", "c") # => "c"
# hash.dig("a", "b", "c", "d") # => nil
# ```
def dig(*args : K)
args.reduce(self) do |acc, i|
if acc.responds_to?(:fetch)
acc.fetch(i, nil)
else
nil
end
end
end
# Returns a new hash with all keys converted using the block operation.
# The block can change a type of keys.
#
# ```
# hash = {:a => 1, :b => 2, :c => 3}
# hash.map_keys { |key| key.to_s } # => {"A" => 1, "B" => 2, "C" => 3}
# ```
def map_keys(&block : K -> K2) forall K2
each_with_object({} of K2 => V) do |(key, value), memo|
memo[yield(key)] = value
end
end
# Returns a new hash with the results of running block once for every value.
# The block can change a type of values.
#
# ```
# hash = {:a => 1, :b => 2, :c => 3}
# hash.map_values { |value| value + 1 } # => {:a => 2, :b => 3, :c => 4}
def map_values(&block : V -> V2) forall V2
each_with_object({} of K => V2) do |(key, value), memo|
memo[key] = yield(value)
end
end
# Destructively transforms all keys using a block. Same as map_keys but modifies in place.
# The block cannot change a type of keys.
#
# ```
# hash = {"a" => 1, "b" => 2, "c" => 3}
# hash.map_keys! { |key| key.succ }
# hash # => {"b" => 1, "c" => 2, "d" => 3}
def map_keys!(&block : K -> K)
current = @first
while current
current.key = yield(current.key)
current = current.fore
end
end
# Destructively transforms all values using a block. Same as map_values but modifies in place.
# The block cannot change a type of values.
#
# ```
# hash = {:a => 1, :b => 2, :c => 3}
# hash.map_values! { |value| value + 1 }
# hash # => {:a => 2, :b => 3, :c => 4}
def map_values!(&block : V -> V)
current = @first
while current
current.value = yield(current.value)
current = current.fore
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment