Last active
August 19, 2019 17:42
-
-
Save creadone/f7a153550c587f0b206c75073cadd904 to your computer and use it in GitHub Desktop.
Useful snippets for Crystal language
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
# Method alias | |
# ------------ | |
macro alias_method(new_name, existing_method) | |
def {{new_name.id}}(*args) | |
{{existing_method.id}}(*args) | |
end | |
end | |
# Generate Union type from array of classes | |
# ----------------------------------------- | |
class Test1; end | |
class Test2; end | |
class Test3; end | |
FULL = [ | |
Test1, | |
Test2, | |
Test3 | |
] | |
LITE = [ | |
Test1, | |
Test2 | |
] | |
macro finished | |
alias FullStack = {{ FULL.join(" | ").id }} | |
alias LiteStack = {{ LITE.join(" | ").id }} | |
end | |
p! FullStack # => (Test1 | Test2 | Test3) | |
p! LiteStack # => (Test1 | Test2) | |
# Simple memoization (not only for Crystal, Ruby too) | |
# --------------------------------------------------- | |
class HeavyWorker | |
@@time = Time.now | |
def time | |
return @@time if @@time | |
@@time = Time.now | |
end | |
def drop_cache! | |
@@time = nil | |
end | |
end | |
puts HeavyWorker.new.time | |
sleep 2 | |
puts HeavyWorker.new.time | |
sleep 1 | |
puts HeavyWorker.new.drop_cache! | |
sleep 1 | |
puts HeavyWorker.new.time | |
# User-defined annotations | |
# ------------------------ | |
annotation Custom; end | |
class Object | |
macro inherited | |
macro method_added(method) | |
\{% if method.annotation(Custom) %} | |
\{% pp method.name.id %} | |
\{% pp method.annotation(Custom)[:x] %} | |
\{% end %} | |
end | |
end | |
end | |
class CustomAnnotationTest | |
@[Custom] | |
def first_method(x : String) | |
x | |
end | |
@[Custom(x: 2)] | |
def second_method(x : Int32) | |
x | |
end | |
end | |
# Any type in macro | |
# ----------------- | |
def foo(bar : T) forall T | |
{% pp! T %} | |
end | |
foo(42) | |
def foo(**values : **T) forall T | |
{% pp! T %} | |
end | |
foo(bar: 42) | |
# Debug class methods with annotations | |
# ------------------------------------ | |
require "logger" | |
LOGGER = Logger.new(STDOUT) | |
annotation Explain; end | |
class Object | |
macro inherited | |
macro method_added(method) | |
\{% if method.annotation(Explain) %} | |
def \{{method.name.id}}(\{{method.args.splat}}) | |
LOGGER.\{{method.annotation(Explain)[:severity].id}}("Method \{{method.name.id.symbolize}} defined on line \{{ method.line_number }} invoked with args \{{method.args.splat}} and return #{previous_def}") | |
return previous_def | |
end | |
\{% end %} | |
end | |
end | |
end | |
class DebugWithAnnotations | |
@[Explain(severity: "info")] | |
def first_method(x : Int32) | |
x * x | |
end | |
@[Explain(severity: "fatal")] | |
def second_method(x : Int32) | |
x + 2 | |
end | |
end | |
DebugWithAnnotations.new.first_method(1) | |
DebugWithAnnotations.new.second_method(5) | |
# link and use own C library | |
# -------------------------- | |
# file: prog.c | |
#include <stdio.h> | |
void say(const char * name){ | |
printf("Back my many %s!\n", name); | |
} | |
# compile lib: gcc -c prog.c -o prog.o | |
# file: prog.cr | |
@[Link(ldflags: "#{__DIR__}/prog.o")] | |
lib LibProg | |
fun say(name : LibC::Char*) : Void | |
end | |
LibProg.say("now") | |
# build crystal release: crystal build prog.cr --release, then run ./prog | |
# Build chain | |
# -------------------------- | |
class Transforma | |
property hash : String? | |
def build | |
yield self | |
end | |
def add(bla : String) | |
self.hash = bla | |
end | |
def show_me | |
p! hash | |
end | |
end | |
Transforma.new.build do |t| | |
t.add "some string" | |
t.show_me | |
end | |
# Convert parsed data to hash | |
# ------------------------------ | |
require "json" | |
class Parser | |
include JSON::Serializable | |
@[JSON::Field(key: "event_date")] | |
property event_date : String | |
@[JSON::Field(key: "event_name")] | |
property event_name : String | |
macro finished | |
def to_hash | |
{% parser_methods = @type.methods.map(&.name).select { |m| !m.includes?("=") }.map(&.stringify) %} | |
{ | |
{% for parser_method in parser_methods %} | |
{{ parser_method.id.stringify }} => {{ parser_method.id }}, | |
{% end %} | |
} | |
end | |
end | |
end | |
json_string = "{\"event_date\":\"2019-01-01\", \"event_name\":\"user:click:welcome_button\"}" | |
result = Parser.from_json(json_string) | |
p result.to_hash | |
# => {"event_date" => "2019-01-01", "event_name" => "user:click:welcome_button"} | |
# Instance variable on object level (by @vladfaust) | |
# --------------------------------- | |
class User | |
property id : Int32? | |
property name : Int32? | |
macro finished | |
{% ivars = @type.methods.select { |_def| _def.body.is_a?(InstanceVar) }.map(&.body) %} | |
{% pp ivars %} | |
end | |
end | |
# Change Instanse self from outside modifier | |
# ------------------------------------------ | |
class Exp | |
property bla : String = "bla" | |
def external_modifier | |
yield self | |
end | |
end | |
exp = Exp.new | |
p exp.bla # => "bla" | |
exp.external_modifier do |instance| | |
instance.bla = "blo" | |
end | |
p exp.bla # => "blo" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment