A very basic HTTP server require "http/server" server = HTTP::Server.new(8080) do |context| context.response.content_type = "text/plain" context.response.print "Hello world, got #{context.request.path}!" end puts "Listening on http://127.0.0.1:8080" server.listen
sidekiq.cr: Simple, efficient job processing - amethyst: a Rails inspired web-framework - crystal-db: common db api for crystal - crystal-pg: a postgres driver for crystal - active_record.cr: Active Record pattern implementation for Crystal. - immutable: Thread-safe, persistent, immutable collections - commander: Command-line interface builder - crystalline: A collection of containers & algorithms - micrate: database migration tool - NuummiteOS: OS Kernel written in Crystal (POC) - crystal-gl: OpenGL bindings - tons more! source
arguments to restrict the types accepted by that method. def add(x : Number, y : Number) x + y end # Ok add 1, 2 # Error: no overload matches 'add' with types Bool, Bool add true, false
compiler will try to infer the type of instance and class variables using a bunch of syntactic rules. class Person def initialize(name) @name = name @age = 0 end end # @age is inferred to be a Int32 Can't infer the type of instance variable '@name' of Person def initialize(@name) ^~~~~
nilable variables are represented as an union between the type and nil. if rand(2) > 1 my_string = "hello world" end puts my_string.upcase Error in hello_world.cr:5: undefined method 'upcase' for Nil (compile-time type is (String | Nil)) puts my_string.upcase ^~~~~~
type of arguments. class Person @age = 0 def become_older @age += 1 end def become_older(years) @age += years end end john = Person.new "John" # age = 0 John.become_older # age = 1 john.become_older 5 # age = 6
are considered different overloads. class Person @age = 0 def become_older @age += 1 end def become_older(years) @age += years end def become_older(&block) @age += yield @age end end
the type of every yield expression in that position. def some yield 1, 'a' yield true, "hello" yield 2, nil end some do |first, second| # first is ( Int32 | Bool ) # second is ( Char | String | Nil ) end
context (the closure data). # A proc without arguments ->{ 1 } # Proc(Int32) # A proc with one argument ->(x : Int32) { x.to_s } # Proc(Int32, String) # A proc with two arguments: ->(x : Int32, y : Int32) { x + y } # Proc(Int32, Int32, Int32)
and produce code that is pasted into a program. macro define_method(name, body) def {{name}} {{body}} end end # This generates: # # def foo # 1 # end define_method foo, 1 foo #=> 1
AST nodes at compile-time. These methods are documented in a fictitious Crystal::Macros module. macro define_method(name, body) def {{name.id}} {{body}} end end # This correctly generates: # def foo # 1 # end # instead of # def :foo # 1 # end define_method :foo, 1
at compile-time: - inherited is invoked when a subclass is defined - included is invoked when a module is included - extended is invoked when a module is extended - method_missing is invoked when a method is not found
each other using channels without having to turn to shared memory or locks. channel = Channel(Int32).new total_lines = 0 files = Dir.glob("*.txt") files.each do |f| spawn do lines = File.read(f) .lines.size channel.send lines end end files.size.times do total_lines += channel.receive end puts total_lines
libraries, eliminating the need to reimplement low-level tasks # Fragment of the BigInt implementation that uses GMP @[Link("gmp")] lib LibGMP alias Int = LibC::Int alias ULong = LibC::ULong struct MPZ _mp_alloc : Int32 _mp_size : Int32 _mp_d : ULong* end fun init_set_str = __gmpz_init_set_str( rop : MPZ*, str : UInt8*, base : Int) : Int fun cmp = __gmpz_cmp( op1 : MPZ*, op2 : MPZ*) : Int end
command line argument # (not the executable name) # ARGV is an array of strings puts "Number of command line arguments: #{ARGV.size}" ARGV.each_with_index { |arg, i| puts "Argument #{i}: #{arg}" } # The executable name is available as PROGRAM_NAME puts "Executable name: #{PROGRAM_NAME}"
major issue is clear: stability. While Crystal is a beautiful language to play with, investing on using it at work to implement a system that should be maintained for the long run seems risky for many developers. And with good reason: we are still labeling Crystal as alpha stage, even if it has been production-ready for quite some time already. As such, and in line with our goal of seeing the language grow, we are setting a new year resolution to have Crystal reach the 1.0 milestone in 2017." Roadmap