├── README.md ├── code ├── advanced_features │ ├── a.txt │ ├── b.txt │ ├── buffered_channel.cr │ ├── c.txt │ ├── c_bindings.cr │ ├── c_libsdl.cr │ ├── channel_select.cr │ ├── chinook.db │ ├── crchinook │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── crchinook │ │ ├── shard.lock │ │ ├── shard.yml │ │ ├── spec │ │ │ ├── crchinook_spec.cr │ │ │ └── spec_helper.cr │ │ └── src │ │ │ ├── crchinook.cr │ │ │ └── crchinook │ │ │ └── version.cr │ ├── greet │ ├── greet.c │ ├── greet.cr │ ├── greet.o │ ├── lines_files.cr │ ├── low_level.cr │ ├── macros.cr │ ├── main_fiber1.cr │ ├── main_fiber2.cr │ ├── main_fiber5.cr │ ├── spawn_method.cr │ └── synchronizing.cr ├── classes_and_structs │ ├── classes.cr │ ├── inheritance.cr │ ├── private.cr │ ├── program.cr │ ├── protected.cr │ ├── structs.cr │ ├── types.cr │ ├── useful │ ├── useful.cr │ └── virtual.cr ├── crystal_new │ ├── compound_types_arrays.cr │ ├── compound_types_hashes.cr │ ├── control_flow.cr │ ├── fibers.cr │ ├── methods.cr │ ├── methods2.cr │ ├── mineral.cr │ ├── mineral.rb │ ├── modules.cr │ └── variables.cr ├── dirA │ └── fileA.cr ├── fileA.cr ├── libs │ └── file.cr ├── managing_projects │ ├── benchmarking │ ├── benchmarking.cr │ ├── mineral │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── mineral │ │ ├── shard.yml │ │ ├── spec │ │ │ ├── mineral_spec.cr │ │ │ └── spec_helper.cr │ │ └── src │ │ │ ├── mineral.cr │ │ │ └── mineral │ │ │ └── version.cr │ └── mineral_log │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── shard.lock │ │ ├── shard.yml │ │ ├── spec │ │ ├── mineral_log_spec.cr │ │ └── spec_helper.cr │ │ └── src │ │ ├── katip │ │ └── logfiles │ │ │ └── 2017-6-28.json │ │ ├── katipdeneme │ │ └── logfiles │ │ │ └── 2017-6-28.json │ │ ├── mineral_log.cr │ │ └── mineral_log │ │ └── version.cr ├── methods_and_procs │ ├── exceptions.cr │ ├── exceptions2.cr │ ├── factorial.cr │ ├── factorial2.cr │ ├── factorial3.cr │ ├── methods.cr │ ├── overloading.cr │ ├── overloading3.cr │ └── procs.cr ├── setting_up │ ├── hello_world │ ├── hello_world.cr │ ├── hello_world_class.cr │ └── test.cr ├── types_and_control_flow │ ├── argv.cr │ ├── arrays.cr │ ├── chaining.cr │ ├── control_flow.cr │ ├── conversions.cr │ ├── enums.cr │ ├── getting_input.cr │ ├── getting_input_exception.cr │ ├── hashes.cr │ ├── regex.cr │ ├── sets.cr │ ├── strings.cr │ ├── symbols.cr │ └── tuples.cr ├── web_frameworks_and_shards │ ├── appviews │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── public │ │ │ ├── css │ │ │ │ ├── appviews.css │ │ │ │ └── bootstrap.css │ │ │ ├── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ └── js │ │ │ │ └── bootstrap.js │ │ ├── shard.lock │ │ ├── shard.yml │ │ ├── spec │ │ │ ├── appviews_spec.cr │ │ │ └── spec_helper.cr │ │ └── src │ │ │ ├── appviews.cr │ │ │ └── views │ │ │ ├── about.ecr │ │ │ ├── contact.ecr │ │ │ ├── home.ecr │ │ │ └── layouts │ │ │ └── main_layout.ecr │ ├── chinook.db │ ├── db_json │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── db_json │ │ ├── shard.lock │ │ ├── shard.yml │ │ ├── spec │ │ │ ├── db_json_spec.cr │ │ │ └── spec_helper.cr │ │ └── src │ │ │ ├── db_json.cr │ │ │ ├── db_json │ │ │ └── version.cr │ │ │ └── views │ │ │ └── tables.ecr │ ├── simple_kemal_app │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── shard.lock │ │ ├── shard.yml │ │ ├── simple_kemal_app │ │ ├── spec │ │ │ ├── simple_kemal_app_spec.cr │ │ │ └── spec_helper.cr │ │ └── src │ │ │ ├── simple_kemal_app.cr │ │ │ └── simple_kemal_app │ │ │ └── version.cr │ └── web_server.cr ├── why_crystal │ ├── error1.cr │ ├── error2.cr │ ├── fibonacci.cr │ ├── hello_world.cr │ ├── hello_world.java │ ├── kemal.cr │ ├── overloading1.cr │ ├── overloading12.cr │ ├── overloading123.cr │ ├── overloading1234.cr │ ├── ruby_add.rb │ └── socket_error.cr └── working_with_modules │ ├── ancestors.cr │ ├── comparable.cr │ ├── dirA │ ├── dirB.cr │ ├── dirB │ │ ├── dirB.cr │ │ └── fileB.cr │ ├── dirC │ │ ├── fileC1.cr │ │ └── fileC2.cr │ ├── fileA.cr │ ├── fileA2.cr │ └── fileA3.cr │ ├── enumerable.cr │ ├── fileA.cr │ ├── iterator.cr │ ├── mixins.cr │ ├── moral.cr │ ├── moral2.cr │ ├── namespaces.cr │ ├── namespaces2.cr │ ├── require.cr │ ├── trig.cr │ └── visibility.cr └── exercises ├── advanced_features ├── def_method.cr ├── main_fiber3.cr └── main_fiber4.cr ├── classes_and_structs ├── employee.cr ├── increment.cr ├── reopen.cr └── shape.cr ├── crystal_new ├── 99_bottles_of_beer.cr ├── class.cr ├── fibers.cr ├── method.cr ├── squares.cr └── union.cr ├── managing_projects ├── array_last_elem ├── array_last_elem.cr ├── building_vs_concat ├── building_vs_concat.cr └── mineral │ ├── .gitignore │ ├── .travis.yml │ ├── LICENSE │ ├── README.md │ ├── mineral │ ├── shard.yml │ ├── spec │ ├── mineral_spec.cr │ └── spec_helper.cr │ └── src │ ├── mineral.cr │ └── mineral │ └── version.cr ├── methods_and_procs ├── bubblesort.cr ├── overloading.cr ├── overloading2.cr ├── return_proc.cr ├── splat_a_tuple.cr ├── syntax_sugar.cr └── total.cr ├── setting_up_a_Crystal_environment ├── hello_world.cr ├── overloading.cr └── test.cr ├── types_and_control_flow ├── compile_runtime.cr ├── destructuring.cr ├── exception_union.cr ├── hashes.cr ├── if_elsif_else.cr ├── object_id.cr ├── read_line.cr ├── string_symbol.cr ├── times_and_dates.cr ├── union_types.cr ├── utf8.cr └── var1.cr ├── web_frameworks_and_shards ├── index_server.cr ├── public │ ├── index.html │ └── index_files │ │ ├── analytics.js │ │ ├── bountysource.png │ │ ├── bundle.js │ │ ├── count-data.js │ │ ├── count.js │ │ ├── d3.js │ │ ├── fly_io_.png │ │ ├── icon.css │ │ ├── jquery-3.js │ │ ├── manas-orange.svg │ │ ├── mdavid.jpg │ │ ├── neuralegion.jpg │ │ ├── openredis.svg │ │ ├── sdogruyol.jpg │ │ └── stylesheet.css └── time_server.cr ├── why_crystal ├── overloading2.cr └── test.cr └── working_with_modules ├── comparable2.cr └── math_sin.cr /README.md: -------------------------------------------------------------------------------- 1 | # Code from Programming Crystal book 2 | -------------------------------------------------------------------------------- /code/advanced_features/a.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 -------------------------------------------------------------------------------- /code/advanced_features/b.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 -------------------------------------------------------------------------------- /code/advanced_features/buffered_channel.cr: -------------------------------------------------------------------------------- 1 | ch = Channel(Char).new(2) # A buffered channel of capacity 2 2 | 3 | spawn do 4 | puts "Before send 1" 5 | ch.send('\u03B1') 6 | puts "Before send 2" 7 | ch.send('\u03B2') 8 | if ch.empty? 9 | puts "Channel is empty" 10 | else 11 | puts "Channel is not empty" 12 | end 13 | puts "Before send 3" 14 | ch.send('\u03C9') 15 | puts "After send" 16 | end 17 | 18 | 3.times do |i| 19 | puts ch.receive 20 | end 21 | 22 | # => 23 | # Before send 1 24 | # Before send 2 25 | # Channel is not empty 26 | # Before send 3 27 | # α 28 | # β 29 | # After send 30 | # ω 31 | -------------------------------------------------------------------------------- /code/advanced_features/c.txt: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /code/advanced_features/c_bindings.cr: -------------------------------------------------------------------------------- 1 | lib LibC 2 | fun rand : UInt32 3 | fun sleep(seconds : UInt32) : UInt32 4 | fun atoi(str : UInt8*) : Int32 5 | fun printf(format : UInt8*, ...) : Int32 6 | fun cos(val : Float64) : Float64 7 | fun exit(status : Int32) : NoReturn 8 | end 9 | 10 | LibC.rand # => 1804289383 11 | LibC.sleep(1_u32) # => wait 1 second 12 | LibC.atoi("28").class # => Int32 13 | 14 | a = 1 15 | b = 2 16 | LibC.printf "%d + %d = %d\n", a, b, a + b # => 1 + 2 = 3 17 | LibC.cos(1.5) # => 0.0707372016677029 18 | 19 | LibC.exit(0) # => NoReturn 20 | puts "hello" # this will never be executed 21 | -------------------------------------------------------------------------------- /code/advanced_features/c_libsdl.cr: -------------------------------------------------------------------------------- 1 | @[Link("SDL")] 2 | lib LibSDL 3 | INIT_TIMER = 0x00000001_u32 4 | INIT_AUDIO = 0x00000010_u32 5 | 6 | fun init = SDL_Init(flags : UInt32) : Int32 7 | end 8 | 9 | value = LibSDL.init(LibSDL::INIT_TIMER) # => 0 10 | -------------------------------------------------------------------------------- /code/advanced_features/channel_select.cr: -------------------------------------------------------------------------------- 1 | def generator(n : T) forall T 2 | chan = Channel(T).new 3 | spawn do 4 | loop do 5 | sleep n 6 | chan.send n 7 | end 8 | end 9 | chan 10 | end 11 | 12 | ch1 = generator(1) 13 | ch2 = generator(1.5) 14 | ch3 = generator(5) 15 | 16 | loop do 17 | select 18 | when n1 = ch1.receive 19 | puts "Int: #{n1}" 20 | when f1 = ch2.receive 21 | puts "Float: #{f1}" 22 | when ch3.receive 23 | break 24 | end 25 | end 26 | 27 | # Output: 28 | # Int: 1 29 | # Float: 1.5 30 | # Int: 1 31 | # Float: 1.5 32 | # Int: 1 33 | # Int: 1 34 | # Float: 1.5 35 | -------------------------------------------------------------------------------- /code/advanced_features/chinook.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/advanced_features/chinook.db -------------------------------------------------------------------------------- /code/advanced_features/crchinook/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cr] 2 | charset = utf-8 3 | end_of_line = lf 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ivo-Balbaert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/README.md: -------------------------------------------------------------------------------- 1 | # crchinook 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | TODO: Write installation instructions here 8 | 9 | ## Usage 10 | 11 | TODO: Write usage instructions here 12 | 13 | ## Development 14 | 15 | TODO: Write development instructions here 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( https://github.com/[your-github-name]/crchinook/fork ) 20 | 2. Create your feature branch (git checkout -b my-new-feature) 21 | 3. Commit your changes (git commit -am 'Add some feature') 22 | 4. Push to the branch (git push origin my-new-feature) 23 | 5. Create a new Pull Request 24 | 25 | ## Contributors 26 | 27 | - [[your-github-name]](https://github.com/[your-github-name]) Ivo-Balbaert - creator, maintainer 28 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/crchinook: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/advanced_features/crchinook/crchinook -------------------------------------------------------------------------------- /code/advanced_features/crchinook/shard.lock: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | shards: 3 | db: 4 | github: crystal-lang/crystal-db 5 | version: 0.4.2 6 | 7 | sqlite3: 8 | github: crystal-lang/crystal-sqlite3 9 | version: 0.8.2 10 | 11 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/shard.yml: -------------------------------------------------------------------------------- 1 | name: crchinook 2 | version: 0.1.0 3 | 4 | authors: 5 | - Ivo-Balbaert 6 | 7 | targets: 8 | crchinook: 9 | main: src/crchinook.cr 10 | 11 | crystal: 0.23.1 12 | 13 | license: MIT 14 | 15 | dependencies: 16 | sqlite3: 17 | github: crystal-lang/crystal-sqlite3 18 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/spec/crchinook_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe Crchinook do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/crchinook" 3 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/src/crchinook.cr: -------------------------------------------------------------------------------- 1 | require "./crchinook/*" 2 | require "sqlite3" 3 | 4 | DB.open "sqlite3://../chinook.db" do |db| 5 | # (1) read all artists 6 | sql = "SELECT artistid, name FROM artists ORDER BY name ASC;" 7 | db.query sql do |rs| 8 | p "#{rs.column_name(1)} (#{rs.column_name(0)})" 9 | rs.each do # perform for each row in the ResultSet 10 | artistid = rs.read(Int32) 11 | name = rs.read(String) 12 | p "#{name} (#{artistid})" 13 | # => Name (ArtistId) 14 | # => A Cor Do Som (43) 15 | # => AC/DC (1) 16 | # => Aaron Copland & London Symphony Orchestra (230) 17 | # => ... 18 | end 19 | end 20 | # (2) read one artist by artistid 21 | sql = "SELECT name FROM artists WHERE artistid = 231;" 22 | p db.query_one sql, as: String 23 | # => "Ton Koopman" 24 | # (3) read one value with scalar 25 | sql = "SELECT MIN(birthdate) FROM employees;" 26 | oldest = db.scalar sql # => "1947-09-19 00:00:00" 27 | # (4) read oldest employee by substituting a variable 28 | sql = "SELECT firstname, lastname FROM employees WHERE birthdate = ?;" 29 | firstname, lastname = db.query_one sql, oldest, as: {String, String} 30 | p "#{firstname} #{lastname}" # => "Margaret Park" 31 | # (5) use exec for DDL (Data Definition) statements 32 | db.exec "insert into artists values (?, ?)", 276, "Scott Ross" 33 | args = [] of DB::Any 34 | args << 277 35 | args << "Bernard Foccroules" 36 | db.exec "insert into artists values (?, ?)", args 37 | # (6) read all table names 38 | sql = "SELECT name FROM sqlite_master WHERE type='table';" 39 | db.query_all(sql, as: String) 40 | # => 41 | # [ "albums", 42 | # "sqlite_sequence", 43 | # "artists", 44 | # "customers", 45 | # "employees", 46 | # ..., 47 | # "sqlite_stat1" 48 | # ] 49 | end 50 | -------------------------------------------------------------------------------- /code/advanced_features/crchinook/src/crchinook/version.cr: -------------------------------------------------------------------------------- 1 | module Crchinook 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /code/advanced_features/greet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/advanced_features/greet -------------------------------------------------------------------------------- /code/advanced_features/greet.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void greet(const char* name){ 4 | printf("Hello %s!\n", name); 5 | } -------------------------------------------------------------------------------- /code/advanced_features/greet.cr: -------------------------------------------------------------------------------- 1 | @[Link(ldflags: "#{__DIR__}/greet.o")] 2 | 3 | lib LibSay 4 | fun greet(name : LibC::Char*) : Void 5 | end 6 | 7 | LibSay.greet("Ary") # => Hello Ary! 8 | -------------------------------------------------------------------------------- /code/advanced_features/greet.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/advanced_features/greet.o -------------------------------------------------------------------------------- /code/advanced_features/lines_files.cr: -------------------------------------------------------------------------------- 1 | ch = Channel(Int32).new 2 | total_lines = 0 3 | files = Dir.glob("*.txt") 4 | 5 | files.each do |f| 6 | spawn do 7 | lines = File.read_lines(f).size 8 | ch.send lines 9 | end 10 | end 11 | 12 | files.size.times do 13 | total_lines += ch.receive 14 | end 15 | 16 | puts "Total number of lines in text files: #{total_lines}" 17 | # => Total number of lines in text files: 7 18 | -------------------------------------------------------------------------------- /code/advanced_features/low_level.cr: -------------------------------------------------------------------------------- 1 | ptr = Pointer(UInt8).malloc(20) # malloc allocates memory 2 | ptr.value = 42_u8 # 42 here is of type u8 3 | ptr # => Pointer(UInt8)@0x271dfe0 4 | ptr.value # => 42 5 | ptr.class # => Pointer(UInt8) 6 | 7 | # Converting between pointer types with as: 8 | # Int8* is the same as Pointer(Int8) 9 | ptr.as(Int8*) # => Pointer(Int8)@0x271dfe0 10 | 11 | n = 42 12 | ptr_n = pointerof(n) 13 | ptr_n.value = 108 14 | n # => 108 15 | -------------------------------------------------------------------------------- /code/advanced_features/macros.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | class Mineral 3 | def initialize(@name : String, @hardness : Float64) 4 | end 5 | 6 | def name 7 | @name 8 | end 9 | 10 | def hardness 11 | @hardness 12 | end 13 | end 14 | 15 | min1 = Mineral.new("gold", 2.5) 16 | "#{min1.name} - #{min1.hardness}" # => "gold - 2.5" 17 | # END: p1 18 | 19 | # START: p2 20 | macro get 21 | def name 22 | @name 23 | end 24 | end 25 | 26 | class Mineral 27 | def initialize(@name : String, @hardness : Float64) 28 | end 29 | 30 | get 31 | 32 | def hardness 33 | @hardness 34 | end 35 | end 36 | 37 | min1 = Mineral.new("gold", 2.5) 38 | "#{min1.name} - #{min1.hardness}" # => "gold - 2.5" 39 | # END: p2 40 | 41 | # START: p3 42 | macro get(prop) 43 | def {{prop}} 44 | @{{prop}} 45 | end 46 | end 47 | 48 | class Mineral 49 | def initialize(@name : String, @hardness : Float64) 50 | end 51 | 52 | get name 53 | get hardness 54 | end 55 | 56 | min1 = Mineral.new("gold", 2.5) 57 | "#{min1.name} - #{min1.hardness}" # => "gold - 2.5" 58 | # END: p3 59 | 60 | # START: p4 61 | macro get(*props) 62 | {% for prop in props %} 63 | def {{prop}} 64 | @{{prop}} 65 | end 66 | {% end %} 67 | end 68 | 69 | class Mineral 70 | def initialize(@name : String, @hardness : Float64) 71 | end 72 | 73 | get name, hardness 74 | end 75 | 76 | min1 = Mineral.new("gold", 2.5) 77 | "#{min1.name} - #{min1.hardness}" # => "gold - 2.5" 78 | # END: p4 79 | 80 | # START: p5 81 | record Mineral, name : String, hardness : Float64 82 | 83 | min1 = Mineral.new("gold", 2.5) 84 | "#{min1.name} - #{min1.hardness}" # => "gold - 2.5" 85 | # END: p5 86 | 87 | # START: p6 88 | class Mineral 89 | getter name, hardness 90 | 91 | def initialize(@name : String, @hardness : Float64) 92 | end 93 | 94 | macro method_missing(call) 95 | print "Unknown method: ", {{call.name.id.stringify}}, 96 | " with ", {{call.args.size}}, " argument(s): ", 97 | {{call.args}}, '\n' 98 | end 99 | end 100 | 101 | min1 = Mineral.new("gold", 2.5) 102 | min1.alien_planet?(42) 103 | # => Unknown method: alien_planet? with 1 argument(s): [42] 104 | # END: p6 105 | -------------------------------------------------------------------------------- /code/advanced_features/main_fiber1.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | puts "Before start fiber" 3 | spawn do 4 | puts "Hello from within fiber" 5 | end 6 | puts "After fiber" 7 | # END: p1 8 | 9 | # => 10 | # Before start fiber 11 | # After fiber 12 | 13 | sleep 1.second 14 | # => 15 | # Before start fiber 16 | # After fiber 17 | # Hello from within fiber 18 | 19 | Fiber.yield 20 | # => 21 | # Before start fiber 22 | # After fiber 23 | # Hello from within fiber 24 | -------------------------------------------------------------------------------- /code/advanced_features/main_fiber2.cr: -------------------------------------------------------------------------------- 1 | ch = Channel(Int32).new 2 | 3 | spawn do 4 | puts "start fiber" 5 | n = ch.receive # fiber will block here if nothing on the channel yet 6 | puts "fiber received #{n}" 7 | end 8 | 9 | puts "before send" 10 | ch.send 42 11 | puts "main has send 42" 12 | # => 13 | # before send # (1) 14 | # start fiber # (2) 15 | # fiber received 42 # (3) 16 | # main has send 42 # (4) 17 | -------------------------------------------------------------------------------- /code/advanced_features/main_fiber5.cr: -------------------------------------------------------------------------------- 1 | ch = Channel(String).new 2 | spawn do 3 | while line = gets 4 | ch.send(line) 5 | end 6 | end 7 | 8 | puts ch.receive 9 | 10 | # For example: 11 | # => 12 | # hello 13 | # hello 14 | -------------------------------------------------------------------------------- /code/advanced_features/spawn_method.cr: -------------------------------------------------------------------------------- 1 | def pname(name) 2 | 3.times do |i| 3 | puts "#{name} - #{i}" 4 | end 5 | end 6 | 7 | spawn pname "spawned" # started on another fiber (in background) 8 | pname("normal") # started by main fiber 9 | Fiber.yield 10 | # => 11 | # normal - 0 12 | # normal - 1 13 | # normal - 2 14 | # spawned - 0 15 | # spawned - 1 16 | # spawned - 2 17 | -------------------------------------------------------------------------------- /code/advanced_features/synchronizing.cr: -------------------------------------------------------------------------------- 1 | # # Synchronization of channels: 2 | # background worker signals on channel when it is done 3 | # main fiber only continues when that signal is received 4 | def worker(done : Channel(Bool)) 5 | puts "worker: working" 6 | sleep 2 7 | puts "worker: done" 8 | done.send true 9 | end 10 | 11 | done = Channel(Bool).new 12 | spawn worker(done) 13 | 14 | done.receive # main blocks here 15 | puts "main: next" 16 | 17 | # => 18 | # worker: working 19 | # worker: done 20 | # main: next 21 | -------------------------------------------------------------------------------- /code/classes_and_structs/classes.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | class Mineral 3 | getter name, hardness, crystal_struct 4 | 5 | def initialize(@name : String, 6 | @hardness : Float64, 7 | @crystal_struct : String) 8 | end 9 | end 10 | 11 | # END: p1 12 | min1 = Mineral.new("gold", 1.0, "cubic") 13 | min1 # => # 14 | min1.object_id # => 41012992 == 0x271cf00 15 | 16 | typeof(min1) # => Mineral 17 | min1.class # => Mineral 18 | Mineral.class # => Class 19 | 20 | # generic class: 21 | # START: p2 22 | class Mineralg(T) 23 | getter name 24 | 25 | def initialize(@name : T) 26 | end 27 | end 28 | 29 | min = Mineralg.new("gold") 30 | min2 = Mineralg.new(42) 31 | min3 = Mineralg(String).new(42) 32 | 33 | # => Error: no overload matches 'Mineralg(String).new' with type Int32 34 | # END: p2 35 | 36 | # START: p3 37 | class Mineral 38 | @@planet = "Earth" 39 | 40 | getter name, hardness, crystal_struct 41 | setter id 42 | property quantity : Float32 43 | 44 | def initialize(@id : Int32, @name : String, @hardness : Float64, 45 | @crystal_struct : String) 46 | @quantity = 0f32 47 | end 48 | 49 | def self.planet 50 | @@planet 51 | end 52 | 53 | def finalize 54 | puts "Bye bye from this #{self}!" 55 | end 56 | end 57 | 58 | min1 = Mineral.new(101, "gold", 1.0, "cubic") 59 | min1.quantity = 453.0f32 60 | min1.id # => Error: undefined method 'id' for Mineral 61 | Mineral.planet # => "Earth" 62 | # END: p3 63 | 64 | # loop do 65 | # Mineral.new(101, "gold", 1.0, "cubic") 66 | # end 67 | 68 | # START: p4 69 | class Mineral 70 | getter id, name, hardness, crystal_struct 71 | property quantity : Float32 72 | 73 | def initialize(@id : Int32, @name : String, @hardness : Float64, 74 | @crystal_struct : String) 75 | @quantity = 0f32 76 | end 77 | 78 | def ==(other : self) # self is Mineral 79 | id == other.id 80 | end 81 | 82 | def ==(other) 83 | false 84 | end 85 | 86 | def self.compare(m1 : self, m2 : self) 87 | m1.id == m2.id 88 | end 89 | end 90 | 91 | m1 = Mineral.new(101, "gold", 1.0, "cubic") 92 | m2 = Mineral.new(108, "gold", 1.0, "cubic") 93 | m3 = Mineral.new(101, "gold", 1.0, "cubic") 94 | m1 == m2 # => false 95 | m1 == m3 # => true 96 | Mineral.compare(m1, m2) # => false 97 | # END: p4 98 | 99 | # START: p5 100 | class Mineral 101 | getter id, name, hardness, crystal_struct 102 | property quantity : Float32 103 | 104 | def initialize(@id : Int32, @name : String, @hardness : Float64, 105 | @crystal_struct : String) 106 | @quantity = 0f32 107 | end 108 | 109 | def initialize(@id : Int32) 110 | @quantity = 0f32 111 | @name = "rock" 112 | @hardness = 0 113 | @crystal_struct = "unknown" 114 | end 115 | end 116 | 117 | m1 = Mineral.new(101, "gold", 1.0, "cubic") 118 | m4 = Mineral.new(42) 119 | # => # 125 | # END: p5 126 | -------------------------------------------------------------------------------- /code/classes_and_structs/inheritance.cr: -------------------------------------------------------------------------------- 1 | # Inheriting constructor 2 | # START: p1 3 | class Document 4 | property name 5 | 6 | def initialize(@name : String) 7 | end 8 | 9 | def print 10 | puts "Hi, I'm printing #{@name}" 11 | end 12 | end 13 | 14 | class PDFDocument < Document 15 | end 16 | 17 | doc = PDFDocument.new("Salary Report Q4 2018") 18 | doc.print # => Hi, I'm printing Salary Report Q4 2018 19 | # END: p1 20 | 21 | # START: p2 22 | class PDFDocument < Document 23 | def initialize(@name : String, @company : String) 24 | end 25 | 26 | def print 27 | super 28 | puts "From company #{@company}" 29 | end 30 | end 31 | 32 | # doc = PDFDocument.new("Salary Report Q4 2018") 33 | # => Error: wrong number of arguments for 'PDFDocument.new' (given 1, expected 2) 34 | doc = PDFDocument.new("Salary Report Q4 2018", "ACME") 35 | doc.print 36 | 37 | # => Hi, I'm printing Salary Report Q4 2018 38 | # From company ACME 39 | # END: p2 40 | 41 | # START: p3 42 | class PDFDocument < Document 43 | def initialize(@name : String, @company : String) 44 | end 45 | 46 | def print(date : Time) 47 | puts "Printing #{@name}" 48 | puts "From company #{@company} at date #{date}" 49 | end 50 | end 51 | 52 | doc = PDFDocument.new("Salary Report Q4 2018", "ACME") 53 | doc.print(Time.now) 54 | 55 | # => Printing Salary Report Q4 2018 56 | # From company ACME at date 2017-05-25 12:12:45 +0200 57 | # END: p3 58 | 59 | # START: p4 60 | abstract class Shape 61 | abstract def area 62 | abstract def perim 63 | end 64 | 65 | class Rect < Shape 66 | def initialize(@width : Int32, @height : Int32) 67 | end 68 | 69 | def area 70 | @width * @height 71 | end 72 | 73 | def perim 74 | 2 * (@width + @height) 75 | end 76 | end 77 | 78 | s = Shape.new # => can't instantiate abstract class Shape 79 | Rect.new(3, 6).area # => 18 80 | # END: p4 81 | -------------------------------------------------------------------------------- /code/classes_and_structs/private.cr: -------------------------------------------------------------------------------- 1 | class Document 2 | property name 3 | 4 | def initialize(@name : String) 5 | end 6 | 7 | private def print(message) 8 | puts message 9 | end 10 | 11 | def printing 12 | print "Hi, I'm printing #{@name}" 13 | # self.print "Printing with self does not work" 14 | # => Error: private method 'print' called for Document 15 | end 16 | end 17 | 18 | class PDFDocument < Document 19 | def printing 20 | super 21 | print "End printing PDFDocument" 22 | end 23 | end 24 | 25 | doc = Document.new("Salary Report Q4 2018") 26 | doc.printing # => Hi, I'm printing Salary Report Q4 2018 27 | 28 | pdoc = PDFDocument.new("Financial Report Q4 2018") 29 | pdoc.printing # => 30 | # Hi, I'm printing Financial Report Q4 2018 31 | # End printing PDFDocument 32 | # doc.print("test") # => Error: private method 'print' called for Document 33 | -------------------------------------------------------------------------------- /code/classes_and_structs/program.cr: -------------------------------------------------------------------------------- 1 | # puts self # => Error: there's no self in this scope 2 | 3 | # START: p1 4 | def display 5 | puts "Top-level display" 6 | end 7 | 8 | class Mineral 9 | puts self # => Mineral 10 | getter name 11 | getter hardness 12 | getter crystal_struct 13 | 14 | def initialize(@name : String, @hardness : Float64, 15 | @crystal_struct : String) 16 | end 17 | 18 | def display 19 | ::display # => Top-level display 20 | p self # => 22 | end 23 | end 24 | 25 | min1 = Mineral.new("gold", 1.0, "cubic") 26 | min1.display 27 | # END: p1 28 | -------------------------------------------------------------------------------- /code/classes_and_structs/protected.cr: -------------------------------------------------------------------------------- 1 | class Document 2 | property name 3 | 4 | def initialize(@name : String) 5 | end 6 | 7 | protected def print(message) 8 | puts message 9 | end 10 | 11 | def printing 12 | print "Hi, I'm printing #{@name}" 13 | self.print("This works too: self is a Document") 14 | doc = Document.new("Taxes") 15 | doc.print("This also: doc is a Document") 16 | end 17 | end 18 | 19 | class BankAccount < Document 20 | def printing 21 | doc = Document.new ("TestDoc") 22 | doc.print "inside BankAccount" 23 | end 24 | end 25 | 26 | class BankAccount2 27 | def printing 28 | doc = Document.new ("TestDoc") 29 | doc.print "inside BankAccount2" 30 | end 31 | end 32 | 33 | doc2 = Document.new "Audit 2017" 34 | doc2.printing 35 | # => Hi, I'm printing Audit 2017 36 | # => This works too: self is a Document 37 | # => This also: doc is a Document 38 | doc2.print "Audit printing" # => Error: protected method 'print' called for Document 39 | ba = BankAccount.new "test" 40 | ba.printing # => inside BankAccount 41 | ba2 = BankAccount2.new 42 | # ba2.printing # Error: protected method 'print' called for Document 43 | -------------------------------------------------------------------------------- /code/classes_and_structs/structs.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | struct User 3 | property name, age 4 | 5 | def initialize(@name : String, @age : Int32) 6 | end 7 | 8 | def print 9 | puts "#{age} - #{name}" 10 | end 11 | end 12 | 13 | d = User.new("Donald", 42) 14 | d.name # => Donald 15 | d.age = 78 16 | d.print # => 78 - Donald 17 | # END: p1 18 | 19 | # START: p2 20 | def no_change(user) 21 | user.age = 50 22 | end 23 | 24 | def change(user) 25 | user.age = 50 26 | user 27 | end 28 | 29 | d = User.new("Donald", 78) 30 | d.print # => 78 - Donald 31 | no_change(d) 32 | d.print # => 78 - Donald 33 | d = change(d) 34 | d.print # => 50 - Donald 35 | # END: p2 36 | -------------------------------------------------------------------------------- /code/classes_and_structs/types.cr: -------------------------------------------------------------------------------- 1 | alias PInt32 = Pointer(Int32) 2 | 3 | module JSON 4 | alias Type = Nil | 5 | Bool | 6 | Int64 | 7 | Float64 | 8 | String | 9 | Array(Type) | 10 | Hash(String, Type) 11 | end 12 | -------------------------------------------------------------------------------- /code/classes_and_structs/useful: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/classes_and_structs/useful -------------------------------------------------------------------------------- /code/classes_and_structs/useful.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | class Mineral 3 | getter name, hardness 4 | 5 | def initialize(@name : String, @hardness : Float64) 6 | end 7 | 8 | # Good 9 | def to_s(io) 10 | io << name << ", " << hardness 11 | end 12 | 13 | # Bad 14 | def to_s(io) 15 | # using string interpolation creates an intermediate string 16 | io << "#{name}, #{hardness}" 17 | end 18 | 19 | # Bad 20 | def to_s(io) 21 | # using to_s and + create an intermediate string 22 | io << name.to_s + hardness.to_s 23 | end 24 | end 25 | 26 | min1 = Mineral.new("gold", 42.0) 27 | io = IO::Memory.new 28 | # To see what io contains, use to_s: 29 | min1.to_s(io).to_s # => "gold, 42.0" 30 | # END: p1 31 | 32 | # Exceptions: 33 | class CoolException < Exception 34 | end 35 | 36 | raise CoolException.new("Somebody pushed the red button") 37 | # => Somebody pushed the red button (CoolException) 38 | 39 | # START: p2 40 | ex = begin 41 | raise CoolException.new 42 | rescue ex1 : IndexError 43 | ex1.message 44 | rescue ex2 : CoolException | KeyError 45 | ex2.message 46 | rescue ex3 : Exception 47 | ex3.message 48 | rescue # catch any kind of exception 49 | "an unknown exception" 50 | end # => "ex2" 51 | # END: p2 52 | 53 | # START: p3 54 | require "json" 55 | path = "path/to/file" 56 | 57 | begin 58 | if File.exists?(path) 59 | raw_file = File.read(path) 60 | map = JSON.parse(raw_file) 61 | File.write(path, "ok") 62 | :ok 63 | end 64 | rescue JSON::ParseException # Parsing error 65 | raise "Could not parse file" 66 | rescue ex 67 | raise "Other error: #{ex.message}" 68 | end 69 | 70 | # END: p3 71 | 72 | # START: p4 73 | class MineralC 74 | def initialize 75 | @callbacks = [] of -> 76 | end 77 | 78 | def after_save(&block) 79 | @callbacks << block 80 | end 81 | 82 | # save in database, then execute callbacks 83 | def save 84 | # save 85 | 86 | rescue ex 87 | p "Exception occurred: #{ex.message}" 88 | else 89 | @callbacks.each &.call 90 | end 91 | end 92 | 93 | min = MineralC.new 94 | min.after_save { puts "Save in DB successful" } 95 | min.after_save { puts "Logging save" } 96 | min.after_save { puts "Replicate save to failover node" } 97 | min.save # => 98 | # Save in DB successful 99 | # Logging save 100 | # Replicate save to failover node 101 | # END: p4 102 | 103 | # START: p5 104 | struct Vec2D 105 | property x, y 106 | 107 | def initialize(@x : Int32, @y : Int32) 108 | end 109 | 110 | def +(other : self) 111 | Vec2D.new(x + other.x, y + other.y) 112 | end 113 | 114 | def - 115 | Vec2D.new(-x, -y) 116 | end 117 | end 118 | 119 | # END: p5 120 | 121 | # START: p6 122 | v1 = Vec2D.new(41, 42) 123 | v2 = Vec2D.new(107, 108) 124 | v1 + v2 # => Vec2D(@x=148, @y=150) 125 | # v1 + 78 # Error: no overload matches 'Vec2D#+' with type Int32 126 | 127 | v1 = Vec2D.new(42, 108) 128 | -v1 # => Vec2D(@x=-42, @y=-108) 129 | # END: p6 130 | -------------------------------------------------------------------------------- /code/classes_and_structs/virtual.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | class Document 3 | end 4 | 5 | class PDFDocument < Document 6 | def print 7 | puts "PDF header" 8 | end 9 | end 10 | 11 | class XMLDocument < Document 12 | def print 13 | puts "XML header" 14 | end 15 | end 16 | 17 | class Report 18 | getter doc 19 | 20 | def initialize(@name : String, @doc : Document) 21 | end 22 | end 23 | 24 | salq4 = Report.new "Salary Report Q4", PDFDocument.new 25 | taxQ1 = Report.new "Tax Report Q1", XMLDocument.new 26 | # END: p1 27 | 28 | if 4 < 5 29 | d = PDFDocument.new 30 | else 31 | d = XMLDocument.new 32 | end 33 | typeof(d) # => Document 34 | 35 | # START: p2 36 | abstract class Document 37 | end 38 | 39 | salq4.doc.print # => PDF header 40 | # END: p2 41 | -------------------------------------------------------------------------------- /code/crystal_new/compound_types_arrays.cr: -------------------------------------------------------------------------------- 1 | # Arrays 2 | # START:p1 3 | minerals = ["alunite", "chromium", "vlasovite"] 4 | # creating the same array with another notation: 5 | minerals2 = %w(alunite chromium vlasovite) 6 | typeof(minerals) # => Array(String) 7 | # END:p1 8 | 9 | # START:p2 10 | minerals << "wagnerite" 11 | minerals << "muscovite" 12 | minerals 13 | # => ["alunite", "chromium", "vlasovite", "wagnerite", "muscovite"] 14 | minerals.size # => 5 15 | # END:p2 16 | 17 | 18 | # START:p3 19 | minerals << 666 20 | # => Error: no overload matches 'Array(String)#<<' with type Int32 21 | # END:p3 22 | 23 | # START:p4 24 | precious_minerals = [] 25 | # => Error: for empty arrays use '[] of ElementType' 26 | # END:p4 27 | 28 | # START:p5 29 | precious_minerals = [] of String 30 | precious_minerals2 = Array(String).new 31 | 32 | # END:p5 33 | 34 | # indexing 35 | # START:p6 36 | minerals[0] # => "alunite" 37 | minerals[3] # => "wagnerite" 38 | minerals[-2] # => "wagnerite" 39 | # => negative indices count from the end, which is -1 40 | # END:p6 41 | 42 | # START:p7 43 | minerals[2, 3] # => ["vlasovite", "wagnerite", "muscovite"] 44 | minerals[2..4] # => ["vlasovite", "wagnerite", "muscovite"] 45 | # END:p7 46 | 47 | # START:p8 48 | minerals[7] # => Runtime error: Index out of bounds (IndexError) 49 | # END:p8 50 | 51 | # START:p9 52 | minerals[7]? # => nil 53 | # END:p9 54 | 55 | # START:p10 56 | pseudo_minerals = ["alunite", 'C', 42] 57 | # END:p10 58 | 59 | # START:p11 60 | typeof(pseudo_minerals) # => Array(Char | Int32 | String) 61 | # END:p11 -------------------------------------------------------------------------------- /code/crystal_new/compound_types_hashes.cr: -------------------------------------------------------------------------------- 1 | # Hashes 2 | # START:p1 3 | mohs = { 4 | "talc" => 1, 5 | "calcite" => 3, 6 | "apatite" => 5, 7 | "corundum" => 9, 8 | } 9 | typeof(mohs) # => Hash(String, Int32) 10 | # END:p1 11 | 12 | # START:p2 13 | mohs["apatite"] # => 5 14 | # END:p2 15 | 16 | # START:p3 17 | mohs["gold"] 18 | # => Runtime error: Missing hash key: "gold" (KeyError) 19 | # END:p3 20 | 21 | # START:p4 22 | mohs["gold"]? # => nil 23 | # END:p4 24 | 25 | # START:p5 26 | mohs.has_key? "gold" # => false 27 | # END:p5 28 | 29 | # START:p6 30 | mohs["diamond"] = 9 # adding key 31 | mohs["diamond"] = 10 # changing value 32 | mohs 33 | # => {"talc" => 1, "calcite" => 3, "apatite" => 5, 34 | # "corundum" => 9, "diamond" => 10} 35 | mohs.size # => 5 36 | # END:p6 37 | 38 | # START:p7 39 | mohs['C'] = 4.5 # Error: no overload matches 40 | # 'Hash(String, Int32)#[]=' with types Char, Float64 41 | # END:p7 42 | 43 | # creating an empty hash: 44 | # START:p8 45 | mohs = {} # Error: Syntax error: for empty hashes use 46 | # '{} of KeyType => ValueType' 47 | # END:p8 48 | 49 | # START:p9 50 | mohs = {} of String => Int32 # {} 51 | mohs = Hash(String, Int32).new 52 | # END:p9 53 | -------------------------------------------------------------------------------- /code/crystal_new/control_flow.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | hardness = 5.25 3 | if 0 < hardness < 5 4 | puts "softer than apatite" 5 | elsif hardness < 8 6 | puts "harder than apatite, softer than topaz" 7 | else 8 | puts "topaz or harder!" 9 | end 10 | # => harder than apatite, softer than topaz 11 | # END:p1 12 | 13 | # if as an expression 14 | # START:p2 15 | output = if 0 < hardness < 5 16 | "softer than apatite" 17 | elsif hardness < 8 18 | "harder than apatite, softer than topaz" 19 | else 20 | "topaz or harder!" 21 | end 22 | output # => harder than apatite, softer than topaz 23 | # END:p2 24 | 25 | # if as a suffix 26 | # START:p3 27 | output = "softer than topaz" if hardness < 8 # => softer than topaz 28 | # END:p3 29 | 30 | # unless 31 | # START:p4 32 | output = "softer than topaz" unless hardness >= 8 33 | output # => softer than topaz 34 | # END:p4 35 | 36 | # case 37 | # START:p5 38 | output = case hardness 39 | when 4 40 | "hard as fluorite" 41 | when 7 42 | "hard as quartz" 43 | when 10 44 | "hard as diamond" 45 | else 46 | "can't say how hard" 47 | end # => "can't say how hard" 48 | # END:p5 49 | 50 | # START:p6 51 | output = case 52 | when 0 < hardness < 5 53 | "softer than apatite" 54 | when hardness < 8 55 | "harder than apatite, softer than topaz" 56 | else 57 | "topaz or harder!" 58 | end # => harder than apatite, softer than topaz" 59 | # END:p6 60 | 61 | # simple loops: 62 | # START:p7 63 | # Int#times 64 | 5.times do 65 | p "Hi" 66 | p "Low" 67 | end 68 | # same as: 69 | 5.times { p "Hi"; p "Low" } 70 | # END:p7 71 | 72 | # START:p8 73 | # Range#each 74 | ('a'..'d').each do |i| 75 | puts "Item: #{i}" 76 | end 77 | # produces: 78 | # Item: a 79 | # Item: b 80 | # Item: c 81 | # Item: d 82 | # END:p8 83 | 84 | # infinite loop with break: 85 | # START:p9 86 | n = 1 87 | loop do 88 | puts "a mighty crystal" 89 | n += 1 90 | break if n == 3 91 | end 92 | # => a mighty crystal 93 | # END:p9 94 | 95 | # while 96 | # START:p10 97 | a = 1 98 | while (a += 1) < 10 99 | if a == 3 100 | next 101 | elsif a > 6 102 | break 103 | end 104 | puts a 105 | end # => 2, 4, 5 and 6 on successive lines 106 | # END:p10 107 | -------------------------------------------------------------------------------- /code/crystal_new/fibers.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | chan = Channel(String).new 3 | i = 0 4 | num = 10000 5 | num.times do 6 | spawn do 7 | chan.send "fiber #{i}: I like crystals!" 8 | end 9 | i += 1 10 | puts chan.receive 11 | end 12 | # => 13 | # fiber 1: I like crystals! 14 | # fiber 2: I like crystals! 15 | # fiber 3: I like crystals! 16 | # fiber 4: I like crystals! 17 | # ... 18 | # fiber 10000: I like crystals! 19 | # END:p1 20 | -------------------------------------------------------------------------------- /code/crystal_new/methods.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | def data 3 | mohs = {"talc" => 1, "calcite" => 3, "apatite" => 5, "corundum" => 9} 4 | end 5 | 6 | def hardness(mineral) 7 | data[mineral] 8 | end 9 | 10 | hardness("calcite") # => 3 11 | # END:p1 12 | 13 | hardness(456) 14 | 15 | # => Runtime error: Missing hash key: 456 (KeyError) 16 | 17 | # START:p2 18 | def hardness(mineral : String) 19 | data[mineral] 20 | end 21 | 22 | hardness("calcite") # => 3 23 | hardness(456) 24 | # => Error: no overload matches 'hardness' with type Int32 25 | # END:p2 26 | -------------------------------------------------------------------------------- /code/crystal_new/methods2.cr: -------------------------------------------------------------------------------- 1 | def data 2 | mohs = {"talc" => 1, "calcite" => 3, "apatite" => 5, 3 | "corundum" => 9} 4 | end 5 | 6 | def hardness(mineral : String) 7 | mohs = data 8 | mohs[mineral] 9 | end 10 | 11 | def hardness(mineral) 12 | "hardness is not defined for #{mineral}" 13 | end 14 | 15 | hardness("calcite") # => 3 16 | hardness(456) # => "hardness is not defined for 456" 17 | -------------------------------------------------------------------------------- /code/crystal_new/mineral.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | class Mineral 3 | getter name : String 4 | getter hardness : Float64 5 | getter crystal_struct : String 6 | 7 | def initialize(@name, @hardness, @crystal_struct) 8 | end 9 | end 10 | 11 | def mineral_with_crystal_struct(crstruct, minerals) 12 | minerals.find { |m| m.crystal_struct == crstruct } 13 | end 14 | 15 | def longest_name(minerals) 16 | minerals.map { |m| m.name }.max_by { |name| name.size } 17 | end 18 | 19 | minerals = [ 20 | Mineral.new("gold", 1.0, "cubic"), 21 | Mineral.new("topaz", 8.0, "orthorombic"), 22 | Mineral.new("apatite", 5.0, "hexagonal"), 23 | Mineral.new("wolframite", 4.5, "monoclinic"), 24 | Mineral.new("calcite", 3.0, "trigonal"), 25 | Mineral.new("diamond", 10.0, "cubic"), 26 | ] 27 | 28 | min = mineral_with_crystal_struct("hexagonal", minerals) 29 | if min 30 | puts "#{min.crystal_struct} - #{min.name} - #{min.hardness}" 31 | else 32 | puts "No mineral found with this crystal structure!" 33 | end 34 | # => hexagonal - apatite - 5 35 | 36 | min = mineral_with_crystal_struct("triclinic", minerals) 37 | if min 38 | puts "#{min.crystal_struct} - #{min.name} - #{min.hardness}" 39 | else 40 | puts "No mineral found with this crystal structure!" 41 | end 42 | # => "No mineral found with this crystal structure!" 43 | 44 | puts longest_name(minerals) 45 | # => wolframite 46 | # END:p1 47 | 48 | # crystal build 3.5_mineral.cr --release 49 | # $ time ./3.5_mineral # => real 0.002 s 50 | -------------------------------------------------------------------------------- /code/crystal_new/mineral.rb: -------------------------------------------------------------------------------- 1 | 2 | # START:p1 3 | class Mineral 4 | attr_reader :name, :hardness, :crystal_struct 5 | 6 | def initialize(name, hardness, crystal_struct) 7 | @name = name 8 | @hardness = hardness 9 | @crystal_struct = crystal_struct 10 | end 11 | end 12 | 13 | def mineral_with_crystal_struct(crstruct, minerals) 14 | minerals.find { |m| m.crystal_struct == crstruct } 15 | end 16 | 17 | def longest_name(minerals) 18 | minerals.map { |m| m.name }.max_by { |name| name.size } 19 | end 20 | # END:p1 21 | 22 | # START:p2 23 | minerals = [ 24 | Mineral.new("gold", 1, 'cubic'), 25 | Mineral.new("topaz", 8, 'orthorombic'), 26 | Mineral.new("apatite", 5, 'hexagonal'), 27 | Mineral.new("wolframite", 4.5, 'monoclinic'), 28 | Mineral.new("calcite", 3, 'trigonal'), 29 | Mineral.new("diamond", 10, 'cubic'), 30 | ] 31 | 32 | min = mineral_with_crystal_struct('hexagonal', minerals) 33 | puts "#{min.crystal_struct} - #{min.name} - #{min.hardness}" 34 | # => hexagonal - apatite - 5 35 | 36 | puts longest_name(minerals) 37 | # => wolframite 38 | # END:p2 39 | 40 | # START:p3 41 | # Runtime error: 42 | min = mineral_with_crystal_struct('triclinic', minerals) 43 | puts "#{min.crystal_struct} - #{min.name} - #{min.hardness}" 44 | # 3.5_mineral.rb:39:in `
': undefined method 'crystal_struct' 45 | # for nil:NilClass (NoMethodError) 46 | # END:p3 47 | 48 | # $ time ruby 3.5_mineral.rb # => real 0.087 s 49 | 50 | -------------------------------------------------------------------------------- /code/crystal_new/modules.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | module Hardness 3 | def data 4 | mohs = {"talc" => 1, "calcite" => 3, "apatite" => 5, 5 | "corundum" => 9} 6 | end 7 | 8 | def hardness 9 | data[self.name] 10 | end 11 | end 12 | 13 | # END:p1 14 | 15 | # h1 = Hardness.new # => undefined method 'new' for Hardness:Module 16 | 17 | # START:p2 18 | class Mineral 19 | include Hardness 20 | getter name : String 21 | 22 | def initialize(@name) 23 | end 24 | end 25 | 26 | # END:p2 27 | 28 | # START:p3 29 | min = Mineral.new("corundum") 30 | min.hardness # => 9 31 | # END:p3 32 | -------------------------------------------------------------------------------- /code/crystal_new/variables.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | str = "What a beautiful mineral!" 3 | str1 = "What a 4 | beautiful mineral!" # multi-line string 5 | # END:p1 6 | 7 | # START:p2 8 | ch = 'C' 9 | ch == "C" # => false 10 | typeof(ch) # => Char 11 | typeof(Char) # => Class 12 | !true # => false 13 | # END:p2 14 | 15 | # START:p3 16 | ch = 42 17 | typeof(ch) # => Int32 18 | # END:p3 19 | 20 | # START:p4 21 | a = 42_i64 22 | f = 1.5e-10 23 | typeof(f) # => Float64 24 | # END:p4 25 | 26 | # START:p5 27 | puts a1 # => Error: undefined local variable or method 'a1' 28 | # END:p5 29 | 30 | # START:p6 31 | a1 : String 32 | # END:p6 33 | 34 | # START:p7 35 | a1 : String = "hello" 36 | a1 = 42 # => Error: type must be String, not (Int32 | String) 37 | # END:p7 38 | 39 | # START:p8 40 | str.size # => 25 41 | ch.size # => Error: undefined method 'size' on Int32" 42 | # END:p8 43 | 44 | # START:p9 45 | ch + str # => Error: no overload matches 'Int32#+' with type String 46 | # Overloads are: 47 | # - Int32#+(other : Int8) 48 | # - Int32#+(other : Int16) 49 | # - Int32#+(other : Int32) 50 | # - Int32#+(other : Int64) 51 | # - Int32#+(other : UInt8) 52 | # - Int32#+(other : UInt16) 53 | # - Int32#+(other : UInt32) 54 | # - Int32#+(other : UInt64) 55 | # - Int32#+(other : Float32) 56 | # - Int32#+(other : Float64) 57 | # - Number#+() 58 | # END:p9 59 | 60 | # START:p10 61 | str, num = "Diamond", 42 62 | str # => "Diamond" 63 | num # => 42 64 | # END:p10 65 | 66 | # START:p11 67 | # swap 68 | n = 41 69 | m = 42 70 | n, m = m, n 71 | n # => 42 72 | m # => 41 73 | # END:p11 74 | 75 | # START:p12 76 | # multiple statements on one line 77 | n = 3; n += 1; p n # => 4 78 | # END:p12 79 | 80 | # START:p13 81 | n = begin 82 | a = 3 83 | a += 1 84 | a 85 | end # => 4 86 | # END:p13 87 | 88 | # START:p14 89 | # string interpolation 90 | "The sum = #{41 + 2.5}" # => "The sum = 43.5" 91 | # END:p14 92 | 93 | # START:p15 94 | GRAVC = 6.67e-11 # gravitational constant 95 | GRAVC = 5 # => Error: already initialized constant 96 | # END:p15 97 | 98 | # START:p16 99 | nil # => nil 100 | typeof(nil) # => Nil 101 | # END:p16 102 | -------------------------------------------------------------------------------- /code/dirA/fileA.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileA in dirA in the parent folder" 2 | -------------------------------------------------------------------------------- /code/fileA.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileA.cr in the parent folder" 2 | -------------------------------------------------------------------------------- /code/libs/file.cr: -------------------------------------------------------------------------------- 1 | puts "I am from file.cr in folder libs in the current working directory" 2 | -------------------------------------------------------------------------------- /code/managing_projects/benchmarking: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/managing_projects/benchmarking -------------------------------------------------------------------------------- /code/managing_projects/benchmarking.cr: -------------------------------------------------------------------------------- 1 | # Benchmark.ips: 2 | # START:p1 3 | require "benchmark" 4 | 5 | IOM = IO::Memory.new 6 | 7 | Benchmark.ips do |x| 8 | x.report("Appending") do 9 | append 10 | IOM.clear 11 | end 12 | 13 | x.report("Using to_s") do 14 | to_s 15 | IOM.clear 16 | end 17 | 18 | x.report("Interpolation") do 19 | interpolation 20 | IOM.clear 21 | end 22 | end 23 | 24 | def append 25 | IOM << 42 26 | end 27 | 28 | def to_s 29 | IOM << 42.to_s 30 | end 31 | 32 | def interpolation 33 | IOM << "#{42}" 34 | end 35 | 36 | # END:p1 37 | # Results Benchmark.ips: 38 | # Appending 34.06M ( 29.36ns) (± 3.97%) fastest 39 | # Using to_s 12.67M ( 78.92ns) (± 7.55%) 2.69× slower 40 | # Interpolation 2.8M (356.75ns) (± 3.84%) 12.15× slower 41 | 42 | # START:p2 43 | puts Benchmark.measure { 44 | 10_000_000.times do 45 | append 46 | end 47 | } 48 | # END:p2 49 | # => 0.250000 0.030000 0.280000 ( 0.276182) 50 | 51 | # Benchmark.bm: 52 | # START:p3 53 | Benchmark.bm do |x| 54 | x.report("Appending bm") do 55 | IOM.clear 56 | 10_000_000.times do 57 | append 58 | end 59 | end 60 | end 61 | # END:p3 62 | # => 63 | # user system total real 64 | # Appending bm 0.240000 0.000000 0.240000 ( 0.242289) 65 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ivo-Balbaert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/README.md: -------------------------------------------------------------------------------- 1 | # mineral 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | TODO: Write installation instructions here 8 | 9 | ## Usage 10 | 11 | TODO: Write usage instructions here 12 | 13 | ## Development 14 | 15 | TODO: Write development instructions here 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( https://github.com/[your-github-name]/mineral/fork ) 20 | 2. Create your feature branch (git checkout -b my-new-feature) 21 | 3. Commit your changes (git commit -am 'Add some feature') 22 | 4. Push to the branch (git push origin my-new-feature) 23 | 5. Create a new Pull Request 24 | 25 | ## Contributors 26 | 27 | - [[your-github-name]](https://github.com/[your-github-name]) Ivo-Balbaert - creator, maintainer 28 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/mineral: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/managing_projects/mineral/mineral -------------------------------------------------------------------------------- /code/managing_projects/mineral/shard.yml: -------------------------------------------------------------------------------- 1 | name: mineral 2 | version: 0.1.0 3 | 4 | authors: 5 | - Ivo-Balbaert 6 | 7 | targets: 8 | mineral: 9 | main: src/mineral.cr 10 | 11 | crystal: 0.22.0 12 | 13 | license: MIT 14 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/spec/mineral_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe Mineral do 4 | # TODO: Write tests 5 | 6 | # it "works" do 7 | # false.should eq(true) 8 | # end 9 | 10 | it "creates a default mineral" do 11 | min1 = Mineral::Mineral.new(108) 12 | min1.id.should eq(108) 13 | min1.name.should eq ("rock") 14 | min1.crystal_struct.should eq("unknown") 15 | end 16 | 17 | it "creates a mineral with parameters" do 18 | min1 = Mineral::Mineral.new(42, "apatite", "hexagonal") 19 | min1.id.should eq(42) 20 | min1.name.should eq ("apatite") 21 | min1.crystal_struct.should eq("hexagonal") 22 | end 23 | 24 | it "creates correct csv format" do 25 | min1 = Mineral::Mineral.new(101, "gold", "cubic") 26 | min1.to_csv.should eq("101,gold,2.5,cubic") 27 | end 28 | 29 | it "gold has hardness 2.5" do 30 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 31 | min1.hardness.should eq(2.5) 32 | end 33 | 34 | it "== works for same mineral" do 35 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 36 | (min1 == min1).should eq(true) 37 | end 38 | 39 | it "== works for different mineral" do 40 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 41 | min2 = Mineral::Mineral.new(43, "corundum", "trigonal") 42 | (min1 == min2).should eq(false) 43 | end 44 | 45 | it "kind_of_crystal works" do 46 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 47 | (min1.kind_of_crystal).should eq("cubic") 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/mineral" 3 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/src/mineral.cr: -------------------------------------------------------------------------------- 1 | require "./mineral/*" 2 | 3 | module Mineral 4 | puts "app mineral is started!" 5 | 6 | module Hardness 7 | def data 8 | mohs = {"talc" => 1, "gold" => 2.5, "calcite" => 3, 9 | "apatite" => 5, "corundum" => 9} 10 | end 11 | 12 | def hardness 13 | data[self.name] 14 | end 15 | end 16 | 17 | # Every Mineral has **hardness** (see the `Hardness` module). 18 | # 19 | # To create a standard rocky Mineral: 20 | # 21 | # ``` 22 | # min1 = Mineral.new(108) 23 | # min1.to_s 24 | # ``` 25 | # 26 | # The above produces: 27 | # 28 | # ```text 29 | # "This is a mineral with id 108 and is called rock" 30 | # ``` 31 | # 32 | # Checks the hardness with `#hardness`. 33 | class Mineral 34 | include Hardness 35 | getter id, name 36 | setter crystal_struct 37 | 38 | # Creates a mineral with given parameters 39 | def initialize(@id : Int32, @name : String, @crystal_struct : String) 40 | end 41 | 42 | # Creates a mineral with name "rock", 0 hardness and "unknown" structure 43 | def initialize(@id : Int32) 44 | @name = "rock" 45 | @crystal_struct = "unknown" 46 | end 47 | 48 | # Prints out a description of this mineral 49 | def to_s 50 | puts "This is a mineral with id #{id} and it is called #{name} " 51 | puts "It has #{crystal_struct} as crystal structure" 52 | end 53 | 54 | # Returns object properties in csv-format 55 | def to_csv 56 | "#{id},#{name},#{hardness},#{crystal_struct}" 57 | end 58 | 59 | def ==(other : self) 60 | id == other.id 61 | end 62 | 63 | def ==(other) 64 | false 65 | end 66 | 67 | # Returns crystal structure of this mineral 68 | def kind_of_crystal 69 | @crystal_struct 70 | end 71 | 72 | # :nodoc: 73 | class Helper # no docs are created for this class 74 | end # neither for private or protected classes 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /code/managing_projects/mineral/src/mineral/version.cr: -------------------------------------------------------------------------------- 1 | module Mineral 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ivo-Balbaert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/README.md: -------------------------------------------------------------------------------- 1 | # mineral_log 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | TODO: Write installation instructions here 8 | 9 | ## Usage 10 | 11 | TODO: Write usage instructions here 12 | 13 | ## Development 14 | 15 | TODO: Write development instructions here 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( https://github.com/[your-github-name]/mineral_log/fork ) 20 | 2. Create your feature branch (git checkout -b my-new-feature) 21 | 3. Commit your changes (git commit -am 'Add some feature') 22 | 4. Push to the branch (git push origin my-new-feature) 23 | 5. Create a new Pull Request 24 | 25 | ## Contributors 26 | 27 | - [[your-github-name]](https://github.com/[your-github-name]) Ivo-Balbaert - creator, maintainer 28 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/shard.lock: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | shards: 3 | katip: 4 | github: guvencenanguvenal/katip 5 | commit: 3964d4f7a276cda11e12ae23d04e213fb3c45b62 6 | 7 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/shard.yml: -------------------------------------------------------------------------------- 1 | name: mineral_log 2 | version: 0.1.0 3 | 4 | authors: 5 | - Ivo-Balbaert 6 | 7 | targets: 8 | mineral_log: 9 | main: src/mineral_log.cr 10 | 11 | crystal: 0.22.0 12 | 13 | license: MIT 14 | 15 | dependencies: 16 | katip: 17 | github: guvencenanguvenal/katip 18 | branch: master 19 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/spec/mineral_log_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe MineralLog do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/mineral_log" 3 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/src/katip/logfiles/2017-6-28.json: -------------------------------------------------------------------------------- 1 | {"katip":"0.1.0","info":{"description":"","project":"","version":""},"errors":[{"date":"2017-06-28 11:34:00 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 12:30:04 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 12:30:04 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 12:30:04 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 12:32:21 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 12:32:21 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 12:32:21 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 12:32:21 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 12:41:13 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 12:45:17 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 12:45:17 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 12:45:17 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 13:59:50 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 13:59:50 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 13:59:50 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 14:44:05 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:44:05 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 14:44:05 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 14:45:10 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:45:10 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 14:45:10 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 14:50:50 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:50:50 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 14:50:50 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 14:51:13 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:51:23 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:52:09 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:54:52 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:56:18 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:59:09 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 14:59:09 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:00:35 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:01:43 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:04:52 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:06:33 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:16:01 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:16:01 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:16:01 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:20:44 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:20:44 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:20:44 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:30:16 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:30:16 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:30:16 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:34:52 +0200", "class":"Class", "message":"app mineral_log is started!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"INFO"},{"date":"2017-06-28 15:34:52 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:34:52 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"}]} -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/src/katipdeneme/logfiles/2017-6-28.json: -------------------------------------------------------------------------------- 1 | {"katip":"0.1.0","info":{"description":"","project":"","version":""},"errors":[{"date":"2017-06-28 14:59:09 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:00:35 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:00:35 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:01:43 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:01:43 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:04:52 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:04:52 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:06:33 +0200", "class":"Class", "message":"A new mineral is created!", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"},{"date":"2017-06-28 15:06:33 +0200", "class":"Class", "message":"to_csv method is called", "exception_type":"Katip::NotSetException", "exception_message":"Not Init", "log_level":"DEBUG"}]} -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/src/mineral_log.cr: -------------------------------------------------------------------------------- 1 | require "./mineral_log/*" 2 | require "katip" 3 | 4 | LOGGER = Katip::Logger.new 5 | 6 | LOGGER.configure do |config| 7 | config.loglevel = Katip::LogLevel::DEBUG 8 | config.logclassification = Katip::LogClassification::DATE_DAY 9 | config.path = "src/katip/logfiles" 10 | config.info.description = "This is the Mineral Log project." 11 | config.info.project = "Mineral Log." 12 | config.info.version = MineralLog::VERSION # project version 13 | end 14 | 15 | # START:p1 16 | module MineralLog 17 | LOGGER.info("app mineral_log is started!") 18 | 19 | min1 = Mineral.new(101, "gold", "cubic") 20 | puts min1.to_csv 21 | end 22 | 23 | class Mineral 24 | getter id, name 25 | property crystal_struct 26 | 27 | def initialize(@id : Int32, @name : String, @crystal_struct : String) 28 | LOGGER.debug("A new mineral is created!") 29 | end 30 | 31 | def initialize(@id : Int32, logger) 32 | @name = "rock" 33 | @crystal_struct = "unknown" 34 | LOGGER.debug("A new default mineral is created!") 35 | end 36 | 37 | def to_s 38 | puts "This is a mineral with id #{id} and is called #{name} " 39 | puts "It has #{crystal_struct} as crystal structure" 40 | end 41 | 42 | def to_csv 43 | "#{id},#{name},#{crystal_struct}" 44 | LOGGER.debug("to_csv method is called") 45 | end 46 | end 47 | # END:p1 48 | -------------------------------------------------------------------------------- /code/managing_projects/mineral_log/src/mineral_log/version.cr: -------------------------------------------------------------------------------- 1 | module MineralLog 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /code/methods_and_procs/exceptions.cr: -------------------------------------------------------------------------------- 1 | puts "Enter the numbers one by one, and end with an empty line:" 2 | input_array # => for example: [78, 56, 12] 3 | 4 | def input_array 5 | arr = [] of Int8 6 | while number = gets 7 | number = number.strip # removes leading or trailing whitespace 8 | if number == "" || number == "stop" 9 | break 10 | end 11 | add_to_array(arr, number) 12 | end 13 | arr 14 | end 15 | 16 | def add_to_array(arr, number) 17 | begin 18 | arr << number.to_i8 19 | rescue 20 | puts "integer bigger than 255" 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /code/methods_and_procs/exceptions2.cr: -------------------------------------------------------------------------------- 1 | puts "Enter the numbers one by one, and end with an empty line:" 2 | p input_array # => for example: [78, 56, 12] 3 | 4 | 5 | def input_array 6 | arr = [] of Int8 7 | while number = gets 8 | number = number.strip # removes leading or trailing whitespace 9 | if number == "" || number == "stop" 10 | break 11 | end 12 | add_to_array(arr, number) 13 | end 14 | arr 15 | end 16 | 17 | # START: p1 18 | def add_to_array(arr, number) 19 | arr << number.to_i8 20 | rescue 21 | puts "integer bigger than 255" 22 | end 23 | # END: p1 24 | -------------------------------------------------------------------------------- /code/methods_and_procs/factorial.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | def fact(n) 3 | n == 0 ? 1 : n * fact(n - 1) 4 | end 5 | 6 | fact(5) # => 120 7 | # END:p1 8 | 9 | fact(-2) 10 | # => Runtime error: Invalid memory access (signal 11) at address 0x7ffbff7fdff8 11 | fact("Crystal") # => Error: undefined method '-' for String 12 | -------------------------------------------------------------------------------- /code/methods_and_procs/factorial2.cr: -------------------------------------------------------------------------------- 1 | def fact(n : Int) : Int 2 | if n < 0 3 | raise ("n cannot be negative!") 4 | end 5 | n == 0 ? 1 : n * fact(n - 1) 6 | end 7 | 8 | fact(5) # => 120 9 | 10 | begin 11 | fact(-2) # => Runtime error: n cannot be negative! (Exception) 12 | rescue ex 13 | p ex.message 14 | end 15 | # => "n cannot be negative!" 16 | 17 | fact("Crystal") # => Error: no overload matches 'fact' with type String 18 | -------------------------------------------------------------------------------- /code/methods_and_procs/factorial3.cr: -------------------------------------------------------------------------------- 1 | def fact(n : Int) : Int 2 | if n < 0 3 | puts "n cannot be negative!" 4 | exit 5 | end 6 | n == 0 ? 1 : n * fact(n - 1) 7 | end 8 | 9 | fact(5) # => 120 10 | fact(-2) # => "n cannot be negative!" 11 | -------------------------------------------------------------------------------- /code/methods_and_procs/methods.cr: -------------------------------------------------------------------------------- 1 | # Variables declared in a program are not visible inside methods 2 | # START:p1 3 | x = 1 4 | 5 | def add(y) 6 | x + y # Error: undefined local variable or method 'x' 7 | end 8 | 9 | add(2) 10 | 11 | # END:p1 12 | 13 | # Duck typing: 14 | # START:p2 15 | def add(x, y) 16 | # return x + y # return is optional 17 | x + y 18 | end 19 | 20 | add(2, 3) # (1) => 5 21 | add 2, 3 # (2) => 5 22 | add(1.0, 3.14) # (3) => 4.14 23 | add("Hello ", "Crystal") # (4) => "Hello Crystal" 24 | add(42, " times") # (5) => Error: no overload matches 'Int32#+' with type String 25 | add # (6) => Error: wrong number of arguments for 'add' 26 | # (given 0, expected 2) 27 | # END:p2 28 | 29 | # only y is typed: 30 | def add(x, y : Int) 31 | x + y 32 | end 33 | 34 | add 3, 4 # => 7 35 | add 2.14, 7 # => 9.14 36 | 37 | # Arguments: 38 | # START:p3 39 | 40 | 41 | def show(x, y = 1, z = 2, w = 3) 42 | "x: #{x}, y: #{y}, z: #{z}, w: #{w}" 43 | end 44 | 45 | show 10 # => "x: 10, y: 1, z: 2, w: 3" 46 | show 10, 10 # => "x: 10, y: 10, z: 2, w: 3" 47 | show 10, 30, 2, 3 # => "x: 10, y: 30, z: 2, w: 3" 48 | show 10, 20 # => "x: 10, y: 20, z: 2, w: 3" 49 | 50 | show 10, z: 10 # => "x: 10, y: 1, z: 10, w: 3" 51 | show 10, w: 30, y: 2, z: 3 # => "x: 10, y: 2, z: 3, w: 30" 52 | show y: 10, x: 20 # => "x: 20, y: 10, z: 2, w: 3" 53 | show y: 10 # Error, missing argument: x 54 | # END:p3 55 | 56 | # Using named arguments: 57 | require "oauth2" 58 | 59 | client = OAuth2::Client.new( 60 | host: "martian1", 61 | client_id: "7594", 62 | client_secret: "W*GDFUY75HSVS#@!" 63 | ) 64 | 65 | def display(n, *, hight, width) 66 | "#The shape has hight {#hight} and width {#width}" 67 | end 68 | 69 | display 3, hight: 2, width: 5 70 | 71 | # Return values: 72 | # START:p4 73 | 74 | def typed_method : Array(Int32) 75 | (42..47).to_a.select { |n| n % 4 == 0 } 76 | end 77 | 78 | typed_method # => [44] 79 | # END:p4 80 | 81 | # START:p5 82 | # Multiple return values 83 | def triple_and_array(s) 84 | {s * 3, s.split} 85 | end 86 | 87 | # unpacking: 88 | ret = triple_and_array("42") # => {"424242", ["42"]} 89 | ret[0] # => "424242" 90 | ret[1] # => ["42"] 91 | # or: 92 | num, arr = triple_and_array("gold") 93 | num # => "goldgoldgold" 94 | arr # => ["gold"] 95 | # END:p5 96 | 97 | # START:p6 98 | def salaries(*employees) 99 | employees.each do |emp| 100 | # calculate salary 101 | puts "#{emp}'s salary is: 2500" 102 | end 103 | end 104 | 105 | salaries() # => 106 | salaries("Jones") # => Jones's salary is: 2500 107 | salaries("Baudelaire", "Rogers", "Gandhi") 108 | 109 | # => 110 | # Baudelaire's salary is: 2500 111 | # Rogers's salary is: 2500 112 | # Gandhi's salary is: 2500 113 | # END:p6 114 | 115 | # START:p7 116 | def increment(number, by value) 117 | number + value 118 | end 119 | 120 | p increment(10, by: 10) # => 20 121 | # END:p7 122 | 123 | # START:p8 124 | 125 | 126 | def join(*args, with joiner) 127 | String.build do |str| 128 | args.each_with_index do |arg, index| 129 | str << joiner if index > 0 130 | str << arg 131 | end 132 | end 133 | end 134 | 135 | join 1, 2, 3, with: "-" # => "1-2-3" 136 | join 1, 2, 3, 4, 5, with: "*" # => "1*2*3*4*5" 137 | # END:p8 138 | -------------------------------------------------------------------------------- /code/methods_and_procs/overloading.cr: -------------------------------------------------------------------------------- 1 | # version 1: 2 | def add(x : Int, y : Int) 3 | x + y 4 | end 5 | 6 | # version 2: 7 | def add(x : Number, y : Number) 8 | x + y 9 | end 10 | 11 | # version 3: 12 | def add(x : Number, y : String) 13 | x.to_s + y # convert a number to a string with to_s method 14 | end 15 | 16 | # version 4: 17 | def add(x, y) 18 | x + y 19 | end 20 | 21 | # new methods: 22 | # version 5: 23 | def add(x : Number, y : Bool) 24 | y ? x : 0 25 | end 26 | 27 | # version 6: 28 | def add(x : String, y : String) 29 | if x.to_i? && y.to_i? 30 | add x.to_i, y.to_i # calls version 1 31 | else 32 | x + y 33 | end 34 | end 35 | 36 | add(2, 3) # (1) => 5 37 | add(1.0, 3.14) # (2) => 4.14 38 | add("Hello ", "Crystal") # (3) => "Hello Crystal" 39 | add(42, " times") # (4) => "42 times" 40 | add 5, true # (5) => 5 41 | add 13, false # (5) => 0 42 | add("12", "13") # (6) => 25 43 | -------------------------------------------------------------------------------- /code/methods_and_procs/overloading3.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | def display(x : Number) # overloading 1 3 | puts "#{x} is a number" 4 | end 5 | 6 | def display(x : String) # overloading 2 7 | puts "#{x} is a string" 8 | end 9 | 10 | n = 42 11 | display n # => 42 is a number 12 | 13 | str = "magic" 14 | display str # => magic is a string 15 | 16 | r = rand < 0.5 ? n : str 17 | typeof(r) # => (Int32 | String) 18 | display r 19 | 20 | # END:p1 21 | 22 | # START:p2 23 | def method1(*args : Int32) 24 | end 25 | 26 | def method1(*args : String) 27 | end 28 | 29 | method1 41, 42, 43 # OK, invokes first overload 30 | method1 "Crystal", "Ruby", "Go" # OK, invokes second overload 31 | method1 1, 2, "No" 32 | # Error: no overload matches 'method1' with types Int32, Int32, String 33 | method1() # Error: no overload matches 'method1' 34 | # END:p2 35 | -------------------------------------------------------------------------------- /code/methods_and_procs/procs.cr: -------------------------------------------------------------------------------- 1 | # Yield: 2 | def testing 3 | puts "at top of method" 4 | yield 5 | puts "back inside method" 6 | yield 7 | puts "at end of method" 8 | end 9 | 10 | testing do 11 | puts "in code block" 12 | end 13 | 14 | # => 15 | # at top of method 16 | # in code block 17 | # back inside method 18 | # in code block 19 | # at end of method 20 | 21 | # Yield with parameters: 22 | # START: p1 23 | def testing 24 | puts "at top of method" 25 | yield 1 26 | puts "back inside method" 27 | yield 2 28 | puts "at end of method" 29 | end 30 | 31 | testing do |n| 32 | puts "in code block #{n}" 33 | end 34 | 35 | # => 36 | # at top of method 37 | # in code block 1 38 | # back inside method 39 | # in code block 2 40 | # at end of method 41 | # END:p1 42 | 43 | # START: p2 44 | def testing(&block) 45 | puts "at top of method" 46 | block.call 47 | puts "back inside method" 48 | block.call 49 | puts "at end of method" 50 | end 51 | 52 | testing do 53 | puts "in code block" 54 | end 55 | # => 56 | # at top of method 57 | # in code block 58 | # back inside method 59 | # in code block 60 | # at end of method 61 | # END: p2 62 | 63 | # START: p3 64 | langs = %w[Java Go Crystal] 65 | langs.map { |lang| lang.upcase } # (1) => ["JAVA", "GO", "CRYSTAL"] 66 | langs.map &.upcase # (2) => ["JAVA", "GO", "CRYSTAL"] 67 | # END: p3 68 | 69 | # START: p4 70 | nums = [42, 43, 44] 71 | nums.map { |num| num + 2 } # (1) => [44, 45, 46] 72 | nums.map &.+(2) # (2) => [44, 45, 46] 73 | # END: p4 74 | 75 | # START: p5 76 | fn = ->(n : Int32, m : Int32) { n + m } 77 | typeof(fn) # => Proc(Int32, Int32, Int32) 78 | fn.call(42, 108) # => 150 79 | # END: p5 80 | 81 | # START: p6 82 | fn = Proc(Int32, Int32, Int32).new { |n, m| n + m } 83 | fn.call(42, 108) # => 150 84 | # END: p6 85 | 86 | # START: p7 87 | 88 | def add(n, m) 89 | n + m 90 | end 91 | 92 | fn = ->add(Int32, Int32) 93 | fn.call(42, 108) # => 150 94 | # END: p7 95 | 96 | # START: p8 97 | n = 42 98 | fn = ->(m : Int32) { n + m } 99 | fn.call(108) # => 150 100 | n = 20 101 | fn.call(108) # => 128 102 | # END: p8 103 | 104 | # START: p9 105 | def capture(&block : Int32 -> Int32) 106 | block 107 | end 108 | 109 | n = 42 110 | proc = capture { |m| n + m } 111 | proc.call(108) # => 150 112 | n = 20 113 | proc.call(108) # => 128 114 | # END: p9 115 | -------------------------------------------------------------------------------- /code/setting_up/hello_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/setting_up/hello_world -------------------------------------------------------------------------------- /code/setting_up/hello_world.cr: -------------------------------------------------------------------------------- 1 | puts "Hello, Crystal World!" # => Hello Crystal world! 2 | p "Hello, Crystal World!" # => "Hello Crystal world!"" 3 | -------------------------------------------------------------------------------- /code/setting_up/hello_world_class.cr: -------------------------------------------------------------------------------- 1 | class HelloWorld 2 | def initialize(@name : String) 3 | end 4 | 5 | def greet 6 | puts "Hello, #{@name}!" 7 | end 8 | end 9 | 10 | hw = HelloWorld.new("world") 11 | hw.greet # => Hello, world! 12 | -------------------------------------------------------------------------------- /code/setting_up/test.cr: -------------------------------------------------------------------------------- 1 | x = 1 2 | puts x + 1 3 | puts x.snap -------------------------------------------------------------------------------- /code/types_and_control_flow/argv.cr: -------------------------------------------------------------------------------- 1 | puts "Number of command line arguments: #{ARGV.size}" # => (1) 2 | ARGV.each_with_index do |arg, i| 3 | puts "Argument #{i}: #{arg}" # => (2) 4 | end 5 | ARGV # => (3) 6 | p "Executable name: #{PROGRAM_NAME}" # => (4) 7 | p "Path to source file: #{__FILE__}" # => (5) 8 | p "Folder of source file: #{__DIR__}" # => (6) 9 | 10 | # (1) Number of command line arguments: 3 11 | # (2) 12 | # Argument 0: 78 13 | # Argument 1: 56 14 | # Argument 2: 12 15 | # (3) ["78", "56", "12"] 16 | # (4) "Executable name: /$HOME/.cache/crystal/crystal-run-argv.tmp" 17 | # or (4) "Executable name: ./argv" 18 | # (5) "Path to source file: 19 | # /$HOME/crystal/Book/code/types_and_control_flow/argv.cr" 20 | # (6) "Folder of source file: /$HOME/crystal/Book/code/types_and_control_flow" 21 | -------------------------------------------------------------------------------- /code/types_and_control_flow/arrays.cr: -------------------------------------------------------------------------------- 1 | arr = [56, 123, 5, 42, 108] 2 | arr.includes? 42 # => true 3 | 4 | arr.shift # => 56 5 | arr # => [123, 5, 42, 108] 6 | arr.pop # => 108 7 | arr # => [123, 5, 42] 8 | 9 | arr.each do |i| 10 | puts i 11 | end 12 | # 123 13 | # 5 14 | # 42 15 | -------------------------------------------------------------------------------- /code/types_and_control_flow/chaining.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | p arr = (42..47).to_a # => (1) 3 | .sort { |n, m| m <=> n } # => (2) 4 | .reject { |n| n.odd? } # => (3) 5 | .map { |n| n * n } # => (4) 6 | .select { |n| n % 4 == 0 } # => (5) 7 | .sort! # => (6) 8 | .any? { |num| num > 2000 } # => (7) 9 | 10 | # output of each line: 11 | # (1) [42, 43, 44, 45, 46, 47] 12 | # (2) [47, 46, 45, 44, 43, 42] 13 | # (3) [46, 44, 42] 14 | # (4) [2116, 1936, 1764] 15 | # (5) [2116, 1936, 1764] 16 | # (6) [1764, 1936, 2116] 17 | # (7) true 18 | # END:p1 19 | -------------------------------------------------------------------------------- /code/types_and_control_flow/control_flow.cr: -------------------------------------------------------------------------------- 1 | var1 = 1 > 2 ? 3 : 4 # => 4 2 | 3 | var1 = rand < 0.5 ? 42 : "Crystal" # => 42 or "Crystal" 4 | typeof(var1) # => (Int32 | String) 5 | # var1.abs # => Error: undefined method 'abs' for String 6 | # ivar1 = var1.as(Int32) 7 | # ok if var1 == 42, else: cast from String to Int32 failed (TypeCastError) 8 | ivar1 = var1.as?(Int32) # => 42 or nil 9 | if ivar1 = var1.as?(Int32) 10 | p ivar1.abs # => 42 11 | end 12 | 13 | var1 = 42 14 | if var1.is_a?(Number) 15 | # here var1 is a Number, which can be integer or floating point 16 | end 17 | 18 | case var1 19 | when Number 20 | p var1 + 42 21 | when String 22 | p "we have a string" 23 | else 24 | p "is not a number or a string" 25 | end 26 | # => 84 27 | 28 | var1 = "Crystal" 29 | if var1.responds_to?(:abs) # false in this case 30 | var1.abs 31 | end 32 | 33 | # START:p1 34 | num = 42 35 | case num 36 | when .even? 37 | puts "you have an even number" 38 | when .odd? 39 | puts "you have an odd number" 40 | end 41 | # => you have an even number 42 | # END:p1 43 | 44 | # START:p2 45 | (1..100).each do |i| 46 | case {i % 3, i % 5} 47 | when {0, 0} 48 | puts "FizzBuzz" 49 | when {0, _} 50 | puts "Fizz" 51 | when {_, 0} 52 | puts "Buzz" 53 | else 54 | puts i 55 | end 56 | end 57 | # END:p2 58 | -------------------------------------------------------------------------------- /code/types_and_control_flow/conversions.cr: -------------------------------------------------------------------------------- 1 | # "99.999".to_i # => Runtime error: Invalid Int32: 99.999 (ArgumentError) 2 | 3 | var = 3.1415 4 | var.to_i # => 3 5 | 6 | var1 = 42 7 | var2 = "7" 8 | # var1 + var2 # Error: no overload matches 'Int32#+' with type Strin 9 | var1 + var2.to_i # => 49 10 | var1.to_s + var2 # => "427" 11 | 12 | var1.to_f # => 42.0 13 | var2.to_f # => 7.0 14 | 15 | var3 = "crystal" 16 | # var3.to_i # => Runtime error: Invalid Int32: crystal (ArgumentError) 17 | -------------------------------------------------------------------------------- /code/types_and_control_flow/enums.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | enum Direction 3 | North # value 0 4 | East # value 1 5 | South # value 2 6 | West # value 3 7 | end 8 | 9 | Direction::South # South 10 | Direction::South.value # => 2 11 | # END: p1 12 | 13 | # Direction::Eest # Error: undefined constant Direction::Eest 14 | :gold 15 | :goold 16 | -------------------------------------------------------------------------------- /code/types_and_control_flow/getting_input.cr: -------------------------------------------------------------------------------- 1 | puts "Enter the numbers one by one, and end with an empty line:" 2 | arr = [] of Int8 3 | 4 | # alternative: 5 | # arr1 = [75, 42, 156] 6 | # typeof(arr1) # => Array(Int32) 7 | 8 | # number = gets 9 | # p "You entered #{number}" # => "You entered 42" 10 | # p "You entered " + number + "." 11 | # => no overload matches 'String#+' with type (String | Nil) 12 | 13 | # arr << number 14 | # Error: no overload matches 'Array(Int8)#<<' with type (String | Nil) 15 | 16 | # p typeof(number) # => (String | Nil) 17 | # p number.class # => String 18 | 19 | # if number 20 | # arr << number.to_i8 21 | # # => Error: no overload matches 'Array(Int8)#<<' with type String 22 | # # Overloads are: - Array(T)#<<(value : T) 23 | # p arr # => [42] 24 | # end 25 | 26 | while number = gets 27 | number = number.strip # removes leading or trailing whitespace 28 | if number == "" || number == "stop" 29 | break 30 | end 31 | if number.to_i? 32 | # if number.to_i8? 33 | arr << number.to_i8 34 | else 35 | puts "input is no integer" 36 | # raise "not a small integer" 37 | end 38 | end 39 | p arr # => for example: [78, 56, 12] 40 | 41 | # aside: 42 | mem = nil 43 | mem ||= 1 44 | mem # => 1 45 | mem ||= "crystal" 46 | mem # => 1 47 | -------------------------------------------------------------------------------- /code/types_and_control_flow/getting_input_exception.cr: -------------------------------------------------------------------------------- 1 | # first version: 2 | puts "Enter the numbers one by one, and end with an empty line:" 3 | arr = [] of Int8 4 | while number = gets 5 | number = number.strip # removes leading or trailing whitespace 6 | if number == "" || number == "stop" 7 | break 8 | end 9 | if number.to_i? 10 | arr << number.to_i8 11 | else 12 | puts "input is no integer" 13 | # raise "input is no integer" 14 | end 15 | end 16 | 17 | # second version: 18 | # START:rescue 19 | puts "Enter the numbers one by one, and end with an empty line:" 20 | arr = [] of Int8 21 | while number = gets 22 | number = number.strip # removes leading or trailing whitespace 23 | if number == "" || number == "stop" 24 | break 25 | end 26 | begin 27 | arr << number.to_i8 28 | rescue 29 | puts "integer bigger than 255" 30 | end 31 | end 32 | p arr # => for example: [78, 56, 12] 33 | # END:rescue 34 | 35 | # general exception-handling mechanism: 36 | begin 37 | # some dangerous code here 38 | # possibly your own raise "..." 39 | rescue ex 40 | # execute if an exception is raised 41 | p ex.message 42 | else 43 | # execute if an exception isn't raised 44 | ensure 45 | # this will always be executed 46 | puts "Cleanup..." 47 | end 48 | -------------------------------------------------------------------------------- /code/types_and_control_flow/hashes.cr: -------------------------------------------------------------------------------- 1 | # Shortcut for adding a pair 2 | h = {1 => 'A'} 3 | h[3] ||= 'C' 4 | h # => {1 => 'A', 3 => 'C'} 5 | 6 | # Instead of {:key1 => 'a', :key2 => 'b'} you can use: 7 | {key1: 'a', key2: 'b'} 8 | # Instead of {"key1" => 'a', "key2" => 'b'} you can use: 9 | {"key1": 'a', "key2": 'b'} 10 | -------------------------------------------------------------------------------- /code/types_and_control_flow/regex.cr: -------------------------------------------------------------------------------- 1 | int = /\d+/ # + = one or more digits 2 | pat1 = /(.+)gold(.+)/ # searches for gold 3 | pat2 = %r(talc | gold) # searches for talc or gold 4 | 5 | str = "carbonantimonygolddiamond" 6 | str =~ pat1 # => 0 7 | $1 # => "carbonantimony" 8 | $2 # => "diamond" 9 | 10 | str.match pat1 # => 11 | # 13 | -------------------------------------------------------------------------------- /code/types_and_control_flow/sets.cr: -------------------------------------------------------------------------------- 1 | # Set literal 2 | set = Set{41, 42, 43} # => Set{41, 42, 43} 3 | set.class # => Set(Int32) 4 | 5 | # The above is equivalent to 6 | set = Set(Int32).new 7 | set << 42 8 | set << 41 9 | set << 43 10 | set << 41 11 | set # => Set{42, 41, 43} 12 | Set{42, 41, 43} == Set{41, 42, 43} # => true 13 | -------------------------------------------------------------------------------- /code/types_and_control_flow/strings.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | var1 = "Crystal" 3 | var1[2..4] # => "yst" 4 | var1.reverse # => "latsyrC" 5 | var1.size # => 7 # length or len do not exist 6 | var1.upcase # => "CRYSTAL" 7 | var1.capitalize # => "Crystal" 8 | var1.includes? "ys" # => true 9 | var1.count "t" # => 1 10 | var1.starts_with? "cr" # => false 11 | var1.ends_with? "al" # => true 12 | var1.index("a") # => 5 13 | var1.sub("ys", "is") # => "Cristal" # gsub changes all occurrences 14 | var1.gsub(/([aeiou])/, "*\\1*") # => "Cryst*a*l" 15 | var2 = var1.split("") # => ["C", "r", "y", "s", "t", "a", "l"] 16 | var2.join("-") # => "C-r-y-s-t-a-l" 17 | # END:p1 18 | 19 | s = "crys" 20 | s[2] = 'b' # => undefined method '[]=' for String 21 | 22 | age = 61 23 | p "age: " + age.to_s # => age: 61 # creates a string on the heap! 24 | # better: 25 | p "age: + #{age}" # => age: 61 26 | # best: 27 | str = String.build do |io| 28 | io << "age: " << age 29 | end 30 | p str # => age: 61 31 | -------------------------------------------------------------------------------- /code/types_and_control_flow/symbols.cr: -------------------------------------------------------------------------------- 1 | mineral1 = :talc # => :talc 2 | mineral2 = :calcite # => :calcite 3 | # etc. 4 | :gold.class # => Symbol 5 | 6 | ask = :ask1? 7 | call = :call! 8 | op1 = :* 9 | -------------------------------------------------------------------------------- /code/types_and_control_flow/tuples.cr: -------------------------------------------------------------------------------- 1 | tpl = {42, "silver", 'C'} 2 | tpl.class # => Tuple(Int32, String, Char) 3 | 4 | # Empty tuple 5 | empty = Tuple.new 6 | 7 | # Creating a tuple with new 8 | a = Tuple.new(42, "silver", 'C') 9 | a # => {42, "silver", 'C'} 10 | 11 | tpl[0] # => 42 (Int32) 12 | tpl[1] # => "silver" (String) 13 | tpl[2] # => 'C' (Char) 14 | # tpl[7] # => Error: index out of bounds for Tuple(Int32, String, Char) (7 not in 0..2) 15 | var = 89 16 | # tpl[var] # => Index out of bounds (IndexError) 17 | tpl[var]? # => nil 18 | 19 | tpl = {name: "Crystal", year: 2017} # NamedTuple(name: String, year: Int32) 20 | tpl[:name] # => "Crystal" (String) 21 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cr] 2 | charset = utf-8 3 | end_of_line = lf 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | /dev/ 6 | sentry 7 | appviews 8 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ivo-Balbaert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/README.md: -------------------------------------------------------------------------------- 1 | # appviews 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | TODO: Write installation instructions here 8 | 9 | ## Usage 10 | 11 | TODO: Write usage instructions here 12 | 13 | ## Development 14 | 15 | TODO: Write development instructions here 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( https://github.com/[your-github-name]/appviews/fork ) 20 | 2. Create your feature branch (git checkout -b my-new-feature) 21 | 3. Commit your changes (git commit -am 'Add some feature') 22 | 4. Push to the branch (git push origin my-new-feature) 23 | 5. Create a new Pull Request 24 | 25 | ## Contributors 26 | 27 | - [[your-github-name]](https://github.com/[your-github-name]) Ivo-Balbaert - creator, maintainer 28 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/public/css/appviews.css: -------------------------------------------------------------------------------- 1 | body { 2 | min-height: 2000px; 3 | padding-top: 70px; 4 | } 5 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/web_frameworks_and_shards/appviews/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/shard.lock: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | shards: 3 | kemal: 4 | github: kemalcr/kemal 5 | commit: 0b07070237a568d96d1cfbaf7b6df0d0801dbeb5 6 | 7 | kilt: 8 | github: jeromegn/kilt 9 | version: 0.4.0 10 | 11 | radix: 12 | github: luislavena/radix 13 | version: 0.3.8 14 | 15 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/shard.yml: -------------------------------------------------------------------------------- 1 | name: appviews 2 | version: 0.1.0 3 | 4 | authors: 5 | - Ivo-Balbaert 6 | 7 | targets: 8 | appviews: 9 | main: src/appviews.cr 10 | 11 | crystal: 0.23.1 12 | 13 | license: MIT 14 | 15 | dependencies: 16 | kemal: 17 | github: kemalcr/kemal 18 | branch: master 19 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/spec/appviews_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe Appviews do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/appviews" 3 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/src/appviews.cr: -------------------------------------------------------------------------------- 1 | require "./appviews/*" 2 | require "kemal" 3 | 4 | get "/" do |env| 5 | title = "Home" 6 | page_message = "Your app's home page" 7 | render "src/views/home.ecr", "src/views/layouts/main_layout.ecr" 8 | end 9 | 10 | get "/about" do |env| 11 | title = "About" 12 | page_message = "Your app's description page" 13 | render "src/views/about.ecr", "src/views/layouts/main_layout.ecr" 14 | end 15 | 16 | get "/contact" do |env| 17 | title = "Contact" 18 | page_message = "Your app's contact page" 19 | render "src/views/contact.ecr", "src/views/layouts/main_layout.ecr" 20 | end 21 | 22 | Kemal.run 23 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/src/views/about.ecr: -------------------------------------------------------------------------------- 1 |
2 |

