1# Examples taken from http://crystal-lang.org/docs/ 2# Copyright 2012-2018 Manas Technology Solutions. 3# Updated on May 17th, 2018 by @faustinoaq. 4 5require "http/server" 6 7server = HTTP::Server.new(8080) do |context| 8 context.response.content_type = "text/plain" 9 context.response.print "Hello world! The time is #{Time.now}" 10end 11 12puts "Listening on http://0.0.0.0:8080" 13server.listen 14 15module HTTP 16 class RequestHandler 17 end 18end 19 20alias NumericValue = Float32 | Float64 | Int32 | Int64 21 22enum Time::DayOfWeek 23end 24 25class Greeting 26 class_property global_greeting = "Hello world" 27 28 @@default_greeting = "Hello world" 29 30 def initialize(@custom_greeting = nil) 31 end 32 33 def print_greeting 34 greeting = @custom_greeting || @@default_greeting 35 puts greeting 36 end 37end 38 39LUCKY_NUMBERS = [3, 7, 11] 40DOCUMENTATION_URL = "http://crystal-lang.org/docs" 41 42module Scorecard 43 class Parser 44 def parse(score_text) 45 begin 46 score_text.scan(SCORE_PATTERN) do |match| 47 handle_match(match) 48 end 49 rescue err : ParseError 50 # handle error ... 51 end 52 end 53 end 54end 55 56module Money 57 CURRENCIES = { 58 "EUR" => 1.0, 59 "ARS" => 10.55, 60 "USD" => 1.12, 61 "JPY" => 134.15, 62 } 63 64 class Amount 65 getter :currency, :value 66 67 def initialize(@currency, @value) 68 end 69 end 70 71 class CurrencyConversion 72 def initialize(@amount, @target_currency) 73 end 74 75 def amount 76 # implement conversion ... 77 end 78 end 79end 80 81i = 0 82while i < 10 83 proc = ->(x : Int32) do 84 spawn do 85 puts(x) 86 end 87 end 88 proc.call(i) 89 i += 1 90end 91 92Fiber.yield 93 94# A buffered channel of capacity 2 95channel = Channel(Int32).new(2) 96 97spawn do 98 channel.send(1) 99 channel.send(2) 100 channel.send(3) 101end 102 1033.times do |i| 104 puts channel.receive 105end 106 107class MyDictionary(K, V) 108end 109 110MyBox.new(1) # :: MyBox(Int32) 111MyBox.new("hello") # :: MyBox(String) 112 113module Moo(T) 114 def t 115 T 116 end 117end 118 119class Foo(U) 120 include Moo(U) 121 122 def initialize(@value : U) 123 end 124end 125 126foo = Foo.new(1) 127foo.t # Int32 128 129class Parent(T) 130end 131 132class Int32Child < Parent(Int32) 133end 134 135class GenericChild(T) < Parent(T) 136end 137 138class Person 139end 140 141a = 1 142ptr = pointerof(a) 143ptr[100_000] = 2 # undefined behaviour, probably a segmentation fault 144 145alias Int32OrString = Int32 | String 146 147alias Int32OrNil = Int32? 148 149alias Int32OrNil_ = Int32 | ::Nil 150 151alias Int32Ptr = Int32* 152 153alias Int32Ptr_ = Pointer(Int32) 154 155alias Int32_8 = Int32[8] 156 157alias Int32_8_ = StaticArray(Int32, 8) 158 159alias Int32StringTuple = {Int32, String} 160 161alias Int32StringTuple_ = Tuple(Int32, String) 162 163alias Int32ToString = Int32 -> String 164 165alias Int32ToString_ = Proc(Int32, String) 166 167alias ProcThatReturnsInt32 = -> Int32 168 169alias Int32AndCharToString = Int32, Char -> String 170 171alias ComplexProc = (Int32 -> Int32) -> String 172 173def foo(x : Int32) 174 "instance" 175end 176 177def foo(x : Int32.class) 178 "class" 179end 180 181foo 1 # "instance" 182foo Int32 # "class" 183 184class Parent 185end 186 187class Child1 < Parent 188end 189 190class Child2 < Parent 191end 192 193ary = [] of Parent.class 194ary << Child1 195ary << Child2 196 197# Same as not specifying a restriction, not very useful 198def foo(x : _) 199end 200 201# A bit more useful: any two arguments Proc that returns an Int32: 202def foo(x : _, _ -> Int32) 203end 204 205# alias SameAsInt32 = typeof(2) 206# alias Int32OrString_ = typeof(1, "a") 207 208class Person 209 def initialize(name) 210 @name = name 211 @age = 0 212 end 213 214 def name 215 @name 216 end 217 218 def age 219 @age 220 end 221end 222 223john = Person.new "John" 224peter = Person.new "Peter" 225 226john.name # => "John" 227john.age # => 0 228 229peter.name # => "Peter" 230 231class Person 232 def self.new(name) 233 instance = Person.allocate 234 instance.initialize(name) 235 instance 236 end 237end 238 239if a.is_a?(String) 240 # here a is a String 241end 242 243if b.is_a?(Number) 244 # here b is a Number 245end 246 247a = some_condition ? 1 : "hello" 248# a : Int32 | String 249 250if a.is_a?(Number) 251 # a : Int32 252else 253 # a : String 254end 255 256if a.is_a?(String) && b.is_a?(Number) 257 # here a is a String and b is a Number 258end 259 260a.+(b) 261 262struct Vector2 263 getter x, y 264 265 def initialize(@x, @y) 266 end 267 268 def +(other) 269 Vector2.new(x + other.x, y + other.y) 270 end 271end 272 273v1 = Vector2.new(1, 2) 274v2 = Vector2.new(3, 4) 275v1 + v2 # => Vector2(@x=4, @y=6) 276 277struct Vector2 278 def - 279 Vector2.new(-x, -y) 280 end 281end 282 283v1 = Vector2.new(1, 2) 284-v1 # => Vector2(@x=-1, @y=-2) 285 286class MyArray 287 def [](index) 288 # ... 289 end 290 291 def [](index1, index2, index3) 292 # ... 293 end 294 295 def []=(index, value) 296 # ... 297 end 298end 299 300array = MyArray.new 301 302array[1] # invokes the first method 303array[1, 2, 3] # invokes the second method 304array[1] = 2 # invokes the third method 305 306array.[](1) # invokes the first method 307array.[](1, 2, 3) # invokes the second method 308array.[]=(1, 2) # invokes the third method 309 310raise "OH NO!" 311raise Exception.new("Some error") 312 313class MyException < Exception 314end 315 316begin 317 raise MyException.new("OH NO!") 318rescue ex : MyException 319 puts "Rescued MyException: #{ex.message}" 320end 321 322begin 323 # ... 324rescue ex : MyException | MyOtherException 325 # only MyException or MyOtherException 326rescue 327 # any other kind of exception 328ensure 329 puts "Cleanup..." 330end 331 332def some_method 333 something_dangerous 334rescue 335 # execute if an exception is raised 336end 337 338array = [1, 2, 3] 339array[4] # raises because of IndexError 340array[4]? # returns nil because of index out of bounds 341 342def some_proc(&block : Int32 -> Int32) 343 block 344end 345 346x = 0 347proc = ->(i : Int32) { x += i } 348proc = some_proc(&proc) 349proc.call(1) # => 1 350proc.call(10) # => 11 351x # => 11 352 353def add(x, y) 354 x + y 355end 356 357adder = ->add(Int32, Int32) 358adder.call(1, 2) # => 3 359 360module Curses 361 class Window 362 end 363end 364 365Curses::Window.new 366 367module ItemsSize 368 def size 369 items.size 370 end 371end 372 373class Items 374 include ItemsSize 375 376 def items 377 [1, 2, 3] 378 end 379end 380 381items = Items.new 382items.size # => 3 383 384module Base64 385 extend self 386 387 def encode64(string) 388 # ... 389 end 390 391 def decode64(string) 392 # ... 393 end 394end 395 396Base64.encode64 "hello" # => "aGVsbG8=" 397 398if some_condition 399 a = 1 400else 401 a = "hello" 402end 403 404a_as_int = a.as(Int32) 405a_as_int.abs # works, compiler knows that a_as_int is Int32 406 407ptr = Pointer(Int32).malloc(1) 408ptr.as(Int8*) # :: Pointer(Int8) 409 410array = [1, 2, 3] 411 412# object_id returns the address of an object in memory, 413# so we create a pointer with that address 414ptr = Pointer(Void).new(array.object_id) 415 416# Now we cast that pointer to the same type, and 417# we should get the same value 418array2 = ptr.as(Array(Int32)) 419array2.same?(array) # => true 420 421a = 1 422b = a.as(Int32 | Float64) 423b # :: Int32 | Float64 424 425ary = [1, 2, 3] 426 427# We want to create an array 1, 2, 3 of Int32 | Float64 428ary2 = ary.map { |x| x.as(Int32 | Float64) } 429 430ary2 # :: Array(Int32 | Float64) 431ary2 << 1.5 # OK 432 433class Person 434 def initialize(@name) 435 end 436 437 def name 438 @name 439 end 440end 441 442a = [] of Person 443x = a.map { |f| f.name } # Error: can't infer block return type 444 445a = [] of Person 446x = a.map { |f| f.name.as(String) } # OK 447 448Person.new "John" 449 450a = [] of Person 451x = a.map { |f| f.name } # OK 452 453loop do 454 do_something 455 break if some_condition 456end 457 458class Point 459 def initialize(@x, @y) 460 end 461end 462 463Point.new 1, 2 464 465# 2 x Int32 = 2 x 4 = 8 466instance_sizeof(Point) # => 12 467 468a = 1 469while a < 5 470 a += 1 471 if a == 3 472 next 473 end 474 puts a 475end 476 477# The above prints the numbers 2, 4 and 5 478 479lib C 480 # In C: double cos(double x) 481 fun cos(value : Float64) : Float64 482 483 fun getch : Int32 484 485 fun srand(seed : UInt32) 486 487 fun exit(status : Int32) : NoReturn 488 489 fun printf(format : UInt8*, ...) : Int32 490end 491 492C.cos(1.5) # => 0.0707372 493C.srand(1_u32) 494 495a = 1 496b = 2 497C.printf "%d + %d = %d\n", a, b, a + b 498 499lib LibSDL 500 fun init = SDL_Init(flags : UInt32) : Int32 501end 502 503lib LLVMIntrinsics 504 fun ceil_f32 = "llvm.ceil.f32"(value : Float32) : Float32 505end 506 507lib MyLib 508 fun my_fun(some_size : LibC::SizeT) 509end 510 511@[Link("pcre")] 512lib LibPCRE 513end 514 515lib C 516 {% if flag?(:x86_64) %} 517 alias SizeT = UInt64 518 {% else %} 519 alias SizeT = UInt32 520 {% end %} 521 522 fun memcmp(p1 : Void*, p2 : Void*, size : C::SizeT) : Int32 523end 524 525lib X 526 enum SomeEnum 527 Ten = 10 528 Twenty = 10 * 2 529 ThirtyTwo = 1 << 5 530 end 531end 532 533lib X 534 enum SomeEnum 535 A = 1_u32 536 end 537end 538 539X::SomeEnum::Zero # => 0_i8 540X::SomeEnum::Two # => 2_i8 541 542lib X 543 fun callback(f : Int32 -> Int32) 544end 545 546f = ->(x : Int32) { x + 1 } 547X.callback(f) 548 549X.callback ->(x) { x + 1 } 550 551X.callback nil 552 553lib LibFoo 554 fun store_callback(callback : ->) 555 fun execute_callback 556end 557 558LibFoo.store_callback ->{ raise "OH NO!" } 559LibFoo.execute_callback 560 561lib LibFoo 562 fun store_callback(callback : ->) 563 564 @[Raises] 565 fun execute_callback 566end 567 568@[Link("pcre")] 569lib PCRE 570 INFO_CAPTURECOUNT = 2 571end 572 573PCRE::INFO_CAPTURECOUNT # => 2 574 575lib U 576 # In C: 577 # 578 # union IntOrFloat { 579 # int some_int; 580 # double some_float; 581 # }; 582 union IntOrFloat 583 some_int : Int32 584 some_float : Float64 585 end 586end 587 588value = U::IntOrFloat.new 589 590value = uninitialized U::IntOrFlaot 591value.some_int # => some garbage value 592 593value = U::IntOrFloat.new 594value.some_int = 1 595value.some_int # => 1 596value.some_float # => 4.94066e-324 597 598def change_it(value) 599 value.some_int = 1 600end 601 602value = U::IntOrFloat.new 603change_it value 604value.some_int # => 0 605 606lib C 607 # In C: 608 # 609 # struct TimeZone { 610 # int minutes_west; 611 # int dst_time; 612 # }; 613 struct TimeZone 614 minutes_west : Int32 615 dst_time : Int32 616 end 617end 618 619lib C 620 # This is a forward declaration 621 struct Node 622 end 623 624 struct Node 625 node : Node* 626 end 627end 628 629tz = C::TimeZone.new 630 631tz = uninitialized C::TimeZone 632tz.minutes_west # => some garbage value 633 634tz = C::TimeZone.new 635tz.minutes_west = 1 636tz.minutes_west # => 1 637 638tz = C::TimeZone.new minutes_west: 1, dst_time: 2 639tz.minutes_west # => 1 640tz.dst_time # => 2 641 642def change_it(tz) 643 tz.minutes_west = 1 644end 645 646tz = C::TimeZone.new 647change_it tz 648tz.minutes_west # => 0 649 650lib C 651 $errno : Int32 652end 653 654C.errno # => some value 655C.errno = 0 656C.errno # => 0 657 658lib C 659 @[ThreadLocal] 660 $errno : Int32 661end 662 663lib C 664 fun waitpid(pid : Int32, status_ptr : Int32*, options : Int32) : Int32 665end 666 667status_ptr = uninitialized Int32 668 669C.waitpid(pid, pointerof(status_ptr), options) 670 671C.waitpid(pid, out status_ptr, options) 672 673lib X 674 type CInt = Int32 675end 676 677{% if flag?(:x86_64) %} 678 # some specific code for 64 bits platforms 679{% else %} 680 # some specific code for non-64 bits platforms 681{% end %} 682 683{% if flag?(:linux) && flag?(:x86_64) %} 684 # some specific code for linux 64 bits 685{% end %} 686 687lib C 688 {% if flag?(:linux) && flag?(:x86_64) %} 689 struct SomeStruct 690 some_field : Int32 691 end 692 {% else %} 693 struct SomeStruct 694 some_field : Int64 695 end 696 {% end %} 697end 698 699# Assigns to a local variable 700local = 1 701 702# Assigns to a global property 703class Global 704 class_property global1 = 1 705 class_getter global2 = 2 706 class_setter global3 = 3 707 708 # Fails on nil 709 class_property! global4 = 4 710 class_getter! global5 = 5 711 class_setter! global6 = 6 712end 713 714class Testing 715 # Assigns to an instance variable 716 @instance = 2 717 718 # Assigns to a class variable 719 @@class = 3 720end 721 722local += 1 # same as: local = local + 1 723 724# The above is valid with these operators: 725# +, -, *, /, %, |, &, ^, **, <<, >> 726 727local ||= 1 # same as: local || (local = 1) 728local &&= 1 # same as: local && (local = 1) 729 730# A setter 731person.name=("John") 732 733# The above can be written as: 734person.name = "John" 735 736# An indexed assignment 737objects.[]=(2, 3) 738 739# The above can be written as: 740objects[2] = 3 741 742# Not assignment-related, but also syntax sugar: 743objects.[](2, 3) 744 745# The above can be written as: 746objects[2, 3] 747 748person.age += 1 # same as: person.age = person.age + 1 749 750person.name ||= "John" # same as: person.name || (person.name = "John") 751person.name &&= "John" # same as: person.name && (person.name = "John") 752 753objects[1] += 2 # same as: objects[1] = objects[1] + 2 754 755objects[1] ||= 2 # same as: objects[1]? || (objects[1] = 2) 756objects[1] &&= 2 # same as: objects[1]? && (objects[1] = 2) 757 758alias PInt32 = Pointer(Int32) 759 760ptr = PInt32.malloc(1) # : Pointer(Int32) 761 762alias RecArray = Array(Int32) | Array(RecArray) 763 764ary = [] of RecArray 765ary.push [1, 2, 3] 766ary.push ary 767ary # => [[1, 2, 3], [...]] 768 769module Json 770 alias Type = Nil | 771 Bool | 772 Int64 | 773 Float64 | 774 String | 775 Array(Type) | 776 Hash(String, Type) 777end 778 779a = 1 780if a > 0 781 a = 10 782end 783a # => 10 784 785b = 1 786if b > 2 787 b = 10 788else 789 b = 20 790end 791b # => 20 792 793if some_condition 794 do_something 795elsif some_other_condition 796 do_something_else 797else 798 do_that 799end 800 801a = 1 802if some_condition 803 a = "hello" 804else 805 a = true 806end 807# a : String | Bool 808 809b = 1 810if some_condition 811 b = "hello" 812end 813# b : Int32 | String 814 815if some_condition 816 c = 1 817else 818 c = "hello" 819end 820# c : Int32 | String 821 822if some_condition 823 d = 1 824end 825# d : Int32 | Nil 826 827a = 1 828if some_condition 829 a = "hello" 830 # a : String 831 a.size 832end 833# a : String | Int32 834 835if some_condition 836 e = 1 837else 838 e = "hello" 839 # e : String 840 return 841end 842# e : Int32 843 844enum Color : UInt8 845 Red # 0 846 Green # 1 847 Blue = 5 # overwritten to 5 848 Yellow # 6 (5 + 1) 849 850 def red? 851 self == Color::Red 852 end 853end 854 855Color::Red.value # :: UInt8 856 857@[Flags] 858enum IOMode 859 Read # 1 860 Write # 2 861 Async # 4 862end 863 864IOMode::None.value # => 0 865IOMode::All.value # => 7 866 867puts(Color::Red) # prints "Red" 868puts(IOMode::Write | IOMode::Async) # prints "Write, Async" 869 870puts Color.new(1) # => prints "Green" 871 872puts Color.new(10) # => prints "10" 873 874Color::Red.red? # => true 875Color::Blue.red? # => false 876 877def paint(color : Color) 878 case color 879 when Color::Red 880 # ... 881 else 882 # Unusual, but still can happen 883 raise "unknown color: #{color}" 884 end 885end 886 887paint Color::Red 888 889def paint(color : Symbol) 890 case color 891 when :red 892 # ... 893 else 894 raise "unknown color: #{color}" 895 end 896end 897 898paint :red 899 900name = "Crystal" 901age = 1 902 903flower = "Tulip" 904# At this point 'flower' is a String 905 906flower = 1 907 908# At this point 'flower' is an Int32 909 910class Foo 911 def finalize 912 # Invoked when Foo is garbage-collected 913 puts "Bye bye from #{self}!" 914 end 915end 916 917# Prints "Bye bye ...!" for ever 918loop do 919 Foo.new 920end 921 922# Defines a method in the program 923def add(x, y) 924 x + y 925end 926 927# Invokes the add method in the program 928add(1, 2) # => 3 929 930def even?(num) 931 if num % 2 == 0 932 return true 933 end 934 935 return false 936end 937 938def add(x, y) 939 x + y 940end 941 942class Foo 943 def bar 944 # invokes the program's add method 945 add(1, 2) 946 947 # invokes Foo's baz method 948 baz(1, 2) 949 end 950 951 def baz(x, y) 952 x * y 953 end 954end 955 956def baz(x, y) 957 x + y 958end 959 960class Foo 961 def bar 962 baz(4, 2) # => 2 963 ::baz(4, 2) # => 6 964 end 965 966 def baz(x, y) 967 x - y 968 end 969end 970 971x = 1 972 973def add(y) 974 x + y # error: undefined local variable or method 'x' 975end 976 977add(2) 978 979add 1, 2 # same as add(1, 2) 980 981class Counter 982 @@instances = 0 983 984 def initialize 985 @@instances += 1 986 end 987 988 def self.instances 989 @@instances 990 end 991end 992 993Counter.instances # => 0 994Counter.new 995Counter.new 996Counter.new 997Counter.instances # => 3 998 999class Counter 1000 def self.increment 1001 @@instances += 1 1002 end 1003end 1004 1005Counter.increment # Error: undefined method '+' for Nil 1006 1007class Parent 1008 @@counter = 0 1009end 1010 1011class Child < Parent 1012 def self.counter 1013 @@counter 1014 end 1015end 1016 1017Child.counter # => nil 1018 1019unless some_condition 1020 then_expression 1021else 1022 else_expression 1023end 1024 1025# Can also be written as a suffix 1026close_door unless door_closed? 1027 1028a = 1 1029b = typeof(a) # => Int32 1030 1031typeof(1, "a", 'a') # => (Int32 | String | Char) 1032 1033hash = {} of Int32 => String 1034another_hash = typeof(hash).new # :: Hash(Int32, String) 1035 1036class Array 1037 def self.elem_type(typ) 1038 if typ.is_a?(Array) 1039 elem_type(typ.first) 1040 else 1041 typ 1042 end 1043 end 1044end 1045 1046nest = [1, ["b", [:c, ['d']]]] 1047flat = Array(typeof(Array.elem_type(nest))).new 1048typeof(nest) # => Array(Int32 | Array(String | Array(Symbol | Array(Char)))) 1049typeof(flat) # => Array(String | Int32 | Symbol | Char) 1050 1051a = 2 if some_condition 1052 1053x = 0 1054proc = ->{ x += 1; x } 1055proc.call # => 1 1056proc.call # => 2 1057x # => 2 1058 1059def counter 1060 x = 0 1061 ->{ x += 1; x } 1062end 1063 1064proc = counter 1065proc.call # => 1 1066proc.call # => 2 1067 1068def foo 1069 yield 1070end 1071 1072x = 1 1073foo do 1074 x = "hello" 1075end 1076x # : Int32 | String 1077 1078x = 1 1079foo do 1080 x = "hello" 1081end 1082x # : Int32 | String 1083 1084x = 'a' 1085x # : Char 1086 1087def capture(&block) 1088 block 1089end 1090 1091x = 1 1092capture { x = "hello" } 1093 1094x = 'a' 1095x # : Int32 | String | Char 1096 1097def capture(&block) 1098 block 1099end 1100 1101x = 1 1102->{ x = "hello" } 1103 1104x = 'a' 1105x # : Int32 | String | Char 1106 1107abstract class Animal 1108 # Makes this animal talk 1109 abstract def talk 1110end 1111 1112class Dog < Animal 1113 def talk 1114 "Woof!" 1115 end 1116end 1117 1118class Cat < Animal 1119 def talk 1120 "Miau" 1121 end 1122end 1123 1124class Person 1125 getter pet 1126 1127 def initialize(@name, @pet) 1128 end 1129end 1130 1131john = Person.new "John", Dog.new 1132peter = Person.new "Peter", Cat.new 1133 1134john.pet.talk # => "Woof!" 1135 1136a = 1 > 2 ? 3 : 4 1137 1138# The above is the same as: 1139a = if 1 > 2 1140 3 1141 else 1142 4 1143 end 1144 1145def some_method : String 1146 "hello" 1147end 1148 1149PI = 3.14 1150 1151module Earth 1152 RADIUS = 6_371_000 1153end 1154 1155PI # => 3.14 1156Earth::RADIUS # => 6_371_000 1157 1158TEN = begin 1159 a = 0 1160 while a < 10 1161 a += 1 1162 end 1163 a 1164end 1165 1166TEN # => 10 1167 1168class Person 1169 getter name 1170 1171 def initialize(@name) 1172 @age = 0 1173 end 1174end 1175 1176john = Person.new "John" 1177john.name # => "John" 1178john.name.size # => 4 1179 1180one = Person.new 1 1181one.name # => 1 1182one.name + 2 # => 3 1183 1184john = Person.new "John" 1185one = Person.new 1 1186 1187john = Person.new "John" 1188one = Person.new 1 1189 1190# Error: undefined method 'size' for Int32 1191john.name.size 1192 1193# Error: no overload matches 'String#+' with types Int32 1194john.name + 3 1195 1196john = Person.new "John" 1197john.name.size 1198one = Person.new 1 1199 1200class Person 1201 getter name 1202 1203 def initialize(@name) 1204 @age = 0 1205 end 1206 1207 def address 1208 @address 1209 end 1210 1211 def address=(@address) 1212 end 1213end 1214 1215john = Person.new "John" 1216john.address = "Argentina" 1217 1218# Error: undefined method 'size' for Nil 1219john.address.size 1220 1221class Person 1222 @age = 0 1223 1224 def initialize(@name) 1225 end 1226end 1227 1228class Person 1229 @age : Int32 1230 1231 def initialize(@name) 1232 @age = 0 1233 end 1234end 1235 1236a = if 2 > 1 1237 3 1238 else 1239 4 1240 end 1241a # => 3 1242 1243if 1 > 2 1244else 1245 3 1246end 1247 1248def twice(&block) 1249 yield 1250 yield 1251end 1252 1253twice() do 1254 puts "Hello!" 1255end 1256 1257twice do 1258 puts "Hello!" 1259end 1260 1261twice { puts "Hello!" } 1262 1263def twice 1264 yield 1 1265 yield 2 1266end 1267 1268twice do |i| 1269 puts "Got #{i}" 1270end 1271 1272twice { |i| puts "Got #{i}" } 1273 1274def many 1275 yield 1, 2, 3 1276end 1277 1278many do |x, y, z| 1279 puts x + y + z 1280end 1281 1282# Output: 6 1283 1284def many 1285 yield 1, 2, 3 1286end 1287 1288many do |x, y| 1289 puts x + y 1290end 1291 1292# Output: 3 1293 1294def twice 1295 yield 1296 yield 1297end 1298 1299twice do |i| 1300 puts i.inspect 1301end 1302 1303def some 1304 yield 1, 'a' 1305 yield true, "hello" 1306 yield 2 1307end 1308 1309some do |first, second| 1310 # first is Int32 | Bool 1311 # second is Char | String | Nil 1312end 1313 1314method do |argument| 1315 argument.some_method 1316end 1317 1318method(&.some_method) 1319 1320method &.some_method(arg1, arg2) 1321 1322method &.+(2) 1323method &.[index] 1324 1325def twice 1326 v1 = yield 1 1327 puts v1 1328 1329 v2 = yield 2 1330 puts v2 1331end 1332 1333twice do |i| 1334 i + 1 1335end 1336 1337ary = [1, 2, 3] 1338ary.map { |x| x + 1 } # => [2, 3, 4] 1339ary.select { |x| x % 2 == 1 } # => [1, 3] 1340 1341def transform(value) 1342 yield value 1343end 1344 1345transform(1) { |x| x + 1 } # => 2 1346 1347def thrice 1348 puts "Before 1" 1349 yield 1 1350 puts "Before 2" 1351 yield 2 1352 puts "Before 3" 1353 yield 3 1354 puts "After 3" 1355end 1356 1357thrice do |i| 1358 if i == 2 1359 break 1360 end 1361end 1362 1363def twice 1364 yield 1 1365 yield 2 1366end 1367 1368twice { |i| i + 1 } # => 3 1369twice { |i| break "hello" } # => "hello" 1370 1371value = twice do |i| 1372 if i == 1 1373 break "hello" 1374 end 1375 i + 1 1376end 1377value # :: Int32 | String 1378 1379values = twice { break 1, 2 } 1380values # => {1, 2} 1381 1382value = twice { break } 1383value # => nil 1384 1385def twice 1386 yield 1 1387 yield 2 1388end 1389 1390twice do |i| 1391 if i == 1 1392 puts "Skipping 1" 1393 next 1394 end 1395 1396 puts "Got #{i}" 1397end 1398 1399def twice 1400 v1 = yield 1 1401 puts v1 1402 1403 v2 = yield 2 1404 puts v2 1405end 1406 1407twice do |i| 1408 if i == 1 1409 next 10 1410 end 1411 1412 i + 1 1413end 1414 1415# Output 1416# 10 1417# 3 1418 1419class Foo 1420 def one 1421 1 1422 end 1423 1424 def yield_with_self 1425 with self yield 1426 end 1427 1428 def yield_normally 1429 yield 1430 end 1431end 1432 1433def one 1434 "one" 1435end 1436 1437Foo.new.yield_with_self { one } # => 1 1438Foo.new.yield_normally { one } # => "one" 1439 1440def twice 1441 yield 1 1442 yield 2 1443end 1444 1445twice do |i| 1446 puts "Got: #{i}" 1447end 1448 1449i = 1 1450puts "Got: #{i}" 1451i = 2 1452puts "Got: #{i}" 1453 14543.times do |i| 1455 puts i 1456end 1457 1458struct Int 1459 def times 1460 i = 0 1461 while i < self 1462 yield i 1463 i += 1 1464 end 1465 end 1466end 1467 1468i = 0 1469while i < 3 1470 puts i 1471 i += 1 1472end 1473 1474class Person 1475 def initialize(@name) 1476 end 1477 1478 def greet 1479 puts "Hi, I'm #{@name}" 1480 end 1481end 1482 1483class Employee < Person 1484end 1485 1486employee = Employee.new "John" 1487employee.greet # "Hi, I'm John" 1488 1489class Person 1490 def initialize(@name) 1491 end 1492end 1493 1494class Employee < Person 1495 def initialize(@name, @company_name) 1496 end 1497end 1498 1499Employee.new "John", "Acme" # OK 1500Employee.new "Peter" # Error: wrong number of arguments 1501# for 'Employee:Class#new' (1 for 2) 1502 1503class Person 1504 def greet(msg) 1505 puts "Hi, #{msg}" 1506 end 1507end 1508 1509class Employee < Person 1510 def greet(msg) 1511 puts "Hello, #{msg}" 1512 end 1513end 1514 1515p = Person.new 1516p.greet "everyone" # "Hi, everyone" 1517 1518e = Employee.new 1519e.greet "everyone" # "Hello, everyone" 1520 1521class Person 1522 def greet(msg) 1523 puts "Hi, #{msg}" 1524 end 1525end 1526 1527class Employee < Person 1528 def greet(msg : Int32) 1529 puts "Hi, this is a number: #{msg}" 1530 end 1531end 1532 1533e = Employee.new 1534e.greet "everyone" # "Hi, everyone" 1535 1536e.greet 1 # "Hi, this is a number: 1" 1537 1538class Person 1539 def greet(msg) 1540 puts "Hello, " # {msg}" 1541 end 1542end 1543 1544class Employee < Person 1545 def greet(msg) 1546 super # Same as: super(msg) 1547 super("another message") 1548 end 1549end 1550 1551def int_to_int(&block : Int32 -> Int32) 1552 block 1553end 1554 1555proc = int_to_int { |x| x + 1 } 1556proc.call(1) # => 2 1557 1558class Model 1559 def on_save(&block) 1560 @on_save_callback = block 1561 end 1562 1563 def save 1564 if callback = @on_save_callback 1565 callback.call 1566 end 1567 end 1568end 1569 1570model = Model.new 1571model.on_save { puts "Saved!" } 1572model.save # prints "Saved!" 1573 1574def some_proc(&block : Int32 ->) 1575 block 1576end 1577 1578proc = some_proc { |x| x + 1 } 1579proc.call(1) # void 1580 1581def some_proc(&block : Int32 -> _) 1582 block 1583end 1584 1585proc = some_proc { |x| x + 1 } 1586proc.call(1) # 2 1587 1588proc = some_proc { |x| x.to_s } 1589proc.call(1) # "1" 1590 1591macro update_x 1592 x = 1 1593end 1594 1595x = 0 1596update_x 1597x # => 1 1598 1599macro dont_update_x 1600 %x = 1 1601 puts %x 1602end 1603 1604x = 0 1605dont_update_x # outputs 1 1606x # => 0 1607 1608macro fresh_vars_sample(*names) 1609 # First declare vars 1610 {% for name, index in names %} 1611 print "Declaring: ", "%name{index}", '\n' 1612 %name{index} = {{index}} 1613 {% end %} 1614 1615 # Then print them 1616 {% for name, index in names %} 1617 print "%name{index}: ", %name{index}, '\n' 1618 {% end %} 1619end 1620 1621fresh_vars_sample a, b, c 1622 1623# Sample output: 1624# Declaring: __temp_255 1625# Declaring: __temp_256 1626# Declaring: __temp_257 1627# __temp_255: 0 1628# __temp_256: 1 1629# __temp_257: 2 1630 1631class Object 1632 macro instance_vars_names 1633 def instance_vars_names : Array(String) 1634 {{ @type.instance_vars.map &.name.stringify }} 1635 end 1636 end 1637end 1638 1639class Person 1640 def initialize(@name, @age) 1641 end 1642end 1643 1644person = Person.new "John", 30 1645person.instance_vars_names # => ["name", "age"] 1646 1647class Object 1648 macro has_instance_var?(name) 1649 def has_instance_var?(name) : Bool 1650 # We cannot access name inside the macro expansion here, 1651 # instead we need to use the macro language to construct an array 1652 # and do the inclusion check at runtime. 1653 {{ @type.instance_vars.map &.name.stringify }}.includes? name 1654 end 1655 end 1656end 1657 1658person = Person.new "John", 30 1659person.has_instance_var?("name") # => true 1660person.has_instance_var?("birthday") # => false 1661 1662class Parent 1663 macro inherited 1664 def {{@type.name.downcase.id}} 1665 1 1666 end 1667 end 1668end 1669 1670class Child < Parent 1671end 1672 1673Child.new.child # => 1 1674 1675macro method_missing(name, args, block) 1676 print "Got ", {{name.id.stringify}}, " with ", {{args.size}}, " arguments", '\n' 1677end 1678 1679foo # Prints: Got foo with 0 arguments 1680bar 'a', 'b' # Prints: Got bar with 2 arguments 1681 1682sizeof(Int32) # => 4 1683sizeof(Int64) # => 8 1684 1685# On a 64 bits machine 1686sizeof(Pointer(Int32)) # => 8 1687sizeof(String) # => 8 1688 1689a = 1 1690sizeof(typeof(a)) # => 4 1691 1692class Foo 1693 macro emphasize(value) 1694 "***#{ {{value}} }***" 1695 end 1696 1697 def yield_with_self 1698 with self yield 1699 end 1700end 1701 1702Foo.new.yield_with_self { emphasize(10) } # => "***10***" 1703 1704# This generates: 1705# 1706# def :foo 1707# 1 1708# end 1709define_method :foo, 1 1710 1711macro define_method(name, content) 1712 def {{name.id}} 1713 {{content}} 1714 end 1715end 1716 1717# This correctly generates: 1718# 1719# def foo 1720# 1 1721# end 1722define_method :foo, 1 1723 1724macro define_method(name, content) 1725 def {{name}} 1726 {% if content == 1 %} 1727 "one" 1728 {% else %} 1729 {{content}} 1730 {% end %} 1731 end 1732end 1733 1734define_method foo, 1 1735define_method bar, 2 1736 1737foo # => one 1738bar # => 2 1739 1740{% if env("TEST") %} 1741 puts "We are in test mode" 1742{% end %} 1743 1744macro define_dummy_methods(names) 1745 {% for name, index in names %} 1746 def {{name.id}} 1747 {{index}} 1748 end 1749 {% end %} 1750end 1751 1752define_dummy_methods [foo, bar, baz] 1753 1754foo # => 0 1755bar # => 1 1756baz # => 2 1757 1758macro define_dummy_methods(hash) 1759 {% for key, value in hash %} 1760 def {{key.id}} 1761 {{value}} 1762 end 1763 {% end %} 1764end 1765 1766define_dummy_methods({foo: 10, bar: 20}) 1767foo # => 10 1768bar # => 20 1769 1770{% for name, index in ["foo", "bar", "baz"] %} 1771 def {{name.id}} 1772 {{index}} 1773 end 1774{% end %} 1775 1776foo # => 0 1777bar # => 1 1778baz # => 2 1779 1780macro define_dummy_methods(*names) 1781 {% for name, index in names %} 1782 def {{name.id}} 1783 {{index}} 1784 end 1785 {% end %} 1786end 1787 1788define_dummy_methods foo, bar, baz 1789 1790foo # => 0 1791bar # => 1 1792baz # => 2 1793 1794macro println(*values) 1795 print {{*values}}, '\n' 1796end 1797 1798println 1, 2, 3 # outputs 123\n 1799 1800VALUES = [1, 2, 3] 1801 1802{% for value in VALUES %} 1803 puts {{value}} 1804{% end %} 1805 1806until some_condition 1807 do_this 1808end 1809 1810# The above is the same as: 1811while !some_condition 1812 do_this 1813end 1814 1815a = some_condition ? nil : 3 1816# a is Int32 or Nil 1817 1818if a 1819 # Since the only way to get here is if a is truthy, 1820 # a can't be nil. So here a is Int32. 1821 a.abs 1822end 1823 1824if a = some_expression 1825 # here a is not nil 1826end 1827 1828if a && b 1829 # here both a and b are guaranteed not to be Nil 1830end 1831 1832if @a 1833 # here @a can be nil 1834end 1835 1836# First option: assign it to a variable 1837if a = @a 1838 # here a can't be nil 1839end 1840 1841# Second option: use `Object#try` found in the standard library 1842@a.try do |a| 1843 # here a can't be nil 1844end 1845 1846if method # first call to a method that can return Int32 or Nil 1847 # here we know that the first call did not return Nil 1848 method # second call can still return Int32 or Nil 1849end 1850 1851class Person 1852 def become_older(by = 1) 1853 @age += by 1854 end 1855end 1856 1857john = Person.new "John" 1858john.age # => 0 1859 1860john.become_older 1861john.age # => 1 1862 1863john.become_older 2 1864john.age # => 3 1865 1866john.become_older by: 5 1867 1868def some_method(x, y = 1, z = 2, w = 3) 1869 # do something... 1870end 1871 1872some_method 10 # x = 10, y = 1, z = 2, w = 3 1873some_method 10, z: 10 # x = 10, y = 1, z = 10, w = 3 1874some_method 10, w: 1, y: 2, z: 3 # x = 10, y = 2, z = 3, w = 1 1875 1876case exp 1877when value1, value2 1878 do_something 1879when value3 1880 do_something_else 1881else 1882 do_another_thing 1883end 1884 1885case var 1886when String 1887 # var : String 1888 do_something 1889when Int32 1890 # var : Int32 1891 do_something_else 1892else 1893 # here var is neither a String nor an Int32 1894 do_another_thing 1895end 1896 1897case num 1898when .even? 1899 do_something 1900when .odd? 1901 do_something_else 1902end 1903 1904case 1905when cond1, cond2 1906 do_something 1907when cond3 1908 do_something_else 1909end 1910 1911a = 1 1912a.responds_to?(:abs) # => true 1913a.responds_to?(:size) # => false 1914 1915foo_or_bar = /foo|bar/ 1916heeello = /h(e+)llo/ 1917integer = /\d+/ 1918 1919r = /foo/imx 1920 1921slash = /\// 1922 1923r = %r(regex with slash: /) 1924 1925"hello world" 1926 1927"\"" # double quote 1928"\\" # backslash 1929"\e" # escape 1930"\f" # form feed 1931"\n" # newline 1932"\r" # carriage return 1933"\t" # tab 1934"\v" # vertical tab 1935 1936"\101" # == "A" 1937"\123" # == "S" 1938"\12" # == "\n" 1939"\1" # string with one character with code point 1 1940 1941"\u0041" # == "A" 1942 1943"\u{41}" # == "A" 1944"\u{1F52E}" # == "" 1945 1946"hello 1947 world" # same as "hello\n world" 1948 1949"hello " \ 1950"world, " \ 1951"no newlines" # same as "hello world, no newlines" 1952 1953"hello \ 1954 world, \ 1955 no newlines" # same as "hello world, no newlines" 1956 1957# Supports double quotes and nested parenthesis 1958%(hello ("world")) # same as "hello (\"world\")" 1959 1960# Supports double quotes and nested brackets 1961%[hello ["world"]] # same as "hello [\"world\"]" 1962 1963# Supports double quotes and nested curlies 1964%{hello {"world"}} # same as "hello {\"world\"}" 1965 1966# Supports double quotes and nested angles 1967%<hello <"world">> # same as "hello <\"world\">" 1968 1969<<-XML 1970<parent> 1971 <child /> 1972</parent> 1973XML 1974 1975# Same as "Hello\n world" 1976<<-STRING 1977 Hello 1978 world 1979 STRING 1980 1981# Same as " Hello\n world" 1982<<-STRING 1983 Hello 1984 world 1985 STRING 1986 1987a = 1 1988b = 2 1989"sum = #{a + b}" # "sum = 3" 1990 19911.0 # Float64 19921.0_f32 # Float32 19931_f32 # Float32 1994 19951e10 # Float64 19961.5e10 # Float64 19971.5e-7 # Float64 1998 1999+1.3 # Float64 2000-0.5 # Float64 2001 20021_000_000.111_111 # better than 1000000.111111 2003 2004'a' 2005'z' 2006'0' 2007'_' 2008"ã‚" 2009 2010'\'' # single quote 2011'\\' # backslash 2012'\e' # escape 2013'\f' # form feed 2014'\n' # newline 2015'\r' # carriage return 2016'\t' # tab 2017'\v' # vertical tab 2018 2019"\101" # == 'A' 2020"\123" # == 'S' 2021"\12" # == '\n' 2022"\1" # code point 1 2023 2024'\u0041' # == 'A' 2025 2026'\u{41}' # == 'A' 2027'\u{1F52E}' # == '' 2028 2029{1 => 2, 3 => 4} # Hash(Int32, Int32) 2030{1 => 2, 'a' => 3} # Hash(Int32 | Char, Int32) 2031 2032{} of Int32 => Int32 # same as Hash(Int32, Int32).new 2033 2034{key1: 'a', key2: 'b'} # Hash(Symbol, Char) 2035 2036{"key1": 'a', "key2": 'b'} # Hash(String, Char) 2037 2038MyType{"foo" => "bar"} 2039 2040tmp = MyType.new 2041tmp["foo"] = "bar" 2042tmp 2043 2044tmp = MyType(typeof("foo"), typeof("bar")).new 2045tmp["foo"] = "bar" 2046tmp 2047 2048MyType(String, String){"foo" => "bar"} 2049 2050:hello 2051:good_bye 2052 2053# With spaces and symbols 2054:"symbol with spaces" 2055 2056# Ending with question and exclamation marks 2057:question? 2058:exclamation! 2059 2060# For the operators 2061:+ 2062:- 2063:* 2064:/ 2065:== 2066:< 2067:<= 2068:> 2069:>= 2070:! 2071:!= 2072:=~ 2073:!~ 2074:& 2075:| 2076:^ 2077:~ 2078:** 2079:>> 2080:<< 2081:% 2082:[] 2083:[]? 2084:[]= 2085:<=> 2086:=== 2087 2088x..y # an inclusive range, in mathematics: [x, y] 2089x...y # an exclusive range, in mathematics: [x, y) 2090 2091# A proc without arguments 2092->{ 1 } # Proc(Int32) 2093 2094# A proc with one argument 2095->(x : Int32) { x.to_s } # Proc(Int32, String) 2096 2097# A proc with two arguments: 2098->(x : Int32, y : Int32) { x + y } # Proc(Int32, Int32, Int32) 2099 2100Proc(Int32, String).new { |x| x.to_s } # Proc(Int32, String) 2101 2102proc = ->(x : Int32, y : Int32) { x + y } 2103proc.call(1, 2) # => 3 2104 2105def one 2106 1 2107end 2108 2109proc = ->one 2110proc.call # => 1 2111 2112def plus_one(x) 2113 x + 1 2114end 2115 2116proc = ->plus_one(Int32) 2117proc.call(41) # => 42 2118 2119str = "hello" 2120proc = ->str.count(Char) 2121proc.call('e') # => 1 2122proc.call('l') # => 2 2123 2124tuple = {1, "hello", 'x'} # Tuple(Int32, String, Char) 2125tuple[0] # => 1 (Int32) 2126tuple[1] # => "hello" (String) 2127tuple[2] # => 'x' (Char) 2128 2129[1, 2, 3] # Array(Int32) 2130[1, "hello", 'x'] # Array(Int32 | String | Char) 2131 2132[] of Int32 # same as Array(Int32).new 2133 2134%w(one two three) # ["one", "two", "three"] 2135 2136%i(one two three) # [:one, :two, :three] 2137 2138MyType{1, 2, 3} 2139 2140tmp = MyType.new 2141tmp << 1 2142tmp << 2 2143tmp << 3 2144tmp 2145 2146tmp = MyType(typeof(1, 2, 3)).new 2147tmp << 1 2148tmp << 2 2149tmp << 3 2150tmp 2151 2152MyType(Int32 | String){1, 2, "foo"} 2153 2154nil 2155 21561 # Int32 2157 21581_i8 # Int8 21591_i16 # Int16 21601_i32 # Int32 21611_i64 # Int64 2162 21631_u8 # UInt8 21641_u16 # UInt16 21651_u32 # UInt32 21661_u64 # UInt64 2167 2168+10 # Int32 2169-20 # Int32 2170 21712147483648 # Int64 21729223372036854775808 # UInt64 2173 21741_000_000 # better than 1000000 2175 21760b1101 # == 13 2177 21780o123 # == 83 2179 21800xFE012D # == 16646445 21810xfe012d # == 16646445 2182 2183true # A Bool that is true 2184false # A Bool that is false 2185 2186a = 1 2187 2188ptr = pointerof(a) 2189ptr.value = 2 2190 2191a # => 2 2192 2193class Point 2194 def initialize(@x, @y) 2195 end 2196 2197 def x 2198 @x 2199 end 2200 2201 def x_ptr 2202 pointerof(@x) 2203 end 2204end 2205 2206point = Point.new 1, 2 2207 2208ptr = point.x_ptr 2209ptr.value = 10 2210 2211point.x # => 10 2212 2213def add(x : Number, y : Number) 2214 x + y 2215end 2216 2217# Ok 2218add 1, 2 # Ok 2219 2220# Error: no overload matches 'add' with types Bool, Bool 2221add true, false 2222 2223def add(x, y) 2224 x + y 2225end 2226 2227add true, false 2228 2229# A class that has a + method but isn't a Number 2230class Six 2231 def +(other) 2232 6 + other 2233 end 2234end 2235 2236# add method without type restrictions 2237def add(x, y) 2238 x + y 2239end 2240 2241# OK 2242add Six.new, 10 2243 2244# add method with type restrictions 2245def restricted_add(x : Number, y : Number) 2246 x + y 2247end 2248 2249# Error: no overload matches 'restricted_add' with types Six, Int32 2250restricted_add Six.new, 10 2251 2252class Person 2253 def ==(other : self) 2254 other.name == name 2255 end 2256 2257 def ==(other) 2258 false 2259 end 2260end 2261 2262john = Person.new "John" 2263another_john = Person.new "John" 2264peter = Person.new "Peter" 2265 2266john == another_john # => true 2267john == peter # => false (names differ) 2268john == 1 # => false (because 1 is not a Person) 2269 2270class Person 2271 def self.compare(p1 : self, p2 : self) 2272 p1.name == p2.name 2273 end 2274end 2275 2276john = Person.new "John" 2277peter = Person.new "Peter" 2278 2279Person.compare(john, peter) # OK 2280 2281def foo(x : Int32) 2282end 2283 2284foo 1 # OK 2285foo "hello" # Error 2286 2287def foo(x : Int32.class) 2288end 2289 2290foo Int32 # OK 2291foo String # Error 2292 2293def foo(x : Int32.class) 2294 puts "Got Int32" 2295end 2296 2297def foo(x : String.class) 2298 puts "Got String" 2299end 2300 2301foo Int32 # prints "Got Int32" 2302foo String # prints "Got String" 2303 2304def foo(*args : Int32) 2305end 2306 2307def foo(*args : String) 2308end 2309 2310foo 1, 2, 3 # OK, invokes first overload 2311foo "a", "b", "c" # OK, invokes second overload 2312foo 1, 2, "hello" # Error 2313foo() # Error 2314 2315def foo 2316 # This is the empty-tuple case 2317end 2318 2319def foo(x : T) 2320 T 2321end 2322 2323foo(1) # => Int32 2324foo("hello") # => String 2325 2326def foo(x : Array(T)) 2327 T 2328end 2329 2330foo([1, 2]) # => Int32 2331foo([1, "a"]) # => (Int32 | String) 2332 2333def foo(x : T.class) 2334 Array(T) 2335end 2336 2337foo(Int32) # => Array(Int32) 2338foo(String) # => Array(String) 2339 2340class Person 2341 # Increases age by one 2342 def become_older 2343 @age += 1 2344 end 2345 2346 # Increases age by the given number of years 2347 def become_older(years : Int32) 2348 @age += years 2349 end 2350 2351 # Increases age by the given number of years, as a String 2352 def become_older(years : String) 2353 @age += years.to_i 2354 end 2355 2356 # Yields the current age of this person and increases 2357 # its age by the value returned by the block 2358 def become_older 2359 @age += yield @age 2360 end 2361end 2362 2363person = Person.new "John" 2364 2365person.become_older 2366person.age # => 1 2367 2368person.become_older 5 2369person.age # => 6 2370 2371person.become_older "12" 2372person.age # => 18 2373 2374person.become_older do |current_age| 2375 current_age < 20 ? 10 : 30 2376end 2377person.age # => 28 2378 2379a = 1 2380a.is_a?(Int32) # => true 2381a.is_a?(String) # => false 2382a.is_a?(Number) # => true 2383a.is_a?(Int32 | String) # => true 2384 2385# One for each thread 2386@[ThreadLocal] 2387values = [] of Int32 2388 2389@[AlwaysInline] 2390def foo 2391 1 2392end 2393 2394@[NoInline] 2395def foo 2396 1 2397end 2398 2399lib LibFoo 2400 @[CallConvention("X86_StdCall")] 2401 fun foo : Int32 2402end 2403 2404def sum(*elements) 2405 total = 0 2406 elements.each do |value| 2407 total += value 2408 end 2409 total 2410end 2411 2412# elements is Tuple(Int32, Int32, Int32, Float64) 2413sum 1, 2, 3, 4.5 2414 2415if a.responds_to?(:abs) 2416 # here a's type will be reduced to those responding to the 'abs' method 2417end 2418 2419a = some_condition ? 1 : "hello" 2420# a : Int32 | String 2421 2422if a.responds_to?(:abs) 2423 # here a will be Int32, since Int32#abs exists but String#abs doesn't 2424else 2425 # here a will be String 2426end 2427 2428if (a = @a).responds_to?(:abs) 2429 # here a is guaranteed to respond to `abs` 2430end 2431 2432def capture(&block) 2433 block 2434end 2435 2436def invoke(&block) 2437 block.call 2438end 2439 2440proc = capture { puts "Hello" } 2441invoke(&proc) # prints "Hello" 2442 2443def capture(&block) 2444 block 2445end 2446 2447def twice 2448 yield 2449 yield 2450end 2451 2452proc = capture { puts "Hello" } 2453twice &proc 2454 2455twice &->{ puts "Hello" } 2456 2457def say_hello 2458 puts "Hello" 2459end 2460 2461twice &->say_hello 2462 2463def foo 2464 yield 1 2465end 2466 2467def wrap_foo 2468 puts "Before foo" 2469 foo do |x| 2470 yield x 2471 end 2472 puts "After foo" 2473end 2474 2475wrap_foo do |i| 2476 puts i 2477end 2478 2479def foo 2480 yield 1 2481end 2482 2483def wrap_foo(&block : Int32 -> _) 2484 puts "Before foo" 2485 foo(&block) 2486 puts "After foo" 2487end 2488 2489wrap_foo do |i| 2490 puts i 2491end 2492 2493foo_forward do |i| 2494 break # error 2495end 2496 2497a = 2 2498while (a += 1) < 20 2499 if a == 10 2500 # goes to 'puts a' 2501 break 2502 end 2503end 2504puts a # => 10 2505 2506class Person 2507 private def say(message) 2508 puts message 2509 end 2510 2511 def say_hello 2512 say "hello" # OK, no receiver 2513 self.say "hello" # Error, self is a receiver 2514 2515 other = Person.new "Other" 2516 other.say "hello" # Error, other is a receiver 2517 end 2518end 2519 2520class Employee < Person 2521 def say_bye 2522 say "bye" # OK 2523 end 2524end 2525 2526module Namespace 2527 class Foo 2528 protected def foo 2529 puts "Hello" 2530 end 2531 end 2532 2533 class Bar 2534 def bar 2535 # Works, because Foo and Bar are under Namespace 2536 Foo.new.foo 2537 end 2538 end 2539end 2540 2541Namespace::Bar.new.bar 2542 2543class Person 2544 protected def self.say(message) 2545 puts message 2546 end 2547 2548 def say_hello 2549 Person.say "hello" 2550 end 2551end 2552 2553buffer = uninitialized UInt8[256] 2554 2555foo = rand(5) > 1 ? 1 : nil 2556 2557foo.not_nil!.to_i 2558