├── LICENSE ├── README.md ├── TasksForCourseApply ├── 1-KthFactorial.md ├── 2-Quaternion.md └── 3-Taylor.md ├── week0 ├── 0-setup │ └── README.md ├── 1-standard-types │ ├── .rubocop.yml │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb └── README.md ├── week1 ├── 1-fmi-tribute │ ├── .rubocop.yml │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb ├── 2-hashes │ ├── .rubocop.yml │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb ├── 3-my-enumerable │ ├── .rubocop.yml │ ├── Gemfile │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb └── README.md ├── week2 ├── 1-vectors │ ├── .rubocop.yml │ ├── Gemfile │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb └── 2-tracks │ ├── .rubocop.yml │ ├── Gemfile │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb ├── week3 └── 1-game-of-life │ ├── .rubocop.yml │ ├── Gemfile │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb ├── week4 └── 1-shopping-cart │ ├── .rubocop.yml │ ├── Gemfile │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb ├── week5 └── 1-meta │ ├── .rubocop.yml │ ├── Gemfile │ ├── README.md │ ├── Rakefile │ ├── solution.rb │ └── solution_test.rb └── week6 └── 1-simpletest └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 HackBulgaria 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Core-Ruby-1 2 | 3 | The repository for the [Hack Bulgaria][] [Core Ruby][] class. October 2014. Visit the class [website][Core Ruby] at [http://ruby.hackbulgaria.com][Core Ruby]. 4 | 5 | ## Program 6 | 7 | Initial draft as of _August 31, 2014_. 8 | 9 | Week | Material 10 | ---- | -------- 11 | 0 | Ruby introduction. Rbenv/Ruby Installer and Git setup. Introduction to the basic Ruby types. 12 | 1 | In depth look of Array, Hash, String, Symbol, Numeric. Ruby blocks. Enumerable and all it's magic. 13 | 2 | OOP Introduction. Classes, Modules and Constants. Method resolution lookup and ancestor chain. Custom enumerable objects. 14 | 3 | Lambda vs Proc semantics. Binding. Exceptions. 15 | 4 | Kernel. Module functions. require vs load. Advanced Enumerable. Enumerator. Regexp. 16 | 5 | Singleton classes. Dynamic method definition. Don't be evil: class_eval and instance_eval. Constants, instance variables API. 17 | 6 | Freedom patching. Refinements. Keyword arguments. All the rage in 2.1. 18 | 7 | Threading or: How I Learned to Stop Worrying and Learned to Love the GIL. JRuby and Rubinius. Threading locals. Fibers. Basic networking. 19 | 8 | RubyGems: The structure of a gem. Gem specifications. Rake. Bundler. 20 | 21 | [Hack Bulgaria]: http://hackbulgaria.com 22 | [Core Ruby]: http://ruby.hackbulgaria.com 23 | -------------------------------------------------------------------------------- /TasksForCourseApply/1-KthFactorial.md: -------------------------------------------------------------------------------- 1 | # Kth Factorial 2 | 3 | In mathematics, the factorial of a non-negative integer `n`, denoted by n!, is 4 | the product of all positive integers less than or equal to `n`. For example: 5 | 6 | ``` 7 | 5! = 5 * 4 * 3 * 2 * 1 = 120 8 | ``` 9 | 10 | To make things more interesting, we want you to find the `kth` factorial of any 11 | number `n`. 12 | 13 | ``` 14 | kth_factorial = (n!) * (n!) * (n!) ... k times 15 | ``` 16 | 17 | The interface of the function is `kth_factorial(k, n)`. Think about the 18 | constraints of the types of input `k` and `n` parameters and the output of the 19 | whole function. 20 | -------------------------------------------------------------------------------- /TasksForCourseApply/2-Quaternion.md: -------------------------------------------------------------------------------- 1 | # Quaternion (optional) 2 | 3 | [Quaternions][Quaternion] are cool! They find uses in both theoretical and 4 | applied mathematics, in particular for calculations involving three-dimensional 5 | rotations such as in three-dimensional computer graphics and computer vision. 6 | 7 | Choose an OOP language of your liking and design a [Quaternion] class 8 | implementing all of the properties by its [definition]. 9 | 10 | _Hint: you can name the component 1 as `e`._ 11 | 12 | The interface is up to you. How should you create a Quaternion? Should you 13 | override operators for [Quaternion] operations, if your language of choice 14 | supports it? Should you have any static properties? Why? 15 | 16 | Please, answer all those question in a comment above the class definition. 17 | 18 | [Quaternion]: http://en.wikipedia.org/wiki/Quaternion 19 | [definition]: http://mathworld.wolfram.com/Quaternion.html 20 | 21 | ## Optional task 22 | 23 | You can apply without solving this problem. But if you manage to solve it, this will help you in the interview process :) 24 | -------------------------------------------------------------------------------- /TasksForCourseApply/3-Taylor.md: -------------------------------------------------------------------------------- 1 | # Taylor Series 2 | 3 | Because we know you love your calculus classes, we present you the final of our 4 | _Y U GIVE US SOME MUCH MATH_ series with the, ahem, [Taylor series]. 5 | 6 | In mathematics, a [Taylor series] is a representation of a function as an 7 | infinite sum of terms that are calculated from the values of the function's 8 | derivatives at a single point. It is common practice to approximate a function 9 | by using a finite number of terms of its [Taylor series]. 10 | 11 | In particular, you can easily calculate common trigonometric functions. And 12 | that's want we want you to do. Calculate [Sine] and [Cosine] using their 13 | respective [Taylor series]. You can find them [here]. 14 | 15 | The interface for the [Sine] and [Cosine] functions should be `sine(x, 16 | precision)` and `cosine(x, precision)`, where `precision` is the upper limit of 17 | `n`. The higher the `precision` is, the better the approximation. 18 | 19 | [Taylor series]: http://en.wikipedia.org/wiki/Taylor_series 20 | [Sine]: http://en.wikipedia.org/wiki/Sine 21 | [Cosine]: http://en.wikipedia.org/wiki/Cosine 22 | [here]: http://en.wikipedia.org/wiki/Trigonometric_functions#Series_definitions 23 | -------------------------------------------------------------------------------- /week0/0-setup/README.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | Installing Ruby 2.1.3, isn't newbie friendly. Here are our tips on how to 4 | install it on your favourite OS. 5 | 6 | ## Windows 7 | 8 | The easiest way to get Ruby 2.1.3 on Windows is this [Ruby Installer][]. Don't 9 | forget to add the `C:\Ruby-213\bin` to the beginning of `%PATH%`. 10 | [Here][Windows Path] is how to do it. 11 | 12 | ## Linux & OSX 13 | 14 | Follow the instructions on [rbenv installation page][]. After rbenv is 15 | installed, run the following in a fresh terminal session. 16 | 17 | ```bash 18 | rbenv install 2.1.3 && rbenv global 2.1.3 19 | ``` 20 | 21 | [Ruby Intaller]: http://rubyinstaller.org/ 22 | [Windows Path]: http://www.computerhope.com/issues/ch000549.htm 23 | [rbenv installation page]: https://github.com/sstephenson/rbenv#installation 24 | -------------------------------------------------------------------------------- /week0/1-standard-types/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week0/1-standard-types/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week0/1-standard-types/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ast (2.0.0) 5 | astrolabe (1.3.0) 6 | parser (>= 2.2.0.pre.3, < 3.0) 7 | minitest (5.4.2) 8 | parser (2.2.0.pre.5) 9 | ast (>= 1.1, < 3.0) 10 | slop (~> 3.4, >= 3.4.5) 11 | powerpack (0.0.9) 12 | rainbow (2.0.0) 13 | rake (10.3.2) 14 | rubocop (0.26.1) 15 | astrolabe (~> 1.3) 16 | parser (>= 2.2.0.pre.4, < 3.0) 17 | powerpack (~> 0.0.6) 18 | rainbow (>= 1.99.1, < 3.0) 19 | ruby-progressbar (~> 1.4) 20 | ruby-progressbar (1.6.0) 21 | slop (3.6.0) 22 | 23 | PLATFORMS 24 | ruby 25 | 26 | DEPENDENCIES 27 | minitest 28 | rake 29 | rubocop 30 | -------------------------------------------------------------------------------- /week0/1-standard-types/README.md: -------------------------------------------------------------------------------- 1 | # Standard Types 2 | 3 | Welcome to the first set of problems for week 0. Here are a couple of resources 4 | you may find useful, while digging into them: 5 | 6 | * http://www.ruby-doc.org/core-2.1.3/Array.html 7 | * http://www.ruby-doc.org/core-2.1.3/Hash.html 8 | * http://www.ruby-doc.org/core-2.1.3/String.html 9 | 10 | If you don't feel confident with the building blocks yet, a couple of lessons 11 | on http://tryruby.org/ can help you digest the above documentation better. 12 | 13 | ## Solutions 14 | 15 | The file to write your solutions in is called `solutions.rb`. For the following 16 | problems, you need to define several methods. 17 | 18 | A boilerplate of a test file is provided in `solution_test.rb`. You can write 19 | your tests there and work your way in a TDD fusion. 20 | 21 | The workflow is write a test. See it fail. Write a solution that makes it pass. 22 | Then repeat for as many corner cases you can think of and move to the next 23 | problem. 24 | 25 | We'll help you with that on the spot, if you don't get it now, don't worry. 26 | 27 | ## Problems 28 | 29 | To run the tests for the problems install bundler with `gem install bundler`. 30 | 31 | ```bash 32 | # This will install all the dependencies for the current set of problems. 33 | bundle install 34 | 35 | # To run just the tests. 36 | bundle exec rake test 37 | 38 | # To run just the rubocop style validations. 39 | bundle exec rake rubocop 40 | 41 | # Runs both the tests and the default style checks. 42 | bundle exec rake 43 | ``` 44 | 45 | ### Histogram 46 | 47 | Create a histogram with each character and the number of its occurrences in 48 | arbitrary string. 49 | 50 | ```ruby 51 | def histogram(string) 52 | # Your code goes here. 53 | end 54 | 55 | >> histogram "abraca" 56 | => {"a"=>3, "b"=>1, "r"=>1, "c"=>1} 57 | ``` 58 | 59 | ### Prime 60 | 61 | A prime number is any integer greater than 1 that is divisible only by 1 and 62 | itself. Bonus points for an outline of proof of why 1 isn't a prime number. 63 | Tip: ask @RadoRado. 64 | 65 | ```ruby 66 | def prime?(n) 67 | # Your code goes here. 68 | end 69 | 70 | >> prime? 7 71 | => true 72 | ``` 73 | 74 | ### Ordinal 75 | 76 | In linguistics, ordinal numbers are words representing position or rank in a 77 | sequential order. The order may be of size, importance, chronology, and so on. 78 | In English, they are adjectives such as 'third' and 'tertiary'. 79 | 80 | Ordinal numbers may be written in English with numerals and letter suffixes: 81 | 1st, 2nd or 2d, 3rd or 3d, 4th, 11th, 21st, 101st, 477th, etc. In some 82 | countries, written dates omit the suffix, although it is nevertheless 83 | pronounced. 84 | 85 | ```ruby 86 | def ordinal(n) 87 | # Your code goes here. 88 | end 89 | 90 | >> ordinal 2 91 | => 2nd 92 | 93 | >> ordinal 112 94 | => 112th 95 | ``` 96 | 97 | See http://en.wikipedia.org/wiki/Ordinal_number_(linguistics) 98 | 99 | ### Palindrome 100 | 101 | A palindrome is a word, phrase, number, or other sequence of symbols or 102 | elements that reads the same forward or reversed, with general allowances for 103 | adjustments to punctuation and word dividers. 104 | 105 | ```ruby 106 | def palindrome?(object) 107 | # Your code goes here. 108 | end 109 | 110 | >> palindome? 12321 111 | => true 112 | 113 | >> palindome? 'Race car' 114 | => true 115 | ``` 116 | 117 | ### Anagram 118 | 119 | An anagram is a type of word play, the result of rearranging the letters of a 120 | word or phrase to produce a new word or phrase, using all the original letters 121 | exactly once; for example Torchwood can be rearranged into Doctor Who. 122 | 123 | ```ruby 124 | def anagram?(word, other) 125 | # Your code goes here. 126 | end 127 | 128 | >> anagram? 'silent', 'listen' 129 | => true 130 | 131 | >> anagram? 'Mr Mojo Risin', 'Jim Morisson' 132 | => false 133 | ``` 134 | 135 | ### Remove Prefix 136 | 137 | Given the string `Ladies Night Out` and the prefix `Ladies `, this operation 138 | should produce the string `Night Out`. 139 | 140 | 141 | ```ruby 142 | def remove_prefix(string, prefix) 143 | # Your code goes here. 144 | end 145 | 146 | >> remove_prefix 'Ladies Night Out', 'Ladies' 147 | => "Night Out" 148 | ``` 149 | 150 | ### Remove Suffix 151 | 152 | Given the string `Ladies Night Out` and the suffix ` Night Out`, this operation 153 | should produce the string `Ladies`. 154 | 155 | 156 | ```ruby 157 | def remove_suffix(string, suffix) 158 | # Your code goes here. 159 | end 160 | 161 | >> remove_suffix 'Ladies Night Out', ' Night Out' 162 | => "Ladies" 163 | ``` 164 | 165 | ### Digits 166 | 167 | Given the integer `n`, transform it to an array of its digits. 168 | 169 | ```ruby 170 | def digits(n) 171 | # Your code goes here. 172 | end 173 | 174 | >> digits 12345 175 | => [1, 2, 3, 4, 5] 176 | ``` 177 | 178 | ### Fizz Buzz 179 | 180 | 181 | Players generally sit in a circle. The player designated to go first says the 182 | number "1", and each player thenceforth counts one number in turn. However, any 183 | number divisible by three is replaced by the word fizz and any divisible by 184 | five by the word buzz. Numbers divisible by both become fizz buzz. A player who 185 | hesitates or makes a mistake is eliminated from the game. For example, a 186 | typical round of fizz buzz would start as follows: 187 | 188 | ``` 189 | 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz, 16, 190 | 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, Fizz Buzz, 31, 191 | 32, Fizz, 34, Buzz, Fizz, ... 192 | ``` 193 | 194 | ```ruby 195 | def fizzbuzz(range) 196 | # Your code goes here. 197 | end 198 | 199 | >> fizzbuzz 1..7 200 | => [1, 2, :fizz, 4, :buzz, :fizz, 7] 201 | ``` 202 | 203 | ## Extra Problems 204 | 205 | ### Count 206 | 207 | Given any array, return a hash with the count of every object. 208 | 209 | ```ruby 210 | def count(array) 211 | # Your code goes here. 212 | end 213 | 214 | >> count [1, 2, 3, 1] 215 | => {1=>2, 2=>1, 3=>1} 216 | 217 | >> count %w(this is an array of words words words) 218 | => {"this"=>1, "is"=>1, "an"=>1, "array"=>1, "of"=>1, "words"=>3} 219 | ``` 220 | 221 | ### Count Words 222 | 223 | Create a function which counts the words in a variadic list of sentences. There 224 | should be no difference between `Word` and `word`. 225 | 226 | ```ruby 227 | def count_words(*sentences) 228 | # Your code goes here. 229 | end 230 | 231 | >> count_words "This is a sentence, bro.", "Bro, this is it." 232 | => {"this"=>2, "is"=>2, "a"=>1, "bro"=>2, "it"=>1, "sentence"=>1} 233 | 234 | Bonus, catch words with apostrophes like `won't`. 235 | ``` 236 | 237 | ## Easy 238 | 239 | Solved the problems already? Try to rewrite them in the minimal amounts of 240 | code, without sacrificing readability. 241 | -------------------------------------------------------------------------------- /week0/1-standard-types/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week0/1-standard-types/solution.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackBulgaria/Core-Ruby-1/7e43a7f9e04cb94de189655773d19015f0dd2b8d/week0/1-standard-types/solution.rb -------------------------------------------------------------------------------- /week0/1-standard-types/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class SolutionTest < Minitest::Unit::TestCase 6 | def test_the_truth 7 | assert_equal true, true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /week0/README.md: -------------------------------------------------------------------------------- 1 | # Materials & Suggestions 2 | 3 | Welcome to the first ever Core Ruby class in [Hack Bulgaria][]! We're going to give you a couple of existing materials to wet your appetite. 4 | 5 | ## The PickAxe 6 | 7 | A great book to get you started. You can [read][PickAxe] it online for free! 8 | 9 | ## Why's Poignant Guide to Ruby 10 | 11 | [![image](http://mislav.uniqpath.com/poignant-guide/images/2007-cover-open.jpg)](http://mislav.uniqpath.com/poignant-guide/images/2007-cover-open.jpg) 12 | 13 | If you are feeling a bit more adventurous, this is an interesting take on the first steps in Ruby. 14 | 15 | You can [read][why] it online. Soundtrack included. 16 | 17 | ## FMI 18 | 19 | The parrallel Ruby course in the Sofia University. If you have the time, please, do yourself a favor and visit their lectures Monday and Wednesday. The best Ruby lectures by far and away. 20 | 21 | Visit their [website][fmi] for more information. 22 | 23 | Send a shout-out to @mitio and @skanev while there :heart: 24 | 25 | [PickAxe]: http://ruby-doc.com/docs/ProgrammingRuby/ 26 | [why]: http://mislav.uniqpath.com/poignant-guide/ 27 | [fmi]: http://fmi.ruby.bg/ 28 | [Hack Bulgaria]: https://hackbulgaria.com 29 | -------------------------------------------------------------------------------- /week1/1-fmi-tribute/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week1/1-fmi-tribute/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week1/1-fmi-tribute/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ast (2.0.0) 5 | astrolabe (1.3.0) 6 | parser (>= 2.2.0.pre.3, < 3.0) 7 | minitest (5.4.2) 8 | parser (2.2.0.pre.5) 9 | ast (>= 1.1, < 3.0) 10 | slop (~> 3.4, >= 3.4.5) 11 | powerpack (0.0.9) 12 | rainbow (2.0.0) 13 | rake (10.3.2) 14 | rubocop (0.26.1) 15 | astrolabe (~> 1.3) 16 | parser (>= 2.2.0.pre.4, < 3.0) 17 | powerpack (~> 0.0.6) 18 | rainbow (>= 1.99.1, < 3.0) 19 | ruby-progressbar (~> 1.4) 20 | ruby-progressbar (1.6.0) 21 | slop (3.6.0) 22 | 23 | PLATFORMS 24 | ruby 25 | 26 | DEPENDENCIES 27 | minitest 28 | rake 29 | rubocop 30 | -------------------------------------------------------------------------------- /week1/1-fmi-tribute/README.md: -------------------------------------------------------------------------------- 1 | # FMI 2 | 3 | 2011 was a great year for Ruby. Colomb have just discovered the new earth, the 4 | first space shuffle has landed on Mars and the dinosaurs have just went MIA. In 5 | this great age of time, FMI had a great Ruby student, named Genadi. 6 | 7 | Let me share my experience with you and present you with my [first] ever Ruby 8 | homework. 9 | 10 | :kiss: to [@skanev] and [@mitio] for this one. 11 | 12 | ## Resources 13 | 14 | Enumerable is a gem. Go through its documentation. Array builds on top of it. 15 | 16 | * http://www.ruby-doc.org/core-2.1.3/Enumerable.html 17 | * http://www.ruby-doc.org/core-2.1.3/Array.html 18 | 19 | ## Handycap 20 | 21 | Avoid using `Enumerable#each` and you get a sticker :) 22 | 23 | [@skanev]: http://github.com/skanev 24 | [@mitio]: http://github.com/mitio 25 | [first]: http://2011.fmi.ruby.bg/tasks/1 26 | -------------------------------------------------------------------------------- /week1/1-fmi-tribute/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week1/1-fmi-tribute/solution.rb: -------------------------------------------------------------------------------- 1 | class Array 2 | # Your code goes here. 3 | end 4 | -------------------------------------------------------------------------------- /week1/1-fmi-tribute/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class ArrayTest < Minitest::Test 6 | def test_to_hash 7 | assert_equal({one: 1, two: 2}, [[:one, 1], [:two, 2]].to_hash) 8 | end 9 | 10 | def test_index_by 11 | assert_equal({'Coltrane' => 'John Coltrane', 'Davis' => 'Miles Davis' }, ['John Coltrane', 'Miles Davis'].index_by { |name| name.split(' ').last }) 12 | end 13 | 14 | def test_occurences_count 15 | assert_equal({foo: 2, bar: 1}, [:foo, :bar, :foo].occurences_count) 16 | end 17 | 18 | def test_subarray_count 19 | assert_equal 2, [1, 2, 3, 2, 3, 1].subarray_count([2, 3]) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /week1/2-hashes/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week1/2-hashes/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week1/2-hashes/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | ast (2.0.0) 5 | astrolabe (1.3.0) 6 | parser (>= 2.2.0.pre.3, < 3.0) 7 | minitest (5.4.2) 8 | parser (2.2.0.pre.5) 9 | ast (>= 1.1, < 3.0) 10 | slop (~> 3.4, >= 3.4.5) 11 | powerpack (0.0.9) 12 | rainbow (2.0.0) 13 | rake (10.3.2) 14 | rubocop (0.26.1) 15 | astrolabe (~> 1.3) 16 | parser (>= 2.2.0.pre.4, < 3.0) 17 | powerpack (~> 0.0.6) 18 | rainbow (>= 1.99.1, < 3.0) 19 | ruby-progressbar (~> 1.4) 20 | ruby-progressbar (1.6.0) 21 | slop (3.6.0) 22 | 23 | PLATFORMS 24 | ruby 25 | 26 | DEPENDENCIES 27 | minitest 28 | rake 29 | rubocop 30 | -------------------------------------------------------------------------------- /week1/2-hashes/README.md: -------------------------------------------------------------------------------- 1 | # FMI 2 | 3 | How can I follow those FMI problems, heh? Watashi wa besuto o tsukushimasu! 4 | 5 | ## Resources 6 | 7 | Enumerable is a gem. Go through its documentation. Hash builds on top of it. 8 | 9 | * http://www.ruby-doc.org/core-2.1.3/Enumerable.html 10 | * http://www.ruby-doc.org/core-2.1.3/Hash.html 11 | 12 | ## Problems 13 | 14 | ### Hash#pick 15 | 16 | `Hash#pick` returns a new hash, with only the specified keys in it. 17 | 18 | ```ruby 19 | class Hash 20 | def pick(*keys) 21 | # Your code goes here. 22 | end 23 | end 24 | 25 | >> {a: 1, b: 2, c: 3}.pick(:a, :b) 26 | => {:a=>1, :b=>2} 27 | ``` 28 | 29 | ### Hash#except 30 | 31 | `Hash#except` returns a new hash, without the specified keys in it. Kind of like 32 | a reversed `Hash#pluck`. 33 | 34 | ```ruby 35 | class Hash 36 | def except(*keys) 37 | # Your code goes here. 38 | end 39 | end 40 | 41 | >> {a: 1, b: 2, d: nil}.except(:d) 42 | => {:a=>1, :b=>2} 43 | ``` 44 | 45 | ### Hash#compact_values 46 | 47 | `Hash#compact_values` returns a new hash, with only the truthy keys in it. 48 | 49 | ```ruby 50 | class Hash 51 | def compact_values 52 | # Your code goes here. 53 | end 54 | end 55 | 56 | >> {a: 1, b: 2, c: false, d: nil}.compact_values 57 | => {:a=>1, :b=>2} 58 | ``` 59 | 60 | ### Hash#defaults 61 | 62 | `Hash#defaults` returns a new hash, setting values only if they were not already 63 | present in the hash. 64 | 65 | ```ruby 66 | class Hash 67 | def defaults(hash) 68 | # Your code goes here. 69 | end 70 | end 71 | 72 | >> {a: 1, b: 2}.defaults(a: 4, c: 3) 73 | => {:a=>1, :b=>2, :c=>3} 74 | ``` 75 | 76 | ## Bang Bang 77 | 78 | Add bang version methods (e.g. Hash#pick!) that change the hash inplace. Think 79 | whether you can reuse the implementations with the non-bang version methods. 80 | 81 | [@skanev]: http://github.com/skanev 82 | [@mitio]: http://github.com/mitio 83 | -------------------------------------------------------------------------------- /week1/2-hashes/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week1/2-hashes/solution.rb: -------------------------------------------------------------------------------- 1 | class Hash 2 | # Your code goes here. 3 | end 4 | -------------------------------------------------------------------------------- /week1/2-hashes/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class HashTest < Minitest::Test 6 | def test_the_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /week1/3-my-enumerable/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week1/3-my-enumerable/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week1/3-my-enumerable/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | The great power of Ruby iteration comes out of a simple module. I bet, you can 4 | implement part of it as well. 5 | 6 | ## Resources 7 | 8 | Reading the Enumerable documentation one more time won't hurt. Read it again, 9 | and again, and again... You get the idea :) 10 | 11 | * http://www.ruby-doc.org/core-2.1.3/Enumerable.html 12 | 13 | ## My Enumerable 14 | 15 | Implement a module called `MyEnumerable` which implements a similar module to 16 | Enumerable, but with own little twist. _Meaning, we have methods Enumerable 17 | doesn't, we named filter how we liked it, etc._ 18 | 19 | ```ruby 20 | module MyEnumerable 21 | def map 22 | # Your code goes here. 23 | end 24 | 25 | def filter 26 | # Your code goes here. 27 | end 28 | 29 | def reject 30 | # Your code goes here. 31 | end 32 | 33 | def reduce(initial = nil) 34 | # Your code goes here. 35 | end 36 | 37 | def any? 38 | # Your code goes here. 39 | end 40 | 41 | def one? 42 | # Your code goes here. 43 | end 44 | 45 | def all? 46 | # Your code goes here. 47 | end 48 | 49 | # Yield each consequative n elements. 50 | def each_cons(n) 51 | # Your code goes here. 52 | end 53 | 54 | def include?(element) 55 | # Your code goes here. 56 | end 57 | 58 | # Count the occurences of an element in the collection. If no element is 59 | # given, count the size of the collection. 60 | def count(element = nil) 61 | # Your code goes here. 62 | end 63 | 64 | # Count the size of the collection. 65 | def size 66 | # Your code goes here. 67 | end 68 | 69 | # Groups the collection by result of the block. 70 | # Returns a hash where the keys are the evaluated 71 | # result from the block and the values are arrays 72 | # of elements in the collection that correspond to 73 | # the key. 74 | def group_by 75 | end 76 | 77 | def min 78 | # Your code goes here. 79 | end 80 | 81 | def min_by 82 | # Your code goes here. 83 | end 84 | 85 | def max 86 | # Your code goes here. 87 | end 88 | 89 | def max_by 90 | # Your code goes here. 91 | end 92 | 93 | def minmax 94 | # Your code goes here. 95 | end 96 | 97 | def minmax_by 98 | # Your code goes here. 99 | end 100 | 101 | def take(n) 102 | # Your code goes here. 103 | end 104 | 105 | def take_while 106 | # Your code goes here. 107 | end 108 | 109 | def drop(n) 110 | # Your code goes here. 111 | end 112 | 113 | def drop_while 114 | # Your code goes here. 115 | end 116 | end 117 | ``` 118 | 119 | ## Enumerator 120 | 121 | Return an iterator for the method, if no block is given. 122 | 123 | ## Aliases 124 | 125 | As a bonus, create aliases for the following methods, so they can be invoked 126 | with different names. 127 | 128 | ``` 129 | #map -> #collect 130 | #filter -> #select 131 | #reduce -> #foldl 132 | ``` 133 | 134 | ## Strict 135 | 136 | As a bigger challenge, try to strictly follow Enumerable. For example if no 137 | initial element is given to `#reduce` Ruby's Enumerable will take the first one 138 | of the collection as the initial value. 139 | 140 | This is what makes `(1..10).reduce { |sum, n| sum + n }` work. Consult with 141 | [rubyspec][] to better mimic Ruby's Enumerable behaviour. 142 | 143 | [rubyspec]: https://github.com/rubyspec/rubyspec/tree/7fb7465aac1ec8e2beffdfa9053758fa39b443a5/core/enumerable 144 | -------------------------------------------------------------------------------- /week1/3-my-enumerable/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week1/3-my-enumerable/solution.rb: -------------------------------------------------------------------------------- 1 | module MyEnumerable 2 | def map 3 | # Your code goes here. 4 | end 5 | 6 | def filter 7 | # Your code goes here. 8 | end 9 | 10 | def reject 11 | # Your code goes here. 12 | end 13 | 14 | def reduce(initial = nil) 15 | # Your code goes here. 16 | end 17 | 18 | def any? 19 | # Your code goes here. 20 | end 21 | 22 | def all? 23 | # Your code goes here. 24 | end 25 | 26 | def each_cons(n) 27 | # Your code goes here. 28 | end 29 | 30 | def include?(element) 31 | # Your code goes here. 32 | end 33 | 34 | def count(element = nil) 35 | # Your code goes here. 36 | end 37 | 38 | def size 39 | # Your code goes here. 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /week1/3-my-enumerable/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class SolutionTest < Minitest::Test 6 | class Collection 7 | include MyEnumerable 8 | 9 | def initialize(*data) 10 | @data = data 11 | end 12 | 13 | def each(&block) 14 | @data.each(&block) 15 | end 16 | end 17 | 18 | def test_map 19 | collection = Collection.new(*1..5) 20 | 21 | assert_equal [2, 3, 4, 5, 6], collection.map(&:succ) 22 | end 23 | 24 | def test_filter 25 | collection = Collection.new(*1..10) 26 | 27 | assert_equal [1, 3, 5, 7, 9], collection.filter(&:odd?) 28 | end 29 | 30 | def test_reject 31 | collection = Collection.new(*1..10) 32 | 33 | assert_equal [1, 3, 5, 7, 9], collection.reject(&:even?) 34 | end 35 | 36 | def test_reduce 37 | collection = Collection.new(*1..10) 38 | 39 | assert_equal 55, collection.reduce(0) { |sum, n| sum + n } 40 | end 41 | 42 | def test_include? 43 | collection = Collection.new(*1..10) 44 | 45 | assert_equal true, collection.include?(5) 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /week1/README.md: -------------------------------------------------------------------------------- 1 | # Prelude 2 | 3 | We have a [website]! Don't forget to visit it for news and lectures. 4 | 5 | [website]: http://coreruby.github.io 6 | -------------------------------------------------------------------------------- /week2/1-vectors/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week2/1-vectors/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week2/1-vectors/README.md: -------------------------------------------------------------------------------- 1 | # Vectors 2 | 3 | ## Vector2D 4 | 5 | Implement class named Vector2D with the following interface: 6 | 7 | ```ruby 8 | class Vector2D 9 | attr_accessor :x, :y 10 | 11 | # The unit vector (1, 0). 12 | def self.e 13 | # Your code goes here. 14 | end 15 | 16 | # The unit vector (0, 1). 17 | def self.j 18 | # Your code goes here. 19 | end 20 | 21 | def initialize(x, y) 22 | # Your code goes here. 23 | end 24 | 25 | def length 26 | # Your code goes here. 27 | end 28 | 29 | def magnitude 30 | # The same as #length. Can we implement it without duplicating or calling 31 | # the #length method? 32 | end 33 | 34 | def normalize 35 | # Your code goes here. 36 | end 37 | 38 | def ==(other) 39 | # Your code goes here. 40 | end 41 | 42 | def +(other) 43 | # Your code goes here. 44 | end 45 | 46 | def -(other) 47 | # Your code goes here. 48 | end 49 | 50 | def *(scalar) 51 | # Your code goes here. 52 | end 53 | 54 | def /(scalar) 55 | # Your code goes here. 56 | end 57 | 58 | def to_s 59 | # Your code goes here. 60 | end 61 | 62 | def inspect 63 | # Your code goes here. 64 | end 65 | end 66 | ``` 67 | 68 | ## Vector 69 | 70 | Now that we got our hands dirty with classes and vectors, let's implement a 71 | more generic n-dimensional vector. Let's use this vector as the basis for the 72 | implementation of two other vector types. 73 | 74 | * `Vector2D` the same vector as above, implemented in terms of `Vector`. 75 | * `Vector3D` similar to `Vector2D`, but has a `z` attribute as well. 76 | 77 | The `Vector` interface should be: 78 | 79 | ```ruby 80 | class Vector 81 | def initialize(*components) 82 | # Let's make it more interesting here. I wanna initialize the vector with 83 | # `Vector.new(1, 2, 3, 4)` and `Vector.new([1, 2, 3, 4])` and expect the 84 | # same vector. 85 | end 86 | 87 | def dimension 88 | # Your code goes here 89 | end 90 | 91 | def length 92 | # Your code goes here. 93 | end 94 | 95 | def magnitude 96 | # The same as #length. Can we implement it without duplicating or calling 97 | # the #length method? 98 | end 99 | 100 | def normalize 101 | # Your code goes here. 102 | end 103 | 104 | def [](index) 105 | # Your code goes here. 106 | end 107 | 108 | def []=(index, value) 109 | # Your code goes here. 110 | end 111 | 112 | def ==(other) 113 | # Your code goes here. 114 | end 115 | 116 | def +(vector_of_same_dimension_or_scalar) 117 | # Your code goes here. 118 | end 119 | 120 | def -(vector_of_same_dimension_or_scalar) 121 | # Your code goes here. 122 | end 123 | 124 | def *(scalar) 125 | # Your code goes here. 126 | end 127 | 128 | def /(scalar) 129 | # Your code goes here. 130 | end 131 | 132 | def to_s 133 | # Your code goes here. 134 | end 135 | 136 | def inspect 137 | # Your code goes here. 138 | end 139 | end 140 | ``` 141 | -------------------------------------------------------------------------------- /week2/1-vectors/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week2/1-vectors/solution.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackBulgaria/Core-Ruby-1/7e43a7f9e04cb94de189655773d19015f0dd2b8d/week2/1-vectors/solution.rb -------------------------------------------------------------------------------- /week2/1-vectors/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class SolutionTest < Minitest::Test 6 | def test_the_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /week2/2-tracks/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week2/2-tracks/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week2/2-tracks/README.md: -------------------------------------------------------------------------------- 1 | # Tracks 2 | 3 | Music is awesome, everybody gets it. Let's model a small part of a music player 4 | functionality -- its ability to manage tracks. 5 | 6 | ## Track 7 | 8 | First, model the track class. It should store the fields 9 | `:artist, :name, :album, :genre`. 10 | 11 | 12 | ```ruby 13 | class Track 14 | # Your code goes here. 15 | end 16 | 17 | track.respond_to? :artist #=> true 18 | track.respond_to? :name #=> true 19 | track.respond_to? :album #=> true 20 | track.respond_to? :genre #=> true 21 | 22 | track.respond_to? :artist= #=> true 23 | track.respond_to? :name= #=> true 24 | track.respond_to? :album= #=> true 25 | track.respond_to? :genre= #=> true 26 | 27 | # I wanna be able to initialize a track like this: 28 | track = Track.new "KAYTRANADA feat. Shay Lia", "Leave me alone", "So Bad", "Dance" 29 | 30 | # To make it more clear, I also wanna instantiate it like this: 31 | track = Track.new artist:"KAYTRANADA feat. Shay Lia", 32 | name: "Leave me alone", 33 | album: "So Bad", 34 | genre: "Dance" 35 | 36 | # If I miss a field, I want a gentle reminder that I need to pass it. Hint, 37 | # look up [Hash#fetch][]. 38 | track = Track.new artist:"KAYTRANADA feat. Shay Lia", 39 | name: "Leave me alone", 40 | album: "So Bad", 41 | genre: "Dance" 42 | ``` 43 | 44 | ## Playlist 45 | 46 | Playlist is an ordered collection of tracks. A neat functionality is that we 47 | can search tracks. 48 | 49 | I want you to test out an idea. Implement `Playlist#each`, that returns an 50 | enumerator if no block given. That way, we can get all the benefits of 51 | including Enumerable, without polluting the class with a ton of methods. 52 | 53 | ```ruby 54 | class Playlist 55 | def self.from_yaml(path) 56 | # Your code goes here. 57 | end 58 | 59 | def initialize(*tracks) 60 | # Your code goes here. 61 | end 62 | 63 | def each 64 | # Your code goes here. 65 | end 66 | 67 | def find(&block) 68 | # Filter the playlist by a block. Should return a new Playlist. 69 | end 70 | 71 | def find_by(*filters) 72 | # Filter is any object that responds to the method #call. #call accepts one 73 | # argument, the track it should match or not match. 74 | # 75 | # Should return a new Playlist. 76 | end 77 | 78 | def find_by_name(name) 79 | # Finds all the tracks by the name. Should return a new Playlist. 80 | end 81 | 82 | def find_by_artist(artist) 83 | # Finds all the tracks by the artist. Should return a new Playlist. 84 | end 85 | 86 | def find_by_album(album) 87 | # Finds all the tracks from the album. Should return a new Playlist. 88 | end 89 | 90 | def find_by_genre(genre) 91 | # Finds all the tracks by genre. Should return a new Playlist. 92 | end 93 | 94 | def shuffle 95 | # Give me a new playlist that shuffles the tracks of the current one. 96 | end 97 | 98 | def random 99 | # Give me a random track. 100 | end 101 | 102 | def to_s 103 | # It should return a nice tabular representation of all the tracks. 104 | # Checkout the String class for something that can help you with that. 105 | end 106 | 107 | def &(playlist) 108 | # Your code goes here. This _should_ return new playlist. 109 | end 110 | 111 | def |(playlist) 112 | # Your code goes here. This _should_ return new playlist. 113 | end 114 | 115 | def -(playlist) 116 | # Your code goes here. This _should_ return new playlist. 117 | end 118 | end 119 | 120 | # I wanna be able to initialize a playlist like this: 121 | playlist = Playlist.new(track1, track2, track3) 122 | 123 | # To make things more interesting, I wanna be able to initialize it like this 124 | # too: 125 | playlist = Playlist.new([track1, track2, track3]) 126 | 127 | # I wanna choose only the jazzy house tracks. 128 | jazz_playlist & house_playlist 129 | 130 | # I wanna exclude any house tracks from my playlist. 131 | jazz_playlist - house_playlist 132 | 133 | # I wanna combine my soul and funk tracks. 134 | soul_playlist | funk_playlist 135 | 136 | # I wanna be able to filter the tracks by a block. 137 | playlist.find { |track| ["Led Zeppellin", "The Doors"].include? track.artist } 138 | 139 | # I wanna be able to filter the playlist by a filter object. 140 | class AwesomeRockFilter 141 | AWESOME_ARTISTS = %w(Led\ Zeppellin The\ Doors Black\ Sabbath) 142 | 143 | def call(track) 144 | AWESOME_ARTISTS.include? track.artist 145 | end 146 | end 147 | 148 | playlist.find_by AwesomeRockFilter.new 149 | 150 | # Because of the interface, I wanna be able to filter it out with a proc too. 151 | awesome_rock_filter = proc do |track| 152 | awesome_artists = %w(Led\ Zeppellin The\ Doors Black\ Sabbath) 153 | awesome_artists.include? track.artist 154 | end 155 | 156 | playlist.find_by awesome_rock_filter 157 | ``` 158 | 159 | For the self.from_yaml(path) method check the Ruby YAML here: 160 | http://ruby-doc.org/stdlib-1.9.3/libdoc/yaml/rdoc/YAML.html 161 | 162 | You need to create a .yml file with tracks and load them in 163 | the playlist. Below there is an example of a yml file with two tracks: 164 | 165 | ```yaml 166 | - 167 | artist: "KAYTRANADA feat. Shay Lia" 168 | name: "Leave me alone" 169 | album: "So Bad" 170 | genre: "Dance" 171 | 172 | - 173 | artist: "Iron Maiden" 174 | name: "The numnber of the beast" 175 | album: "The numnber of the beast" 176 | genre: "heavy metal" 177 | ``` 178 | 179 | ## HashWithIndifferentAccess 180 | 181 | Wait, but the YAML serializes the hash keys as strings? 182 | I cannot use my Track initializer ;( 183 | 184 | To overcome this, let's implement a special Hash. A 185 | hash in which `hash[:key]` and `hash["key"]` give us 186 | the same object. 187 | 188 | Then, let's monkey patch hash to be able to convert a 189 | regular hash to one with indifferent access. 190 | 191 | ```ruby 192 | class HashWithIndifferentAccess < Hash 193 | # Your code goes here. 194 | end 195 | 196 | class Hash 197 | def with_indifferent_access 198 | HashWithIndifferentAccess.new(self) 199 | end 200 | end 201 | 202 | hash = {key1: 1, key2: 2}.with_indifferent_access 203 | hash[:key1] == hash["key1"] #=> true 204 | hash.fetch(:key2) == hash.fetch("key2") #=> true 205 | ``` 206 | 207 | [Hash#fetch]: http://ruby-doc.org/core-2.1.4/Hash.html#fetch 208 | -------------------------------------------------------------------------------- /week2/2-tracks/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week2/2-tracks/solution.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackBulgaria/Core-Ruby-1/7e43a7f9e04cb94de189655773d19015f0dd2b8d/week2/2-tracks/solution.rb -------------------------------------------------------------------------------- /week2/2-tracks/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class SolutionTest < Minitest::Test 6 | def test_the_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /week3/1-game-of-life/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week3/1-game-of-life/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week3/1-game-of-life/README.md: -------------------------------------------------------------------------------- 1 | # Game of Life 2 | 3 | A classic problem in Ruby land. The nice folks over FMI have it well described [here][]. 4 | 5 | [here]: http://2011.fmi.ruby.bg/tasks/6 6 | -------------------------------------------------------------------------------- /week3/1-game-of-life/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week3/1-game-of-life/solution.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackBulgaria/Core-Ruby-1/7e43a7f9e04cb94de189655773d19015f0dd2b8d/week3/1-game-of-life/solution.rb -------------------------------------------------------------------------------- /week3/1-game-of-life/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class SolutionTest < Minitest::Test 6 | def test_the_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /week4/1-shopping-cart/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week4/1-shopping-cart/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week4/1-shopping-cart/README.md: -------------------------------------------------------------------------------- 1 | # Shopping cart 2 | 3 | You can find the description of the Shopping cart task [here](http://2011.fmi.ruby.bg/tasks/3). 4 | -------------------------------------------------------------------------------- /week4/1-shopping-cart/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week4/1-shopping-cart/solution.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackBulgaria/Core-Ruby-1/7e43a7f9e04cb94de189655773d19015f0dd2b8d/week4/1-shopping-cart/solution.rb -------------------------------------------------------------------------------- /week4/1-shopping-cart/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class SolutionTest < Minitest::Test 6 | def test_the_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /week5/1-meta/.rubocop.yml: -------------------------------------------------------------------------------- 1 | Style/Documentation: 2 | Enabled: false 3 | -------------------------------------------------------------------------------- /week5/1-meta/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'rubocop' 6 | -------------------------------------------------------------------------------- /week5/1-meta/README.md: -------------------------------------------------------------------------------- 1 | # Meta 2 | 3 | To exercise our meta programming let's do some problems! 4 | 5 | ## Object#singleton_class 6 | 7 | In older versions of Ruby, there wasn't `Object#singleton_class`. Let's 8 | implement our own! 9 | 10 | ## Object#define_singleton_method 11 | 12 | While at it, define `Object#define_singleton_method` as well. 13 | 14 | ## String#to_proc 15 | 16 | Symbol#to_proc wasn't around in older Rubies. It came out of Active Support, 17 | the community driven monkey patches used by Ruby on Rails. Let's try to start 18 | another trend by implementing String#to_proc. 19 | 20 | Bonus: 21 | 22 | Let's make this working: 23 | 24 | ```ruby 25 | [2, 3, 4, 5].map(&'succ.succ') #=> [4, 5, 6, 7] 26 | ``` 27 | 28 | ## Module#private_attr_accessor 29 | 30 | Pretty simple, `Module#private_attr_accesssor` should act like 31 | `attr_accessor`, but always create private accessors. Some kids like to access 32 | their data through accessors only. Let them do that. 33 | 34 | Of course, you should implement `private_attr_reader` and 35 | `private_attr_writter`. The `protected_*` family as well. 36 | 37 | ## Module#cattr_accessor 38 | 39 | Define an accessor exposing API for class variables. This includes 40 | `Module#cattr_reader` and `Module#cattr_writter`. 41 | 42 | As a bonus, let us specify default values, like this: 43 | 44 | ```ruby 45 | class TestCase 46 | cattr_accessor(:tests) { [] } 47 | end 48 | 49 | TestCase.tests #=> [] 50 | ``` 51 | 52 | ## Blackhole Object 53 | 54 | Nils are annoying, right? They get into your way, they crash the program. Such 55 | a bummer! 56 | 57 | Instead of fixing our program, let's hide our nils by monkey patching `nil` in 58 | such a way, that we no longer get a `NoMethodError` when we access a method 59 | that doesn't exist. 60 | 61 | Hint: You have to patch `NilClass`. 62 | 63 | ## Proxy 64 | 65 | Create a Proxy class, that delegates every method call to its target object. 66 | 67 | ```ruby 68 | proxy = Proxy.new [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 69 | 70 | proxy.size #=> 10 71 | proxy.sizes #=> NoMethodError 72 | proxy[0] #=> 1 73 | proxy & [2] #=> [2] 74 | 75 | proxy.respond_to? :size #=> true 76 | proxy.respond_to? :zzzz #=> false 77 | ``` 78 | 79 | Bonus: 80 | 81 | Make sure it respects `#method_missing` and `#respond_to_missing?` to the 82 | target class. 83 | 84 | ## Object#delegate 85 | 86 | Delegating a method to existing object is a commonly used task in Rubyland. 87 | Let's make it easier by defining a helper. 88 | 89 | ```ruby 90 | User = Struct.new(:first_name, :last_name) 91 | 92 | class Invoce 93 | delegate :fist_name, to: '@user' 94 | delegate :last_name, to: '@user' 95 | 96 | def initialize(user) 97 | @user = user 98 | end 99 | end 100 | 101 | user = User.new 'Genadi', 'Samokovarov' 102 | invoice = Invoce.new(user) 103 | 104 | invoice.fist_name #=> "Genadi" 105 | invoice.last_name #=> "Samokovarov" 106 | ``` 107 | 108 | ## FMI 109 | 110 | 2008 was a great year for Ruby! Check out the [metaprogramming problems], our 111 | friends over FMI gave for that year. 112 | 113 | [metaprogramming problems]: http://2008.fmi.ruby.bg/tasks/2.html 114 | -------------------------------------------------------------------------------- /week5/1-meta/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | require 'rubocop/rake_task' 3 | 4 | RuboCop::RakeTask.new 5 | 6 | Rake::TestTask.new do |t| 7 | t.test_files = FileList['*_test.rb'] 8 | t.verbose = true 9 | end 10 | 11 | task default: %i(test rubocop) 12 | -------------------------------------------------------------------------------- /week5/1-meta/solution.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HackBulgaria/Core-Ruby-1/7e43a7f9e04cb94de189655773d19015f0dd2b8d/week5/1-meta/solution.rb -------------------------------------------------------------------------------- /week5/1-meta/solution_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative 'solution' 4 | 5 | class SolutionTest < Minitest::Test 6 | def test_the_truth 7 | assert true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /week6/1-simpletest/README.md: -------------------------------------------------------------------------------- 1 | # Simple Test 2 | 3 | The Ruby community cares for testing. There is a valid reason behind it - it 4 | creates better software and happier, more confident developers. 5 | 6 | Let's create our own [xUnit](http://en.wikipedia.org/wiki/XUnit) compatible 7 | testing framework. 8 | 9 | ## Interface 10 | 11 | We should create a gem called simpletest. Create it as an own git repo in 12 | your GitHub account. 13 | 14 | ## SimpleTest 15 | 16 | The top namespace for your framework should be a module named `SimpleTest`. 17 | 18 | ## SimpleTest::Test 19 | 20 | The class `SimpleTest::Test` should represent a test case. It should include 21 | a module named `SimpleTest::Assertions` and define the following class 22 | methods. 23 | 24 | ### SimpleTest::Test.test 25 | 26 | Defines a test method. A test method is an instance method that begins with 27 | `test_`. This is sugar on top of it, so we can write tests like that: 28 | 29 | ```ruby 30 | class RequestTest < SimpleTest::Test 31 | test 'it represent a networ request' do 32 | assert true 33 | end 34 | end 35 | ``` 36 | 37 | ### SimpleTest::Test.xtest 38 | 39 | Defines a test method that will be skipped for now. Useful if you commit a 40 | test, that's still unused or incomplete. 41 | 42 | ### SimpleTest::Test.setup 43 | 44 | Defines a setup step to be executed before any test method run. 45 | 46 | ```ruby 47 | class RequestTest < SimpleTest::Test 48 | setup do 49 | ensure_database_is_created 50 | end 51 | 52 | test 'that requires database' do 53 | # ... 54 | end 55 | end 56 | ``` 57 | 58 | ### SimpleTest::Test.teardown 59 | 60 | Defines a tear down step to be executed after any test method run. 61 | 62 | ```ruby 63 | class RequestTest < SimpleTest::Test 64 | setup do 65 | ensure_database_is_created 66 | end 67 | 68 | teardown do 69 | close_database_connection 70 | end 71 | 72 | test 'that requires database' do 73 | # ... 74 | end 75 | 76 | test 'another test that requires database' do 77 | # ... 78 | end 79 | end 80 | ``` 81 | 82 | ### SimpleTest::Test#setup 83 | 84 | An instance method called before any test method run. 85 | 86 | ### SimpleTest::Test#teardown 87 | 88 | An instance method called after any test method run. 89 | 90 | ### SimpleTest::Test#fail 91 | 92 | Fails the current test. 93 | 94 | ### SimpleTest::Test#pending 95 | 96 | Marks the current test method as pending. A pending method doesn't fail a 97 | test run. 98 | 99 | ### SimpleTest::Test#skip 100 | 101 | Skips the current test method. 102 | 103 | ## SimpleTest::Assertions 104 | 105 | A module to be mixed into `SimpleTest::Test` that holds all of our assertion 106 | methods. 107 | 108 | 109 | ### SimpleTest::Assertions#assert 110 | 111 | Asserts whether a condition is met. Raises SimpleTest::AssertionError if the 112 | assertion isn't met. Can have an 113 | 114 | ```ruby 115 | test 'the truth' do 116 | assert true, "This is the truth yo, if its false we're doomed" 117 | end 118 | ``` 119 | 120 | ### SimpleTest::Assertions#assert_not 121 | 122 | Asserts whether a condition is unmet. The opposite of #assert. 123 | 124 | ```ruby 125 | test 'the lie' do 126 | assert_not false, "This is THE lie" 127 | end 128 | ``` 129 | 130 | ### SimpleTest::Assertions#assert_equal 131 | 132 | A nicer version of #assert. Instead of just telling you that an assertion 133 | wasn't met, it should tell you that it wasn't met because we expected it to 134 | be of _this_ value. 135 | 136 | ```ruby 137 | test 'the truth' do 138 | assert true, something_that_is_truthy 139 | end 140 | ``` 141 | ### SimpleTest::Assertions#assert_true 142 | 143 | Asserts whether a condition is exactly the value `true`. 144 | 145 | ### SimpleTest::Assertions#assert_false 146 | 147 | Asserts whether a condition is exactly the value `false`. 148 | 149 | ### SimpleTest::Assertions#assert_nil 150 | 151 | Asserts whether a condition is exactly the value `nil`. 152 | 153 | ### SimpleTest::Assertions#assert_is_a 154 | 155 | Asserts whether a condition is results in on object that is #is_a? another 156 | one. 157 | 158 | ### SimpleTest::Assertions#assert_kind_of 159 | 160 | An alias of #assert_is_a. 161 | 162 | ### SimpleTest::Assertions#assert_instance_of 163 | 164 | Asserts whether a condition is results in on object that is #instance_of? 165 | another one. 166 | 167 | ### More 168 | 169 | SimpleTest::Assertions#assert_raises 170 | SimpleTest::Assertions#assert_not_raises 171 | 172 | SimpleTest::Assertions#assert_include, SimpleTest::Assertions#assert_contains 173 | SimpleTest::Assertions#assert_length, SimpleTest::Assertions#assert_size, SimpleTest::Assertions#assert_count 174 | 175 | ## SimpleTest::Runner 176 | 177 | Once we have test cases, we have to be able to run them. The whole purpose of this class is to find them. 178 | 179 | ## SimpleTest::TextReporter 180 | 181 | A text reporter should create a report after all the test cases have been 182 | run. Think the dots you currently see when you run your test cases. 183 | 184 | ## SimpleTest::HtmlReporter 185 | 186 | An HTML reporter should create a report in HTML form after all the test cases 187 | have been run. 188 | 189 | ## Bonus 190 | 191 | Test the test framework with the test framework. 192 | --------------------------------------------------------------------------------