<%= page_message %>

3 |

4 |

Use this area to provide additional info ...

5 |

6 | 7 |

8 |
9 |
10 |
11 |

© 2017-18 - My Crystal App

12 |
13 | 14 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/src/views/contact.ecr: -------------------------------------------------------------------------------- 1 |
2 |

<%= page_message %>

3 |

4 |
5 |
6 | My Company
7 | My Way 108
8 | Metropolis, XX Universe4
9 | P: 10 | 444.658.0168 11 | 12 |

13 |
14 | Support:support@myapp.com
15 | Marketing:marketing@myapp.com
16 | 17 |
18 |

19 |
20 |
21 |
22 |

Newsletter

23 | 24 |

Subscribe to our weekly Newsletter and stay tuned.

25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |

© 2017-18 - My Crystal App

40 |
41 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/src/views/home.ecr: -------------------------------------------------------------------------------- 1 |
2 |

<%= page_message %>

3 |

Your home page text starts here ...

4 |

5 | Learn more » 6 |

7 |
8 | 9 |
10 |
11 |

Getting started

12 |

13 | This app will make your business management so much easier! 14 |

15 |

16 | Learn more » 17 |

18 |
19 |
20 |

Get more opportunities

21 |

22 | Look at the bright side! 23 |

24 |

25 | Learn more » 26 |

27 |
28 |
29 |

Get followers

30 |

31 | Thousands of people will follow you! 32 |

33 |

34 | Learn more » 35 |

36 |
37 |
38 |
39 |
40 |

© 2017-18 - My Crystal App

41 |
42 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/appviews/src/views/layouts/main_layout.ecr: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= title %> | App's name 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 48 | 49 |
50 | <%= content %> 51 |
52 | 53 | 54 | 55 | 57 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/chinook.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/web_frameworks_and_shards/chinook.db -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cr] 2 | charset = utf-8 3 | end_of_line = lf 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ivo-Balbaert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/README.md: -------------------------------------------------------------------------------- 1 | # db_json 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | TODO: Write installation instructions here 8 | 9 | ## Usage 10 | 11 | TODO: Write usage instructions here 12 | 13 | ## Development 14 | 15 | TODO: Write development instructions here 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( https://github.com/[your-github-name]/db_json/fork ) 20 | 2. Create your feature branch (git checkout -b my-new-feature) 21 | 3. Commit your changes (git commit -am 'Add some feature') 22 | 4. Push to the branch (git push origin my-new-feature) 23 | 5. Create a new Pull Request 24 | 25 | ## Contributors 26 | 27 | - [[your-github-name]](https://github.com/[your-github-name]) Ivo-Balbaert - creator, maintainer 28 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/db_json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/web_frameworks_and_shards/db_json/db_json -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/shard.lock: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | shards: 3 | db: 4 | github: crystal-lang/crystal-db 5 | version: 0.4.2 6 | 7 | kemal: 8 | github: kemalcr/kemal 9 | commit: 5d737ee8f33f36af24fc4d316e0dd275875afee7 10 | 11 | kilt: 12 | github: jeromegn/kilt 13 | version: 0.4.0 14 | 15 | radix: 16 | github: luislavena/radix 17 | version: 0.3.8 18 | 19 | sqlite3: 20 | github: crystal-lang/crystal-sqlite3 21 | version: 0.8.2 22 | 23 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/shard.yml: -------------------------------------------------------------------------------- 1 | name: db_json 2 | version: 0.1.0 3 | 4 | authors: 5 | - Ivo-Balbaert 6 | 7 | targets: 8 | db_json: 9 | main: src/db_json.cr 10 | 11 | crystal: 0.23.1 12 | 13 | license: MIT 14 | 15 | dependencies: 16 | kemal: 17 | github: kemalcr/kemal 18 | branch: master 19 | 20 | sqlite3: 21 | github: crystal-lang/crystal-sqlite3 22 | 23 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/spec/db_json_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe DbJson do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/db_json" 3 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/src/db_json.cr: -------------------------------------------------------------------------------- 1 | require "kemal" 2 | require "sqlite3" 3 | 4 | require "./db_json/*" 5 | 6 | db = DB.open "sqlite3://../chinook.db" 7 | 8 | def table_names(db) 9 | sql = "SELECT name FROM sqlite_master WHERE type='table';" 10 | db.query_all(sql, as: String) 11 | end 12 | 13 | def write_json(io, col_names, rs) 14 | JSON.build(io) do |json| 15 | json.object do 16 | col_names.each do |col| 17 | json_encode_field json, col, rs.read 18 | end 19 | end 20 | end 21 | io << "\n" 22 | end 23 | 24 | def json_encode_field(json, col, value) 25 | case value 26 | when Bytes 27 | json.field col do 28 | json.array do 29 | value.each do |e| 30 | json.scalar e 31 | end 32 | end 33 | end 34 | else 35 | json.field col do 36 | value.to_json(json) 37 | end 38 | end 39 | end 40 | 41 | # routing handlers: 42 | get "/" do |env| 43 | env.response.content_type = "application/json" 44 | tables = table_names(db) 45 | tables.to_json 46 | end 47 | 48 | # show tables in a view: 49 | # get "/" do |env| 50 | # tables = table_names(db) 51 | # render "src/views/tables.ecr" 52 | # end 53 | 54 | get "/:table_name" do |env| 55 | env.response.content_type = "application/json" 56 | table_name = env.params.url["table_name"] 57 | # avoid SQL injection by checking table name 58 | unless table_names(db).includes?(table_name) 59 | # ignore if the requested table does not exist. 60 | env.response.status_code = 404 61 | else 62 | db.query "select * from #{table_name}" do |rs| 63 | col_names = rs.column_names 64 | rs.each do 65 | write_json(env.response.output, col_names, rs) 66 | # force chunked response even on small tables 67 | env.response.output.flush 68 | end 69 | end 70 | end 71 | end 72 | 73 | Kemal.run 74 | 75 | db.close 76 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/src/db_json/version.cr: -------------------------------------------------------------------------------- 1 | module DbJson 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/db_json/src/views/tables.ecr: -------------------------------------------------------------------------------- 1 |
2 |

All tables

3 |
4 | 5 | 6 | <% if tables %> 7 | <% tables.each do |table| %> 8 |

<%= table %>

9 | <% end %> 10 | <% end %> 11 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ivo-Balbaert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/README.md: -------------------------------------------------------------------------------- 1 | # simple_kemal_app 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | TODO: Write installation instructions here 8 | 9 | ## Usage 10 | 11 | TODO: Write usage instructions here 12 | 13 | ## Development 14 | 15 | TODO: Write development instructions here 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( https://github.com/[your-github-name]/simple_kemal_app/fork ) 20 | 2. Create your feature branch (git checkout -b my-new-feature) 21 | 3. Commit your changes (git commit -am 'Add some feature') 22 | 4. Push to the branch (git push origin my-new-feature) 23 | 5. Create a new Pull Request 24 | 25 | ## Contributors 26 | 27 | - [[your-github-name]](https://github.com/[your-github-name]) Ivo-Balbaert - creator, maintainer 28 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/shard.lock: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | shards: 3 | kemal: 4 | github: sdogruyol/kemal 5 | commit: 61caa077b733a2c1dc64db2361ba96737c4431aa 6 | 7 | kilt: 8 | github: jeromegn/kilt 9 | version: 0.4.0 10 | 11 | radix: 12 | github: luislavena/radix 13 | version: 0.3.8 14 | 15 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/shard.yml: -------------------------------------------------------------------------------- 1 | name: simple_kemal_app 2 | version: 0.1.0 3 | 4 | authors: 5 | - Ivo-Balbaert 6 | 7 | targets: 8 | simple_kemal_app: 9 | main: src/simple_kemal_app.cr 10 | 11 | crystal: 0.23.3 12 | 13 | license: MIT 14 | 15 | dependencies: 16 | kemal: 17 | github: sdogruyol/kemal 18 | branch: master 19 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/simple_kemal_app: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/code/web_frameworks_and_shards/simple_kemal_app/simple_kemal_app -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/spec/simple_kemal_app_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe SimpleKemalApp do 4 | # TODO: Write tests 5 | 6 | it "works" do 7 | false.should eq(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/simple_kemal_app" 3 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/src/simple_kemal_app.cr: -------------------------------------------------------------------------------- 1 | require "./simple_kemal_app/*" 2 | require "kemal" # (1) 3 | 4 | get "/" do # (2) 5 | "My first Kemal app is alive!" 6 | end 7 | 8 | Kemal.run # (3) 9 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/simple_kemal_app/src/simple_kemal_app/version.cr: -------------------------------------------------------------------------------- 1 | module SimpleKemalApp 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /code/web_frameworks_and_shards/web_server.cr: -------------------------------------------------------------------------------- 1 | require "http/server" 2 | 3 | server = HTTP::Server.new(8080) do |ctx| # (1) 4 | ctx.response.content_type = "text/plain" # (2) 5 | ctx.response.print "Crystal web server: got #{ctx.request.path}" # (3) 6 | end 7 | 8 | puts "Crystal web server listening on http://localhost:8080" 9 | server.listen # (4) 10 | 11 | # => in browser with the URL http://localhost:8080/ 12 | # "Crystal web server: got /" 13 | -------------------------------------------------------------------------------- /code/why_crystal/error1.cr: -------------------------------------------------------------------------------- 1 | # START:code 2 | def add(x, y) 3 | x + y 4 | end 5 | 6 | puts add(2, 3) # => 5 # same as puts add 2, 3 7 | # () can be left out in method calls 8 | puts add(1.0, 3.14) # => 4.14 9 | puts add("Hello ", "Crystal") # => "Hello Crystal" 10 | # + concatenates two strings 11 | # END:code 12 | 13 | puts add(42, " times") # => Error 14 | 15 | # Ruby runtime error 16 | # in '+': String can't be coerced into Fixnum (TypeError) 17 | 18 | # Crystal compile error: 19 | # Error in error1.cr:7: instantiating 'add(Int32, String)' 20 | 21 | # add(42, " times") 22 | # ^~~ 23 | 24 | # in error1.cr:2: no overload matches 'Int32#+' with type String 25 | -------------------------------------------------------------------------------- /code/why_crystal/error2.cr: -------------------------------------------------------------------------------- 1 | # START:code 2 | str = "Crystal" 3 | ix = str.index('z') 4 | puts str[ix] 5 | # END:code 6 | 7 | # Ruby runtime error: $ ruby error.cr 8 | # error.cr:3:in `[]': no implicit conversion from nil to integer (TypeError) 9 | # from error.cr:3:in `
' 10 | 11 | # Crystal compile time error: $ crystal error.cr 12 | # Error in error.cr:3: no overload matches 'String#[]' with type (Int32 | Nil) 13 | # Overloads are: 14 | # - String#[](start : Int, count : Int) 15 | # - String#[](regex : Regex, group) 16 | # - String#[](index : Int) 17 | # - String#[](range : Range(Int, Int)) 18 | # - String#[](str : String | Char) 19 | # - String#[](regex : Regex) 20 | # Couldn't find overloads for these types: 21 | # - String#[](Nil) 22 | 23 | # how to remedy: 24 | # START:sol 25 | if ix 26 | puts str[ix] 27 | end 28 | # END:sol 29 | -------------------------------------------------------------------------------- /code/why_crystal/fibonacci.cr: -------------------------------------------------------------------------------- 1 | # START:code 2 | def fib(n) 3 | return n if n <= 1 4 | fib(n - 1) + fib(n - 2) 5 | end 6 | 7 | sum = 0 8 | (1..42).each do |i| 9 | sum += fib(i) 10 | end 11 | 12 | puts sum # => 701408732 13 | # END:code 14 | 15 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ time ruby fibonacci.cr 16 | 17 | # 102334155 18 | 19 | # real 3m44.437s 20 | # user 3m43.848s 21 | # sys 0m0.048s 22 | 23 | 24 | # 18.5 x 25 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ time crystal fibonacci.cr 26 | # 102334155 27 | 28 | # real 0m12.149s 29 | # user 0m12.044s 30 | # sys 0m0.356s 31 | 32 | 33 | # 19,5 x 34 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ crystal build fibonacci.cr 35 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ ls -l fib* 36 | # -rwxrwxr-x 1 ivo ivo 453288 Jan 3 10:45 fib 37 | # -rwxrwxr-x 1 ivo ivo 827088 Jan 4 11:48 fibonacci 38 | # -rw-rw-r-- 1 ivo ivo 100 Jan 4 11:45 fibonacci.cr 39 | # -rw-rw-r-- 1 ivo ivo 111 Jan 3 10:43 fib.cr 40 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ time ./fibonacci 41 | # 102334155 42 | 43 | # real 0m11.536s 44 | # user 0m11.524s 45 | # sys 0m0.000s 46 | 47 | 48 | # 21 x 49 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ crystal build --release fibonacci.cr 50 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ ls -l fib* 51 | # -rwxrwxr-x 1 ivo ivo 453288 Jan 3 10:45 fib 52 | # -rwxrwxr-x 1 ivo ivo 453288 Jan 4 11:50 fibonacci 53 | # -rw-rw-r-- 1 ivo ivo 100 Jan 4 11:45 fibonacci.cr 54 | # -rw-rw-r-- 1 ivo ivo 111 Jan 3 10:43 fib.cr 55 | # ivo@ivo-SATELLITE-L50D-B:~/crystal$ time ./fibonacci 56 | # 102334155 57 | 58 | # real 0m10.642s 59 | # user 0m10.636s 60 | # sys 0m0.000s 61 | -------------------------------------------------------------------------------- /code/why_crystal/hello_world.cr: -------------------------------------------------------------------------------- 1 | puts "Hello, Crystal World!" # => Hello Crystal world! 2 | p "Hello, Crystal World!" # => "Hello Crystal world!"" 3 | -------------------------------------------------------------------------------- /code/why_crystal/hello_world.java: -------------------------------------------------------------------------------- 1 | public class HelloWorld { 2 | 3 | public static void main(String[] args) { 4 | // Prints "Hello, World" to the terminal window. 5 | System.out.println("Hello, World!"); 6 | } 7 | 8 | } 9 | // => Hello, World! -------------------------------------------------------------------------------- /code/why_crystal/kemal.cr: -------------------------------------------------------------------------------- 1 | require "kemal" 2 | 3 | get "/" do 4 | "Hello from Kemal!" 5 | end 6 | 7 | Kemal.run -------------------------------------------------------------------------------- /code/why_crystal/overloading1.cr: -------------------------------------------------------------------------------- 1 | # overloading 1: 2 | def add(x : Int, y : Int) 3 | x + y 4 | end 5 | 6 | puts add(2, 3) # (1) => 5 7 | puts add(1.0, 3.14) # (2) => 8 | # Error: "no overload matches 'add' with types Float, Float" 9 | puts add("Hello ", "Crystal") # (3) => 10 | # Error: "no overload matches 'add' with types String, String" 11 | puts add(42, " times") # (4) 12 | # => Error: "no overload matches 'add' with types Int32, String" 13 | -------------------------------------------------------------------------------- /code/why_crystal/overloading12.cr: -------------------------------------------------------------------------------- 1 | # overloading 1: 2 | def add(x : Int, y : Int) 3 | x + y 4 | end 5 | 6 | # START:ovl2 7 | # overloading 1: ... 8 | # overloading 2: 9 | def add(x : Number, y : Number) 10 | x + y 11 | end 12 | 13 | puts add(2, 3) # (1) => 5 14 | puts add(1.0, 3.14) # (2) => 4.140000000000001 15 | puts add("Hello ", "Crystal") # (3) => 16 | # Error: "no overload matches 'add' with types String, String" 17 | puts add(42, " times") # (4) 18 | # => Error: "no overload matches 'add' with types Int32, String" 19 | # END:ovl2 20 | -------------------------------------------------------------------------------- /code/why_crystal/overloading123.cr: -------------------------------------------------------------------------------- 1 | # overloading 1: 2 | def add(x : Int, y : Int) 3 | x + y 4 | end 5 | 6 | # overloading 2: 7 | def add(x : Number, y : Number) 8 | x + y 9 | end 10 | 11 | # START:ovl3 12 | # overloading 1: ... 13 | # overloading 2: ... 14 | # overloading 3: 15 | def add(x, y) 16 | print "in generic add: " 17 | x + y 18 | end 19 | 20 | puts add(2, 3) # (1) => 5 21 | puts add(1.0, 3.14) # (2) => 4.140000000000001 22 | puts add("Hello ", "Crystal") # (3) => "in generic add: Hello Crystal" 23 | puts add(42, " times") # (4) 24 | # => Error: "no overload matches 'add' with types Int32, String" 25 | # END:ovl3 26 | -------------------------------------------------------------------------------- /code/why_crystal/overloading1234.cr: -------------------------------------------------------------------------------- 1 | # overloading 1: 2 | def add(x : Int, y : Int) 3 | x + y 4 | end 5 | 6 | # overloading 2: 7 | def add(x : Number, y : Number) 8 | x + y 9 | end 10 | 11 | # overloading 3: 12 | def add(x, y) 13 | print "in generic add: " 14 | x + y 15 | end 16 | 17 | # START:ovl4 18 | # overloading 1: ... 19 | # overloading 2: ... 20 | # overloading 3: ... 21 | # overloading 4: 22 | def add(x : Number, y : String) 23 | x.to_s + y # convert a number to a string with to_s method 24 | end 25 | 26 | puts add(2, 3) # (1) => 5 27 | puts add(1.0, 3.14) # (2) => 4.140000000000001 28 | puts add("Hello ", "Crystal") # (3) => "in generic add: Hello Crystal" 29 | puts add(42, " times") # (4) => "42 times" 30 | # END:ovl4 31 | -------------------------------------------------------------------------------- /code/why_crystal/ruby_add.rb: -------------------------------------------------------------------------------- 1 | def add(x, y) 2 | if x.is_a?(Numeric) and y.is_a?(String) 3 | x.to_s + y 4 | else 5 | x + y 6 | end 7 | end 8 | 9 | puts add(2, 3) # (1) => 5 10 | puts add(1.0, 3.14) # (2) => 4.14 11 | puts add("Hello ", "Ruby") # (3) => "Hello Ruby" 12 | puts add(42, " times") # (4) => "42 times" -------------------------------------------------------------------------------- /code/why_crystal/socket_error.cr: -------------------------------------------------------------------------------- 1 | # code that can give a nil pointer exception 2 | # because connection can be closed, --> gets returns nil 3 | # START:code 4 | require "socket" 5 | 6 | server = TCPServer.new(8080) # (1) create a new TCPServer at port 8080 7 | socket = server.accept # (2) accept a connection 8 | puts socket.gets.upcase # (3) read a line and output it in uppercase 9 | # END:code 10 | # Error: => undefined method 'upcase' for nil 11 | # compile-time type is (String | Nil) 12 | 13 | # Solution: 14 | # START:code2 15 | line = socket.gets 16 | if line 17 | puts line.capitalize # Crystal knows that line cannot be nil here! 18 | else 19 | puts "Nothing in the socket" 20 | end 21 | # END:code2 22 | -------------------------------------------------------------------------------- /code/working_with_modules/ancestors.cr: -------------------------------------------------------------------------------- 1 | module M1 2 | def meth1 3 | 41 4 | end 5 | end 6 | 7 | class C1 8 | def meth1 9 | 42 10 | end 11 | end 12 | 13 | class D1 < C1 14 | include M1 15 | end 16 | 17 | class E1 < D1 18 | end 19 | 20 | E1.new.m1 # => Error: undefined method 'm1' for E1 21 | E1.new.meth1 # => 41 # meth1 from module M1 is called 22 | -------------------------------------------------------------------------------- /code/working_with_modules/comparable.cr: -------------------------------------------------------------------------------- 1 | class Person 2 | include Comparable(Person) 3 | 4 | getter name, age 5 | 6 | def initialize(@name : String, @age : Int32) 7 | end 8 | 9 | def <=>(other : self) # other must be of type self, which is Person 10 | if self.age < other.age # here self is the current Person object 11 | -1 12 | elsif self.age > other.age 13 | 1 14 | else # == case 15 | 0 16 | end 17 | end 18 | end 19 | 20 | john = Person.new("John", 42) 21 | martha = Person.new("Martha", 74) 22 | diana = Person.new("Diana", 42) 23 | john > martha # => false 24 | john == diana # => true 25 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/dirB.cr: -------------------------------------------------------------------------------- 1 | puts "I am from dirB.cr in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/dirB/dirB.cr: -------------------------------------------------------------------------------- 1 | puts "I am from dirB.cr in dirB in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/dirB/fileB.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileB.cr in dirB in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/dirC/fileC1.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileC1.cr in dirC in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/dirC/fileC2.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileC2.cr in dirC in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/fileA.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileA.cr in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/fileA2.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileA2.cr in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/dirA/fileA3.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileA3.cr in dirA" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/enumerable.cr: -------------------------------------------------------------------------------- 1 | class Sequence 2 | include Enumerable(Int32) 3 | 4 | def initialize(@top : Int32) 5 | end 6 | 7 | def each 8 | 0.upto(@top) do |num| 9 | yield num 10 | end 11 | end 12 | end 13 | 14 | seq = Sequence.new(7) 15 | # using some methods of module Enumerable: 16 | seq.to_a # => [0, 1, 2, 3, 4, 5, 6, 7] 17 | seq.select &.even? # => [0, 2, 4, 6] 18 | seq.map { |x| x ** 2 } # => [0, 1, 4, 9, 16, 25, 36, 49] 19 | -------------------------------------------------------------------------------- /code/working_with_modules/fileA.cr: -------------------------------------------------------------------------------- 1 | puts "I am from fileA.cr in the current folder" 2 | -------------------------------------------------------------------------------- /code/working_with_modules/iterator.cr: -------------------------------------------------------------------------------- 1 | n = 0 2 | inc = Iterator.of do 3 | n += 1 4 | n 5 | end 6 | 7 | inc.next # => 1 8 | inc.next # => 2 9 | inc.next # => 3 10 | 11 | n = 0 12 | m = 1 13 | fib = Iterator.of { ret = n; n = m; m += ret; ret } 14 | 15 | fib 16 | .select { |x| x.even? } 17 | .first(10) 18 | .to_a # => [0, 2, 8, 34, 144, 610, 2584, 10946, 46368, 196418] 19 | -------------------------------------------------------------------------------- /code/working_with_modules/mixins.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | class Basic 3 | def initialize(@name : String) 4 | end 5 | 6 | def to_s 7 | @name 8 | end 9 | end 10 | 11 | module Debug 12 | def who_am_i? 13 | "#{self.class.name} (\##{self.object_id}): #{self.to_s}" 14 | end 15 | end 16 | 17 | class DVD < Basic 18 | include Debug 19 | # ... 20 | end 21 | 22 | class BlueRay < Basic 23 | include Debug 24 | # ... 25 | end 26 | 27 | dv = DVD.new("West End Blues") 28 | br = BlueRay.new("Attack of the Martians") 29 | dv.who_am_i? # => DVD (#40886016): West End Blues 30 | br.who_am_i? # => BlueRay (#40885984): Attack of the Martians 31 | # END: p1 32 | 33 | # START: p2 34 | 35 | module DebugC 36 | def who_am_i? 37 | "#{self.class.name}: #{self.to_s}" 38 | end 39 | end 40 | 41 | class CD < Basic 42 | extend DebugC 43 | # ... 44 | end 45 | 46 | cd = CD.new("Bach's Cello Suites") 47 | cd.who_am_i? # => Error: undefined method 'who_am_i?' for CD 48 | CD.who_am_i? # => "Class: CD" 49 | # END: p2 50 | -------------------------------------------------------------------------------- /code/working_with_modules/moral.cr: -------------------------------------------------------------------------------- 1 | module Moral 2 | VERY_BAD = 0 3 | BAD = 1 4 | 5 | def self.sin(badness) 6 | puts "Assessing the sin of #{badness}" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /code/working_with_modules/moral2.cr: -------------------------------------------------------------------------------- 1 | module Moral 2 | extend self 3 | VERY_BAD = 0 4 | BAD = 1 5 | 6 | def sin(badness) 7 | puts "Assessing the sin of #{badness}" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /code/working_with_modules/namespaces.cr: -------------------------------------------------------------------------------- 1 | # START: p1 2 | module Crystals 3 | class Rhombic 4 | end 5 | 6 | class Triclinic 7 | end 8 | end 9 | 10 | t = Crystals::Rhombic.new 11 | typeof(Crystals) # => Class 12 | # END: p1 13 | 14 | # START: p2 15 | require "./trig" 16 | require "./moral" 17 | 18 | y = sin(Trig::PI/4) # => Error: undefined method 'sin' 19 | y = Trig.sin(Trig::PI/4) # => Calculating the sin of 0.7853981635 20 | wrongdoing = Moral.sin(Moral::VERY_BAD) # => Assessing the sin of 0 21 | # END: p2 22 | 23 | # START: p3 24 | require "./moral2" 25 | 26 | y = Math.sin(Math::PI/4) # => 0.70710678118654746 27 | wrongdoing = Moral.sin(Moral::VERY_BAD) # => Assessing the sin of 0 28 | # END: p3 29 | -------------------------------------------------------------------------------- /code/working_with_modules/namespaces2.cr: -------------------------------------------------------------------------------- 1 | require "./moral2" 2 | include Moral 3 | 4 | y = Math.sin(Math::PI/4) # => 0.70710678118654746 5 | wrongdoing = sin(Moral::VERY_BAD) # => Assessing the sin of 0 6 | -------------------------------------------------------------------------------- /code/working_with_modules/require.cr: -------------------------------------------------------------------------------- 1 | # current folder: 2 | # START: p1 3 | require "./fileA" 4 | # I am from fileA.cr in the current folder 5 | # OR (if present): fileA.cr in subfolder fileA 6 | require "./dirA/fileA" 7 | # I am from fileA.cr in dirA 8 | require "./dirA/dirB" 9 | # I am from dirB.cr in dirA 10 | # OR: I am from dirB.cr in dirB in dirA 11 | # END: p1 12 | 13 | # parent folder: 14 | # START: p2 15 | require "../fileA" 16 | # I am from fileA.cr in the parent folder 17 | require "../dirA/fileA" 18 | # I am from fileA.cr in dirA in the parent folder 19 | # END: p2 20 | 21 | # nested form: 22 | # START: p3 23 | require "./dirA/dirB/fileB" 24 | # I am from fileB.cr in dirB in dirA 25 | # END: p3 26 | 27 | # forms using wildcard *: 28 | # START: p4 29 | require "./dirA/*" 30 | # I am from fileA2.cr in dirA 31 | # I am from fileA3.cr in dirA 32 | # END: p4 33 | 34 | # forms using wildcard **: 35 | # START: p5 36 | require "./dirA/**" 37 | # I am from fileC1.cr in dirC in dirA 38 | # I am from fileC2.cr in dirC in dirA 39 | # END: p5 40 | 41 | # require path: 42 | # START: p6 43 | require "file" 44 | # END: p6 45 | -------------------------------------------------------------------------------- /code/working_with_modules/trig.cr: -------------------------------------------------------------------------------- 1 | module Trig 2 | PI = 3.141592654 3 | 4 | def self.sin(x) 5 | puts "Calculating the sin of #{x}" 6 | end 7 | 8 | def self.cos(x) 9 | # .. 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /code/working_with_modules/visibility.cr: -------------------------------------------------------------------------------- 1 | module Languages 2 | class Crystal 3 | protected def shout 4 | puts "Hello, I am written in Crystal" 5 | end 6 | end 7 | 8 | class Ruby 9 | def shout 10 | Crystal.new.shout 11 | end 12 | end 13 | end 14 | 15 | Languages::Ruby.new.shout # => Hello, I am written in Crystal 16 | Languages::Crystal.new.shout 17 | # => Error: protected method 'shout' called for Languages::Crystal 18 | -------------------------------------------------------------------------------- /exercises/advanced_features/def_method.cr: -------------------------------------------------------------------------------- 1 | macro define_method(mname, body) 2 | def {{mname}} 3 | {{body}} 4 | end 5 | end 6 | 7 | define_method greets, puts "Hi!" 8 | # This generates: 9 | # 10 | # def greets 11 | # puts "Hi!" 12 | # end 13 | 14 | define_method add, 1 + 2 15 | # This generates: 16 | # 17 | # def add 18 | # 1 + 2 19 | # end 20 | 21 | greets # => Hi! 22 | add # => 3 23 | 24 | # ## Some additions: 25 | # Use id when calling a macro with a symbol 26 | macro define_method(name, content) 27 | def {{name.id}} 28 | {{content}} 29 | end 30 | end 31 | 32 | define_method :greets, puts "Hi!" 33 | 34 | greets # => Hi! 35 | 36 | # Use body to get the code of a block 37 | macro define_method(name, &block) 38 | def {{name.id}} 39 | {{block.body}} 40 | end 41 | end 42 | 43 | define_method :greets do 44 | puts "Hi!" 45 | end 46 | 47 | greets # => "Hi!" 48 | -------------------------------------------------------------------------------- /exercises/advanced_features/main_fiber3.cr: -------------------------------------------------------------------------------- 1 | ch = Channel(Int32).new 2 | 3 | spawn do 4 | puts "start fiber" 5 | n = ch.send 42 6 | puts "fiber has sent value #{n}" # not printed, because main exits 7 | end 8 | 9 | puts "before receive" 10 | val = ch.receive # main waits 11 | puts "main has received value #{val}" 12 | # => 13 | # before receive 14 | # start fiber 15 | # main has received value 42 16 | -------------------------------------------------------------------------------- /exercises/advanced_features/main_fiber4.cr: -------------------------------------------------------------------------------- 1 | # Part 1: 2 | ch = Channel(Int32).new 3 | 4 | # (1..10).each { |i| ch.send i } # main blocks, because value is not received 5 | 6 | # fiber 1: 7 | spawn do 8 | loop do 9 | num = ch.receive 10 | puts "Got number #{num}" 11 | end 12 | end 13 | 14 | # main: 15 | (1..10).each { |i| ch.send i } 16 | 17 | # => 18 | # Got number 1 19 | # Got number 2 20 | # Got number 3 21 | # Got number 4 22 | # Got number 5 23 | # Got number 6 24 | # Got number 7 25 | # Got number 8 26 | # Got number 9 27 | # Got number 10 28 | 29 | # Part 2: 30 | # fiber 1: 31 | spawn do 32 | (1..10).each { |i| ch.send i } 33 | end 34 | 35 | # main: 36 | loop do 37 | num = ch.receive 38 | puts "Got number #{num}" 39 | end 40 | 41 | # => 42 | # Got number 1 43 | # Got number 2 44 | # Got number 3 45 | # Got number 4 46 | # Got number 5 47 | # Got number 6 48 | # Got number 7 49 | # Got number 8 50 | # Got number 9 51 | # Got number 10 52 | -------------------------------------------------------------------------------- /exercises/classes_and_structs/employee.cr: -------------------------------------------------------------------------------- 1 | class Employee 2 | getter name 3 | property age 4 | 5 | def initialize(@name : String, @age : Int32) 6 | end 7 | end 8 | 9 | e = Employee.new("Jones", 42) 10 | e.name # => "Jones" : String 11 | e.age # => 42 : Int32 12 | e.age += 1 # => 43 : Int32 13 | e.name = "Other person" # undefined method 'name=' for Employee 14 | -------------------------------------------------------------------------------- /exercises/classes_and_structs/increment.cr: -------------------------------------------------------------------------------- 1 | class Increment 2 | getter amount 3 | 4 | def initialize (@amount = 0) 5 | end 6 | 7 | def increment 8 | @amount += 1 9 | end 10 | 11 | def increment(inc_amount) 12 | @amount += inc_amount 13 | end 14 | end 15 | 16 | inc = Increment.new 17 | inc.increment 18 | inc.amount # => 1 19 | inc.increment(5) 20 | inc.amount # => 6 21 | -------------------------------------------------------------------------------- /exercises/classes_and_structs/reopen.cr: -------------------------------------------------------------------------------- 1 | x = rand < 0.0001 ? 1 : "hello" 2 | typeof(x) # => (Int32 | String) 3 | 4 | x - 1 # => Error: undefined method '-' for String 5 | 6 | class String 7 | def -(n) 8 | self[0...size - n] 9 | end 10 | end 11 | 12 | x = "hello" 13 | x - 1 # => "hell" 14 | x - 2 # => "hel" 15 | x - 3 # => "he" 16 | -------------------------------------------------------------------------------- /exercises/classes_and_structs/shape.cr: -------------------------------------------------------------------------------- 1 | include Math 2 | 3 | abstract class Shape 4 | abstract def area 5 | abstract def perim 6 | end 7 | 8 | class Square < Shape 9 | def initialize(@side : Int32) 10 | end 11 | 12 | def area 13 | @side * @side 14 | end 15 | 16 | def perim 17 | 4 * @side 18 | end 19 | end 20 | 21 | class Circle < Shape 22 | def initialize(@radius : Float64) 23 | end 24 | 25 | def area 26 | 4 * PI * @radius * @radius 27 | end 28 | 29 | def perim 30 | 2 * PI * @radius 31 | end 32 | end 33 | 34 | p Square.new(3).area # => 9 35 | p Circle.new(5.0).area # => 314.15926535897933 36 | p Circle.new(5.0).perim # => 31.415926535897931 37 | -------------------------------------------------------------------------------- /exercises/crystal_new/99_bottles_of_beer.cr: -------------------------------------------------------------------------------- 1 | # with while and if: 2 | num_of_bottles = 99 3 | while num_of_bottles >= 1 4 | if num_of_bottles == 1 5 | p "#{num_of_bottles} bottle of beer on the wall..." 6 | else 7 | p "#{num_of_bottles} bottles of beer on the wall..." 8 | end 9 | num_of_bottles -= 1 10 | end 11 | p "You drank the whole case!" 12 | 13 | # with downto: 14 | num_of_bottles = 99 15 | num_of_bottles.downto(1) do |count| 16 | if count == 1 17 | p "#{count} bottle of beer on the wall..." 18 | else 19 | p "#{count} bottles of beer on the wall..." 20 | end 21 | end 22 | p "You drank the whole case!" 23 | 24 | # => 25 | # "99 bottles of beer on the wall..." 26 | # "98 bottles of beer on the wall..." 27 | # "97 bottles of beer on the wall..." 28 | # "96 bottles of beer on the wall..." 29 | # "95 bottles of beer on the wall..." 30 | # "94 bottles of beer on the wall..." 31 | # "93 bottles of beer on the wall..." 32 | # "92 bottles of beer on the wall..." 33 | # "91 bottles of beer on the wall..." 34 | # "90 bottles of beer on the wall..." 35 | # "89 bottles of beer on the wall..." 36 | # "88 bottles of beer on the wall..." 37 | # "87 bottles of beer on the wall..." 38 | # "86 bottles of beer on the wall..." 39 | # "85 bottles of beer on the wall..." 40 | # "84 bottles of beer on the wall..." 41 | # "83 bottles of beer on the wall..." 42 | # "82 bottles of beer on the wall..." 43 | # "81 bottles of beer on the wall..." 44 | # "80 bottles of beer on the wall..." 45 | # "79 bottles of beer on the wall..." 46 | # "78 bottles of beer on the wall..." 47 | # "77 bottles of beer on the wall..." 48 | # "76 bottles of beer on the wall..." 49 | # "75 bottles of beer on the wall..." 50 | # "74 bottles of beer on the wall..." 51 | # "73 bottles of beer on the wall..." 52 | # "72 bottles of beer on the wall..." 53 | # "71 bottles of beer on the wall..." 54 | # "70 bottles of beer on the wall..." 55 | # "69 bottles of beer on the wall..." 56 | # "68 bottles of beer on the wall..." 57 | # "67 bottles of beer on the wall..." 58 | # "66 bottles of beer on the wall..." 59 | # "65 bottles of beer on the wall..." 60 | # "64 bottles of beer on the wall..." 61 | # "63 bottles of beer on the wall..." 62 | # "62 bottles of beer on the wall..." 63 | # "61 bottles of beer on the wall..." 64 | # "60 bottles of beer on the wall..." 65 | # "59 bottles of beer on the wall..." 66 | # "58 bottles of beer on the wall..." 67 | # "57 bottles of beer on the wall..." 68 | # "56 bottles of beer on the wall..." 69 | # "55 bottles of beer on the wall..." 70 | # "54 bottles of beer on the wall..." 71 | # "53 bottles of beer on the wall..." 72 | # "52 bottles of beer on the wall..." 73 | # "51 bottles of beer on the wall..." 74 | # "50 bottles of beer on the wall..." 75 | # "49 bottles of beer on the wall..." 76 | # "48 bottles of beer on the wall..." 77 | # "47 bottles of beer on the wall..." 78 | # "46 bottles of beer on the wall..." 79 | # "45 bottles of beer on the wall..." 80 | # "44 bottles of beer on the wall..." 81 | # "43 bottles of beer on the wall..." 82 | # "42 bottles of beer on the wall..." 83 | # "41 bottles of beer on the wall..." 84 | # "40 bottles of beer on the wall..." 85 | # "39 bottles of beer on the wall..." 86 | # "38 bottles of beer on the wall..." 87 | # "37 bottles of beer on the wall..." 88 | # "36 bottles of beer on the wall..." 89 | # "35 bottles of beer on the wall..." 90 | # "34 bottles of beer on the wall..." 91 | # "33 bottles of beer on the wall..." 92 | # "32 bottles of beer on the wall..." 93 | # "31 bottles of beer on the wall..." 94 | # "30 bottles of beer on the wall..." 95 | # "29 bottles of beer on the wall..." 96 | # "28 bottles of beer on the wall..." 97 | # "27 bottles of beer on the wall..." 98 | # "26 bottles of beer on the wall..." 99 | # "25 bottles of beer on the wall..." 100 | # "24 bottles of beer on the wall..." 101 | # "23 bottles of beer on the wall..." 102 | # "22 bottles of beer on the wall..." 103 | # "21 bottles of beer on the wall..." 104 | # "20 bottles of beer on the wall..." 105 | # "19 bottles of beer on the wall..." 106 | # "18 bottles of beer on the wall..." 107 | # "17 bottles of beer on the wall..." 108 | # "16 bottles of beer on the wall..." 109 | # "15 bottles of beer on the wall..." 110 | # "14 bottles of beer on the wall..." 111 | # "13 bottles of beer on the wall..." 112 | # "12 bottles of beer on the wall..." 113 | # "11 bottles of beer on the wall..." 114 | # "10 bottles of beer on the wall..." 115 | # "9 bottles of beer on the wall..." 116 | # "8 bottles of beer on the wall..." 117 | # "7 bottles of beer on the wall..." 118 | # "6 bottles of beer on the wall..." 119 | # "5 bottles of beer on the wall..." 120 | # "4 bottles of beer on the wall..." 121 | # "3 bottles of beer on the wall..." 122 | # "2 bottles of beer on the wall..." 123 | # "1 bottle of beer on the wall..." 124 | # "You drank the whole case!" 125 | # "99 bottles of beer on the wall..." 126 | # "98 bottles of beer on the wall..." 127 | # "97 bottles of beer on the wall..." 128 | # "96 bottles of beer on the wall..." 129 | # "95 bottles of beer on the wall..." 130 | # "94 bottles of beer on the wall..." 131 | # "93 bottles of beer on the wall..." 132 | # "92 bottles of beer on the wall..." 133 | # "91 bottles of beer on the wall..." 134 | # "90 bottles of beer on the wall..." 135 | # "89 bottles of beer on the wall..." 136 | # "88 bottles of beer on the wall..." 137 | # "87 bottles of beer on the wall..." 138 | # "86 bottles of beer on the wall..." 139 | # "85 bottles of beer on the wall..." 140 | # "84 bottles of beer on the wall..." 141 | # "83 bottles of beer on the wall..." 142 | # "82 bottles of beer on the wall..." 143 | # "81 bottles of beer on the wall..." 144 | # "80 bottles of beer on the wall..." 145 | # "79 bottles of beer on the wall..." 146 | # "78 bottles of beer on the wall..." 147 | # "77 bottles of beer on the wall..." 148 | # "76 bottles of beer on the wall..." 149 | # "75 bottles of beer on the wall..." 150 | # "74 bottles of beer on the wall..." 151 | # "73 bottles of beer on the wall..." 152 | # "72 bottles of beer on the wall..." 153 | # "71 bottles of beer on the wall..." 154 | # "70 bottles of beer on the wall..." 155 | # "69 bottles of beer on the wall..." 156 | # "68 bottles of beer on the wall..." 157 | # "67 bottles of beer on the wall..." 158 | # "66 bottles of beer on the wall..." 159 | # "65 bottles of beer on the wall..." 160 | # "64 bottles of beer on the wall..." 161 | # "63 bottles of beer on the wall..." 162 | # "62 bottles of beer on the wall..." 163 | # "61 bottles of beer on the wall..." 164 | # "60 bottles of beer on the wall..." 165 | # "59 bottles of beer on the wall..." 166 | # "58 bottles of beer on the wall..." 167 | # "57 bottles of beer on the wall..." 168 | # "56 bottles of beer on the wall..." 169 | # "55 bottles of beer on the wall..." 170 | # "54 bottles of beer on the wall..." 171 | # "53 bottles of beer on the wall..." 172 | # "52 bottles of beer on the wall..." 173 | # "51 bottles of beer on the wall..." 174 | # "50 bottles of beer on the wall..." 175 | # "49 bottles of beer on the wall..." 176 | # "48 bottles of beer on the wall..." 177 | # "47 bottles of beer on the wall..." 178 | # "46 bottles of beer on the wall..." 179 | # "45 bottles of beer on the wall..." 180 | # "44 bottles of beer on the wall..." 181 | # "43 bottles of beer on the wall..." 182 | # "42 bottles of beer on the wall..." 183 | # "41 bottles of beer on the wall..." 184 | # "40 bottles of beer on the wall..." 185 | # "39 bottles of beer on the wall..." 186 | # "38 bottles of beer on the wall..." 187 | # "37 bottles of beer on the wall..." 188 | # "36 bottles of beer on the wall..." 189 | # "35 bottles of beer on the wall..." 190 | # "34 bottles of beer on the wall..." 191 | # "33 bottles of beer on the wall..." 192 | # "32 bottles of beer on the wall..." 193 | # "31 bottles of beer on the wall..." 194 | # "30 bottles of beer on the wall..." 195 | # "29 bottles of beer on the wall..." 196 | # "28 bottles of beer on the wall..." 197 | # "27 bottles of beer on the wall..." 198 | # "26 bottles of beer on the wall..." 199 | # "25 bottles of beer on the wall..." 200 | # "24 bottles of beer on the wall..." 201 | # "23 bottles of beer on the wall..." 202 | # "22 bottles of beer on the wall..." 203 | # "21 bottles of beer on the wall..." 204 | # "20 bottles of beer on the wall..." 205 | # "19 bottles of beer on the wall..." 206 | # "18 bottles of beer on the wall..." 207 | # "17 bottles of beer on the wall..." 208 | # "16 bottles of beer on the wall..." 209 | # "15 bottles of beer on the wall..." 210 | # "14 bottles of beer on the wall..." 211 | # "13 bottles of beer on the wall..." 212 | # "12 bottles of beer on the wall..." 213 | # "11 bottles of beer on the wall..." 214 | # "10 bottles of beer on the wall..." 215 | # "9 bottles of beer on the wall..." 216 | # "8 bottles of beer on the wall..." 217 | # "7 bottles of beer on the wall..." 218 | # "6 bottles of beer on the wall..." 219 | # "5 bottles of beer on the wall..." 220 | # "4 bottles of beer on the wall..." 221 | # "3 bottles of beer on the wall..." 222 | # "2 bottles of beer on the wall..." 223 | # "1 bottle of beer on the wall..." 224 | # "You drank the whole case!" 225 | -------------------------------------------------------------------------------- /exercises/crystal_new/class.cr: -------------------------------------------------------------------------------- 1 | class Mineral 2 | getter name : String 3 | getter hardness : Float64 4 | getter crystal_struct : String 5 | 6 | def initialize(name, hardness, crystal_struct) 7 | @name = name 8 | @hardness = hardness 9 | @crystal_struct = crystal_struct 10 | end 11 | 12 | def to_s 13 | "#{self.crystal_struct} - #{self.name} - #{self.hardness}" 14 | end 15 | end 16 | 17 | def mineral_with_crystal_struct(crstruct, minerals) 18 | minerals.find { |m| m.crystal_struct == crstruct } 19 | end 20 | 21 | def longest_name(minerals) 22 | minerals.map { |m| m.name }.max_by { |name| name.size } 23 | end 24 | 25 | minerals = [ 26 | Mineral.new("gold", 1.0, "cubic"), 27 | Mineral.new("topaz", 8.0, "orthorombic"), 28 | Mineral.new("apatite", 5.0, "hexagonal"), 29 | Mineral.new("wolframite", 4.5, "monoclinic"), 30 | Mineral.new("calcite", 3.0, "trigonal"), 31 | Mineral.new("diamond", 10.0, "cubic"), 32 | ] 33 | 34 | min = mineral_with_crystal_struct("hexagonal", minerals) 35 | if min 36 | puts min.to_s 37 | else 38 | puts "No mineral found with this crystal structure!" 39 | end 40 | # => hexagonal - apatite - 5 41 | 42 | min = mineral_with_crystal_struct("triclinic", minerals) 43 | if min 44 | puts min.to_s 45 | else 46 | puts "No mineral found with this crystal structure!" 47 | end 48 | # => "No mineral found with this crystal structure!" 49 | 50 | puts longest_name(minerals) 51 | # => wolframite 52 | 53 | # crystal build 3.5_mineral.cr --release 54 | # $ time ./3.5_mineral # => real 0.002 s 55 | -------------------------------------------------------------------------------- /exercises/crystal_new/fibers.cr: -------------------------------------------------------------------------------- 1 | # START:p1 2 | chan = Channel(String).new 3 | i = 0 4 | num = 10000 5 | num.times do 6 | spawn do 7 | chan.send "fiber #{i}: I like crystals!" 8 | end 9 | i += 1 10 | puts chan.receive 11 | end 12 | # => 13 | # fiber 1: I like crystals! 14 | # fiber 2: I like crystals! 15 | # fiber 3: I like crystals! 16 | # fiber 4: I like crystals! 17 | # ... 18 | # fiber 10000: I like crystals! 19 | # END:p1 20 | -------------------------------------------------------------------------------- /exercises/crystal_new/method.cr: -------------------------------------------------------------------------------- 1 | def sample(n) 2 | res = [] of Float64 3 | n.times do 4 | res << rand 5 | end 6 | res 7 | end 8 | 9 | sample 5 10 | # Output for example: 11 | # [0.42584667462080578, 0.22326633752060512, 0.68064089397146432, 0.57965191049681586, 0.63821448407129489] 12 | -------------------------------------------------------------------------------- /exercises/crystal_new/squares.cr: -------------------------------------------------------------------------------- 1 | # ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 2 | ary = (1..10).to_a 3 | ary.each do |i| 4 | if i.odd? 5 | p "The square of #{i} is #{i * i}" 6 | end 7 | end 8 | # => 9 | # "The square of 1 is 1" 10 | # "The square of 3 is 9" 11 | # "The square of 5 is 25" 12 | # "The square of 7 is 49" 13 | # "The square of 9 is 81" 14 | -------------------------------------------------------------------------------- /exercises/crystal_new/union.cr: -------------------------------------------------------------------------------- 1 | m : (Int32 | String) = 42 2 | m = "Crystal" # => OK 3 | m = false # => type must be (Int32 | String), not (Bool | Int32 | String) 4 | -------------------------------------------------------------------------------- /exercises/managing_projects/array_last_elem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/managing_projects/array_last_elem -------------------------------------------------------------------------------- /exercises/managing_projects/array_last_elem.cr: -------------------------------------------------------------------------------- 1 | require "benchmark" 2 | 3 | ARY = [1..100] 4 | 5 | def index 6 | ARY[-1] 7 | end 8 | 9 | def last 10 | ARY.last 11 | end 12 | 13 | Benchmark.ips do |x| 14 | x.report("Array#[-1]") { index } 15 | x.report("Array#last") { last } 16 | end 17 | 18 | # Results: 19 | # Array#[-1] 21.17M ( 47.23ns) (± 3.89%) 1.49× slower 20 | # Array#last 31.64M ( 31.6ns) (± 3.29%) fastest 21 | -------------------------------------------------------------------------------- /exercises/managing_projects/building_vs_concat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/managing_projects/building_vs_concat -------------------------------------------------------------------------------- /exercises/managing_projects/building_vs_concat.cr: -------------------------------------------------------------------------------- 1 | require "benchmark" 2 | 3 | N = 100_000 4 | 5 | Benchmark.bm do |x| 6 | x.report("String#+") do 7 | concat 8 | end 9 | 10 | x.report("String.build") do 11 | build 12 | end 13 | end 14 | 15 | def concat 16 | str = "" 17 | N.times do |i| 18 | str += "#{i}" 19 | end 20 | end 21 | 22 | def build 23 | String.build do |str| 24 | N.times do |i| 25 | str << i 26 | end 27 | end 28 | end 29 | 30 | # Results with ips: 31 | # String#+ 0.07 ( 14.66s ) (± 0.00%) 1569.57× slower 32 | # String.build 107.07 ( 9.34ms) (± 2.20%) fastest 33 | 34 | # Reults with bm: 35 | # user system total real 36 | # String#+ 10.140000 3.800000 13.940000 ( 9.552760) 37 | # String.build 0.010000 0.000000 0.010000 ( 0.010519) 38 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/.gitignore: -------------------------------------------------------------------------------- 1 | /doc/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/.travis.yml: -------------------------------------------------------------------------------- 1 | language: crystal 2 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ivo-Balbaert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/README.md: -------------------------------------------------------------------------------- 1 | # mineral 2 | 3 | TODO: Write a description here 4 | 5 | ## Installation 6 | 7 | TODO: Write installation instructions here 8 | 9 | ## Usage 10 | 11 | TODO: Write usage instructions here 12 | 13 | ## Development 14 | 15 | TODO: Write development instructions here 16 | 17 | ## Contributing 18 | 19 | 1. Fork it ( https://github.com/[your-github-name]/mineral/fork ) 20 | 2. Create your feature branch (git checkout -b my-new-feature) 21 | 3. Commit your changes (git commit -am 'Add some feature') 22 | 4. Push to the branch (git push origin my-new-feature) 23 | 5. Create a new Pull Request 24 | 25 | ## Contributors 26 | 27 | - [[your-github-name]](https://github.com/[your-github-name]) Ivo-Balbaert - creator, maintainer 28 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/mineral: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/managing_projects/mineral/mineral -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/shard.yml: -------------------------------------------------------------------------------- 1 | name: mineral 2 | version: 0.1.0 3 | 4 | authors: 5 | - Ivo-Balbaert 6 | 7 | targets: 8 | mineral: 9 | main: src/mineral.cr 10 | 11 | crystal: 0.22.0 12 | 13 | license: MIT 14 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/spec/mineral_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe Mineral do 4 | # TODO: Write tests 5 | 6 | # it "works" do 7 | # false.should eq(true) 8 | # end 9 | 10 | it "creates a default mineral" do 11 | min1 = Mineral::Mineral.new(108) 12 | min1.id.should eq(108) 13 | min1.name.should eq ("rock") 14 | min1.crystal_struct.should eq("unknown") 15 | end 16 | 17 | it "creates a mineral with parameters" do 18 | min1 = Mineral::Mineral.new(42, "apatite", "hexagonal") 19 | min1.id.should eq(42) 20 | min1.name.should eq ("apatite") 21 | min1.crystal_struct.should eq("hexagonal") 22 | end 23 | 24 | it "creates correct csv format" do 25 | min1 = Mineral::Mineral.new(101, "gold", "cubic") 26 | min1.to_csv.should eq("101,gold,2.5,cubic") 27 | end 28 | 29 | it "gold has hardness 2.5" do 30 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 31 | min1.hardness.should eq(2.5) 32 | end 33 | 34 | it "== works for same mineral" do 35 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 36 | (min1 == min1).should eq(true) 37 | end 38 | 39 | it "== works for different mineral" do 40 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 41 | min2 = Mineral::Mineral.new(43, "corundum", "trigonal") 42 | (min1 == min2).should eq(false) 43 | end 44 | 45 | it "kind_of_crystal works" do 46 | min1 = Mineral::Mineral.new(42, "gold", "cubic") 47 | (min1.kind_of_crystal).should eq("cubic") 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/mineral" 3 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/src/mineral.cr: -------------------------------------------------------------------------------- 1 | require "./mineral/*" 2 | 3 | module Mineral 4 | puts "app mineral is started!" 5 | 6 | module Hardness 7 | def data 8 | mohs = {"talc" => 1, "gold" => 2.5, "calcite" => 3, 9 | "apatite" => 5, "corundum" => 9} 10 | end 11 | 12 | def hardness 13 | data[self.name] 14 | end 15 | end 16 | 17 | # Every Mineral has **hardness** (see the `Hardness` module). 18 | # 19 | # To create a standard rocky Mineral: 20 | # 21 | # ``` 22 | # min1 = Mineral.new(108) 23 | # min1.to_s 24 | # ``` 25 | # 26 | # The above produces: 27 | # 28 | # ```text 29 | # "This is a mineral with id 108 and is called rock" 30 | # ``` 31 | # 32 | # Checks the hardness with `#hardness`. 33 | 34 | class Mineral 35 | include Hardness 36 | getter id 37 | getter name 38 | property crystal_struct 39 | 40 | # Creates a mineral with given parameters 41 | def initialize(@id : Int32, @name : String, @crystal_struct : String) 42 | end 43 | 44 | # Creates a mineral with as "rock", 0 hardness and unknown structure 45 | def initialize(@id : Int32) 46 | @name = "rock" 47 | @crystal_struct = "unknown" 48 | end 49 | 50 | # Prints out a description of this mineral 51 | def to_s 52 | puts "This is a mineral with id #{id} and is called #{name} " 53 | puts "It has #{crystal_struct} as crystal structure" 54 | end 55 | 56 | # Returns object properties in csv-format 57 | def to_csv 58 | "#{id},#{name},#{hardness},#{crystal_struct}" 59 | end 60 | 61 | def ==(other : self) 62 | id == other.id 63 | end 64 | 65 | def ==(other) 66 | false 67 | end 68 | 69 | # Returns crystal structure of this mineral 70 | def kind_of_crystal 71 | @crystal_struct 72 | end 73 | 74 | # :nodoc: 75 | class Helper # no docs are created for this class 76 | end # neither for private or protected classes 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /exercises/managing_projects/mineral/src/mineral/version.cr: -------------------------------------------------------------------------------- 1 | module Mineral 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /exercises/methods_and_procs/bubblesort.cr: -------------------------------------------------------------------------------- 1 | # Array#dup returns a new array with the same elements 2 | # Object#tap passes its object into the given block and, 3 | # after the block finishes, returns the object 4 | 5 | def bubblesort(input) 6 | input.dup.tap do |arr| 7 | arr.each_index do |i| 8 | (arr.size - 1).downto(i) do |j| 9 | # swap consecutive elements: 10 | arr[j], arr[j - 1] = arr[j - 1], arr[j] if yield arr[j - 1], arr[j] 11 | end 12 | end 13 | end 14 | end 15 | 16 | def bubblesort_ascending(input) 17 | bubblesort(input) { |a, b| a > b } 18 | end 19 | 20 | def bubblesort_descending(input) 21 | bubblesort(input) { |a, b| a < b } 22 | end 23 | 24 | input = [78, -56, 108, 42, 0] 25 | p bubblesort_ascending(input) # => [-56, 0, 42, 78, 108] 26 | p bubblesort_descending(input) # => [108, 78, 42, 0, -56] 27 | -------------------------------------------------------------------------------- /exercises/methods_and_procs/overloading.cr: -------------------------------------------------------------------------------- 1 | # version 1: 2 | def add(x : Int, y : Int) 3 | x + y 4 | end 5 | 6 | # version 2: 7 | def add(x : Number, y : Number) 8 | x + y 9 | end 10 | 11 | # version 3: 12 | def add(x : Number, y : String) 13 | x.to_s + y # convert a number to a string with to_s method 14 | end 15 | 16 | # version 4: generic version 17 | def add(x, y) 18 | x + y 19 | end 20 | 21 | # new methods: 22 | # version 5: 23 | def add(x : Number, y : Bool) 24 | y ? x : 0 25 | end 26 | 27 | # version 6: 28 | def add(x : String, y : String) 29 | if x.to_i? && y.to_i? 30 | add x.to_i, y.to_i # calls version 1 31 | else 32 | x + y 33 | end 34 | end 35 | 36 | add(2, 3) # (1) => 5 37 | add(1.0, 3.14) # (2) => 4.14 38 | add("Hello ", "Crystal") # (3) => "Hello Crystal" 39 | add(42, " times") # (4) => "42 times" 40 | add 5, true # (5) => 5 41 | add 13, false # (5) => 0 42 | add("12", "13") # (6) => 25 43 | -------------------------------------------------------------------------------- /exercises/methods_and_procs/overloading2.cr: -------------------------------------------------------------------------------- 1 | def add(x, y) 2 | y == 0 ? nil : x + y 3 | end 4 | 5 | n = add(2, 3) # => 5 6 | typeof(n) # => (Int32 | Nil) 7 | # n + 10 # => Runtime error: undefined method '+' for Nil 8 | 9 | if n 10 | p n + 10 # => 15 11 | end 12 | 13 | if n.is_a? Int32 14 | p n + 10 # => 15 15 | end 16 | -------------------------------------------------------------------------------- /exercises/methods_and_procs/return_proc.cr: -------------------------------------------------------------------------------- 1 | def incr 2 | n = 0 3 | ->{ n += 1; n } 4 | end 5 | 6 | typeof(incr) # => Proc(Int32) 7 | p incr.call # => 1 8 | p incr.call # => 1 9 | 10 | cnt = incr 11 | typeof(cnt) # => Proc(Int32) 12 | p cnt.call # => 1 13 | p cnt.call # => 2 14 | 15 | cnt2 = incr 16 | cnt2.call # => 1 17 | -------------------------------------------------------------------------------- /exercises/methods_and_procs/splat_a_tuple.cr: -------------------------------------------------------------------------------- 1 | def add(n, m) 2 | n + m 3 | end 4 | 5 | tpl = {42, 108} 6 | # add tpl # => Error: wrong number of arguments for 'add' (given 1, expected 2) 7 | add *tpl # => 150 8 | 9 | ntpl = {n: 42, m: 108} 10 | add **ntpl # => 150 11 | 12 | # 13 | 14 | 15 | def ret_named_tuple(a, **ntpl) 16 | # Return the captured named arguments as a NamedTuple 17 | ntpl 18 | end 19 | 20 | ret_named_tuple 1, y: 2, z: 3 # => {y: 2, z: 3} 21 | ret_named_tuple y: 2, a: 1, z: 3 # => {y: 2, z: 3} 22 | -------------------------------------------------------------------------------- /exercises/methods_and_procs/syntax_sugar.cr: -------------------------------------------------------------------------------- 1 | (1..10).map(&.**(3)) # => [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] 2 | (1..10).map &.**(3) # => [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] 3 | 4 | langs = %w[Java Go Crystal] 5 | 6 | langs.sort_by &.size # => ["Go", "Java", "Crystal"] 7 | 8 | langs.map &.split(//) 9 | # => [["J", "a", "v", "a"], ["G", "o"], ["C", "r", "y", "s", "t", "a", "l"]] 10 | langs.map &.split(//).sort 11 | # => [["J", "a", "a", "v"], ["G", "o"], ["C", "a", "l", "r", "s", "t", "y"]] 12 | langs.map &.split(//).sort.reverse 13 | # => [["v", "a", "a", "J"], ["o", "G"], ["y", "t", "s", "r", "l", "a", "C"]] 14 | langs.map &.split(//).sort.reverse.join 15 | # => ["vaaJ", "oG", "ytsrlaC"] 16 | langs.map(&.split(//).sort.reverse.join) # => ["vaaJ", "oG", "ytsrlaC"] 17 | -------------------------------------------------------------------------------- /exercises/methods_and_procs/total.cr: -------------------------------------------------------------------------------- 1 | def total(*items) 2 | total = 0 3 | items.each do |value| 4 | total += value 5 | end 6 | total 7 | end 8 | 9 | total(1, 2, 3) # => 6 # type of items is Tuple(Int32, Int32, Int32) 10 | total(1, 2, 3, 4.5) # => 10.5 # type of items is Tuple(Int32, Int32, Int32, Float64) 11 | 12 | def total(*items, initial = 0) 13 | total = initial 14 | items.each do |value| 15 | total += value 16 | end 17 | total 18 | end 19 | 20 | total(1, 2, 3) # => 6 21 | total(1, 2, 3, initial: 10) # => 16 22 | -------------------------------------------------------------------------------- /exercises/setting_up_a_Crystal_environment/hello_world.cr: -------------------------------------------------------------------------------- 1 | puts "Hello, Crystal World!" # => Hello Crystal world! 2 | p "Hello, Crystal World!" # => "Hello Crystal world!"" 3 | -------------------------------------------------------------------------------- /exercises/setting_up_a_Crystal_environment/overloading.cr: -------------------------------------------------------------------------------- 1 | # START:ovl1 2 | # overloading 1: 3 | def add(x : Int, y : Int) 4 | x + y 5 | end 6 | 7 | puts add(2, 3) # (1) => 5 8 | puts add(1.0, 3.14) # (2) => 9 | # Error: "no overload matches 'add' with types Float, Float" 10 | puts add("Hello ", "Crystal") # (3) => 11 | # Error: "no overload matches 'add' with types String, String" 12 | puts add(42, " times") # (4) 13 | # => Error: "no overload matches 'add' with types Int32, String" 14 | # END:ovl1 15 | 16 | # START:ovl2 17 | # overloading 2: 18 | 19 | 20 | def add(x : Number, y : Number) 21 | x + y 22 | end 23 | 24 | puts add(2, 3) # (1) => 5 25 | puts add(1.0, 3.14) # (2) => 4.14 26 | puts add("Hello ", "Crystal") # (3) => 27 | # Error: "no overload matches 'add' with types String, String" 28 | puts add(42, " times") # (4) 29 | # => Error: "no overload matches 'add' with types Int32, String" 30 | # END:ovl2 31 | 32 | # START:ovl3 33 | # overloading 3: 34 | 35 | 36 | def add(x, y) 37 | x + y 38 | end 39 | 40 | puts add(2, 3) # (1) => 5 41 | puts add(1.0, 3.14) # (2) => 4.14 42 | puts add("Hello ", "Crystal") # (3) => "Hello Crystal" 43 | puts add(42, " times") # (4) 44 | # => Error: "no overload matches 'add' with types Int32, String" 45 | # END:ovl3 46 | 47 | # START:ovl4 48 | # overloading 4: 49 | 50 | 51 | def add(x : Number, y : String) 52 | x.to_s + y # convert a number to a string with to_s method 53 | end 54 | 55 | puts add(2, 3) # (1) => 5 56 | puts add(1.0, 3.14) # (2) => 4.14 57 | puts add("Hello ", "Crystal") # (3) => "Hello Crystal" 58 | puts add(42, " times") # (4) => "42 times" 59 | # END:ovl4 60 | -------------------------------------------------------------------------------- /exercises/setting_up_a_Crystal_environment/test.cr: -------------------------------------------------------------------------------- 1 | x = 1 2 | puts x + 1 3 | puts x.snap -------------------------------------------------------------------------------- /exercises/types_and_control_flow/compile_runtime.cr: -------------------------------------------------------------------------------- 1 | if rand < 0.5 2 | var1 = 7 3 | end 4 | var1 # => 7 or nil 5 | typeof(var1) # => (Int32 | Nil) 6 | var1.class # => Int32 7 | 8 | var1 = 42 9 | if rand < 0.5 10 | var1 = "Crystal" 11 | end 12 | var1 # => 42 (or "Crystal") 13 | typeof(var1) # => (Int32 | String) 14 | var1.class # => Int32 (or String) 15 | 16 | var1 = 42 17 | if rand < 0.7 18 | var1 = "Crystal" 19 | else 20 | var1 = true 21 | end 22 | var1 # => "Crystal" (or true) 23 | typeof(var1) # => (Bool | String) 24 | var1.class # => String (or Bool) 25 | 26 | if rand < 0.5 27 | var1 = 42 28 | else 29 | var1 = "Crystal" 30 | end 31 | var2 = var1 * 2 # => 84 (or "CrystalCrystal") 32 | typeof(var2) # => type is (Int32 | String) 33 | var2.class # => Int32 (or String) 34 | # var2 = var1 - 1 # => Error: undefined method '-' for String 35 | # solved: 36 | if var1.is_a?(Int32) 37 | var2 = var1 - 1 38 | end 39 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/destructuring.cr: -------------------------------------------------------------------------------- 1 | var1, var2, var3 = [78, 56, 42] # array 2 | var1, var2, var3 = {78, 56, 42} # tuple 3 | # Both give the same result: 4 | var1 # => 78 5 | var2 # => 56 6 | var3 # => 42 7 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/exception_union.cr: -------------------------------------------------------------------------------- 1 | begin 2 | a = 4 + 6 3 | rescue 4 | puts "an ex occurred" 5 | ensure 6 | puts a + 42 7 | # puts a.as(Int32) + 42 # => 52 8 | end 9 | # => Error, undefined method '+' for Nil 10 | # compile-time type is (Int32 | Nil) 11 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/hashes.cr: -------------------------------------------------------------------------------- 1 | h1 = Hash(Int32 | Char, Int32).new 2 | h1[1] = 42 3 | h1['C'] = 99 4 | h1 # => {1 => 42, 'C' => 99}" 5 | # h1["Crystal"] = 89 6 | # => Error: no overload matches 7 | # 'Hash(Char | Int32, Int32)#[]=' with types String, Int32 8 | 9 | h2 = {} of String | Int32 => Bool | String 10 | h2["Crystal"] = true 11 | h2["gold"] = "OK" 12 | h2[108] = "perfect" 13 | h2[13] = false 14 | h2 # => {"Crystal" => true, "gold" => "OK", 108 => "perfect", 13 => false} 15 | h2["Crystal"] = 89 16 | # => Error: no overload matches 'Hash(Int32 | String, Bool | String)#[]=' 17 | # with types String, Int32 18 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/if_elsif_else.cr: -------------------------------------------------------------------------------- 1 | if (num = 9) < 0 2 | puts "#{num}, is negative" 3 | elsif num < 10 4 | puts "#{num}, has 1 digit" 5 | else 6 | puts "#{num}, has multiple digits" 7 | end 8 | # => 9, has 1 digit 9 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/object_id.cr: -------------------------------------------------------------------------------- 1 | # Strings are immutable 2 | s = "Crystal" # => "Crystal" : String 3 | p s.object_id # => 4861712 : UInt64 4 | t = "Crystal" # => "Crystal" : String 5 | p t.object_id # => 4861712 : UInt64 6 | p s == t # => true 7 | p s === t # => true 8 | 9 | # 42.object_id # => undefined method 'object_id' for Int32 10 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/read_line.cr: -------------------------------------------------------------------------------- 1 | puts "Enter the numbers one by one, and end with an empty line:" 2 | arr = [] of Int8 3 | number = read_line 4 | arr << number.to_i8 5 | p arr 6 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/string_symbol.cr: -------------------------------------------------------------------------------- 1 | :carbon == "carbon" # => false : Bool 2 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/times_and_dates.cr: -------------------------------------------------------------------------------- 1 | puts Time.now # => 2017-05-29 11:42:13 +0200 2 | t = Time.new(2002, 10, 31, 2, 2, 2, 999, Time::Kind::Local) 3 | p t # => 2002-10-31 02:02:02 +0100 4 | puts t.millisecond # => 999 5 | puts t.day_of_week # => Thursday 6 | 7 | time = Time.new(2016, 2, 15, 10, 20, 30) 8 | time.year # => 2016 9 | time.month # => 2 10 | time.day # => 15 11 | time.hour # => 10 12 | time.minute # => 20 13 | time.second # => 30 14 | time.monday? # => true 15 | 16 | # Creating a time instance with a date only 17 | Time.new(2016, 2, 15) # => 2016-02-15 00:00:00 18 | 19 | # Specifying a time 20 | Time.new(2016, 2, 15, 10, 20, 30) # => 2016-02-15 10:20:30 UTC 21 | 22 | # Formatting 23 | time = Time.new(2015, 10, 12) 24 | time.to_s("%Y-%m-%d") # => "2015-10-12" 25 | 26 | # Time::Span 27 | Time.new(2015, 10, 10) - 5.days # => 2015-10-05 00:00:00 28 | 29 | # Time calculation returns a Time::Span instance 30 | span = Time.new(2015, 10, 10) - Time.new(2015, 9, 10) 31 | span.days # => 30 32 | span.total_hours # => 720 33 | span.total_minutes # => 43200 34 | 35 | # Calculation between Time::Span instances 36 | span_a = Time::Span.new(3, 0, 0) 37 | span_b = Time::Span.new(2, 0, 0) 38 | span = span_a - span_b 39 | span # => 01:00:00 40 | span.class # => Time::Span 41 | span.hours # => 1 42 | 43 | # Epoch 44 | puts Time.epoch(628232400) 45 | t = Time.new(1989, 11, 28, 5, 0, 0) # 1989-11-28 05:00:00 UTC 46 | puts t.epoch # => 628228800 47 | puts t.epoch_ms # => 628228800000 48 | 49 | # Time formatting 50 | puts Time.parse("2012-11-01 22:08:12", "%F %T") # => 2012-11-01 22:08:12 51 | puts Time.parse("Fri Oct 31 23:00:24 2014", "%c") # => 2014-10-31 23:00:24 52 | puts Time.parse("20150624", "%Y%m%d") # => 2015-06-24 00:00:00 53 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/union_types.cr: -------------------------------------------------------------------------------- 1 | # Union types: 2 | arr = ["anadite", "humite", "roselite"] 3 | # mineral = arr[4]? # => returns a value of type String | Nil 4 | if mineral = arr[4]? 5 | puts "The mineral at index 4 is : #{mineral}" 6 | else 7 | puts "No mineral at index 4" 8 | end 9 | # => No mineral at index 4 10 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/utf8.cr: -------------------------------------------------------------------------------- 1 | "hi 猫".each_char do |char| 2 | print char 3 | end # => hi 猫 4 | puts 5 | "hi 猫".each_codepoint do |pnt| 6 | print pnt; print "-" 7 | end 8 | puts # => 104-105-32-29483- 9 | "hi 猫".each_byte do |byte| 10 | print byte; print "-" 11 | end # => 104-105-32-231-140-171- 12 | -------------------------------------------------------------------------------- /exercises/types_and_control_flow/var1.cr: -------------------------------------------------------------------------------- 1 | if var1 = 1 2 | puts "inside if" 3 | var1 = 2 4 | puts var1 5 | end 6 | puts var1 # 2 7 | -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/index_server.cr: -------------------------------------------------------------------------------- 1 | # serving index.html 2 | require "http/server" 3 | 4 | port = 3000 5 | host = "127.0.0.1" 6 | mime = "text/html" 7 | 8 | server = HTTP::Server.new(host, port, [ 9 | HTTP::ErrorHandler.new, 10 | HTTP::LogHandler.new, 11 | ]) do |ctx| 12 | req = ctx.request 13 | ctx.response.content_type = mime 14 | 15 | if req.method == "GET" && req.path == "/public" 16 | filename = "./public/index.html" 17 | ctx.response.content_length = File.size(filename) 18 | ctx.response.content_type = mime 19 | File.open(filename) do |file| 20 | IO.copy(file, ctx.response) 21 | end 22 | next 23 | end 24 | end 25 | 26 | puts "Listening at #{host}:#{port}" 27 | server.listen 28 | -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/bountysource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/web_frameworks_and_shards/public/index_files/bountysource.png -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/count-data.js: -------------------------------------------------------------------------------- 1 | var DISQUSWIDGETS; 2 | 3 | if (typeof DISQUSWIDGETS != 'undefined') { 4 | DISQUSWIDGETS.displayCount({"text":{"and":"and","comments":{"zero":"0 Comments","multiple":"{num} Comments","one":"1 Comment"}},"counts":[{"id":"\/2017\/09\/25\/neuralegion-and-crystal","comments":5},{"id":"\/2017\/03\/23\/announcing-crystal-codecamp-sf2017","comments":7},{"id":"\/2017\/07\/31\/launching-the-2017-state-of-crystal-survey","comments":3}]}); 5 | } -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/count.js: -------------------------------------------------------------------------------- 1 | var DISQUSWIDGETS,disqus_domain,disqus_shortname; 2 | typeof DISQUSWIDGETS==="undefined"&&(DISQUSWIDGETS=function(){var f=document,a=f.getElementById("dsq-count-scr"),a=a&&a.src.match(/(https?:)?\/\/(?:www\.)?([\w_\-]+)\.((?:dev\.)?disqus\.(?:com|org)(?::\d+)?)/i),e={},s=f.head||f.body,j={},q={identifier:1,url:2};e.domain=a&&a[3]||disqus_domain||"disqus.com";e.forum=a&&a[2]||disqus_shortname;e.proto=a&&a[1]||"";e.getCount=function(b){var c;c=encodeURIComponent;var a=e.proto+"//"+e.forum+"."+e.domain+"/count-data.js?",d=[],k=0,l=10,r="",b=b||{};b.reset&& 3 | (j={},r="&_="+ +new Date);for(var b=[f.getElementsByTagName("A"),f.getElementsByClassName&&f.getElementsByClassName("disqus-comment-count")||[]],m,i,g,h,n=0;n=0;d--)a[d].innerHTML=c}};return e}());DISQUSWIDGETS.getCount(); -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/fly_io_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/web_frameworks_and_shards/public/index_files/fly_io_.png -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/icon.css: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: url(https://fonts.gstatic.com/s/materialicons/v29/2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2) format('woff2'); 7 | } 8 | /* cyrillic-ext */ 9 | @font-face { 10 | font-family: 'Roboto Mono'; 11 | font-style: normal; 12 | font-weight: 400; 13 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v4/hMqPNLsu_dywMa4C_DEpYzTOQ_MqJVwkKsUn0wKzc2I.woff2) format('woff2'); 14 | unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F; 15 | } 16 | /* cyrillic */ 17 | @font-face { 18 | font-family: 'Roboto Mono'; 19 | font-style: normal; 20 | font-weight: 400; 21 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v4/hMqPNLsu_dywMa4C_DEpYzUj_cnvWIuuBMVgbX098Mw.woff2) format('woff2'); 22 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 23 | } 24 | /* greek-ext */ 25 | @font-face { 26 | font-family: 'Roboto Mono'; 27 | font-style: normal; 28 | font-weight: 400; 29 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v4/hMqPNLsu_dywMa4C_DEpY0bcKLIaa1LC45dFaAfauRA.woff2) format('woff2'); 30 | unicode-range: U+1F00-1FFF; 31 | } 32 | /* greek */ 33 | @font-face { 34 | font-family: 'Roboto Mono'; 35 | font-style: normal; 36 | font-weight: 400; 37 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v4/hMqPNLsu_dywMa4C_DEpY2o_sUJ8uO4YLWRInS22T3Y.woff2) format('woff2'); 38 | unicode-range: U+0370-03FF; 39 | } 40 | /* vietnamese */ 41 | @font-face { 42 | font-family: 'Roboto Mono'; 43 | font-style: normal; 44 | font-weight: 400; 45 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v4/hMqPNLsu_dywMa4C_DEpY76up8jxqWt8HVA3mDhkV_0.woff2) format('woff2'); 46 | unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB; 47 | } 48 | /* latin-ext */ 49 | @font-face { 50 | font-family: 'Roboto Mono'; 51 | font-style: normal; 52 | font-weight: 400; 53 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v4/hMqPNLsu_dywMa4C_DEpYyYE0-AqJ3nfInTTiDXDjU4.woff2) format('woff2'); 54 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; 55 | } 56 | /* latin */ 57 | @font-face { 58 | font-family: 'Roboto Mono'; 59 | font-style: normal; 60 | font-weight: 400; 61 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v4/hMqPNLsu_dywMa4C_DEpY44P5ICox8Kq3LLUNMylGO4.woff2) format('woff2'); 62 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215; 63 | } 64 | 65 | .material-icons { 66 | font-family: 'Material Icons'; 67 | font-weight: normal; 68 | font-style: normal; 69 | font-size: 24px; 70 | line-height: 1; 71 | letter-spacing: normal; 72 | text-transform: none; 73 | display: inline-block; 74 | white-space: nowrap; 75 | word-wrap: normal; 76 | direction: ltr; 77 | -moz-font-feature-settings: 'liga'; 78 | -moz-osx-font-smoothing: grayscale; 79 | } 80 | -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/manas-orange.svg: -------------------------------------------------------------------------------- 1 | m 2 | -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/mdavid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/web_frameworks_and_shards/public/index_files/mdavid.jpg -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/neuralegion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/web_frameworks_and_shards/public/index_files/neuralegion.jpg -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/openredis.svg: -------------------------------------------------------------------------------- 1 | openredis -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/public/index_files/sdogruyol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ivo-Balbaert/programming_crystal/3de67bfd008c318d3ed9b5fadbc69bd0a4806362/exercises/web_frameworks_and_shards/public/index_files/sdogruyol.jpg -------------------------------------------------------------------------------- /exercises/web_frameworks_and_shards/time_server.cr: -------------------------------------------------------------------------------- 1 | require "http/server" 2 | 3 | server = HTTP::Server.new(5000) do |ctx| 4 | ctx.response.content_type = "text/xml" 5 | time = Time.now 6 | message = if time.hour < 12 7 | "Good morning" 8 | elsif time.hour < 18 9 | "Good afternoon" 10 | else 11 | "Good night" 12 | end 13 | ctx.response.print "" 15 | end 16 | 17 | puts "Listening on http://localhost:5000" 18 | server.listen 19 | # => in browser with the URL http://localhost:5000/ 20 | # This XML file does not appear to have any style information associated with it. 21 | # The document tree is shown below. 22 | # 27 | -------------------------------------------------------------------------------- /exercises/why_crystal/overloading2.cr: -------------------------------------------------------------------------------- 1 | # START:ovl1 2 | # overloading 1: 3 | def add(x : Int, y : Int) 4 | x + y 5 | end 6 | 7 | puts add(2, 3) # (1) => 5 8 | puts add(1.0, 3.14) # (2) => 9 | # Error: "no overload matches 'add' with types Float, Float" 10 | puts add("Hello ", "Crystal") # (3) => 11 | # Error: "no overload matches 'add' with types String, String" 12 | puts add(42, " times") # (4) 13 | # => Error: "no overload matches 'add' with types Int32, String" 14 | # END:ovl1 15 | 16 | # START:ovl2 17 | # overloading 2: 18 | 19 | 20 | def add(x : Number, y : Number) 21 | x + y 22 | end 23 | 24 | puts add(2, 3) # (1) => 5 25 | puts add(1.0, 3.14) # (2) => 4.14 26 | puts add("Hello ", "Crystal") # (3) => 27 | # Error: "no overload matches 'add' with types String, String" 28 | puts add(42, " times") # (4) 29 | # => Error: "no overload matches 'add' with types Int32, String" 30 | # END:ovl2 31 | 32 | # START:ovl3 33 | # overloading 3: 34 | 35 | 36 | def add(x, y) 37 | x + y 38 | end 39 | 40 | puts add(2, 3) # (1) => 5 41 | puts add(1.0, 3.14) # (2) => 4.14 42 | puts add("Hello ", "Crystal") # (3) => "Hello Crystal" 43 | puts add(42, " times") # (4) 44 | # => Error: "no overload matches 'add' with types Int32, String" 45 | # END:ovl3 46 | 47 | # START:ovl4 48 | # overloading 4: 49 | 50 | 51 | def add(x : Number, y : String) 52 | x.to_s + y # convert a number to a string with to_s method 53 | end 54 | 55 | puts add(2, 3) # (1) => 5 56 | puts add(1.0, 3.14) # (2) => 4.14 57 | puts add("Hello ", "Crystal") # (3) => "Hello Crystal" 58 | puts add(42, " times") # (4) => "42 times" 59 | # END:ovl4 60 | 61 | puts add("times", 42) # Error: no overload matches 'String#+' with type Int32 62 | 63 | 64 | def add(x, y : Number) 65 | x + y.to_s 66 | end 67 | -------------------------------------------------------------------------------- /exercises/why_crystal/test.cr: -------------------------------------------------------------------------------- 1 | x = 1 2 | puts x + 1 3 | puts x.snap -------------------------------------------------------------------------------- /exercises/working_with_modules/comparable2.cr: -------------------------------------------------------------------------------- 1 | class Person 2 | include Comparable(Person) 3 | 4 | getter name, age 5 | 6 | def initialize(@name : String, @age : Int32) 7 | end 8 | 9 | def <=>(other : self) # other must be of type self, which is Person 10 | if self.name < other.name # here self is the current Person object 11 | -1 12 | elsif self.name > other.name 13 | 1 14 | else # == case 15 | 0 16 | end 17 | end 18 | end 19 | 20 | john = Person.new("John", 42) 21 | martha = Person.new("Martha", 74) 22 | diana = Person.new("Diana", 42) 23 | john > martha # => false 24 | john == diana # => false 25 | -------------------------------------------------------------------------------- /exercises/working_with_modules/math_sin.cr: -------------------------------------------------------------------------------- 1 | require "./moral" 2 | 3 | y = Math.sin(Math::PI/4) # => 0.70710678118654746 4 | wrongdoing = Moral.sin(Moral::VERY_BAD) # => Assessing the sin of 0 5 | --------------------------------------------------------------------------------