├── .gitignore ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE.txt ├── README.mdown ├── Rakefile ├── cheatsheets ├── erb-embedded_ruby.rb ├── general.txt ├── reflection_introspection.rb ├── regular_expressions.rb ├── rubygems.rb └── sinatra.rb ├── session1 ├── 1-notes │ ├── 01-intro.rb │ ├── 02-conventions.rb │ ├── 03-object-definition.rb │ ├── 04-variables.rb │ ├── 05-methods.rb │ ├── 06-method-scope.rb │ ├── 07-method-arguments.rb │ ├── 08-operators.rb │ ├── 09-numbers.rb │ ├── 10-introducing-strings.rb │ ├── 11-stdin-and-stdout.rb │ ├── 12-puts.rb │ ├── 13-single-vs-double-quotes.rb │ ├── 14-operators-on-strings.rb │ ├── 15-interpolation.rb │ ├── 16-p.rb │ ├── 17-naming-conventions.rb │ ├── 18-keywords.rb │ ├── 19-nil.rb │ ├── 20-logic.rb │ ├── 21-true-and-false.rb │ ├── 22-if-else.rb │ ├── 23-if-returns-a-value.rb │ └── 24-go-do-the-challenges.rb ├── 2-examples │ ├── 1_first_program.rb │ ├── 2_check_odd.rb │ ├── 3_rememberer.rb │ └── 4_rememberer2.rb ├── 3-challenge │ ├── 1_arithmetic.rb │ ├── 2_arithmetic.rb │ ├── 3_simple_logic.rb │ ├── 4_logic.rb │ ├── 5_string.rb │ ├── 6_string.rb │ └── 7_string.rb ├── 4-spec │ ├── 1.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ └── 7.rb └── 5-solved │ ├── 1.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ └── 7.rb ├── session2 ├── 1-notes │ ├── 01-a-quick-word-about-blocks.rb │ ├── 02-arrays.rb │ ├── 03-array-iterating.rb │ ├── 04-array-filtering.rb │ ├── 05-other-useful-array-methods.rb │ ├── 06-classes.rb │ ├── 07-class-examples.rb │ ├── 08-methods-go-in-classes.rb │ ├── 09-class-questions.rb │ ├── 10-instance-variables.rb │ ├── 11-naming-methods.rb │ ├── 12-attr_accessor.rb │ ├── 13-initializing.rb │ ├── 14-self.rb │ ├── 15-more-on-method-scope.rb │ ├── 16-THIS-IS-GONNA-TRIP-YOU-UP.rb │ ├── 17-singleton-classes.rb │ ├── 18-class-instance-variables.rb │ └── 19-last-words.rb ├── 2-examples │ ├── 1_output.rb │ ├── 2_gets.rb │ ├── 3_array.rb │ └── 4_classes.rb ├── 3-challenge │ ├── 10_classes.rb │ ├── 11_classes.rb │ ├── 12_classes.rb │ ├── 13_classes_iterating_sorting.rb │ ├── 1_input_output.rb │ ├── 2_input_output_control.rb │ ├── 3_array.rb │ ├── 4_array.rb │ ├── 5_array.rb │ ├── 6_array.rb │ ├── 7_array.rb │ ├── 8_array.rb │ └── 9_input_output_logic_string.rb ├── 4-spec │ ├── 1.rb │ ├── 10.rb │ ├── 11.rb │ ├── 12.rb │ ├── 13.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ ├── 9.rb │ └── helper.rb └── 5-solved │ ├── 1.rb │ ├── 10.rb │ ├── 11.rb │ ├── 12.rb │ ├── 13.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ └── 9.rb ├── session3 ├── 1-notes │ ├── 01-symbols-introduction.rb │ ├── 02-symbols-always-the-same.rb │ ├── 03-hash-introduction.rb │ ├── 04-hash-literals.rb │ ├── 05-hash-setting-and-getting.rb │ ├── 06-hash-keys.rb │ ├── 07-hash-iterating.rb │ ├── 08-proc-introduction.rb │ ├── 09-procs-can-see-their-environment.rb │ ├── 10-blocks-introduction.rb │ ├── 11-block-params-and-return.rb │ ├── 12-all-methods-take-blocks.rb │ ├── 13-difference-between-block-syntaxes.rb │ ├── 14-storing-blocks-for-later.rb │ ├── 15-forwarding-blocks.rb │ ├── 16-optional-params.rb │ ├── 17-variable-lengthed-params.rb │ ├── 18-hash-params.rb │ ├── 19-putting-it-all-together.rb │ └── 20-last-words.rb ├── 2-examples │ ├── 1_hashes.rb │ ├── 2_blocks.rb │ ├── 3_stack.rb │ └── 4_recursion.rb ├── 3-challenge │ ├── 10_hashes.rb │ ├── 11_blocks_or_procs.rb │ ├── 12_blocks.rb │ ├── 13_proc.rb │ ├── 14_var_args_and_hash.rb │ ├── 15_hash.rb │ ├── 16_hash.rb │ ├── 17_hashes.rb │ ├── 1_blocks.rb │ ├── 2_hashes.rb │ ├── 3_hashes.rb │ ├── 4_hashes.rb │ ├── 5_blocks.rb │ ├── 6_arguments.rb │ ├── 7_hashes.rb │ ├── 8_blocks.rb │ └── 9_hashes.rb ├── 4-spec │ ├── 1.rb │ ├── 10.rb │ ├── 11.rb │ ├── 12.rb │ ├── 13.rb │ ├── 14.rb │ ├── 15.rb │ ├── 16.rb │ ├── 17.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ ├── 9.rb │ └── helper.rb └── 5-solved │ ├── 1.rb │ ├── 10.rb │ ├── 11.rb │ ├── 12.rb │ ├── 13.rb │ ├── 14.rb │ ├── 15.rb │ ├── 16.rb │ ├── 17.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ └── 9.rb ├── session4 ├── 1-notes │ ├── 01-andand-return-values.rb │ ├── 02-oror-return-values.rb │ ├── 03-ororequals.rb │ ├── 04-introspection.rb │ ├── 05-ranges.rb │ ├── 06-files.rb │ ├── 07-working-dir-vs-file-dir.rb │ ├── 08.a-require.rb │ ├── 08.b-require.rb │ ├── 09-inheritance-introduction.rb │ ├── 10-subclasses-inherit-methods.rb │ ├── 11-overriding-inherited-methods.rb │ ├── 12-super-to-invoke-inherited.rb │ ├── 13-inheritance-example.rb │ ├── 14-ancestors.rb │ ├── 15-exceptions-introduction.rb │ ├── 16-exceptions-rescuing.rb │ └── 17-raising-your-own.rb ├── 3-challenge │ ├── 1_stack_classes_inspect.rb │ ├── 2_subclassing_require.rb │ ├── 3_inject_blocks_enumerable.rb │ ├── 4_oror.rb │ ├── 5_file.rb │ ├── 6_singleton_class_string.rb │ ├── 7_introspection.rb │ ├── 8_exceptions.rb │ └── 9_exceptions.rb ├── 4-spec │ ├── 1.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ └── 9.rb ├── 5-solved │ ├── 1.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ └── 9.rb └── resources │ └── 8.1.template ├── session5 ├── .rvmrc ├── 1-notes │ ├── 01-modules-introduction.rb │ ├── 02-modules-including.rb │ ├── 03-modules-extending.rb │ ├── 04-modules-example.rb │ ├── 05-nesting-classes-and-modules.rb │ ├── 06-modules-namespacing.rb │ ├── 07-extending-main.rb │ ├── 08-regex-introduction.rb │ ├── 09-regex-how-to-match.rb │ ├── 10-regex-characters.rb │ ├── 11-regex-repetition.rb │ ├── 12-regex-boundaries.rb │ ├── 13-regex-groups.rb │ ├── 14-gems-introduction.rb │ ├── 15-rubygems-introduction.rb │ ├── 16-rubygems-updating.rb │ ├── 17-gems-installing.rb │ ├── 18-gems-using-sinatra.rb │ └── 19-go-do-the-challenges.rb ├── 3-challenge │ ├── 1_singleton_class_string_exception.rb │ ├── 2_blocks_var_args.rb │ ├── 3_modules.rb │ ├── 4_modules.rb │ ├── 5_exceptions_regex_reflection.rb │ ├── 6_regex.rb │ ├── 7_regex.rb │ ├── 8_rubygems.rb │ └── 9_regex.rb ├── 4-spec │ ├── 1.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ └── 9.rb └── 5-solved │ ├── 1.rb │ ├── 2.rb │ ├── 3.rb │ ├── 4.rb │ ├── 5.rb │ ├── 6.rb │ ├── 7.rb │ ├── 8.rb │ └── 9.rb └── session6 ├── 1-notes ├── .rvmrc ├── 01-web-introduction.rb ├── 02-servers-and-rack.rb ├── 03-framework-introduction.rb ├── 04-sinatra.rb ├── 05-erb.rb ├── 06-sinatra-views-layouts-params-and-variables │ ├── main.rb │ └── views │ │ ├── cart.erb │ │ ├── home_page.erb │ │ └── layout.erb ├── 07-sinatra-routes.rb ├── 08-rack-and-reloading │ ├── config.ru │ └── main.rb ├── 09-static-files-and-bundler │ ├── .rvmrc │ ├── Gemfile │ ├── Gemfile.lock │ ├── config.ru │ ├── main.rb │ └── public │ │ └── dependencies.png ├── 10-git │ └── notes.rb └── 11-heroku-example │ ├── .rvmrc │ ├── notes.rb │ └── spec │ └── username_spec.rb ├── 3-challenge └── 1_instructions.rb ├── 4-spec └── 1.rb └── 5-solved ├── 1.rb └── 1_build_an_app ├── Gemfile ├── Gemfile.lock ├── config.ru ├── lib └── caesar_cipher.rb ├── main.rb └── views ├── decrypt.erb ├── encrypt.erb ├── home.erb └── layout.erb /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.5.0 4 | script: 5 | - "bundle exec rake {1,2}:all" 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | ruby '2.5.0' 4 | 5 | gem 'rspec' 6 | gem 'rake' 7 | gem 'helloworld' 8 | gem 'sinatra' 9 | gem 'nokogiri' 10 | gem 'capybara' 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.5.2) 5 | public_suffix (>= 2.0.2, < 4.0) 6 | capybara (2.18.0) 7 | addressable 8 | mini_mime (>= 0.1.3) 9 | nokogiri (>= 1.3.3) 10 | rack (>= 1.0.0) 11 | rack-test (>= 0.5.4) 12 | xpath (>= 2.0, < 4.0) 13 | diff-lcs (1.3) 14 | helloworld (0.0.1) 15 | mini_mime (1.0.0) 16 | mini_portile2 (2.3.0) 17 | mustermann (1.0.2) 18 | nokogiri (1.8.2) 19 | mini_portile2 (~> 2.3.0) 20 | public_suffix (3.0.2) 21 | rack (2.0.4) 22 | rack-protection (2.0.1) 23 | rack 24 | rack-test (0.8.3) 25 | rack (>= 1.0, < 3) 26 | rake (12.3.0) 27 | rspec (3.7.0) 28 | rspec-core (~> 3.7.0) 29 | rspec-expectations (~> 3.7.0) 30 | rspec-mocks (~> 3.7.0) 31 | rspec-core (3.7.1) 32 | rspec-support (~> 3.7.0) 33 | rspec-expectations (3.7.0) 34 | diff-lcs (>= 1.2.0, < 2.0) 35 | rspec-support (~> 3.7.0) 36 | rspec-mocks (3.7.0) 37 | diff-lcs (>= 1.2.0, < 2.0) 38 | rspec-support (~> 3.7.0) 39 | rspec-support (3.7.1) 40 | sinatra (2.0.1) 41 | mustermann (~> 1.0) 42 | rack (~> 2.0) 43 | rack-protection (= 2.0.1) 44 | tilt (~> 2.0) 45 | tilt (2.0.8) 46 | xpath (3.0.0) 47 | nokogiri (~> 1.8) 48 | 49 | PLATFORMS 50 | ruby 51 | 52 | DEPENDENCIES 53 | capybara 54 | helloworld 55 | nokogiri 56 | rake 57 | rspec 58 | sinatra 59 | 60 | RUBY VERSION 61 | ruby 2.5.0p0 62 | 63 | BUNDLED WITH 64 | 1.16.1 65 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Joshua Cheek 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /cheatsheets/general.txt: -------------------------------------------------------------------------------- 1 | Terminal: 2 | Make Directory: mkdir directory_name 3 | Change Directories: cd directory_name 4 | Go to Parent Directory: cd .. 5 | List Directory Contents: ls -l 6 | Print Working Directory: pwd 7 | Check for Program: which program_name 8 | Display Contents of File: cat file_name 9 | 10 | Ruby: 11 | Run a Ruby Script: ruby program_name.rb 12 | Stop a Ruby Script: Control + c 13 | See Command Line Options: ruby -h 14 | Install a Gem: [sudo] gem install gem_name 15 | See All Rake Tasks: rake -T 16 | See All Rake Tasks For Ch 2: rake -T ^2 17 | 18 | git: 19 | pull down most recent code: 20 | git add -A 21 | git commit -m "getting ready to pull" 22 | git pull origin master 23 | ( if there is a problem, call me and I'll walk you through it ) -------------------------------------------------------------------------------- /session1/1-notes/02-conventions.rb: -------------------------------------------------------------------------------- 1 | # In the notes, examples and cheat sheets provided, we use a few conventions in our code to make it easy 2 | # to see the results of expressions. To show the results of a line, we use the following notation 3 | 4 | 3 + 9 # => 12 5 | my_var = 4 6 | my_var # => 4 7 | 8 | # This shows what that line evaluates to, and in the case of a line with just a variable on it, shows the value 9 | # of the object it refers to. 10 | 11 | # For more complicated output, such as from a print statement, it'll be placed below the code. 12 | 13 | -------------------------------------------------------------------------------- /session1/1-notes/03-object-definition.rb: -------------------------------------------------------------------------------- 1 | # Ruby organizes related data, and the ways of manipulating it, into an abstract idea called an object. 2 | # For example, the data that defines a number, and the methods on that number, define that number object. 3 | 4 | # At a computer level, the data for the number 5 are just ones and zeros, probably looking like this 5 | "%032b" % 5 # => "00000000000000000000000000000101" 6 | 7 | # and since five is an object, it also has methods on it 8 | 5.even? # => false 9 | 5.odd? # => true 10 | 5.next # => 6 11 | 12 | -------------------------------------------------------------------------------- /session1/1-notes/04-variables.rb: -------------------------------------------------------------------------------- 1 | # The data for the objects exist in a part of memory called the "heap" 2 | # When Ruby wants to store an object, it goes to the heap, finds available memory, and then puts the object's data there. 3 | # But how will we know where we put our object? We need something to keep track of that location (called its address). 4 | # 5 | # Variables are like little fingers that point to memory addresses! 6 | # They let us keep track of where our objects are -- so you can access objects through variables. 7 | 8 | five = 5 # five is a variable, 5 is the object it is pointing to 9 | 10 | five.even? # => false 11 | five.odd? # => true 12 | five.next # => 6 13 | 14 | 15 | # Variables can be set to point to new values 16 | 17 | five # => 5 18 | five = "five" 19 | five # => "five" 20 | 21 | -------------------------------------------------------------------------------- /session1/1-notes/05-methods.rb: -------------------------------------------------------------------------------- 1 | # The way you modify objects is through sequences of instructions called methods. 2 | # For example, there is a set of instructions that know how to capitalize text. We group them into a method named capitalize. 3 | 4 | "josh".capitalize # => "Josh" 5 | 6 | 7 | # You can make methods, too! 8 | 9 | def is_this_a_method? 10 | "Yes, it is!" # "Yes, it is!" is an object. Because this is the last object in the method, its address will be returned. 11 | end 12 | 13 | is_this_a_method? # => "Yes, it is!" 14 | 15 | -------------------------------------------------------------------------------- /session1/1-notes/06-method-scope.rb: -------------------------------------------------------------------------------- 1 | # When you make a method, remember that it is its own little world, 2 | # it doesn't know about anything outside of itself, this is called scope. 3 | 4 | defined? twelve # => nil 5 | twelve = 12 6 | defined? twelve # => "local-variable" 7 | 8 | def my_own_little_world 9 | defined? twelve # => nil 10 | end 11 | 12 | my_own_little_world # => nil 13 | defined? twelve # => "local-variable" 14 | 15 | 16 | # Well that seems pretty useless, eh? Fortunately, there is an Internet connection on this world! 17 | # You can pass objects, into the method. When we pass an object in, the variable that points to it 18 | # is called an argument or a parameter 19 | 20 | # person1 and person2 are arguments or parameters 21 | def beam_me_up(person1, person2) 22 | "The away team consists of #{person1} and #{person2}." 23 | end 24 | 25 | beam_me_up("Ryker", "Data") # => "The away team consists of Ryker and Data." 26 | 27 | -------------------------------------------------------------------------------- /session1/1-notes/07-method-arguments.rb: -------------------------------------------------------------------------------- 1 | # You know how you and I can go to the same website, but even though we both see it in our browser, 2 | # is there only one website? 3 | # 4 | # Objects are the same way, when you pass one in, you can access it from the variable outside 5 | # and inside the method, but there is still just one object. 6 | 7 | def browser_goto(website) 8 | website.object_id # => 2151945040, 2151945040 9 | "Direct your browser towards #{website}" 10 | end 11 | 12 | # the same object id means they are the same object 13 | website = "ruby-kickstart.com" 14 | website.object_id # => 2151945040 15 | browser_goto(website) # => "Direct your browser towards ruby-kickstart.com" 16 | 17 | # Ruby likes to be beautiful, it doesn't make you put parentheses where it can figure out what you meant. 18 | browser_goto website # => "Direct your browser towards ruby-kickstart.com" 19 | 20 | -------------------------------------------------------------------------------- /session1/1-notes/08-operators.rb: -------------------------------------------------------------------------------- 1 | # There are some special methods called operators. 2 | # They are special because the Ruby interpreter lets you use them in pretty ways, even though they are just methods. 3 | # That's called syntactic sugar! 4 | 5 | # there is a method named + 6 | 3.+(5) # => 8 7 | 8 | # but that's ugly, *ick*, Ruby is beautiful, so it lets you say 9 | 3 + 5 # => 8 10 | 2 - 4 # => -2 11 | 10 / 3 # => 3 12 | 10 % 3 # => 1 13 | 14 | # See, it knows what to do :) 15 | # (% tells you the remainder) 16 | 17 | # Ruby wants to help you, but syntactic sugar wouldn't be much help 18 | # if it changed the semantics of math, so Ruby respects order of operations. 19 | 2 * 3 + 10 # => 16 20 | 2 + 3 * 10 # => 32 21 | 22 | # Question: If operators are just methods on objects, can other objects have operators? 23 | # Lets open up irb and try it out! 24 | 25 | -------------------------------------------------------------------------------- /session1/1-notes/09-numbers.rb: -------------------------------------------------------------------------------- 1 | # Because of real world limitations, math can't be implemented as purely as is done in the classroom. 2 | # This means that while you think of 10 and 10.0 as the same thing, most programming languages don't. 3 | 4 | 10.class.ancestors # => [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject] 5 | 10.0.class.ancestors # => [Float, Numeric, Comparable, Object, Kernel, BasicObject] 6 | 7 | #Jordan: The class inheritance tree for Ruby isn't as complicated as you might think... http://edwinmeyer.com/Release_Integrated_RHG_09_10_2008/images/ch_minimum_classtree.jpg 8 | 9 | # They are both numbers (we haven't talked about classes yet, but notice that Numeric is in the ancestry) 10 | # but they have slightly different behavior. For example, integer division gives an integer, 11 | # but float division gives a float. 12 | 10 / 3 # => 3 13 | 10.0 / 3 # => 3.3333333333333335 14 | 15 | # what if you want to convert them? 16 | 10.to_f # => 10.0 17 | 10.0.to_i # => 10 18 | 19 | 20 | # You can also use parentheses, they will take on the value of whatever is inside them. 21 | (1 + 2) * 3 # => 9 22 | (91 + 2).even? # => false 23 | 24 | -------------------------------------------------------------------------------- /session1/1-notes/10-introducing-strings.rb: -------------------------------------------------------------------------------- 1 | # For historical reasons, text in programming languages, is called a "string" 2 | # think of it like you're stringing characters along a clothesline 3 | # question: if 10.to_f converts 10 to a float, how would you convert 10 to a string? 4 | 5 | "text".class # => String 6 | 7 | # You can identify strings because they are surrounded in quotes 8 | 9 | "abc" # => "abc" 10 | 'abc' # => "abc" 11 | 12 | -------------------------------------------------------------------------------- /session1/1-notes/11-stdin-and-stdout.rb: -------------------------------------------------------------------------------- 1 | # Programs that run in a terminal read text in, and write text out. 2 | # This is the common interface that allows lots of different programs to interact with each other. 3 | 4 | # When a program outputs text, we say it sends it to standard output (stdout). 5 | # In the terminal, anything your program sends stdout will display on your terminal. 6 | # For example, cat sends a file's contents to standard output, echo sends its arguments to standard output. 7 | 8 | # When it reads text in, it gets that from standard input (stdin). 9 | # In the terminal, stdin is hooked up to your keyboard. 10 | # Whatever you type will be sent to your program's stdin. 11 | 12 | # Use gets to read a line from stdin 13 | user_response = gets 14 | 15 | # Use puts to write the line to stdout 16 | puts "You said: #{user_response}" 17 | 18 | 19 | 20 | # Watch out! 21 | # 22 | # A line is text that ends in a newline. line = "Line\n" 23 | # When you read in the line, you also read in the newline. 24 | # That means: line + line # => "Line\nLine\n" 25 | # 26 | # If you _actually_ wanted this: "LineLine" 27 | # then you need to remove the newline. 28 | # 29 | # Ruby gives you a method named chomp that will give you that string without the newline 30 | # line.chomp # => "Line" 31 | # line # => "Line\n" 32 | # 33 | # It's like a cookie monster for newlines! 34 | 35 | -------------------------------------------------------------------------------- /session1/1-notes/12-puts.rb: -------------------------------------------------------------------------------- 1 | # Ruby has several methods for sending text to stdout, the most common of which is 'puts': 2 | puts "Welcome to the program!" 3 | 4 | # Output: 5 | # Welcome to the program! 6 | # 7 | 8 | 9 | # Notice that puts places a newline after whatever it prints. And puts can print any object, not just strings: 10 | puts 45 11 | 12 | # Output: 13 | # 45 14 | # 15 | 16 | 17 | # puts can output other objects by using their to_s method to convert them into Strings 18 | # and then outputs the strings. It works like this: 19 | number = 56 20 | thing_to_print = number.to_s 21 | puts thing_to_print 22 | 23 | # Output: 24 | # 56 25 | # 26 | 27 | -------------------------------------------------------------------------------- /session1/1-notes/13-single-vs-double-quotes.rb: -------------------------------------------------------------------------------- 1 | # There are two ways to represent a literal String in Ruby: With double quotes ( "" ) or single quotes ( '' ). 2 | # With double quotes, you can place special sequences, like newlines (\n) in the string that will be converted. 3 | # With single quotes, the string comes out just as it's typed. 4 | 5 | puts "Here's\nTwo lines." 6 | puts 'This will\nonly be one line' 7 | 8 | # Output: 9 | # Here's 10 | # Two lines. 11 | # This will\nonly be one line 12 | 13 | -------------------------------------------------------------------------------- /session1/1-notes/14-operators-on-strings.rb: -------------------------------------------------------------------------------- 1 | # You can use basic operators on Strings, just like other objects: 2 | 3 | my_string = "Face" 4 | your_string = "book" 5 | 6 | my_string + your_string # => "Facebook" 7 | 8 | my_string == your_string # => false 9 | my_string = "book" 10 | my_string == your_string # => true 11 | 12 | -------------------------------------------------------------------------------- /session1/1-notes/15-interpolation.rb: -------------------------------------------------------------------------------- 1 | # Double quotes have even more power. By using a special sequence of characters, you can interpolate code 2 | # into your String. That code will be ran and its results placed into the string. 3 | 4 | small_number = 5 5 | neg_number = -97 6 | 7 | puts "1 + 3 is #{1 + 3}" 8 | puts "My two numbers are #{small_number} and #{neg_number.abs} (all positive here)" 9 | 10 | # Output: 11 | # 1 + 3 is 4 12 | # My two numbers are 5 and 97 (all positive here) 13 | # 14 | 15 | # Notice we can do anything inside of the #{} we want, including referencing objects and calling methods on them. 16 | 17 | -------------------------------------------------------------------------------- /session1/1-notes/16-p.rb: -------------------------------------------------------------------------------- 1 | # One other important output method is the 'p' method. p outputs an object's internal representation: 2 | # think of it as how the object looks in code. This kind of output is what we've been putting to the right of 3 | # lines of code in these notes. 4 | 5 | puts "Rain and lightning" 6 | p "Rain and lightning" 7 | 8 | # Output of puts: 9 | # Rain and lightning 10 | 11 | # Output of p: 12 | # "Rain and lightning" 13 | 14 | 15 | # Notice how the p method puts quote ( "" ) around the string. Here's one more example. 16 | # (in Ruby, a list of objects is called an array. We'll talk about arrays later) 17 | 18 | array = [1, 2, 3] 19 | 20 | puts array 21 | p array 22 | 23 | # Output: 24 | 25 | # puts: 26 | # 1 27 | # 2 28 | # 3 29 | 30 | # p: 31 | # [1, 2, 3] 32 | 33 | -------------------------------------------------------------------------------- /session1/1-notes/17-naming-conventions.rb: -------------------------------------------------------------------------------- 1 | # All the variables we've seen so far have been local variables. 2 | # That means they exist within the current scope, but if we leave it, they go away. 3 | # Local variables begin with a lowercase letter, and can then be followed by alphanumeric values and underscores 4 | # Use snake_case with variables 5 | local_variable = nil 6 | 7 | # Constants are like variables, but you're telling the world that the value should not change. 8 | # Any variable that starts with a capital letter is a constant. 9 | # Use CamelCase with constants. 10 | Constant = nil 11 | 12 | 13 | # Instance variables are variables that belong to an object rather than a scope. 14 | # Any variable that starts with an '@' sigil is an instance variable. 15 | # We'll talk more about these later. 16 | @instance_variable = nil 17 | 18 | 19 | # Remember when I said methods were their own little worlds? I lied. 20 | # Constants can be seen by anything defined in their scope. 21 | 22 | MyConstant = 12 23 | my_variable = 13 24 | def example 25 | begin 26 | MyConstant # => 12 27 | my_variable # => 28 | rescue => exception 29 | exception # => # 30 | end 31 | end 32 | 33 | example # invokes the method 34 | 35 | 36 | # Question: classes begin with uppercase letters, are they constants? 37 | # Remember, constants are just variables that aren't supposed to change. 38 | # go test this in irb 39 | 40 | -------------------------------------------------------------------------------- /session1/1-notes/18-keywords.rb: -------------------------------------------------------------------------------- 1 | # We care about keywords, because they have special meaning to Ruby. 2 | # This means that we can't use them as variable names. 3 | # 4 | # You will know if you've used one, because the interpreter will 5 | # If your text editor highlights it, don't use it. :) 6 | # 7 | # If you _really_ want a list, its at http://www.google.com/search?&q=ruby+keywords+list 8 | 9 | 10 | 11 | 12 | # def is a keyword used for defining methods. It has special meaning, you can't use it. 13 | 14 | def = 3 # !> useless use of a literal in void context 15 | # ~> -:14: syntax error, unexpected '=' 16 | # ~> def = 3 # !> useless use of a literal in void context 17 | # ~> ^ 18 | 19 | -------------------------------------------------------------------------------- /session1/1-notes/19-nil.rb: -------------------------------------------------------------------------------- 1 | # There is a special object named nil 2 | nil.class # => NilClass 3 | 4 | # It's the object you use when you need to represent that you don't have an object! 5 | array = [1,5,7] 6 | array.find { |number| number * 2 == 10 } # => 5 7 | array.find { |number| number * 2 == 11 } # => nil 8 | 9 | -------------------------------------------------------------------------------- /session1/1-notes/20-logic.rb: -------------------------------------------------------------------------------- 1 | # In your life, when you need to conditionally do something, you use logic. 2 | # Logic has two values: true and false. 3 | # You say things like "if it's raining and I have an umbrella I'll go outside, otherwise I'll stay inside." 4 | # This is a logical statement. 5 | # 6 | # Ruby has logic, too, so you can totally write a program to see if you should go outside, in fact, lets do it! 7 | 8 | def go_outside?(raining, umbrella) 9 | raining && umbrella 10 | end 11 | 12 | go_outside?(true, true) # => true 13 | go_outside?(true , false) # => false 14 | go_outside?(false, true ) # => false 15 | go_outside?(false, false) # => false 16 | 17 | # Look, the go_outside? method knows exactly what to do, because it knows about logic! 18 | 19 | -------------------------------------------------------------------------------- /session1/1-notes/21-true-and-false.rb: -------------------------------------------------------------------------------- 1 | # Logic in Ruby operates on "boolean" objects. If I'm not lying, then they're named after the guy who invented logic! 2 | # A boolean object is just an object that can be considered true or false. 3 | 4 | # the true object: 5 | true.class # => TrueClass 6 | 'yep, its true' if true # => "yep, its true" 7 | 8 | # the false object: 9 | false.class # => FalseClass 10 | 'nope, its not true' if false # => nil 11 | 12 | # you can flip them with a leading bang 13 | !true # => false 14 | !false # => true 15 | !!true # => true 16 | !!false # => false 17 | 18 | 19 | # But what about all the other objects? They want to be boolean too! 20 | # Turns out they can! (except nil, he can go sit in the corner with false) 21 | 22 | [0, 1, "two", :three, Object.new, nil].each do |object| 23 | !!object # => true, true, true, true, true, false 24 | end 25 | 26 | -------------------------------------------------------------------------------- /session1/1-notes/22-if-else.rb: -------------------------------------------------------------------------------- 1 | # Lets say you actually want to do something conditionally 2 | 3 | if 4 == (2 + 2) 4 | "I get evaluated" # => "I get evaluated" 5 | else 6 | "I don't :(" # => 7 | end 8 | 9 | 10 | my_number = 56 11 | 12 | if my_number < 12 13 | puts "Fewer than a dozen" 14 | elsif my_number < 64 15 | puts "You could hold me in 6 bits" 16 | else 17 | puts "That's a pretty big number" 18 | end 19 | 20 | # Output: 21 | # You could hold me in 6 bits 22 | # 23 | 24 | 25 | 'one line if statement' if true # => "one line if statement" 26 | 'one line unless statement' unless false # => "one line unless statement" 27 | 28 | -------------------------------------------------------------------------------- /session1/1-notes/23-if-returns-a-value.rb: -------------------------------------------------------------------------------- 1 | # Anywhere you can write code in Ruby returns a value, including if statements. 2 | 3 | result = if true 4 | "yep, it's true" 5 | else 6 | "nope, it's not true" 7 | end 8 | 9 | result # => "yep, it's true" 10 | 11 | 12 | 13 | # Lets put that in a method 14 | def if_returns_value(bool) 15 | if bool 16 | "yep it's true" 17 | else 18 | "nope, it's not true" 19 | end 20 | end 21 | 22 | if_returns_value true # => "yep it's true" 23 | if_returns_value false # => "nope, it's not true" 24 | 25 | 26 | 27 | # So does unless 28 | def unless_returns_value(bool) 29 | unless bool 30 | "nope, it's not true" 31 | else 32 | "yep, it's true" 33 | end 34 | end 35 | 36 | unless_returns_value true # => "yep, it's true" 37 | unless_returns_value false # => "nope, it's not true" 38 | 39 | -------------------------------------------------------------------------------- /session1/1-notes/24-go-do-the-challenges.rb: -------------------------------------------------------------------------------- 1 | # Okay, we made it through :) 2 | # Now you just need to go do the challenges 3 | # 4 | # Open up the challenges in your text editor. Try to complete the first one. 5 | # Then go to the terminal, and navigate to the directory with the Rakefile in it. 6 | # Then run $ rake 1:1 7 | # 8 | # Did you pass? No? 9 | # Okay, look at the output and try again. See what went wrong? 10 | # Try again! 11 | # 12 | # Did you pass? Yeah? 13 | # Great! No go finish the rest :D 14 | 15 | 16 | 17 | # !!!!!!!!!!DON'T FORGET!!!!!!!!! 18 | # There are cheat sheets to help you. You will need to reference them! 19 | # 20 | # How should you use the cheat sheets? 21 | # Read them once so you know what kinds of things they contain. 22 | # Then when you need to use something, first try to remember what it was. 23 | # If you can't remember, then go look it up. 24 | # Make a point of focusing on the answer, and try to recall it again immediately. 25 | # This will help you quickly learn the things you want to use. 26 | # 27 | # You don't need to sit down and try to memorize the whole sheet (if you want to, you can) 28 | # It's mostly important to know what general things they contain, and begin to memorize 29 | # the parts that you use frequently. 30 | # 31 | 32 | # For this section, you'll need: 33 | # https://github.com/JoshCheek/ruby-kickstart/blob/master/cheatsheets/logic_and_control.rb 34 | # https://github.com/JoshCheek/ruby-kickstart/blob/master/cheatsheets/strings.rb 35 | 36 | -------------------------------------------------------------------------------- /session1/2-examples/1_first_program.rb: -------------------------------------------------------------------------------- 1 | # run me by using cd to get to my directory 2 | # then type $ ruby 1_first_program.rb 3 | 4 | puts "Hello reader." 5 | puts "Welcome to Ruby" 6 | 7 | puts "Lets demonstrate a simple calculation" 8 | answer = 2 + 2 9 | puts "2 plus 2 is #{answer}" 10 | 11 | -------------------------------------------------------------------------------- /session1/2-examples/2_check_odd.rb: -------------------------------------------------------------------------------- 1 | # Invoke this program with a number 2 | # $ ruby 2_check_odd.rb number 3 | 4 | 5 | # when a user passes an argument to a ruby program 6 | # it is stored in the ARGV array 7 | unless ARGV.first 8 | puts "You need to submit a number to check" 9 | exit(1) # Use exit(0) to exit the program early. 10 | end # If you're exiting because something went wrong, pass a different number like 1 11 | 12 | 13 | # Unix is too dumb to know the argument is a number, so it passes it in as text. 14 | # We'll have to turn it into a number ourselves with to_i (what if the user didn't pass a number?) 15 | number = ARGV.first.to_i 16 | 17 | if number.odd? 18 | puts "Yes, #{number} is odd" 19 | else 20 | puts "No, #{number} is not odd" 21 | end 22 | 23 | -------------------------------------------------------------------------------- /session1/2-examples/3_rememberer.rb: -------------------------------------------------------------------------------- 1 | # This program uses things you haven't seen yet. 2 | # Can you look at it and figure out what it is doing? 3 | 4 | lines_seen = [] 5 | 6 | 7 | loop do 8 | 9 | # Why do we chomp? Can you use irb to figure out the difference between gets, and gets.chomp ? 10 | line = gets.chomp 11 | break if line == "exit" 12 | 13 | if lines_seen.include? line 14 | puts "Yes, I've seen #{line} before" 15 | else 16 | puts "No, I haven't seen #{line} before" 17 | lines_seen << line 18 | end 19 | end 20 | 21 | -------------------------------------------------------------------------------- /session1/2-examples/4_rememberer2.rb: -------------------------------------------------------------------------------- 1 | # Did you understand the last one? 2 | # This is the same one, but we abstracted the tasks 3 | # into methods that are easier to test, 4 | # and can be reused easily. They also let us talk 5 | # about a task based on the method name, which is 6 | # much simpler than the piece of code behind it. 7 | 8 | 9 | def get_line 10 | gets.chomp 11 | end 12 | 13 | def finished?(line) 14 | line == "exit" 15 | end 16 | 17 | def user_message(lines_seen, line) 18 | if lines_seen.include? line 19 | "Yes, I've seen #{line} before" 20 | else 21 | "No, I haven't seen #{line} before" 22 | end 23 | end 24 | 25 | def record_observation(lines_seen, line) 26 | unless lines_seen.include? line 27 | lines_seen << line 28 | end 29 | end 30 | 31 | 32 | lines_seen = [] 33 | 34 | loop do 35 | line = get_line 36 | break if finished?(line) 37 | puts user_message(lines_seen, line) 38 | record_observation(lines_seen, line) 39 | end 40 | 41 | -------------------------------------------------------------------------------- /session1/3-challenge/1_arithmetic.rb: -------------------------------------------------------------------------------- 1 | # fill out the method below 2 | # then test tho see if you did them correctly with 3 | # $ rake 1:1 4 | 5 | # Given a number, return 20 less than, that number multiplied by 5 6 | # 7 | # arithmetic1(10) # => 30 8 | # arithmetic1(10.5) # => 32.5 9 | # arithmetic1(-6) # => -50 10 | 11 | def arithmetic1(n) 12 | 13 | end 14 | -------------------------------------------------------------------------------- /session1/3-challenge/2_arithmetic.rb: -------------------------------------------------------------------------------- 1 | # fill out the method below, then run the tests with 2 | # $ rake 1:2 3 | 4 | 5 | # Given two numbers, a and b, return half of whichever is smallest, as a float 6 | # 7 | # arithmetic2(1, 2) # => 0.5 8 | # arithmetic2(19, 10) # => 5.0 9 | # arithmetic2(-6, -7) # => -3.5 10 | 11 | def arithmetic2(a, b) 12 | end 13 | -------------------------------------------------------------------------------- /session1/3-challenge/3_simple_logic.rb: -------------------------------------------------------------------------------- 1 | # remember, you can test this file with 2 | # $ rake 1:3 3 | 4 | 5 | # Given a number, n, return 10 if it is even, and 20 if it is odd 6 | # 7 | # ten_twenty(5) # => 20 8 | # ten_twenty(6) # => 10 9 | 10 | def ten_twenty(n) 11 | end 12 | -------------------------------------------------------------------------------- /session1/3-challenge/4_logic.rb: -------------------------------------------------------------------------------- 1 | # A grad student at a local university thinks he has discovered a formula to 2 | # predict what kind of grades a person will get. He says if you own less than 3 | # 10 books, you will get a "D". If you own 10 to 20 books, you will get a "C", 4 | # and if you own more than 20 books, you will get a "B". 5 | # He further hypothesizes that if you actually read your books, then you will 6 | # get a full letter grade higher in every case. 7 | # 8 | # grade(4, false) # => "D" 9 | # grade(4, true) # => "C" 10 | # grade(15, true) # => "B" 11 | 12 | # <10 books => D, 10..20 books => C, >20 book =>B 13 | 14 | 15 | def grade(num_books, has_read_books) 16 | end 17 | 18 | 19 | -------------------------------------------------------------------------------- /session1/3-challenge/5_string.rb: -------------------------------------------------------------------------------- 1 | # Given a string, replace every instance of sad to happy 2 | # 3 | # add_more_ruby("The clowns were sad.") # => "The clowns were happy." 4 | # add_more_ruby("The sad dad said sad stuff.") # => "The happy dad said happy stuff." 5 | # add_more_ruby("Sad times are ahead!") # => "Happy times are ahead!" 6 | 7 | def add_more_ruby(string) 8 | end -------------------------------------------------------------------------------- /session1/3-challenge/6_string.rb: -------------------------------------------------------------------------------- 1 | # You'll get a string and a boolean. 2 | # When the boolean is true, return a new string containing all the odd characters. 3 | # When the boolean is false, return a new string containing all the even characters. 4 | # 5 | # If you have no idea where to begin, remember to check out the cheatsheets for string and logic/control 6 | # 7 | 8 | def odds_and_evens(string, return_odds) 9 | 10 | end -------------------------------------------------------------------------------- /session1/3-challenge/7_string.rb: -------------------------------------------------------------------------------- 1 | # given a string, return the character after every letter "r" 2 | # 3 | # pirates_say_arrrrrrrrr("are you really learning Ruby?") # => "eenu" 4 | # pirates_say_arrrrrrrrr("Katy Perry is on the radio!") # => "rya" 5 | # pirates_say_arrrrrrrrr("Pirates say arrrrrrrrr") # => "arrrrrrrr" 6 | 7 | def pirates_say_arrrrrrrrr(string) 8 | 9 | end 10 | -------------------------------------------------------------------------------- /session1/4-spec/1.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe "arithmetic1" do 2 | it 'returns 30 when passed 10' do 3 | expect(arithmetic1 10).to eq 30 4 | end 5 | 6 | it 'returns 32.5 when passed 10.5' do 7 | expect(arithmetic1 10.5).to eq 32.5 8 | end 9 | 10 | it 'returns -50 when passed -6' do 11 | expect(arithmetic1 -6).to eq -50 12 | end 13 | 14 | it 'returns 480 when passed 100' do 15 | expect(arithmetic1 100).to eq 480 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /session1/4-spec/2.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe "arithmetic2" do 2 | let(:test_array) { 3 | [ -7, -6, -3.5, 4 | 1, -1, -0.5, 5 | -1, 1, -0.5, 6 | -1, -1, -0.5, 7 | 0, 0, 0.0, 8 | 0, 100, 0.0, 9 | ] 10 | } 11 | 12 | it 'returns 0.5 when give 1 , 2' do 13 | expect(arithmetic2 1, 2).to eq 0.5 14 | end 15 | 16 | it 'returns 5.0 when given 19 , 10' do 17 | expect(arithmetic2 19, 10).to eq 5.0 18 | end 19 | 20 | it 'returns -3.5 when given -6 , -7' do 21 | expect(arithmetic2 -6, -7).to eq -3.5 22 | end 23 | 24 | it 'returns pass the test array' do 25 | test_array.each_slice 3 do |a, b, result| 26 | expect(arithmetic2 a, b).to eq result 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /session1/4-spec/3.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe "ten_twenty" do 2 | it 'returns 20 when passed 5' do 3 | expect(ten_twenty 5).to eq 20 4 | end 5 | 6 | it 'returns 10 when passed 6' do 7 | expect(ten_twenty 6).to eq 10 8 | end 9 | 10 | it 'returns 10 when passed 0' do 11 | expect(ten_twenty 0).to eq 10 12 | end 13 | 14 | 1_000_000.step(-1_000_000, -101_275) do |i| 15 | if i % 2 == 0 16 | it "returns #{10} when passed #{i}" do 17 | expect(ten_twenty i).to eq 10 18 | end 19 | else 20 | it "returns #{20} when passed #{i}" do 21 | expect(ten_twenty i).to eq 20 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /session1/4-spec/4.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe "grade" do 2 | context "for non book reader" do 3 | 0.upto 9 do |num_books| 4 | it "returns \"D\" when given #{num_books} books" do 5 | expect(grade num_books, false).to eq "D" 6 | end 7 | end 8 | 9 | 10.upto 20 do |num_books| 10 | it "returns \"C\" when given #{num_books} books" do 11 | expect(grade num_books, false).to eq "C" 12 | end 13 | end 14 | 15 | [21,30,500].each do |num_books| 16 | it "returns \"B\" when given #{num_books} books" do 17 | expect(grade num_books, false).to eq "B" 18 | end 19 | end 20 | end 21 | 22 | context "for book reader" do 23 | 0.upto 9 do |num_books| 24 | it "returns \"C\" when given #{num_books} books" do 25 | expect(grade num_books, true).to eq "C" 26 | end 27 | end 28 | 29 | 10.upto 20 do |num_books| 30 | it "returns \"B\" when given #{num_books} books" do 31 | expect(grade num_books, true).to eq "B" 32 | end 33 | end 34 | 35 | [21,30,500].each do |num_books| 36 | it "returns \"A\" when given #{num_books} books" do 37 | expect(grade num_books, true).to eq "A" 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /session1/4-spec/5.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe "add_more_ruby" do 2 | it 'changes sad to happy' do 3 | expect(add_more_ruby "The clowns were sad.").to eq "The clowns were happy." 4 | end 5 | 6 | it 'changes sad at the end' do 7 | expect(add_more_ruby "abc sad").to eq("abc happy") 8 | end 9 | 10 | it 'changes sad every time it sees it' do 11 | expect(add_more_ruby "The sad dad said sad stuff.").to eq "The happy dad said happy stuff." 12 | end 13 | 14 | it 'makes Happy uppercase if Sad is uppercase' do 15 | expect(add_more_ruby "Sad times are ahead!").to eq "Happy times are ahead!" 16 | end 17 | 18 | it 'changes lots of sads in a row' do 19 | expect(add_more_ruby "sadSadsadsad").to eq "happyHappyhappyhappy" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /session1/4-spec/7.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe "pirates_say_arrrrrrrrr" do 2 | it 'returns "eeu" when given "are you really learning Ruby?"' do 3 | expect(pirates_say_arrrrrrrrr 'are you really learning Ruby?').to eq 'eenu' 4 | end 5 | 6 | it 'returns "rya" when given "Katy Perry is on the radio!"' do 7 | expect(pirates_say_arrrrrrrrr 'Katy Perry is on the radio!').to eq 'rya' 8 | end 9 | 10 | it 'returns "arrrrrrrr" when given "Pirates say arrrrrrrrr"' do 11 | expect(pirates_say_arrrrrrrrr 'Pirates say arrrrrrrrr').to eq 'arrrrrrrr' 12 | end 13 | 14 | it 'returns "12" when given "r1r2r"' do 15 | expect(pirates_say_arrrrrrrrr 'r1r2r').to eq '12' 16 | end 17 | 18 | it 'returns "" when given ""' do 19 | expect(pirates_say_arrrrrrrrr '').to eq '' 20 | end 21 | 22 | it 'returns "" when given "Quickly she consumed the apple."' do 23 | expect(pirates_say_arrrrrrrrr 'Quickly she consumed the apple.').to eq '' 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /session1/5-solved/1.rb: -------------------------------------------------------------------------------- 1 | def arithmetic1(n) 2 | n * 5 - 20 3 | end -------------------------------------------------------------------------------- /session1/5-solved/2.rb: -------------------------------------------------------------------------------- 1 | def arithmetic2(a, b) 2 | if a < b 3 | a / 2.0 4 | else 5 | b / 2.0 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /session1/5-solved/3.rb: -------------------------------------------------------------------------------- 1 | def ten_twenty(n) 2 | if n % 2 == 0 3 | 10 4 | else 5 | 20 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /session1/5-solved/4.rb: -------------------------------------------------------------------------------- 1 | def grade(num_books, reads_books) 2 | if reads_books 3 | return "C" if num_books < 10 4 | return "B" if num_books <= 20 5 | return "A" 6 | else 7 | return "D" if num_books < 10 8 | return "C" if num_books <= 20 9 | return "B" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /session1/5-solved/5.rb: -------------------------------------------------------------------------------- 1 | def add_more_ruby(string) 2 | string.gsub('sad', 'happy').gsub('Sad', 'Happy') 3 | end 4 | -------------------------------------------------------------------------------- /session1/5-solved/6.rb: -------------------------------------------------------------------------------- 1 | def odds_and_evens(string, return_odds) 2 | to_return = "" 3 | string.size.times do |index| 4 | next if return_odds && index.even? 5 | next if !return_odds && index.odd? 6 | to_return << string[index] 7 | end 8 | to_return 9 | end 10 | -------------------------------------------------------------------------------- /session1/5-solved/7.rb: -------------------------------------------------------------------------------- 1 | def pirates_say_arrrrrrrrr(string) 2 | to_return = "" 3 | add_next = false 4 | string.size.times do |index| 5 | current_char = string[index,1] # the second param here tells it to get a str of length 1. This is only necessary on 1.8. If you are on 1.9, just go with string[index] 6 | to_return << current_char if add_next 7 | add_next = (current_char == "r" || current_char == "R") 8 | end 9 | to_return 10 | end 11 | -------------------------------------------------------------------------------- /session2/1-notes/01-a-quick-word-about-blocks.rb: -------------------------------------------------------------------------------- 1 | #Watch this video - https://vimeo.com/24365612 - these notes are supplementary as per the last section 2 | 3 | # We'll talk about blocks more later, but for now just know 4 | # that you declare a parameter in pipes (this is just 5 | # like a method declaring parameters) 6 | 7 | def mah_method!(method_param) 8 | end 9 | 10 | 11 | # This is the syntax for single line blocks 12 | # note that you need parens around that 1, 13 | # we'll discuss why later 14 | mah_method!(1) { |block_parameter| block_parameter * 2 } 15 | 16 | 17 | # you also have multiline syntax 18 | # here you don't need parens around the 1 19 | mah_method! 1 do |param1, param2| 20 | param1 + param2 21 | end 22 | 23 | -------------------------------------------------------------------------------- /session2/1-notes/02-arrays.rb: -------------------------------------------------------------------------------- 1 | # Arrays are ordered lists of objects. 2 | array = ['zero', 'one', 'two'] 3 | 4 | 5 | # You access a given element by its index, 6 | # beginning at zero 7 | array[0] # => "zero" 8 | array[1] # => "one" 9 | array[2] # => "two" 10 | 11 | 12 | # If you go past the end, you get back nil 13 | array[3] # => nil 14 | 15 | 16 | # Negative indexes backwards from the end 17 | array[-1] # => "two" 18 | array[-2] # => "one" 19 | array[-3] # => "zero" 20 | 21 | 22 | # Arrays know where the elements at their indexes are this 23 | # means it is just as cheap to look up an element really 24 | # deep as it is for an element right at the beginning. 25 | array = (0...5000).to_a # the numbers 1 to 5k 26 | 27 | 28 | # about half a second to access element at index 2500 29 | start_time = Time.now 30 | 5_000_000.times { array[2500] } 31 | Time.now - start_time # => 0.545612 32 | 33 | 34 | # about half a second to access element at index 0 35 | start_time = Time.now 36 | 5_000_000.times { array[0] } 37 | Time.now - start_time # => 0.545922 38 | -------------------------------------------------------------------------------- /session2/1-notes/03-array-iterating.rb: -------------------------------------------------------------------------------- 1 | numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 2 | 3 | # Use each to iterate, and pass a block 4 | # We'll cover blocks more later 5 | sum = 0 6 | numbers.each { |number| sum += number } 7 | sum # => 45 8 | 9 | 10 | # Use map to make a new array out of the elements 11 | # returned by the block 12 | squares = numbers.map { |number| number * number } 13 | squares # => [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 14 | numbers # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 15 | 16 | 17 | # iterate over the array two at a time 18 | result = [] 19 | numbers.each_slice(2) { |a, b| result << [a, b] } 20 | result # => [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]] 21 | 22 | 23 | # iterate over the array in groups of two 24 | # hitting each group as we go 25 | result = [] 26 | numbers[0..5].each_cons(2) { |a, b| result << [a, b] } 27 | result # => [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]] 28 | -------------------------------------------------------------------------------- /session2/1-notes/04-array-filtering.rb: -------------------------------------------------------------------------------- 1 | numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 2 | 3 | 4 | # Use select to make a new array of only the elements 5 | # you want if the block returns a truthy value then 6 | # that element will be in the result. 7 | evens = numbers.select { |number| number.even? } 8 | evens # => [0, 2, 4, 6, 8] 9 | 10 | 11 | # Reject is the opposite 12 | odds = numbers.reject { |number| number.even? } 13 | odds # => [1, 3, 5, 7, 9] 14 | 15 | 16 | # None of these modify the original array 17 | # They all return new arrays 18 | numbers # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 19 | -------------------------------------------------------------------------------- /session2/1-notes/05-other-useful-array-methods.rb: -------------------------------------------------------------------------------- 1 | chars = ['a', 'b', 'c'] 2 | 3 | 4 | # Concatenate with + 5 | chars + ['d', 'e'] # => ["a", "b", "c", "d", "e"] 6 | 7 | 8 | # Append to an array 9 | chars # => ["a", "b", "c"] 10 | chars << 'd' 11 | chars # => ["a", "b", "c", "d"] 12 | 13 | 14 | # Replace 15 | chars[1] = 'Bee' 16 | chars # => ["a", "Bee", "c", "d"] 17 | 18 | 19 | # Delete index 20 | chars.delete_at 1 21 | chars # => ["a", "c", "d"] 22 | 23 | 24 | # Delete object 25 | chars.delete 'c' 26 | chars # => ["a", "d"] 27 | 28 | 29 | # Insert 30 | index = 1 31 | chars.insert index, 'b' , 'c' 32 | chars # => ["a", "b", "c", "d"] 33 | 34 | 35 | # Sorting 36 | ['c', 'b', 'd', 'a'].sort # => ["a", "b", "c", "d"] 37 | -------------------------------------------------------------------------------- /session2/1-notes/06-classes.rb: -------------------------------------------------------------------------------- 1 | # We've explained what an object is, data packaged 2 | # together with methods. But how do we define 3 | # what data our object should have, and how do we 4 | # associate methods with that data? 5 | # 6 | # For that, we use classes :) 7 | 8 | 9 | # Classes are containers for methods. 10 | # 11 | # When you have an object that uses those methods, we 12 | # say it is an *instance* of that class. 13 | # 14 | # The instance keeps track of its class, then when you 15 | # invoke a method on it, it finds the method by looking 16 | # it up in the class. 17 | 18 | # So, objects have methods, and those methods are 19 | # defined in its class. 20 | -------------------------------------------------------------------------------- /session2/1-notes/07-class-examples.rb: -------------------------------------------------------------------------------- 1 | # Here are some examples of classes: 2 | String # => String 3 | Hash # => Hash 4 | Array # => Array 5 | Fixnum # => Fixnum 6 | 7 | 8 | # Here are some examples of instances of these classes 9 | "abc".class # => String 10 | {1 => 2}.class # => Hash 11 | [1, 2, 3].class # => Array 12 | 123456789.class # => Fixnum 13 | -------------------------------------------------------------------------------- /session2/1-notes/08-methods-go-in-classes.rb: -------------------------------------------------------------------------------- 1 | # When we say "abc".length, the length method 2 | # is stored in the String class. 3 | length = String.instance_method 'length' 4 | length # => # 5 | 6 | 7 | # So if we want to make a new method on strings, 8 | # we would put it in the String class 9 | class String 10 | def half_length 11 | length / 2 12 | end 13 | end 14 | "abcdef".half_length # => 3 15 | -------------------------------------------------------------------------------- /session2/1-notes/09-class-questions.rb: -------------------------------------------------------------------------------- 1 | # Between Yankees and Baseball team 2 | # which is a class and which is an instance? 3 | 4 | # Between Person and Enoch 5 | # which is a class and which is an instance? 6 | 7 | # Can you think of another class and several instances? 8 | 9 | 10 | 11 | # Are classes objects? 12 | # If no, where do you think their methods are stored? 13 | # If yes, what class are they instances of? 14 | -------------------------------------------------------------------------------- /session2/1-notes/10-instance-variables.rb: -------------------------------------------------------------------------------- 1 | # Objects store their state in instance variables 2 | # Those are the ones that begin with the @asperand 3 | 4 | # Before, we said methods are their own little world. 5 | # That was a lie, they can see instance variables. 6 | # We'll talk more about that in a bit. 7 | class Car 8 | # we call methods like this a "setter" 9 | def set_miles(miles) 10 | @miles = miles 11 | end 12 | 13 | # we call methods like this a "getter" 14 | def get_miles 15 | @miles 16 | end 17 | end 18 | 19 | car = Car.new 20 | car.set_miles 1000 21 | car.get_miles # => 1000 22 | 23 | car.instance_variables # => [:@miles] 24 | car.instance_variable_get '@miles' # => 1000 25 | 26 | 27 | # Question: We create our car by calling Car.new 28 | # where is the new method defined? 29 | -------------------------------------------------------------------------------- /session2/1-notes/11-naming-methods.rb: -------------------------------------------------------------------------------- 1 | # Using set_whatever and get_whatever is kind of 2 | # distracting. It's better to name your setters 3 | # and getters the same as the variable they represent. 4 | 5 | class Car 6 | def miles=(miles) 7 | @miles = miles 8 | end 9 | 10 | def miles 11 | @miles 12 | end 13 | end 14 | 15 | Car.instance_methods false # => [:miles=, :miles] 16 | 17 | car = Car.new 18 | car.miles = 1000 # Ruby knows this is the miles= method 19 | car.miles # => 1000 20 | -------------------------------------------------------------------------------- /session2/1-notes/12-attr_accessor.rb: -------------------------------------------------------------------------------- 1 | # In fact, this naming convention for setters and 2 | # getters is so common that there is a method that 3 | # will write them for you. 4 | 5 | class Car 6 | attr_accessor 'miles' 7 | end 8 | 9 | Car.instance_methods false # => [:miles, :miles=] 10 | 11 | car = Car.new 12 | car.miles = 1000 13 | car.miles # => 1000 14 | 15 | car.instance_variables # => [:@miles] 16 | car.instance_variable_get '@miles' # => 1000 17 | 18 | 19 | # attr_accessor is an example of metaprogramming, 20 | # You can write methods yourself like attr_accessor 21 | -------------------------------------------------------------------------------- /session2/1-notes/13-initializing.rb: -------------------------------------------------------------------------------- 1 | # When you instantiate an object (make an instance 2 | # of a class), you use the new method. After doing all 3 | # the things necessary to make an object, the new method 4 | # will invoke a method named initialize, and pass it 5 | # any arguments you passed to new. This allows you to 6 | # put your object into an initial state. 7 | 8 | class Instrument 9 | def initialize(name, price) 10 | @name = name 11 | @price = price 12 | end 13 | 14 | attr_accessor 'name', 'price' 15 | end 16 | 17 | clarinet = Instrument.new 'Clarinet', 250 18 | clarinet.name # => "Clarinet" 19 | clarinet.price # => 250 20 | 21 | -------------------------------------------------------------------------------- /session2/1-notes/14-self.rb: -------------------------------------------------------------------------------- 1 | # At any given time in Ruby, you are in the context 2 | # of some object. Right now we're in the main object. 3 | 4 | # You can see what object you're in by looking at self. 5 | self # => main 6 | 7 | class String 8 | self # => String 9 | end 10 | 11 | class String 12 | def existential 13 | self # => "abc" 14 | end 15 | end 16 | "abc".existential 17 | 18 | 19 | # For a given context, you can always see your instance 20 | # variables and your methods. 21 | 22 | class Example 23 | self # => Example 24 | 25 | @abc = 123 26 | @abc # => 123 27 | 28 | # These will all work, because they all invoke new on 29 | # Example. Explicitly in the first two cases, implicitly 30 | # in the third. 31 | Example.new # => # 32 | self.new # => # 33 | new # => # 34 | end 35 | 36 | -------------------------------------------------------------------------------- /session2/1-notes/15-more-on-method-scope.rb: -------------------------------------------------------------------------------- 1 | # So methods being their own little world is totally a lie 2 | # They can actually see instance variables and methods 3 | # on their object. 4 | 5 | class Example 6 | 7 | def method1 8 | self # => # 9 | @var = 123 10 | method2 11 | @var # => 500 12 | end 13 | 14 | def method2 15 | self # => # 16 | @var # => 123 17 | @var = 500 18 | end 19 | 20 | end 21 | 22 | Example.new.method1 23 | -------------------------------------------------------------------------------- /session2/1-notes/16-THIS-IS-GONNA-TRIP-YOU-UP.rb: -------------------------------------------------------------------------------- 1 | # When calling a setter method, always use an explicit 2 | # receiver. Otherwise it looks like you're setting a 3 | # local variable. 4 | 5 | class Flight 6 | attr_accessor 'arrival_time' 7 | 8 | def reset 9 | arrival_time # => 1100 10 | arrival_time = 0 11 | 12 | # Wait, wtf is this? 13 | arrival_time # => 0 14 | self.arrival_time # => 1100 15 | 16 | # Oh, it thought we wanted to make a local variable 17 | # named arrival_time 18 | local_variables # => [:arrival_time] 19 | 20 | # We should have made it explicit by specifying that 21 | # arrival_time= is a method on self 22 | self.arrival_time = 0 23 | end 24 | end 25 | 26 | f = Flight.new 27 | f.arrival_time = 1100 28 | f.reset 29 | -------------------------------------------------------------------------------- /session2/1-notes/17-singleton-classes.rb: -------------------------------------------------------------------------------- 1 | # Turns out that every object actually has 2 classes! 2 | # The one we've been using so far, and its singleton 3 | # class -- a class whose only instance is the object. 4 | 5 | # So an object is defined by its class, but it also 6 | # can have its own unique behaviour by defining 7 | # methods on its singleton class. 8 | 9 | 10 | # Singleton classes don't have names 11 | obj = Object.new 12 | obj.singleton_class # => #> 13 | 14 | # You can access the singleton class like this 15 | class << obj 16 | def greet 17 | 'Howdy, partner.' 18 | end 19 | end 20 | obj.singleton_class.instance_methods false # => [:greet] 21 | obj.singleton_methods # => [:greet] 22 | obj.greet # => "Howdy, partner." 23 | 24 | 25 | # Shortcut syntax for the above 26 | def obj.about 27 | "A plain old object with a few tricks." 28 | end 29 | 30 | obj.about # => "A plain old object with a few tricks." 31 | obj.singleton_methods # => [:greet, :about] 32 | 33 | # Question: if everything is an object, and every object 34 | # has a singleton class, then do singleton classes have 35 | # singleton classes? 36 | # 37 | # How can you test your answer out? 38 | 39 | obj = Object.new 40 | puts obj.singleton_class.singleton_class # => #>> 41 | -------------------------------------------------------------------------------- /session2/1-notes/18-class-instance-variables.rb: -------------------------------------------------------------------------------- 1 | # Lets say we wanted to know what planet people are from. 2 | # Well, that information is the same across every person 3 | # so we can keep it in an instance variable on the class. 4 | 5 | class Person 6 | # When we define methods here, they get defined for 7 | # instances of Person, so we need to either store 8 | # them in Person's class or singleton class. It doesn't 9 | # make sense to give EVERY class a home_planet, so 10 | # lets put it on the singleton_class 11 | self # => Person 12 | class << self 13 | attr_accessor 'home_planet' 14 | end 15 | 16 | # remember, self is Person, so @home_planet 17 | # is defined on the Person class itself 18 | @home_planet = 'Erth' 19 | Person.home_planet # => "Erth" 20 | Person.home_planet = 'Earth' 21 | @home_planet # => "Earth" 22 | 23 | 24 | attr_accessor 'name' 25 | def initialize(name) 26 | # self is now an instance of person, so @name 27 | # is defined for this particular person 28 | @name = name 29 | end 30 | 31 | # This one is for instances 32 | def home_planet 33 | Person.home_planet 34 | end 35 | end 36 | 37 | Person.home_planet 38 | kate = Person.new 'Kate Beckinsale' 39 | josh = Person.new 'Josh Cheek' 40 | kate.home_planet # => "Earth" 41 | josh.home_planet # => "Earth" 42 | kate.name # => "Kate Beckinsale" 43 | josh.name # => "Josh Cheek" 44 | 45 | Person.instance_variables # => [:@home_planet] 46 | josh.instance_variables # => [:@name] 47 | -------------------------------------------------------------------------------- /session2/1-notes/19-last-words.rb: -------------------------------------------------------------------------------- 1 | # Okay, ready for challenges ^_^ 2 | # I spent a long time on these, hopefully you'll enjoy them! 3 | 4 | 5 | 6 | # A USEFUL HINT! 7 | # You can return from a method early with the keyword return 8 | def method(condition) 9 | return 1 if condition 10 | 2 11 | end 12 | method true # => 1 13 | method false # => 2 14 | 15 | # Check out cheatsheet for arrays: 16 | # https://github.com/JoshCheek/ruby-kickstart/blob/master/cheatsheets/arrays.rb -------------------------------------------------------------------------------- /session2/2-examples/1_output.rb: -------------------------------------------------------------------------------- 1 | number = 5 2 | other_number = 12 3 | 4 | puts "first line" , "second line" 5 | 6 | puts "The number we have is #{number} and the sum of our numbers is #{number + other_number}" 7 | # >> The number we have is 5 and the sum of our numbers is 17 8 | 9 | print "this will all be " 10 | print "on the same line" 11 | 12 | puts # an empty newline 13 | -------------------------------------------------------------------------------- /session2/2-examples/2_gets.rb: -------------------------------------------------------------------------------- 1 | puts "Hello, start typing!" 2 | 3 | while line = gets 4 | puts "You submitted #{line.inspect}" 5 | break if line.chomp == 'exit' 6 | end 7 | 8 | puts "Goodbye!" 9 | -------------------------------------------------------------------------------- /session2/2-examples/3_array.rb: -------------------------------------------------------------------------------- 1 | # The Unix environment variable $PATH contains a list of paths (go to your terminal and type "echo $PATH") 2 | 3 | 4 | # create an array of paths to check 5 | paths_ary = [ '/bin' , '/opt/local/var' , '/Users/josh' ] 6 | 7 | 8 | # if we were on Michael's or Kris' computer, we might have this in our path (they use Windows) 9 | paths_ary << 'c:\\michael' 10 | paths_ary << 'c:\\kris' 11 | 12 | # let's add one more Unix path as well 13 | paths_ary << '/usr/been' 14 | 15 | paths_ary # => ["/bin", "/opt/local/var", "/Users/josh", "c:\\michael", "c:\\kris", "/usr/been"] 16 | 17 | 18 | # which path will be checked first when the system looks for a program? 19 | paths_ary[0] # => "/bin" 20 | 21 | # which path will be checked last when the system looks for a program? 22 | paths_ary[-1] # => "/usr/been" 23 | 24 | # whoops, we must have been sleep deprived when we put that last one in! 25 | paths_ary[-1] = "/usr/bin" 26 | 27 | 28 | # well, Unix won't know what to do with Windows style file paths, so lets reject them from the array 29 | # if the block is "true" then that element will be removed, so we just check the path for 'c:\\' 30 | # (note that reject! actually changes our array, instead of making a new one, since it ends with a ! ) 31 | paths_ary.reject! { |path| path['c:\\'] } 32 | 33 | 34 | # lets display each one of the paths 35 | paths_ary.each do |path| 36 | puts path 37 | end 38 | 39 | 40 | # now, to be a path variable, it needs all these paths joined together with a colon between each 41 | $PATH = paths_ary.join(':') 42 | puts '' , $PATH 43 | # >> /bin 44 | # >> /opt/local/var 45 | # >> /Users/josh 46 | # >> /usr/bin 47 | # >> 48 | # >> /bin:/opt/local/var:/Users/josh:/usr/bin 49 | -------------------------------------------------------------------------------- /session2/3-challenge/10_classes.rb: -------------------------------------------------------------------------------- 1 | # Make a person class that has a name, age, and birthday 2 | # 3 | # josh = Person.new 'Josh', 28 4 | # 5 | # josh.name # => "Josh" 6 | # josh.age # => 28 7 | # 8 | # josh.name = 'Joshua' 9 | # josh.name # => "Joshua" 10 | # 11 | # josh.birthday # => 29 12 | # josh.age # => 29 13 | # 14 | # josh.birthday # => 30 15 | # josh.age # => 30 16 | # 17 | 18 | class Person 19 | 20 | end 21 | -------------------------------------------------------------------------------- /session2/3-challenge/11_classes.rb: -------------------------------------------------------------------------------- 1 | # DO NOT STRUGGLE ON THIS PROBLEM FOR MORE THAN 30 MINUTES!! 2 | 3 | # Write a program that outputs the lyrics for "Ninety-nine Bottles of Beer on the Wall" 4 | # Your program should print the number of bottles in English, not as a number. For example: 5 | # 6 | # Ninety-nine bottles of beer on the wall, 7 | # Ninety-nine bottles of beer, 8 | # Take one down, pass it around, 9 | # Ninety-eight bottles of beer on the wall. 10 | # ... 11 | # One bottle of beer on the wall, 12 | # One bottle of beer, 13 | # Take one down, pass it around, 14 | # Zero bottles of beer on the wall. 15 | # 16 | # Your program should not use ninety-nine output statements! 17 | # Design your program with a class named BeerSong whose initialize method 18 | # receives a parameter indicating the number of bottles of beer initially on the wall. 19 | # If the parameter is less than zero, set the number of bottles to zero. Similarly, 20 | # if the parameter is greater than 99, set the number of beer bottles to 99 21 | # Then make a public method called print_song that outputs all stanzas from the number of bottles of beer down to zero. 22 | # Add any additional methods you find helpful. 23 | -------------------------------------------------------------------------------- /session2/3-challenge/12_classes.rb: -------------------------------------------------------------------------------- 1 | # DO NOT STRUGGLE ON THIS PROBLEM FOR MORE THAN 30 MINUTES!! 2 | 3 | # Define a class called Fraction 4 | # This class is used to represent a ratio of two integers 5 | # Include setter methods called numerator and denominator that allow the user to change these values 6 | # Also include a method called to_f that returns the ratio as a float (a number with a decimal point, such as 10.3) 7 | # Also include a method called lowest, which returns a new Fraction, where the numerator and denominator 8 | # are reduced to lowest terms (ie 20/60 becomes 1/3) 9 | # This will require finding the greatest common divisor for the numerator and denominator 10 | # then dividing both by that number. 11 | # I have included a greatest common divisor method for you 12 | # You should also define a method, to_s, that will represent the Fraction as a String 13 | # 14 | # EXAMPLE: 15 | # f = Fraction.new 20, 60 16 | # f.numerator # => 20 17 | # f.denominator # => 60 18 | # f.to_s # => "20/60" 19 | # f.lowest.to_s # => "1/3" 20 | # f.numerator = 50 21 | # f.denominator = 100 22 | # f.to_s # => "50/100" 23 | # f.to_f # => 0.5 24 | 25 | class Fraction 26 | def gcd(a,b) 27 | return a if b == 0 28 | gcd(b, a%b) 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /session2/3-challenge/1_input_output.rb: -------------------------------------------------------------------------------- 1 | # Remember you can test this code with 2 | # $ rake 2:1 3 | 4 | # Write a program that reads in two integers typed on the keybaord 5 | # and outputs their sum, difference, and product 6 | # 7 | # Standard input will be like "9 2\n" and will expect you to print 8 | # "11\n7\n18\n" to standard output. 9 | 10 | def sum_difference_product 11 | # your code goes here 12 | 13 | end -------------------------------------------------------------------------------- /session2/3-challenge/2_input_output_control.rb: -------------------------------------------------------------------------------- 1 | # Prompt the user for a number, then read it in and print out "hi" that many times 2 | # 3 | # Repeat this process until the user submits "bye", then say "goodbye" and end the program 4 | # HINT: Check out example 2 if you get stuck 5 | 6 | # example: 7 | # PROGRAM: Enter a number 8 | # USER: 4 9 | # PROGRAM: hi hi hi hi 10 | # PROGRAM: Enter a number 11 | # USER: 2 12 | # PROGRAM: hi hi 13 | # PROGRAM: Enter a number 14 | # USER: bye 15 | # PROGRAM: goodbye 16 | 17 | 18 | # remember you can try your program out with $ ruby 2_input_output_control.rb 19 | # and when you think it is correct, you can test it with $ rake 2:2 20 | 21 | def hi_hi_goodbye 22 | # your code here 23 | 24 | end 25 | 26 | 27 | 28 | 29 | # This will just invoke the method if you run this program directly 30 | # This way you can try it out by running "$ ruby 2_input_output_control.rb" 31 | # but it will still work for our tests 32 | hi_hi_goodbye if $0 == __FILE__ -------------------------------------------------------------------------------- /session2/3-challenge/3_array.rb: -------------------------------------------------------------------------------- 1 | # Write a method named every_other_char for strings that, 2 | # returns a string containing every other character 3 | # 4 | # example: 5 | # "abcdefg".every_other_char # => "aceg" 6 | # "".every_other_char # => "" 7 | 8 | class String 9 | def every_other_char 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /session2/3-challenge/4_array.rb: -------------------------------------------------------------------------------- 1 | # Write a method named get_squares that takes an array of numbers 2 | # and returns a sorted array containing only the numbers whose square is also in the array 3 | # 4 | # get_squares [9] # => [] 5 | # get_squares [9,3] # => [3] 6 | # get_squares [9,3,81] # => [3, 9] 7 | # get_squares [25, 4, 9, 6, 50, 16, 5] # => [4, 5] 8 | 9 | # This time you will have to define the method, it's called: get_squares 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /session2/3-challenge/5_array.rb: -------------------------------------------------------------------------------- 1 | # Write a function named mod_three which takes an array of numbers, 2 | # and return a new array consisting of their remainder when divided by three. 3 | # Exclude any numbers which are actually dividible by three. 4 | # 5 | # EXAMPLES: 6 | # mod_three [0] # => [] 7 | # mod_three [1] # => [1] 8 | # mod_three [2] # => [2] 9 | # mod_three [3] # => [] 10 | # mod_three [4] # => [1] 11 | # mod_three [5] # => [2] 12 | # mod_three [6] # => [] 13 | # mod_three [7] # => [1] 14 | # 15 | # mod_three [0,1,2,3,4,5,6,7] # => [1, 2, 1, 2, 1] 16 | 17 | -------------------------------------------------------------------------------- /session2/3-challenge/6_array.rb: -------------------------------------------------------------------------------- 1 | # Write a method named prime_chars? which takes array of strings 2 | # and returns true if the sum of the characters is prime. 3 | # 4 | # Remember that a number is prime if the only integers that can divide it with no remainder are 1 and itself. 5 | # 6 | # Examples of length three 7 | # prime_chars? ['abc'] # => true 8 | # prime_chars? ['a', 'bc'] # => true 9 | # prime_chars? ['ab', 'c'] # => true 10 | # prime_chars? ['a', 'b', 'c'] # => true 11 | # 12 | # Examples of length four 13 | # prime_chars? ['abcd'] # => false 14 | # prime_chars? ['ab', 'cd'] # => false 15 | # prime_chars? ['a', 'bcd'] # => false 16 | # prime_chars? ['a', 'b', 'cd'] # => false 17 | 18 | -------------------------------------------------------------------------------- /session2/3-challenge/7_array.rb: -------------------------------------------------------------------------------- 1 | # Given a sentence, return an array containing every other word. 2 | # Punctuation is not part of the word unless it is a contraction. 3 | # In order to not have to write an actual language parser, there won't be any punctuation too complex. 4 | # There will be no "'" that is not part of a contraction. 5 | # Assume each of these charactsrs are not to be considered: ! @ $ # % ^ & * ( ) - = _ + [ ] : ; , . / < > ? \ | 6 | # 7 | # Examples 8 | # alternate_words("Lorem ipsum dolor sit amet.") # => ["Lorem", "dolor", "amet"] 9 | # alternate_words("Can't we all get along?") # => ["Can't", "all", "along"] 10 | # alternate_words("Elementary, my dear Watson!") # => ["Elementary", "dear"] 11 | 12 | -------------------------------------------------------------------------------- /session2/3-challenge/8_array.rb: -------------------------------------------------------------------------------- 1 | # Given an array of elements, return true if any element shows up three times in a row 2 | # 3 | # Examples: 4 | # got_three? [1, 2, 2, 2, 3] # => true 5 | # got_three? ['a', 'a', 'b'] # => false 6 | # got_three? ['a', 'a', 'a'] # => true 7 | # got_three? [1, 2, 1, 1] # => false 8 | 9 | -------------------------------------------------------------------------------- /session2/3-challenge/9_input_output_logic_string.rb: -------------------------------------------------------------------------------- 1 | # Taken from http://pragprog.com/titles/fr_ltp/learn-to-program 2 | # 3 | # Write a Deaf Grandma program. Whatever you say to grandma (whatever 4 | # you type in), she should respond with HUH?! SPEAK UP, SONNY!, unless 5 | # you shout it (type in all capitals). If you shout, she can hear you 6 | # (or at least she thinks so) and yells back, NO, NOT SINCE 1938! 7 | # You can't stop talking to grandma until you shout BYE. 8 | # 9 | # Hint: Don't forget about chomp! "BYE\n" is not the same as "BYE" 10 | # (check the String cheatsheet if you need) 11 | # 12 | # remember, you can try your program by going to the terminal and typing $ ruby 9_input_output_logic_string.rb 13 | # 14 | # example: 15 | # 16 | # 17 | # USER: $ ruby 9_input_output_logic_string.rb 18 | # USER: hi grandma. 19 | # GRANDMA: HUH?! SPEAK UP, SONNY! 20 | # USER: HI GRANDMA! 21 | # GRANDMA: NO, NOT SINCE 1938! 22 | # USER: bye 23 | # GRANDMA: HUH?! SPEAK UP, SONNY! 24 | # USER: BYE 25 | 26 | def deaf_grandma 27 | 28 | end 29 | 30 | 31 | 32 | 33 | 34 | # This will call your code so you can run it from the terminal. 35 | # But not call it otherwise, so that it will work with our tests. 36 | deaf_grandma if $0 == __FILE__ 37 | -------------------------------------------------------------------------------- /session2/4-spec/1.rb: -------------------------------------------------------------------------------- 1 | require_relative 'helper' 2 | 3 | RSpec.describe 'sum_difference_product' do 4 | [ 9 , 2 , 5 | 4 , 9 , 6 | 8 , 7 , 7 | 7 , 6 , 8 | 1 , 62 , 9 | 12 , 86 , 10 | 1 , 90 , 11 | 15 , 99 , 12 | 1 , 26 , 13 | 78 , 235 , 14 | 537 , 664 , 15 | 838 , 836 , 16 | 431 , 157 , 17 | 652 , 501 , 18 | 149 , 6483 , 19 | 7227 , 1828 , 20 | 6289 , 8799 , 21 | 6116 , 5278 , 22 | 5050 , 5496 , 23 | 4062 , 84148 , 24 | 65060 , 91283 , 25 | 77229 , 83467 , 26 | 2117 , 45519 , 27 | 79153 , 15579 , 28 | 65874 , 81096 , 29 | -5 , 5 , 30 | -235 , 98 , 31 | 0 , 0 , 32 | 0 , 5 , 33 | ].each_slice 2 do |a, b| 34 | specify %Q[prints out "#{a+b}\\n#{a-b}\\n#{a*b}\\n" when stdin is "#{a} #{b}\\n"] do 35 | printed = input_output("#{a} #{b}"){ sum_difference_product } 36 | expect(printed).to include (a+b).to_s 37 | expect(printed).to include (a-b).to_s 38 | expect(printed).to include (a*b).to_s 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /session2/4-spec/10.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'Person' do 2 | let(:jim) { Person.new 'Jim' , 45 } 3 | 4 | it 'has a name getter' do 5 | expect(jim.name).to eq 'Jim' 6 | end 7 | 8 | it 'has a name setter' do 9 | expect(jim.name).to_not eq 'Jimmy' 10 | jim.name = 'Jimmy' 11 | expect(jim.name).to eq 'Jimmy' 12 | end 13 | 14 | it 'has an age getter' do 15 | expect(jim.age).to eq 45 16 | end 17 | 18 | it 'has an age setter' do 19 | expect(jim.age).to_not eq 30 20 | jim.age = 30 21 | expect(jim.age).to eq 30 22 | end 23 | 24 | it 'has a birthday method which increases the age' do 25 | expect(jim.age).to eq 45 26 | expect(jim.birthday).to eq 46 27 | expect(jim.age).to eq 46 28 | end 29 | 30 | it 'can have multiple birthdays' do 31 | 1.upto 10 do |i| 32 | expect(jim.birthday).to eq 45 + i 33 | expect(jim.age).to eq 45 + i 34 | end 35 | end 36 | 37 | it 'understands the difference between two people' do 38 | jim = Person.new 'Jim' , 45 39 | jan = Person.new 'Jan' , 25 40 | 1.upto 10 do |i| 41 | expect(jim.birthday).to eq 45 + i 42 | expect(jim.age ).to eq 45 + i 43 | expect(jan.birthday).to eq 25 + i 44 | expect(jan.age ).to eq 25 + i 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /session2/4-spec/3.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'String#every_other_char' do 2 | specify '"" -> ""' do 3 | expect("".every_other_char).to eq "" 4 | end 5 | 6 | input = 'Four score and seven years ago...' 7 | output = 'Fu cr n ee er g..' 8 | specify "#{input.inspect} -> #{output.inspect}" do 9 | expect(input.every_other_char).to eq output 10 | end 11 | 12 | %w( 13 | abcdefg aceg 14 | 0101010 0000 15 | 1010101 1111 16 | !@#$%^& !#%& 17 | 1 1 18 | 12 1 19 | 123 13 20 | 1234 13 21 | 12345 135 22 | 123456 135 23 | 1234567 1357 24 | lksjdafoijdsfioewutwekgnsdsoihblskjdklsgjoiuewyghowbnwoeincwe lsdfidfowtegssibsjksjieyhwnoice 25 | ).each_slice 2 do |input, output| 26 | specify "#{input.inspect} -> #{output.inspect}" do 27 | expect(input.every_other_char).to eq output 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /session2/4-spec/8.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'got_three?' do 2 | example { expect(got_three? [1, 2, 2, 2, 3]).to be } 3 | example { expect(got_three? ['a', 'a', 'b']).to_not be } 4 | example { expect(got_three? ['a', 'a', 'a']).to be } 5 | example { expect(got_three? [1, 2, 1, 1]).to_not be } 6 | example { expect(got_three? []).to_not be } 7 | example { expect(got_three? [1]).to_not be } 8 | example { expect(got_three? [1,2]).to_not be } 9 | example { expect(got_three? [1,2,3]).to_not be } 10 | example { expect(got_three? [1,2,3,2,2]).to_not be } 11 | example { expect(got_three? [1,1,2,1,1]).to_not be } 12 | example { expect(got_three? [1,2,5,9,3,5,5,5,10,4,3,2]).to be } 13 | example { expect(got_three? ['a','a','a']).to be } 14 | example { expect(got_three? [1,2,2,2]).to be } 15 | example { expect(got_three? [1,1,1,2]).to be } 16 | example { expect(got_three? [2,1,1,1]).to be } 17 | example { expect(got_three? [2,2,2,1]).to be } 18 | example { expect(got_three? [1,5,6,8,8,4,3,6,4,4,6,1,2,3,3,3]).to be } 19 | example { expect(got_three? [1,21,15,17,9,19,17,24,25,4,10,3,23,5,21,13,16,12,14,15,3,20,3,22,7,20,7,11,15,10,6,24,2,2,19,5,4,21,6,17,1,6,16,4,22,25,18,18,20,11,8,9,2,16,19,13,7,10,23,25,11,8,24,18,5,14,14,8,22,23,1,9,12,12,13]).to_not be } 20 | example { expect(got_three? [1,21,15,17,9,19,17,24,25,4,10,3,23,5,21,13,16,12,14,15,3,20,3,22,7,20,7,11,15,10,6,24,2,2,19,5,4,21,6,17,1,6,16,4,22,25,18,18,20,11,8,9,2,16,19,13,7,10,23,25,11,8,24,18,5,14,14,14,8,22,23,1,9,12,12,13]).to be } 21 | end 22 | -------------------------------------------------------------------------------- /session2/4-spec/9.rb: -------------------------------------------------------------------------------- 1 | require File.join( File.dirname(__FILE__) , 'helper' ) 2 | 3 | RSpec.describe 'deaf_grandma' do 4 | def call_deaf_grandma(input=String.new) 5 | input << "\nBYE\n" 6 | input_output(input) { deaf_grandma }.split("\n") 7 | end 8 | 9 | huh = 'HUH?! SPEAK UP, SONNY!'.freeze 10 | no = 'NO, NOT SINCE 1938!'.freeze 11 | 12 | it 'has no output when the only input is BYE' do 13 | output = input_output("BYE\n") { deaf_grandma } 14 | expect(output).to eq String.new 15 | end 16 | 17 | it "says #{huh} when given a blank line" do 18 | expect(call_deaf_grandma).to eq [huh] 19 | end 20 | 21 | it "says #{huh} when asked 'how are you?'" do 22 | expect(call_deaf_grandma 'how are you?').to eq [huh] 23 | end 24 | 25 | it "says huh, no, huh for input 'hi grandma.', 'HI GRANDMA!', 'bye', 'BYE'" do 26 | expect(call_deaf_grandma "hi grandma.\nHI GRANDMA\nbye").to eq [huh,no,huh] 27 | end 28 | 29 | it "says #{huh}, three times, for 'what was the war like?' three times" do 30 | query = Array.new(3) { "what was the war like?" }.join("\n") 31 | expect(call_deaf_grandma query).to eq [huh] * 3 32 | end 33 | 34 | it 'answers huh, no, for every set of questions asked in lowercase then uppercase' do 35 | questions = <<-QUESTIONS.gsub(/^\s+/,'').split("\n").map { |question| [question , question.upcase] }.flatten 36 | How is the wheather? 37 | What is your favourite movie? 38 | Do you eat cheesecake? 39 | Where did you get those earrings? 40 | My mom says she never told any lies, is that true or is she a liar? 41 | How do you get your garden so green? 42 | QUESTIONS 43 | result = [huh , no] * (questions.size / 2) 44 | expect(call_deaf_grandma questions.join("\n")).to eq result 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /session2/4-spec/helper.rb: -------------------------------------------------------------------------------- 1 | require 'stringio' 2 | 3 | RSpec.configure do |config| 4 | config.disable_monkey_patching! 5 | 6 | test_helpers = Module.new do 7 | def input_output(mock_stdin_with_this_str=String.new) 8 | ARGV.clear # -.0 9 | stdout , stdin = $stdout , $stdin 10 | $stdin = StringIO.new mock_stdin_with_this_str 11 | to_return = $stdout = StringIO.new 12 | yield 13 | $stdout , $stdin = stdout , stdin 14 | to_return.rewind 15 | to_return.read 16 | end 17 | end 18 | 19 | config.include test_helpers 20 | end 21 | -------------------------------------------------------------------------------- /session2/5-solved/1.rb: -------------------------------------------------------------------------------- 1 | def sum_difference_product 2 | a , b = gets.split.map { |num| num.to_i } 3 | puts a + b 4 | puts a - b 5 | puts a * b 6 | end -------------------------------------------------------------------------------- /session2/5-solved/10.rb: -------------------------------------------------------------------------------- 1 | class Person 2 | attr_accessor 'name', 'age' 3 | 4 | def initialize(name, age) 5 | @name = name 6 | @age = age 7 | end 8 | 9 | def birthday 10 | @age += 1 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /session2/5-solved/11.rb: -------------------------------------------------------------------------------- 1 | class BeerSong 2 | attr_accessor :beers 3 | 4 | def initialize(beers) 5 | beers = 0 if beers < 0 6 | beers = 99 if beers > 99 7 | self.beers = beers 8 | end 9 | 10 | def print_song 11 | beers.downto 1 do |i| 12 | print_stanza i 13 | end 14 | end 15 | 16 | def print_stanza(n) 17 | if n.zero? 18 | String.new 19 | else 20 | puts "#{translate n} #{bottle n} of beer on the wall," , 21 | "#{translate n} #{bottle n} of beer," , 22 | "Take one down, pass it around," , 23 | "#{translate n - 1} #{bottle n-1} of beer on the wall." 24 | end 25 | end 26 | 27 | # returns "bottle" or "bottles" 28 | def bottle(n) 29 | if n == 1 then 'bottle' else 'bottles' end 30 | end 31 | 32 | # translates number to English 33 | def translate(n) 34 | if 0 <= n && n <= 19 35 | %w(zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen)[n] 36 | elsif n % 10 == 0 37 | %w(zero ten twenty thirty forty fifty sixty seventy eighty ninety)[n/10] 38 | else 39 | "#{translate n/10*10}-#{translate n%10}".downcase 40 | end.capitalize 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /session2/5-solved/12.rb: -------------------------------------------------------------------------------- 1 | class Fraction 2 | attr_accessor :numerator, :denominator 3 | 4 | def initialize(numerator, denominator) 5 | self.numerator, self.denominator = numerator, denominator 6 | end 7 | 8 | def to_s 9 | "#{numerator}/#{denominator}" 10 | end 11 | 12 | def to_f 13 | numerator / denominator.to_f 14 | end 15 | 16 | def gcd(a, b) 17 | return a if b == 0 18 | gcd b, (a % b) 19 | end 20 | 21 | def lowest 22 | divisor = gcd(numerator, denominator) 23 | Fraction.new(numerator/divisor, denominator/divisor) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /session2/5-solved/13.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | 3 | class User 4 | attr_accessor :username, :blogs 5 | 6 | def initialize(username) 7 | self.username = username 8 | self.blogs = [] 9 | end 10 | 11 | def add_blog(date, text) 12 | added_blog = Blog.new(date, self, text) 13 | blogs << added_blog 14 | self.blogs = blogs.sort_by { |blog| blog.date }.reverse 15 | added_blog 16 | end 17 | end 18 | 19 | 20 | 21 | class Blog 22 | attr_accessor :date, :user, :text 23 | 24 | def initialize(date, user, text) 25 | self.date = date 26 | self.user = user 27 | self.text = text 28 | end 29 | 30 | def summary 31 | text.split[0..9].join(' ') 32 | end 33 | 34 | def entry 35 | "#{user.username} #{date}\n#{text}" 36 | end 37 | 38 | def ==(other) 39 | date == other.date && 40 | user == other.user && 41 | text == other.text 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /session2/5-solved/2.rb: -------------------------------------------------------------------------------- 1 | def prompt 2 | puts 'Enter a number or bye' 3 | end 4 | 5 | def hi_hi_goodbye 6 | prompt 7 | while (line = gets) && (line !~ /bye/) # first is an assignment statement that returns a line or nil, and is thus boolean 8 | line.to_i.times { print 'hi ' } 9 | puts 10 | prompt 11 | end 12 | puts "Goodbye!" 13 | end 14 | 15 | 16 | 17 | 18 | 19 | hi_hi_goodbye if $0 == __FILE__ # a little magic so that you can run with "$ ruby 2_input_output_control.rb" but it will still work for our tests 20 | -------------------------------------------------------------------------------- /session2/5-solved/3.rb: -------------------------------------------------------------------------------- 1 | class String 2 | def every_other_char 3 | to_return = '' 4 | each_char.with_index do |char, index| 5 | to_return << char if index.even? 6 | end 7 | to_return 8 | end 9 | end -------------------------------------------------------------------------------- /session2/5-solved/4.rb: -------------------------------------------------------------------------------- 1 | def get_squares(numbers) 2 | numbers.select { |n| numbers.include? n*n }.sort 3 | end 4 | -------------------------------------------------------------------------------- /session2/5-solved/5.rb: -------------------------------------------------------------------------------- 1 | def mod_three(numbers) 2 | numbers.select { |number| number % 3 != 0 }.map { |number| number % 3 } 3 | end -------------------------------------------------------------------------------- /session2/5-solved/6.rb: -------------------------------------------------------------------------------- 1 | class Integer 2 | def prime? 3 | return false if self < 2 4 | 2.upto Math.sqrt(self) do |i| 5 | return false if self % i == 0 6 | end 7 | true 8 | end 9 | end 10 | 11 | def prime_chars?(strings) 12 | strings.join.length.prime? 13 | end 14 | -------------------------------------------------------------------------------- /session2/5-solved/7.rb: -------------------------------------------------------------------------------- 1 | def alternate_words(sentence) 2 | # this will get better when we learn regular expressions :) 3 | '!@$#%^&*()-=_+[]:;,./<>?\\|'.split(//).each do |char| 4 | sentence = sentence.gsub(char, ' ') 5 | end 6 | words = sentence.split 7 | solution = [] 8 | words.each_with_index do |word, index| 9 | solution << word if index.even? 10 | end 11 | solution 12 | end 13 | -------------------------------------------------------------------------------- /session2/5-solved/8.rb: -------------------------------------------------------------------------------- 1 | def got_three?(elements) 2 | elements.each_cons 3 do |a, b, c| 3 | return true if a == b && b == c 4 | end 5 | false 6 | end 7 | -------------------------------------------------------------------------------- /session2/5-solved/9.rb: -------------------------------------------------------------------------------- 1 | def deaf_grandma 2 | while line = gets 3 | line.chomp! 4 | break if line == "BYE" 5 | if line == line.upcase && line != "" 6 | puts "NO, NOT SINCE 1938!" 7 | else 8 | puts "HUH?! SPEAK UP, SONNY!" 9 | end 10 | end 11 | end 12 | 13 | deaf_grandma if $0 == __FILE__ # this will call your code so you can run it from the terminal 14 | -------------------------------------------------------------------------------- /session3/1-notes/01-symbols-introduction.rb: -------------------------------------------------------------------------------- 1 | #Watch this video - https://vimeo.com/24673123 - these notes are supplementary as per the last section 2 | 3 | # Symbols look like this: 4 | :this_is_a_symbol # => :this_is_a_symbol 5 | :this_is_a_symbol.class # => Symbol 6 | 7 | 8 | # Symbols are Strings that are immutable, meaning they can never 9 | # change, like numbers. They are never garbage collected, so if 10 | # you use one, it will last until your program ends. 11 | 12 | 13 | # They are most commonly used as hash keys, because their hash 14 | # value can be cached, making them as efficient as a number for 15 | # this purpose. They are also used frequently in place of enum types, 16 | # and used internally in Ruby to refer to things like method names. 17 | 18 | 19 | # For example, it is common to declare attr_accessor with a symbol. 20 | # And instance_methods returns back symbols representing the methods, 21 | # because that's what Ruby uses internally. 22 | class Example 23 | instance_methods(false) # => [] 24 | attr_accessor :my_method 25 | instance_methods(false) # => [:my_method, :my_method=] 26 | end 27 | -------------------------------------------------------------------------------- /session3/1-notes/02-symbols-always-the-same.rb: -------------------------------------------------------------------------------- 1 | # Every instance of the symbol is the same object, 2 | # notice they have the same object id. 3 | :this_is_a_symbol.object_id # => 212668 4 | :this_is_a_symbol.object_id # => 212668 5 | 6 | # Whereas each String is a new object, 7 | # notice they have different object ids. 8 | 'this is a string'.object_id # => 2149403240 9 | 'this is a string'.object_id # => 2149402020 10 | 11 | 12 | # This makes them easy to test equality. For a symbol you just check 13 | # if it is the same object, but for a String, you must check that 14 | # each character is the same character (iterate through the entire 15 | # string) this gives symbols a performance boost for checking 16 | # equality. 17 | 18 | 19 | # you typically use symbols in a situation where you wish to use 20 | # a constant, but want it to be named, like a String 21 | -------------------------------------------------------------------------------- /session3/1-notes/03-hash-introduction.rb: -------------------------------------------------------------------------------- 1 | # A hash table is a data structure that allows you to keep track of 2 | # data in key / value pairs. 3 | # 4 | # Where arrays access elements by their index, hashes access 5 | # elements by their keys, and a key can be any object. 6 | # 7 | # Hashes are very fast, with near constant time to look up an element. 8 | -------------------------------------------------------------------------------- /session3/1-notes/04-hash-literals.rb: -------------------------------------------------------------------------------- 1 | # Where Arrays are represented with brackets, 2 | # Hashes are represented in curly braces 3 | [].class # => Array 4 | {}.class # => Hash 5 | 6 | 7 | # Keys are separated from their values with a hash rocket => 8 | # with the key on the left, and the value on the right 9 | {0 => 'first', 1 => 'second'} # => {0=>"first", 1=>"second"} 10 | 11 | key = :one 12 | value = "two" 13 | {key => value} # => {:one=>"two"} 14 | -------------------------------------------------------------------------------- /session3/1-notes/05-hash-setting-and-getting.rb: -------------------------------------------------------------------------------- 1 | # You can set elements into a hash table with hash[key] = value 2 | hash = {} 3 | hash[:number] = 12 4 | hash[:colour] = 'black' 5 | hash # => {:number=>12, :colour=>"black"} 6 | 7 | 8 | # You can get them back out with hash[key] 9 | hash[:number] # => 12 10 | hash[:colour] # => "black" 11 | 12 | 13 | # You can change its value by setting it again 14 | hash[:colour] # => "black" 15 | hash[:colour] = :black 16 | hash[:colour] # => :black 17 | 18 | 19 | # If you access a nonexistent element, nil is returned 20 | hash[:yay_for_pirates!] # => nil 21 | 22 | 23 | # If it makes more sense for your hash, you can change 24 | # what it returns for nonexistent keys by passing it 25 | # a block that will be invoked when a mising key is requested. 26 | character_counts = Hash.new { |this_hash, key| this_hash[key] = 0 } 27 | character_counts["a"] # => 0 28 | character_counts # => {"a"=>0} 29 | 30 | "abcbcbababcbcx".each_char do |char| 31 | character_counts[char] += 1 32 | end 33 | 34 | character_counts # => {"a"=>3, "b"=>6, "c"=>4, "x"=>1} 35 | -------------------------------------------------------------------------------- /session3/1-notes/06-hash-keys.rb: -------------------------------------------------------------------------------- 1 | # Symbols are commonly used as keys because of their efficiency, 2 | # but you can use any object you like. 3 | 4 | hash = Hash.new 5 | hash[0] = 'zero' 6 | hash['nine'] = 9 7 | hash[/regex/] = ['array', 'of', 'strings'] 8 | hash # => {0=>"zero", "nine"=>9, /regex/=>["array", "of", "strings"]} 9 | 10 | -------------------------------------------------------------------------------- /session3/1-notes/07-hash-iterating.rb: -------------------------------------------------------------------------------- 1 | # in 1.8, HASHES ARE NOT ORDERED, if you iterate through them, 2 | # you don't know what order they will be passed 3 | # in 1.9, they will passed to your block in the order they were inserted. 4 | 5 | 6 | # When you iterate over the hash, you pass it a block, just like 7 | # arrays. But this block takes two arguments, the key and value 8 | student_ids = {'Bill' => 25, 'Danya' => 15, 'Mei' => 12} 9 | 10 | student_ids.each do |student, id| 11 | puts "#{student}'s student id is #{id}" 12 | end 13 | # >> Bill's student id is 25 14 | # >> Danya's student id is 15 15 | # >> Mei's student id is 12 16 | -------------------------------------------------------------------------------- /session3/1-notes/08-proc-introduction.rb: -------------------------------------------------------------------------------- 1 | # A Proc is just a way of storing code in an object 2 | # It's just like a method in that it takes parameters, evaluates 3 | # code, and then returns a result. 4 | square_it_proc = Proc.new { |num| num * num } 5 | 6 | 7 | # Its parameters are given in the pipes, so the above |num| is 8 | # the parameter that the proc receives. 9 | 10 | 11 | # You tell it to execute with the call method 12 | square_it_proc.call 5 # => 25 13 | square_it_proc.call 10 # => 100 14 | 15 | 16 | # Compare it to a method 17 | def square_it_method(num) 18 | num * num 19 | end 20 | square_it_method 5 # => 25 21 | square_it_method 10 # => 100 22 | -------------------------------------------------------------------------------- /session3/1-notes/09-procs-can-see-their-environment.rb: -------------------------------------------------------------------------------- 1 | # Unlike methods, procs can see the environment they're defined in. 2 | count = 0 3 | incrementer = Proc.new { count += 1 } 4 | 5 | count # => 0 6 | incrementer.call 7 | count # => 1 8 | incrementer.call 9 | count # => 2 10 | 11 | 12 | # They keep the environment they were defined in 13 | # even if they get passed into a new scope. 14 | def invoke_10_times(proc) 15 | 10.times { proc.call } 16 | end 17 | 18 | count # => 2 19 | invoke_10_times incrementer 20 | count # => 12 21 | -------------------------------------------------------------------------------- /session3/1-notes/10-blocks-introduction.rb: -------------------------------------------------------------------------------- 1 | # Blocks are what we call a proc when we pass it into a method. 2 | # They are defined with "{ }" or "do end" 3 | ary = [3,2,1] # => [3, 2, 1] 4 | 5 | ary.map! { |num| num * 2 } 6 | ary # => [6, 4, 2] 7 | 8 | ary.map! do |num| 9 | num * 2 10 | end 11 | ary # => [12, 8, 4] 12 | 13 | -------------------------------------------------------------------------------- /session3/1-notes/11-block-params-and-return.rb: -------------------------------------------------------------------------------- 1 | # Methods will raise an error if you give them the wrong number 2 | # of arguments. But blocks will not. 3 | [1,2,3].map { 0 } # => [0, 0, 0] 4 | 5 | 6 | # A return statement in a method will return from it. But a return 7 | # statement in a proc will return **from the enclosing environment**. 8 | def first_even(nums) 9 | nums.each do |num| 10 | return num if num.even? 11 | end 12 | nil 13 | end 14 | first_even [1,5,7,4,19,8] # => 4 15 | -------------------------------------------------------------------------------- /session3/1-notes/12-all-methods-take-blocks.rb: -------------------------------------------------------------------------------- 1 | # When you pass a block as a parameter, the block gets put into 2 | # a special slot that every method has, whether they use the 3 | # block or not. 4 | def method 5 | "result" 6 | end 7 | method {} # => "result" 8 | method # => "result" 9 | 10 | 11 | # To access the block, use the ampersand, this will 12 | # give it to you as a proc that you can use. 13 | def method2(&block) 14 | block.call.upcase 15 | end 16 | method2 { 'from the block' } # => "FROM THE BLOCK" 17 | 18 | 19 | # If you didn't pass a block, it will be set to nil. 20 | def method3(&block) 21 | if block 22 | "The block evaluates to #{block.call}" 23 | else 24 | "No block." 25 | end 26 | end 27 | method3 { ":)" } # => "The block evaluates to :)" 28 | method3 # => "No block." 29 | 30 | 31 | # Like with any proc, you can pass arguments to it 32 | def heres_six(&block) 33 | block.call 6 34 | end 35 | result = heres_six { |num| "#{num*2} is Josh's favourite number"} 36 | result # => "12 is Josh's favourite number" 37 | 38 | -------------------------------------------------------------------------------- /session3/1-notes/13-difference-between-block-syntaxes.rb: -------------------------------------------------------------------------------- 1 | def block_checker(array, &block) 2 | [array.to_a, !!block] 3 | end 4 | 5 | # { ... } blocks bind to the method immediately to their left. 6 | # do ... end blocks will bind to the furthest left method. 7 | 8 | # The block is passed to map 9 | block_checker [1,2,3].map { 1 } # => [[1, 1, 1], false] 10 | 11 | # The block is passed to block_checker 12 | block_checker([1,2,3].map) { 1 } # => [[1, 2, 3], true] 13 | 14 | # The block is passed to block_checker 15 | block_checker [1,2,3].map do 1 end # => [[1, 2, 3], true] 16 | 17 | 18 | # This makes { ... } ideal for inline blocks, and 19 | # do ... end ideal for mutli line blocks 20 | -------------------------------------------------------------------------------- /session3/1-notes/14-storing-blocks-for-later.rb: -------------------------------------------------------------------------------- 1 | # Now that we know to use &block, we can do cool things like 2 | # Store the block for later. 3 | class CollegeStudent 4 | 5 | attr_accessor :do_when_twenty_one 6 | 7 | def initialize(age, &block) 8 | @age = age 9 | @do_when_twenty_one = block 10 | end 11 | 12 | def birthday! 13 | @age += 1 14 | return "#{@age}: study :(" unless @age == 21 15 | do_when_twenty_one.call @age 16 | end 17 | 18 | end 19 | 20 | 21 | pam = CollegeStudent.new 18 do |age| 22 | "#{age}: GET SAUCED!" 23 | end 24 | 25 | pam.birthday! # => "19: study :(" 26 | pam.birthday! # => "20: study :(" 27 | pam.birthday! # => "21: GET SAUCED!" 28 | pam.birthday! # => "22: study :(" 29 | pam.birthday! # => "23: study :(" 30 | -------------------------------------------------------------------------------- /session3/1-notes/15-forwarding-blocks.rb: -------------------------------------------------------------------------------- 1 | # Another common thing is to forward blocks to other methods 2 | def meth1(&block) 3 | "(meth1: #{block.call})" 4 | end 5 | 6 | 7 | # Use the & notation when calling a method to put a block into 8 | # the method's block slot. 9 | def meth2(&block) 10 | "#{meth1(&block)} (meth2: #{block.call})" 11 | end 12 | 13 | counter = 0 14 | meth2 { counter += 10 } # => "(meth1: 10) (meth2: 20)" 15 | -------------------------------------------------------------------------------- /session3/1-notes/16-optional-params.rb: -------------------------------------------------------------------------------- 1 | # You have already seen ordinal parameters, they have a name and 2 | # are mandatory. But you can make them optional by giving them 3 | # an equal sign, and listing a default value. 4 | def same_case(str, upcase = true) 5 | return str.upcase if upcase 6 | str.downcase 7 | end 8 | 9 | same_case 'UPPER lower' # => "UPPER LOWER" 10 | same_case 'UPPER lower' , false # => "upper lower" 11 | 12 | 13 | # optional parameters must go to the right of ordinal parameters, 14 | # and are filled in from the left 15 | def what_are_filled_in(a=5, b=4, c=3, d=2, e=1) 16 | "#{a} #{b} #{c} #{d} #{e}" 17 | end 18 | 19 | what_are_filled_in # => "5 4 3 2 1" 20 | what_are_filled_in :A # => "A 4 3 2 1" 21 | what_are_filled_in :A , :B # => "A B 3 2 1" 22 | what_are_filled_in :A , :B , :C # => "A B C 2 1" 23 | what_are_filled_in :A , :B , :C , :D # => "A B C D 1" 24 | what_are_filled_in :A , :B , :C , :D , :E # => "A B C D E" 25 | 26 | # what will this return? 27 | what_are_filled_in :A , :E # => 28 | -------------------------------------------------------------------------------- /session3/1-notes/17-variable-lengthed-params.rb: -------------------------------------------------------------------------------- 1 | # After listing your ordinal and optional parameters, you can take 2 | # a variable length of arguments. To do this, you use '*' before 3 | # the parameter. In Ruby 1.8, it must be the last parameter. 4 | # The parameters that match it will be put into an array. 5 | def variable_length(first, second=:default, *rest) 6 | [first, second, rest] 7 | end 8 | variable_length 1 # => [1, :default, []] 9 | variable_length 1, 2 # => [1, 2, []] 10 | variable_length 1, 2, 3 # => [1, 2, [3]] 11 | variable_length 1, 2, 3, 4 # => [1, 2, [3, 4]] 12 | 13 | 14 | # how might we use it? 15 | def minimum( *numbers ) 16 | min = numbers.first 17 | numbers.each { |number| min = number if number < min } 18 | min 19 | end 20 | 21 | minimum 2, 1 # => 1 22 | minimum 2, 1, 5, -3, 16 # => -3 23 | 24 | 25 | # In the same way that we can use & to take a block out of 26 | # the block slot or put it back in, we can use * to take a 27 | # variable number of arguments out, or put them back in. 28 | ruby_kickstart_favourite_numbers = [12, 13, 3, 43, 7] 29 | minimum( 12, 13, 3, 43, 7 ) # => 3 30 | minimum(*[12, 13, 3, 43, 7]) # => 3 31 | minimum(*ruby_kickstart_favourite_numbers ) # => 3 32 | -------------------------------------------------------------------------------- /session3/1-notes/18-hash-params.rb: -------------------------------------------------------------------------------- 1 | # If we wanted to pass a bunch of options to a method, 2 | # we might use a hash table. 3 | def same_case( str , options = Hash.new ) 4 | return str.upcase if options[:upcase] 5 | return str.upcase if options[:downcase] == false 6 | str.downcase 7 | end 8 | 9 | same_case 'UPPER lower' # => "upper lower" 10 | same_case 'UPPER lower', { :upcase => false } # => "upper lower" 11 | same_case 'UPPER lower', { :downcase => true } # => "upper lower" 12 | same_case 'UPPER lower', { :downcase => false } # => "UPPER LOWER" 13 | same_case 'UPPER lower', { :upcase => true } # => "UPPER LOWER" 14 | 15 | 16 | # The problem is that this looks an awful lot like a block. 17 | # But this is such a common use case that syntactic sugar was added. 18 | # You can now place hash arguments at the end of your regular list, 19 | # and they will be collected into the last argument 20 | same_case 'UPPER lower' # => "upper lower" 21 | same_case 'UPPER lower' , :upcase => false # => "upper lower" 22 | same_case 'UPPER lower' , :downcase => true # => "upper lower" 23 | same_case 'UPPER lower' , :downcase => false # => "UPPER LOWER" 24 | same_case 'UPPER lower' , :upcase => true # => "UPPER LOWER" 25 | -------------------------------------------------------------------------------- /session3/1-notes/19-putting-it-all-together.rb: -------------------------------------------------------------------------------- 1 | # We've seen a lot of things we can do with method parameters. 2 | # But how do they all work together? 3 | def meth(ordinal, optional=true, *variable_length, &block) 4 | end 5 | 6 | # Probably you don't need to use them all in one method like this, 7 | # it is up to you to find the right fit for your use case :). 8 | -------------------------------------------------------------------------------- /session3/1-notes/20-last-words.rb: -------------------------------------------------------------------------------- 1 | # Check out the cheatsheet for Hashes 2 | # https://github.com/JoshCheek/ruby-kickstart/blob/master/cheatsheets/hashes.rb 3 | # 4 | # The material we went over in this section covers almost everything 5 | # else that I think you should know about the topics, so I'm not going 6 | # to bother with any cheatsheet this time. 7 | # 8 | # But if you want to see the docs, they're at 9 | # http://ruby-doc.org/core/classes/Symbol.html 10 | # http://ruby-doc.org/core/classes/Hash.html 11 | # http://ruby-doc.org/core/classes/Proc.html 12 | -------------------------------------------------------------------------------- /session3/2-examples/2_blocks.rb: -------------------------------------------------------------------------------- 1 | class Person 2 | 3 | attr_accessor :name 4 | 5 | def initialize( &initializer ) 6 | @initializer = initializer 7 | initializer.call self 8 | end 9 | 10 | def reinit 11 | @initializer.call self 12 | end 13 | 14 | end 15 | 16 | 17 | 18 | artist = Person.new do |person| 19 | person.name = 'Prince' 20 | end 21 | 22 | artist.name # => "Prince" 23 | artist.name = 'The Artist Formerly Known As Prince' 24 | artist.name # => "The Artist Formarly Known As Prince" 25 | artist.reinit 26 | artist.name # => "Prince" 27 | -------------------------------------------------------------------------------- /session3/2-examples/3_stack.rb: -------------------------------------------------------------------------------- 1 | class Stack 2 | 3 | def initialize(*values) 4 | self.first_node = nil 5 | push *values 6 | end 7 | 8 | def each(&block) 9 | each_node { |node| block.call node[:data] } 10 | self 11 | end 12 | 13 | def push(*datas) 14 | datas.each do |data| 15 | new_node = { :next => first_node , :data => data } 16 | self.first_node = new_node 17 | end 18 | self 19 | end 20 | 21 | def pop 22 | return nil unless node = first_node 23 | self.first_node = first_node[:next] 24 | node[:data] 25 | end 26 | 27 | def empty? 28 | !first_node 29 | end 30 | private 31 | 32 | # we are making these methods private, because they are for internal implementation 33 | # we don't want outside users to have to worry about our implementation (encapsulation) 34 | # really, the Node class should go in here as well, but then I couldn't have told you about Stack::Node :) 35 | attr_accessor :first_node 36 | 37 | def each_node 38 | node = first_node 39 | while node 40 | yield node 41 | node = node[:next] # once it gets to the end, returns nil 42 | end 43 | end 44 | 45 | end 46 | 47 | 48 | stack = Stack.new 77,90,"jkl",[67,90],{0=>8,:acv=>98} 49 | stack.push(5).push(6).push(9).push(10).push('abc') 50 | stack.push 1 , 2 , 3 , 4 , 5 51 | stack.each { |data| p data } 52 | 53 | 54 | puts "\n" * 5 + "using pop" 55 | stack = Stack.new *(1..10) # the splat will invoke the to_a method before lining up params and args 56 | puts stack.pop until stack.empty? -------------------------------------------------------------------------------- /session3/2-examples/4_recursion.rb: -------------------------------------------------------------------------------- 1 | def append(array, n) 2 | return array if n < 0 3 | array << n 4 | append(array, n-1) 5 | end 6 | 7 | def reverse_append(array, n) 8 | return array if n < 0 9 | reverse_append(array, n-1) 10 | array << n 11 | end 12 | 13 | def fib(n) 14 | return 0 if n == 0 15 | return 1 if n == 1 16 | fib(n-1) + fib(n-2) 17 | end 18 | 19 | p append([], 5) #=> [0,1,2,3,4,5] 20 | p reverse_append([], 5) #=> [5,4,3,2,1,0] 21 | p fib(3) #=> 55 22 | 23 | -------------------------------------------------------------------------------- /session3/3-challenge/10_hashes.rb: -------------------------------------------------------------------------------- 1 | # DO NOT STRUGGLE ON THIS PROBLEM FOR MORE THAN 30 MINUTES!! 2 | 3 | # Lets represent a file system with hashes 4 | # You will be passed a hash table, whose keys represent folders. 5 | # Their values will either be arrays of filenames in that directory 6 | # or they will be hashes with the same rules (a treelike structure) 7 | # 8 | # Your job is to take the hashes, and return an array containing 9 | # all of the complete file paths where each directory is separated by a '/' 10 | # 11 | # HINT: 12 | # [1,2,3].is_a? Array # => true 13 | # [1,2,3].is_a? Hash # => false 14 | # {1=>1}.is_a? Array # => false 15 | # {1=>1}.is_a? Hash # => true 16 | # 17 | # HINT2: 18 | # Don't feel constrained, you may create any methods, classes, etc, that 19 | # you need to you may address the problem in any way you need to (I 20 | # haven't tried it yet, but will probably use a recursive approach) 21 | # 22 | # EXAMPLES: 23 | # 24 | # pathify 'usr' => {'bin' => ['ruby']} # => ['/usr/bin/ruby'] 25 | # pathify 'usr' => {'bin' => ['ruby', 'perl'] } # => ['/usr/bin/ruby', '/usr/bin/perl'] 26 | # pathify 'usr' => {'bin' => ['ruby'], 'include' => ['zlib.h'] } # => ['/usr/bin/ruby', '/usr/include/zlib.h'] 27 | # pathify 'usr' => {'bin' => ['ruby']}, 'opt' => {'local' => {'bin' => ['sqlite3', 'rsync']} } # => ['/usr/bin/ruby', 'opt/local/bin/sqlite3', 'opt/local/bin/rsync'] 28 | # pathify # => [] 29 | # 30 | # 31 | # create it from scratch :) 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /session3/3-challenge/11_blocks_or_procs.rb: -------------------------------------------------------------------------------- 1 | # DO NOT STRUGGLE ON THIS PROBLEM FOR MORE THAN 30 MINUTES! 2 | 3 | # Write a method that initializes an Array 4 | # it receives one parameter, which is 5 by default, but can be overridden by the user 5 | # The parameter determines the size of the Array to initialize 6 | # 7 | # If a block is submitted, use that block to initialize each index in the Array (pass it the current index) 8 | # 9 | # If a block is not submitted, initialize the Array to 100 times the array's index, as a String 10 | # 11 | # CONDITIONS: 12 | # Do not loop through the Array to initialize it, instead, use the block form 13 | # 14 | # HINTS: 15 | # Remember that the Array initializer will pass the index being initialized to your block that is doing the initializing 16 | # (if you wish to use blocks) Remember that in the block you pass, to Array.new, you can yield to the block the user passed 17 | # (if you wish to use procs) You can place the block you received into the block spot with the ampersand ( ampersand to get it out, and to put it in ) 18 | # 19 | # EXAMPLES: 20 | # 21 | # array_init(2) { |i| i.to_s } # => ['0', '1'] 22 | # array_init { |i| i.to_s } # => ['0', '1', '2', '3', '4'] 23 | # array_init 2 # => ['0', '100'] 24 | # array_init # => ['0', '100', '200', '300', '400'] 25 | # array_init { 'hi } # => ['hi', 'hi', 'hi', 'hi', 'hi'] 26 | # array_init 10 do |i| # => [0, -5, 400, -15, 800, -25, 1200, -35, 1600, -45] 27 | # if i % 2 == 0 28 | # i * 200 29 | # else 30 | # i * -5 31 | # end 32 | # end 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /session3/3-challenge/14_var_args_and_hash.rb: -------------------------------------------------------------------------------- 1 | # DO NOT SPEND MORE THAN 30-40 MINUTES STRUGGLING THROUGH THIS BEFORE MOVING ON! 2 | 3 | # You have two different problems to solve, you must get which one it is from a hash 4 | # The default value for the hash should be :count_clumps 5 | # If no hash is provided, choose count_clumps 6 | # 7 | # PROBLEM: count_clumps 8 | # Say that a "clump" in an array is a series of 2 or more adjacent elements of the same value. 9 | # Return the number of clumps in the given arguments. 10 | # 11 | # problem_14 1, 2, 2, 3, 4, 4, :problem => :count_clumps # => 2 12 | # problem_14 1, 1, 2, 1, 1, :problem => :count_clumps # => 2 13 | # problem_14 1, 1, 1, 1, 1, :problem => :count_clumps # => 1 14 | # 15 | # 16 | # PROBLEM: same_ends 17 | # Return true if the group of N numbers at the start and end of the array are the same. 18 | # For example, with [5, 6, 45, 99, 13, 5, 6], the ends are the same for n=0 and n=2, and false for n=1 and n=3. 19 | # You may assume that n is in the range 0..nums.length inclusive. 20 | # 21 | # The first parameter will be n, the rest will be the input to look for ends from 22 | # problem_14 1, 5, 6, 45, 99, 13, 5, 6, :problem => :same_ends # => false 23 | # problem_14 2, 5, 6, 45, 99, 13, 5, 6, :problem => :same_ends # => true 24 | # problem_14 3, 5, 6, 45, 99, 13, 5, 6, :problem => :same_ends # => false 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /session3/3-challenge/16_hash.rb: -------------------------------------------------------------------------------- 1 | # DO NOT SPEND MORE THAN 30-40 MINUTES STRUGGLING THROUGH THIS BEFORE MOVING ON! 2 | 3 | # Print to stdout, each element in a hash based linked list. 4 | # If you don't know what that is, go check out the previous problem. 5 | # 6 | # EXAMPLES: 7 | # head = {:data => 1, :next => nil} 8 | # print_list head # >> "1\n" 9 | # head = {:data => 2, :next => head} 10 | # print_list head # >> "2\n1\n" 11 | # head = {:data => 3, :next => head} 12 | # print_list head # >> "3\n2\n1\n" 13 | # head = {:data => 4, :next => head} 14 | # print_list head # >> "4\n3\n2\n1\n" 15 | # head = {:data => 5, :next => head} 16 | # print_list head # >> "5\n4\n3\n2\n1\n" 17 | # head = {:data => 6, :next => head} 18 | # print_list head # >> "6\n5\n4\n3\n2\n1\n" 19 | 20 | -------------------------------------------------------------------------------- /session3/3-challenge/17_hashes.rb: -------------------------------------------------------------------------------- 1 | # DO NOT SPEND MORE THAN 30-40 MINUTES STRUGGLING THROUGH THIS BEFORE MOVING ON! 2 | 3 | # Print to stdout, each element in a hash based linked list, in reverse. 4 | # If you don't know what that is, go check out the previous problem. 5 | # 6 | # EXAMPLES: 7 | # head = {:data => 1, :next => nil} 8 | # head = {:data => 2, :next => head} 9 | # 10 | # print_list_in_reverse head # >> "1\n2\n" 11 | 12 | def print_list_in_reverse list 13 | 14 | end 15 | -------------------------------------------------------------------------------- /session3/3-challenge/1_blocks.rb: -------------------------------------------------------------------------------- 1 | # Write a method, reverse_map, which invokes a block on each of the elements in reverse order, 2 | # and returns an array of their results. 3 | # 4 | # reverse_map(1, 2, 3) { |i| i * 2 } # => [6, 4, 2] 5 | # reverse_map(1, 2, 3) { |i| i * 2 } # => [6, 4, 2] 6 | 7 | -------------------------------------------------------------------------------- /session3/3-challenge/2_hashes.rb: -------------------------------------------------------------------------------- 1 | # Given a nonnegative integer, return a hash whose keys are all the odd nonnegative integers up to it 2 | # and each key's value is an array containing all the even non negative integers up to it. 3 | # 4 | # Examples: 5 | # staircase 1 # => {1 => []} 6 | # staircase 2 # => {1 => []} 7 | # staircase 3 # => {1 => [], 3 => [2]} 8 | # staircase 4 # => {1 => [], 3 => [2]} 9 | # staircase 5 # => {1 => [], 3 => [2], 5 =>[2, 4]} 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /session3/3-challenge/3_hashes.rb: -------------------------------------------------------------------------------- 1 | # Write a method that takes a string and returns an array 2 | # whose keys are all the downcased words in the string, 3 | # and values are the number of times these words were seen. 4 | # 5 | # No punctuation will appear in the strings. 6 | # 7 | # Example: 8 | # word_count "The dog and the cat" # => {"the" => 2, "dog" => 1, "and" => 1, "cat" => 1} -------------------------------------------------------------------------------- /session3/3-challenge/4_hashes.rb: -------------------------------------------------------------------------------- 1 | # Write first_pos, a method which takes a string and , returns a hash 2 | # whose keys are all the words in the string, and values are the 3 | # earliest position they were seen in the string. 4 | # 5 | # There will be no punctuation in the strings. 6 | # 7 | # first_pos "The dog and the cat and the cow" # => {"The" => 0, "dog" => 1, "and" => 2, "the" => 3, "cat" => 4, "cow" => 7} 8 | 9 | -------------------------------------------------------------------------------- /session3/3-challenge/5_blocks.rb: -------------------------------------------------------------------------------- 1 | # DO NOT STRUGGLE ON THIS PROBLEM FOR MORE THAN 30 MINUTES!! IT'S A TOUGH ONE :) 2 | 3 | # Write a method, spiral_access, that takes a 2d square array (an array of arrays) 4 | # and a block, and calls the block for each of the elements, in spiral order. 5 | # 6 | # HINT: This method is probably best sovled recursively 7 | # 8 | # Example: 9 | # two_d = [ 10 | # [ 1, 2, 3, 4, 5], 11 | # [16, 17, 18, 19, 6], 12 | # [15, 24, 25, 20, 7], 13 | # [14, 23, 22, 21, 8], 14 | # [13, 12, 11, 10, 9], 15 | # ] 16 | # order = [] 17 | # spiral_access two_d do |i| 18 | # order << i 19 | # end 20 | # order # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /session3/3-challenge/6_arguments.rb: -------------------------------------------------------------------------------- 1 | # DO NOT STRUGGLE ON THIS PROBLEM FOR MORE THAN 30 MINUTES!! 2 | 3 | # Write a method, match_maker, which will receive an unknown number of 4 | # elements, and return an array where every two elements are represented by true or false. 5 | # 6 | # The very first parameter will not be part of this set. Instead, it will tell 7 | # you how to determine what their value should be. 8 | # If it is true, then they will be true when they are oppositely truthy. 9 | # If it is false, then they will be true when they are similarly truthy. 10 | # 11 | # Examples: 12 | # match_maker false, true, true # => [true] 13 | # match_maker true, true, true # => [false] 14 | # match_maker true, false, false # => [false] 15 | # match_maker true, false, true # => [true] 16 | # match_maker true, true, false # => [true] 17 | # match_maker true, true, true, false, true # => [false, true] 18 | # match_maker true, true, true, false, nil # => [false, false] 19 | # match_maker true, true, true, true, nil # => [false, true] 20 | # match_maker true, true, true, 0, nil # => [false, true] 21 | 22 | -------------------------------------------------------------------------------- /session3/3-challenge/8_blocks.rb: -------------------------------------------------------------------------------- 1 | # This problem is based off of example 2 2 | # Modify it so that it also tracks a person's age and a quote 3 | # Allow any of these to be set with a hash as well, but the block should overwrite the hash 4 | # 5 | # 6 | # EXAMPLE: 7 | # 8 | # artist = Person.new :name => 'Prince' do |person| 9 | # person.age = 47 10 | # person.quote = "Why don't you purify yourself in the waters of Lake Minnetonka?" 11 | # end 12 | # 13 | # artist.name # => "Prince" 14 | # artist.age # => 47 15 | # 16 | # artist.name = 'The Artist Formarly Known As Prince' 17 | # artist.age = 1999 18 | # 19 | # artist.name # => "The Artist Formarly Known As Prince" 20 | # artist.age # => 1999 21 | # 22 | # artist.reinit 23 | # 24 | # artist.name # => "The Artist Formarly Known As Prince" 25 | # artist.age # => 47 26 | 27 | 28 | class Person 29 | 30 | attr_accessor :name 31 | 32 | def initialize( &initializer ) 33 | @initializer = initializer 34 | initializer.call self 35 | end 36 | 37 | def reinit 38 | @initializer.call self 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /session3/3-challenge/9_hashes.rb: -------------------------------------------------------------------------------- 1 | # Write a function which takes two arrays, a, and b 2 | # it should then find the elements that are in both (union) 3 | # 4 | # This is the same as [1,2,3] & [1,2,4] 5 | # but we don't want to use the builtin method 6 | # instead, implement your own by creating a hash table of elements from the first set 7 | # and checking it against the elements from the second set 8 | # 9 | # the keys will be the elements in the arrays 10 | # each value will be a two element array, where the first index is true if the 11 | # key is in a, and the second is true if the key is in b 12 | # if an index is not true, it should be nil 13 | # 14 | # return the hash, and the array of elements in both sets (it should be sorted) 15 | # (do not worry about the order of the hash, remember, on 1.8, hashes have no ordering) 16 | # 17 | # hints: 18 | # you can set up default behaviour for a hash by passing a block, see cheatsheet (essentially a lazy initialization) 19 | # you can get an array of keys from a hash with the keys method 20 | # 21 | # examples: 22 | # 23 | # shared [1,2,3], [1,2,4] # => [{1=>[true, true], 2=>[true, true], 3=>[true, nil], 4=>[nil, true]}, [1, 2]] 24 | # shared %w(a b c d), %w(aa b cc d) # => [{"a"=>[true, nil], "b"=>[true, true], "c"=>[true, nil], "d"=>[true, true], "aa"=>[nil, true], "cc"=>[nil, true]}, ["b", "d"]] 25 | # shared [], [1,2] # => [{1=>[nil, true], 2=>[nil, true]}, []] 26 | # shared [1,2], [] # => [{1=>[true, nil], 2=>[true, nil]}, []] 27 | # shared [], [] # => [{}, []] 28 | # shared [1,2,:c], ['a','b',:c] # => [{1=>[true, nil], 2=>[true, nil], :c=>[true, true], "a"=>[nil, true], "b"=>[nil, true]}, [:c]] 29 | # shared [1,2,3], [3,2,1] # => [{1=>[true, true], 2=>[true, true], 3=>[true, true]}, [1, 2, 3]] 30 | 31 | 32 | -------------------------------------------------------------------------------- /session3/4-spec/1.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'reverse_map' do 2 | it 'defined a reverse_map method' do 3 | expect(method :reverse_map).to be 4 | end 5 | 6 | specify 'reverse_map(1, 2, 3) { |i| i * 2 } # => [6, 4, 2]' do 7 | times_2 = reverse_map(1, 2, 3) { |i| i * 2 } 8 | expect(times_2).to eq [6, 4, 2] 9 | end 10 | 11 | specify 'reverse_map {} # => []' do 12 | expect(reverse_map {}).to eq [] 13 | end 14 | 15 | specify 'reverse_map # => []' do 16 | expect(reverse_map.to_a).to eq [] 17 | end 18 | 19 | specify 'reverse_map("a", "b", "c") { |char| char * 3 } # => ["ccc", "bbb", "aaa"]' do 20 | expect(reverse_map("a", "b", "c") { |char| char * 3 }).to eq ["ccc", "bbb", "aaa"] 21 | end 22 | 23 | specify 'reverse_map(*1..1000) { |i| i * i } # => [1000000, 998001, ..., 9, 4, 1]' do 24 | expected = (1..1000).to_a.reverse.map { |i| i * i } 25 | actual = reverse_map(*1..1000) { |i| i * i } 26 | expect(actual).to eq expected 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /session3/4-spec/10.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'pathify' do 2 | def self.pathify_example(input, expected) 3 | example "pathify(#{input.inspect}) # => #{expected.inspect}" do 4 | actual = pathify input 5 | expect(actual.sort).to eq expected.sort 6 | end 7 | end 8 | 9 | pathify_example({}, 10 | []) 11 | 12 | pathify_example({'bin' => ['sh']}, 13 | ['/bin/sh']) 14 | 15 | pathify_example({'usr' => {'bin' => ['ruby']}}, 16 | ['/usr/bin/ruby']) 17 | 18 | pathify_example({'usr' => {'bin' => ['ruby', 'perl']}}, 19 | ['/usr/bin/ruby', '/usr/bin/perl']) 20 | 21 | pathify_example({'usr' => {'bin' => ['ruby'], 22 | 'include' => ['zlib.h']}}, 23 | ['/usr/bin/ruby', '/usr/include/zlib.h']) 24 | 25 | pathify_example({'usr' => {'bin' => ['ruby']}, 26 | 'opt' => {'local' => {'bin' => ['sqlite3', 27 | 'rsync']}}}, 28 | ['/usr/bin/ruby', '/opt/local/bin/sqlite3', '/opt/local/bin/rsync']) 29 | 30 | pathify_example({'a'=>{'b'=>{'c'=>{'d'=>['e', 'f']}}}}, 31 | ['/a/b/c/d/e', '/a/b/c/d/f']) 32 | 33 | pathify_example({ 34 | 'a' => { 35 | 'b' => { 36 | 'c' => {'d' => %w(e f g h)}, 37 | 'i' => {'j' => %w(k l m n)}, 38 | }, 39 | 'o' => %w(p q r s), 40 | 't' => %w(u v w x), 41 | }, 42 | 'y' => ['z'], 43 | }, %w( 44 | /a/b/c/d/e /a/b/i/j/k /a/o/p /a/t/u /y/z 45 | /a/b/c/d/f /a/b/i/j/l /a/o/q /a/t/v 46 | /a/b/c/d/g /a/b/i/j/m /a/o/r /a/t/w 47 | /a/b/c/d/h /a/b/i/j/n /a/o/s /a/t/x 48 | )) 49 | end 50 | -------------------------------------------------------------------------------- /session3/4-spec/11.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'array_init' do 2 | example "array_init(2) { |i| i.to_s } # => ['0', '1']" do 3 | actual = array_init(2) { |i| i.to_s } 4 | expect(actual).to eq ['0', '1'] 5 | end 6 | 7 | example "array_init { |i| i.to_s } # => ['0', '1', '2', '3', '4']" do 8 | actual = array_init { |i| i.to_s } 9 | expect(actual).to eq ['0', '1', '2', '3', '4'] 10 | end 11 | 12 | example "array_init(2) # => ['0', '100']" do 13 | actual = array_init(2) 14 | expect(actual).to eq ['0', '100'] 15 | end 16 | 17 | example "array_init # => ['0', '100', '200', '300', 400']" do 18 | actual = array_init 19 | expect(actual).to eq ['0', '100', '200', '300', '400'] 20 | end 21 | 22 | example "array_init { 'hi } # => [ 'hi', 'hi', 'hi', 'hi']" do 23 | actual = array_init { 'hi' } 24 | expect(actual).to eq ['hi', 'hi', 'hi', 'hi', 'hi'] 25 | end 26 | 27 | example "array_init(100){ 'hi' } # => ['hi'] * 100" do 28 | actual = array_init(100) { 'hi' } 29 | expect(actual).to eq ['hi'] * 100 30 | end 31 | 32 | it 'works for a more complicated block' do 33 | actual = array_init 10 do |i| 34 | if i % 2 == 0 35 | i * 200 36 | else 37 | i * -5 38 | end 39 | end 40 | expect(actual).to eq [0, -5, 400, -15, 800, -25, 1200, -35, 1600, -45] 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /session3/4-spec/15.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'middle' do 2 | it 'is a toplevel method' do 3 | method :middle # will raise an error if it can't find the method 4 | end 5 | 6 | list = nil 7 | 8 | 1.upto 10 do |i| 9 | head = {:data => i, :next => list} 10 | list = head 11 | expected = (i/2.0).ceil 12 | it "finds #{expected} for #{head.inspect}" do 13 | expect(middle head).to eq expected 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /session3/4-spec/16.rb: -------------------------------------------------------------------------------- 1 | require_relative 'helper' 2 | 3 | RSpec.describe 'print_list' do 4 | it 'is a toplevel method' do 5 | method :print_list # will raise an error if it can't find the method 6 | end 7 | 8 | list = nil 9 | 10 | 1.upto 10 do |i| 11 | head = { :data => i, :next => list } 12 | list = head 13 | expected = (1..i).to_a.reverse.join("\n") + "\n" 14 | it "prints #{expected.inspect} for #{head.inspect}" do 15 | printed = input_output { print_list head } 16 | expect(printed).to eq expected 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /session3/4-spec/17.rb: -------------------------------------------------------------------------------- 1 | require_relative 'helper' 2 | 3 | RSpec.describe 'print_list_in_reverse' do 4 | it 'is a toplevel method' do 5 | method :print_list_in_reverse # will raise an error if it can't find the method 6 | end 7 | 8 | list = nil 9 | 10 | 1.upto 10 do |i| 11 | head = { :data => i, :next => list } 12 | list = head 13 | expected = (1..i).to_a.join("\n") + "\n" 14 | it "prints #{expected.inspect} for #{head.inspect}" do 15 | printed = input_output { print_list_in_reverse head } 16 | expect(printed).to eq expected 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /session3/4-spec/2.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'staircase' do 2 | it 'is defined' do 3 | expect(method :staircase).to be 4 | end 5 | 6 | [ [1, { 1 => [] }], 7 | [2, { 1 => [] }], 8 | [3, { 1 => [], 3 => [2] }], 9 | [4, { 1 => [], 3 => [2] }], 10 | [5, { 1 => [], 3 => [2], 5 => [2, 4] }], 11 | [6, { 1 => [], 3 => [2], 5 => [2, 4] }], 12 | [7, { 1 => [], 3 => [2], 5 => [2, 4], 7 => [2, 4, 6] }], 13 | ].each do |n, result| 14 | specify "staircase(#{n}) # => #{result.inspect}" do 15 | expect(staircase n).to eq result 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /session3/4-spec/5.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'spiral_access' do 2 | def assert_yielded(ary_of_arys, expected) 3 | seen = [] 4 | spiral_access(ary_of_arys) { |element| seen << element } 5 | expect(seen).to eq expected 6 | end 7 | 8 | it 'is defined' do 9 | expect(method :spiral_access).to be 10 | end 11 | 12 | it 'does not call the block when there is nothing to iterate over' do 13 | expect { 14 | spiral_access([[]]) { raise "You invoked the block" } 15 | }.to_not raise_error 16 | end 17 | 18 | it 'yields 1 when given [[1]]' do 19 | assert_yielded [[1]], [1] 20 | end 21 | 22 | it 'yields 1,2,3,4 when given [[1,2],[4,3]]' do 23 | assert_yielded [[1,2],[4,3]], [1,2,3,4] 24 | end 25 | 26 | it 'yields 1,2,3,4,5,6,7,8,9 when given [[1,2,3],[8,9,4],[7,6,5]]' do 27 | assert_yielded [[1,2,3], [8,9,4], [7,6,5]], [1,2,3,4,5,6,7,8,9] 28 | end 29 | 30 | it 'matches the example given in the notes' do 31 | assert_yielded [ 32 | [ 1 , 2 , 3 , 4 , 5 ], 33 | [ 16 , 17 , 18 , 19 , 6 ], 34 | [ 15 , 24 , 25 , 20 , 7 ], 35 | [ 14 , 23 , 22 , 21 , 8 ], 36 | [ 13 , 12 , 11 , 10 , 9 ], 37 | ], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25] 38 | end 39 | 40 | it 'yields 1 through 36 when given a six by six array, populated in the order of traversal' do 41 | assert_yielded [ 42 | [ 1 , 2 , 3 , 4 , 5 , 6 ], 43 | [ 20 , 21 , 22 , 23 , 24 , 7 ], 44 | [ 19 , 32 , 33 , 34 , 25 , 8 ], 45 | [ 18 , 31 , 36 , 35 , 26 , 9 ], 46 | [ 17 , 30 , 29 , 28 , 27 , 10 ], 47 | [ 16 , 15 , 14 , 13 , 12 , 11 ], 48 | ], (1..36).to_a 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /session3/4-spec/helper.rb: -------------------------------------------------------------------------------- 1 | require 'stringio' 2 | 3 | RSpec.configure do |config| 4 | config.disable_monkey_patching! 5 | 6 | test_helpers = Module.new do 7 | def input_output(mock_stdin_with_this_str=String.new) 8 | ARGV.clear # -.0 9 | stdout , stdin = $stdout , $stdin 10 | $stdin = StringIO.new mock_stdin_with_this_str 11 | to_return = $stdout = StringIO.new 12 | yield 13 | $stdout , $stdin = stdout , stdin 14 | to_return.rewind 15 | to_return.read 16 | end 17 | end 18 | 19 | config.include test_helpers 20 | end 21 | -------------------------------------------------------------------------------- /session3/5-solved/1.rb: -------------------------------------------------------------------------------- 1 | def reverse_map(*args, &block) 2 | args.reverse.map(&block) 3 | end -------------------------------------------------------------------------------- /session3/5-solved/10.rb: -------------------------------------------------------------------------------- 1 | def pathify(paths=Hash.new) 2 | # base step 3 | return paths.map { |path| '/' + path } if paths.is_a? Array 4 | 5 | # recursive step 6 | to_return = [] 7 | paths.each do |parent_path, child_dirs| 8 | parent_path = '/' + parent_path # paths begin with a / 9 | child_paths = pathify child_dirs # convert child directories to paths 10 | child_paths.each do |child_path| # join each child path to it's parent path 11 | to_return << (parent_path + child_path) 12 | end 13 | end 14 | to_return 15 | end 16 | -------------------------------------------------------------------------------- /session3/5-solved/11.rb: -------------------------------------------------------------------------------- 1 | def array_init(size=5, &block) 2 | block ||= Proc.new { |i| (100 * i).to_s } 3 | Array.new(size, &block) 4 | end 5 | -------------------------------------------------------------------------------- /session3/5-solved/12.rb: -------------------------------------------------------------------------------- 1 | def pay_by(order) 2 | order.compute_cost 3 | order.compute_shipping 4 | order.compute_tax 5 | yield 6 | order.ship_goods 7 | end 8 | 9 | def pay_by_visa(order, ccn) 10 | pay_by order do 11 | order.payment :type => :visa, :ccn => ccn 12 | order.verify_payment 13 | end 14 | end 15 | 16 | def pay_by_check(order) 17 | pay_by(order) { order.payment :type => :check, :signed => true } 18 | end 19 | 20 | def pay_by_cash(order) 21 | pay_by(order) { order.payment :type => :cash } 22 | end 23 | 24 | def pay_by_store_credit(order,current_user) 25 | pay_by order do 26 | order.payment :type => :store_credit 27 | current_user.store_credit -= order.cost 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /session3/5-solved/13.rb: -------------------------------------------------------------------------------- 1 | def your_sort( array , &orderer ) 2 | # if it is nil, then it hasn't been set, default to spaceship operator for comparison result 3 | orderer ||= Proc.new { |a, b| a <=> b } 4 | 5 | array.each_index do |index1| 6 | array.each_index do |index2| 7 | order = orderer.call(array[index1], array[index2]) 8 | array[index1], array[index2] = array[index2], array[index1] if order < 0 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /session3/5-solved/14.rb: -------------------------------------------------------------------------------- 1 | # This can be handled in a much cleaner way in 1.9, without the params fiddling 2 | 3 | def problem_14(*params) 4 | problem = params.pop[:problem] if params.last.is_a? Hash 5 | problem ||= :count_clumps 6 | 7 | return count_clumps(*params) if problem == :count_clumps 8 | return same_ends(*params) if problem == :same_ends 9 | end 10 | 11 | def count_clumps(*numbers) 12 | clumps = 0 13 | previous = nil 14 | two_before = nil 15 | 16 | numbers.each do |number| 17 | clumps += 1 if (previous == number) && (previous != two_before) 18 | two_before = previous 19 | previous = number 20 | end 21 | clumps 22 | end 23 | 24 | def same_ends(n, *params) 25 | params[0, n] == params[-n, n] 26 | end 27 | -------------------------------------------------------------------------------- /session3/5-solved/15.rb: -------------------------------------------------------------------------------- 1 | def list_size(list) 2 | return 0 unless list 3 | 1 + list_size(list[:next]) 4 | end 5 | 6 | def middle(list, distance=list_size(list)/2) 7 | return list[:data] if distance == 0 8 | middle list[:next], (distance - 1) 9 | end 10 | -------------------------------------------------------------------------------- /session3/5-solved/16.rb: -------------------------------------------------------------------------------- 1 | def print_list(list) 2 | while list 3 | puts list[:data] 4 | list = list[:next] 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /session3/5-solved/17.rb: -------------------------------------------------------------------------------- 1 | def print_list_in_reverse(list) 2 | return unless list 3 | print_list_in_reverse list[:next] 4 | puts list[:data] 5 | end 6 | -------------------------------------------------------------------------------- /session3/5-solved/2.rb: -------------------------------------------------------------------------------- 1 | def staircase(n) 2 | to_return = {} 3 | 1.upto n do |crnt_size| 4 | next if crnt_size.even? 5 | all = Array.new(crnt_size) { |i| i + 1 } 6 | evens = all.select { |i| i.even? } 7 | to_return[crnt_size] = evens 8 | end 9 | to_return 10 | end 11 | -------------------------------------------------------------------------------- /session3/5-solved/3.rb: -------------------------------------------------------------------------------- 1 | def word_count(str) 2 | words = Hash.new { 0 } 3 | str.split.each { |word| words[word.downcase] += 1 } 4 | words 5 | end 6 | -------------------------------------------------------------------------------- /session3/5-solved/4.rb: -------------------------------------------------------------------------------- 1 | def first_pos(str) 2 | to_return = {} 3 | str.split.each_with_index do |word, index| 4 | to_return[word] ||= index 5 | end 6 | to_return 7 | end 8 | -------------------------------------------------------------------------------- /session3/5-solved/5.rb: -------------------------------------------------------------------------------- 1 | def spiral_access(arrays, iteration=0, &block) 2 | y_max = arrays.length - 1 3 | x_max = arrays.first.length - 1 4 | 5 | # base step 6 | return if y_max/2 < iteration || x_max/2 < iteration 7 | 8 | # top row 9 | iteration.upto x_max-iteration do |x| 10 | block.call arrays[iteration][x] 11 | end 12 | 13 | # right column 14 | (iteration + 1).upto y_max-iteration do |y| 15 | block.call arrays[y][x_max-iteration] 16 | end 17 | 18 | # bottom row 19 | (x_max - 1 - iteration).downto iteration do |x| 20 | block.call arrays[y_max-iteration][x] 21 | end 22 | 23 | # left column 24 | (y_max - 1 - iteration).downto iteration+1 do |y| 25 | block.call arrays[y][iteration] 26 | end 27 | 28 | # recursive step 29 | spiral_access arrays, iteration+1, &block 30 | end 31 | -------------------------------------------------------------------------------- /session3/5-solved/6.rb: -------------------------------------------------------------------------------- 1 | def match_maker(opposites_attract, *elements) 2 | to_return = [] 3 | elements.each_slice 2 do |first, last| 4 | first = !!first 5 | last = !!last 6 | result = if opposites_attract 7 | first != last 8 | else 9 | first == last 10 | end 11 | to_return << result 12 | end 13 | to_return 14 | end 15 | -------------------------------------------------------------------------------- /session3/5-solved/7.rb: -------------------------------------------------------------------------------- 1 | class HTMLTag 2 | FONTS = { 3 | :serif => '"Times New Roman", "Georgia"', 4 | :sans_serif => '"Arial", "Verdana"', 5 | :monospace => '"Courier New", "Lucida Console"' , 6 | } 7 | 8 | COLORS = { 9 | :red => '#FF0000', 10 | :green => '#00FF00', 11 | :blue => '#0000FF', 12 | } 13 | 14 | attr_accessor :name, :innerHTML, :font, :color, :multiline 15 | 16 | # options: :multiline should be true or false 17 | def initialize(name, innerHTML, options=Hash.new) 18 | @name, @innerHTML = name, innerHTML 19 | self.font = FONTS[options[:font]] 20 | self.color = COLORS[options[:color]] 21 | self.multiline = options.fetch :multiline, false 22 | end 23 | 24 | def style 25 | return nil unless font || color 26 | to_return = "style='" 27 | to_return << "font-family:#{font};" if font 28 | to_return << "color:#{color};" if color 29 | to_return << "'" 30 | to_return 31 | end 32 | 33 | def to_s 34 | line_end = "" 35 | line_end = "\n" if multiline # remember, if options[:multiline] doesn't exist, it will return nil, and nil is false 36 | "<#{name} #{style}>#{line_end}" \ 37 | "#{innerHTML.chomp}#{line_end}" \ 38 | "\n" 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /session3/5-solved/8.rb: -------------------------------------------------------------------------------- 1 | class Person 2 | attr_accessor :name, :age, :quote 3 | 4 | def initialize(options=Hash.new, &initializer) 5 | self.name = options[:name] 6 | self.age = options[:age] 7 | self.quote = options[:quote] 8 | @initializer = (initializer || Proc.new { |person| }) # this way, it always has a proc, and code like reinit doesn't have to worry that it might not be there 9 | reinit 10 | end 11 | 12 | def reinit 13 | @initializer.call(self) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /session3/5-solved/9.rb: -------------------------------------------------------------------------------- 1 | def shared(a, b) 2 | # union = Hash.new do |hash, key| 3 | # hash[key] = [(a.include?(key)||nil), # include returns true or false, when false, it goes to the RHS of the ||, and becomes nil 4 | # (b.include?(key)||nil)] 5 | # end 6 | 7 | union = {} 8 | a.each do |element| 9 | 10 | union[element] ||= [nil, nil] 11 | union[element][0] = true 12 | end 13 | 14 | b.each do |element| 15 | union[element] ||= [nil, nil] 16 | union[element][1] = true 17 | end 18 | 19 | result = union.select { |key, value| value == [true, true] }.map { |key, value| key } 20 | 21 | return union, result.sort 22 | end 23 | -------------------------------------------------------------------------------- /session4/1-notes/01-andand-return-values.rb: -------------------------------------------------------------------------------- 1 | #Watch this video - https://vimeo.com/24972005 - these notes are supplementary to the 2nd video as per the last section 2 | 3 | # Remember, everything in Ruby is true except for false and nil. 4 | # This means that (1 && 5) returning 5 works just as well 5 | # as if it had returned true. And in fact, that's what it does 6 | # && returns the last object it looks at before making its decision. 7 | 8 | # The LHS is true, so always returns the RHS. 9 | 1 && 5 # => 5 10 | 1 && nil # => nil 11 | 1 && false # => false 12 | 1 && true # => true 13 | 1 && 'abc' # => "abc" 14 | 15 | # The LHS is false, so just returns the LHS 16 | nil && 1 # => nil 17 | false && 1 # => false 18 | 19 | 20 | -------------------------------------------------------------------------------- /session4/1-notes/02-oror-return-values.rb: -------------------------------------------------------------------------------- 1 | # The same short circuit principle applies to ||. 2 | 3 | 4 | 5 | # When the LHS is true, returns the LHS 6 | 1 || nil # => 1 7 | "abc" || false # => "abc" 8 | 9 | 10 | 11 | # When the LHS is false, returns the LHS 12 | nil || 1 # => 1 13 | false || "abc" # => "abc" 14 | 15 | 16 | 17 | # How could this be used? The Sinatra gem, a web "microframework" 18 | # uses it to find the current mime type, or if there isn't one, 19 | # then use the default (http://goo.gl/cVDMK) 20 | mime_type = mime_type(type) || default 21 | -------------------------------------------------------------------------------- /session4/1-notes/03-ororequals.rb: -------------------------------------------------------------------------------- 1 | # A common idiom is to use the conditional or values to only set 2 | # a variable if it hasn't been set yet. Remember that `a += b` 3 | # expands to `a = a + b`, well `a ||= b` expands to `a = (a || b)` 4 | # When it has been set, it returns the value of a. When it hasn't 5 | # been set, it is nil, so returns the value of b. 6 | 7 | 8 | # Here is an example, I am using this in ruby-kickstart.com 9 | # (http://goo.gl/21tEg) I have regular expressions that match 10 | # against your answers, but databases don't know what regular 11 | # expressions are, so I have to convert them into a text format 12 | # called YAML. Then when I want to use them, I convert them out 13 | # of YAML back into a regular expression. 14 | # 15 | # In order to not incure the cost of converting from YAML 16 | # every time I want to use the regex, I only do it the first 17 | # time by using ||= 18 | class QuizRegex < ActiveRecord::Base 19 | belongs_to :quiz_match_answer_problem 20 | 21 | def regex=(regex) 22 | @regex = regex 23 | self.content = YAML.dump regex 24 | end 25 | 26 | def regex 27 | @regex ||= YAML.load(content) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /session4/1-notes/04-introspection.rb: -------------------------------------------------------------------------------- 1 | # See the cheatsheet for more info (http://goo.gl/7lsJk). 2 | 3 | 4 | # The most important ones are (we'll talk more about 5 | # what ancestors and superclasses are in a little bit). 6 | "abc".class # => String 7 | String.ancestors # => [String, Comparable, Object, Kernel, BasicObject] 8 | Fixnum.superclass # => Integer 9 | 10 | 11 | # puts calls to_s, it returns a string for end users 12 | # p calls inspect, it returns a string for developers 13 | # Strings for example, get quotes placed around them. 14 | "abc".inspect # => "\"abc\"" 15 | "abc".to_s # => "abc" 16 | 17 | 18 | require 'date' 19 | Date.today.inspect # => "#" 20 | Date.today.to_s # => "2011-06-11" 21 | -------------------------------------------------------------------------------- /session4/1-notes/05-ranges.rb: -------------------------------------------------------------------------------- 1 | # ranges look like this 2 | 1..5 # => 1..5 3 | 1...5 # => 1...5 4 | 5 | # 2 dots includes the end 6 | (1..3).to_a # => [1, 2, 3] 7 | 8 | # 3 dots excludes the end 9 | (1...3).to_a # => [1, 2] 10 | 11 | 12 | 13 | # They are iterable, using the methods in by Enumerable module 14 | iterated = Array.new 15 | (1..5).each { |n| iterated << n } 16 | iterated # => [1, 2, 3, 4, 5] 17 | 18 | (1...5).map { |n| n * 5 } # => [5, 10, 15, 20] 19 | ('a'..'c').to_a # => ["a", "b", "c"] 20 | 21 | 22 | # They make good arguments to things like arrays 23 | [1,2,3,4,5][1..3] # => [2, 3, 4] 24 | 25 | 26 | # You can use variables also 27 | start = 10 28 | stop = 15 29 | start..stop # => 10..15 30 | 31 | 32 | # They're mostly useless, but you'll see them every now and 33 | # then, so just be aware of what they are. 34 | -------------------------------------------------------------------------------- /session4/1-notes/06-files.rb: -------------------------------------------------------------------------------- 1 | # docs: http://ruby-doc.org/core/classes/File.html 2 | # http://ruby-doc.org/core/classes/IO.html 3 | # 4 | # 5 | # File output basically works the same way as regular output, 6 | # because a File object is an IO object 7 | # and $stdout and $stdin, are also IO objects. 8 | 9 | 10 | # Note that by default, this all happens in the dir 11 | # *you're* in, not the dir that the *file* is in. 12 | 13 | 14 | # Write to a file 15 | File.open "names", "w" do |file| 16 | file.puts "sally" 17 | file.puts "sam" 18 | file.print "billy" 19 | file.print "bob" 20 | file.puts 21 | end 22 | 23 | 24 | # You can see it's in here. 25 | files = Dir.glob('*') # => ["01-&&-return-values.rb", "02-||-return-values.rb", "03-||=.rb", "04-introspection.rb", "05-ranges.rb", "06-files.rb", "names", "notes.rb"] 26 | files.include? 'names' # => true 27 | 28 | 29 | # Read the entire file at once 30 | contents = File.read "names" 31 | contents # => "sally\nsam\nbillybob\n" 32 | 33 | 34 | # Iterate over the lines of the file 35 | # useful if your file is really big. 36 | File.foreach "names" do |line| 37 | line # => "sally\n", "sam\n", "billybob\n" 38 | end 39 | 40 | 41 | # Read each line from the file into an array 42 | File.readlines "names" # => ["sally\n", "sam\n", "billybob\n"] 43 | 44 | 45 | # Cleaning up 46 | File.exist? "names" # => true 47 | File.delete "names" 48 | File.exist? "names" # => false 49 | -------------------------------------------------------------------------------- /session4/1-notes/07-working-dir-vs-file-dir.rb: -------------------------------------------------------------------------------- 1 | # The working directory is the directory you're in when you invoke 2 | # the Ruby program. Use Dir.pwd (print working directory) to find it. 3 | puts "Your working directory is #{Dir.pwd}" 4 | 5 | 6 | # The file's dir, however, is where the file is stored in. Every 7 | # file has a variable it can access called __FILE__ which tells 8 | # it where it is located. You can get the file's directory 9 | # with File.dirname(__FILE__). The "." means "current dir", 10 | # in other words, the file is located in the same dir as we are. 11 | # The ".." means the parent dir, the one containing the 12 | # current dir. 13 | puts "This script is located in #{File.dirname __FILE__}" 14 | 15 | 16 | # Try going to different directories and invoking this script: 17 | 18 | # --- From the RKS root --- 19 | # $ ruby ch4/notes/07-working-dir-vs-file-dir.rb 20 | # Your working directory is /Users/josh/code/RKS 21 | # This script is located in ch4/notes 22 | 23 | # --- From ch3 --- 24 | # $ ruby ../ch4/notes/07-working-dir-vs-file-dir.rb 25 | # Your working directory is /Users/josh/code/RKS/ch3 26 | # This script is located in ../ch4/notes 27 | 28 | # --- From ch4/notes --- 29 | # $ ruby 07-working-dir-vs-file-dir.rb 30 | # Your working directory is /Users/josh/code/RKS/ch4/notes 31 | # This script is located in . 32 | -------------------------------------------------------------------------------- /session4/1-notes/08.a-require.rb: -------------------------------------------------------------------------------- 1 | # When you have code in one file that you want to use in another 2 | # file, you load it by using require. 3 | defined? Date # => nil 4 | require 'date' 5 | defined? Date # => "constant" 6 | 7 | # In this case, Ruby looks in several different places to see a 8 | # list of locations to look for the file you required. It contains 9 | # things like the standard library, a set of files with useful 10 | # things like Date. 11 | 12 | # When you want to load a file that you've written, it won't be 13 | # in that path variable, so you must give Ruby an absolute path 14 | # to the file. 15 | require File.dirname(__FILE__) + '/08.b-require' 16 | 17 | def here 18 | 'from 08.a' 19 | end 20 | 21 | here # => "from 08.a" 22 | there # => "from 08.b" 23 | -------------------------------------------------------------------------------- /session4/1-notes/08.b-require.rb: -------------------------------------------------------------------------------- 1 | # This code will be required by 08.a 2 | 3 | def there 4 | 'from 08.b' 5 | end 6 | -------------------------------------------------------------------------------- /session4/1-notes/09-inheritance-introduction.rb: -------------------------------------------------------------------------------- 1 | # Sometimes you have a generic idea of your class, but it can be 2 | # realized in several specific ways. Sometimes, in Object Oriented 3 | # Programming, we will subclass the generic class, called the 4 | # superclass, and write more specific implementations. (Note that 5 | # this has largely fallen out of favour in the Ruby community). 6 | 7 | class Superclass 8 | end 9 | 10 | # Use the < to indicate inheritance 11 | class Subclass < Superclass 12 | end 13 | 14 | Subclass.superclass # => Superclass 15 | 16 | -------------------------------------------------------------------------------- /session4/1-notes/10-subclasses-inherit-methods.rb: -------------------------------------------------------------------------------- 1 | class Superclass 2 | def self.class_method 3 | 'class_method from Superclass' 4 | end 5 | 6 | def instance_method 7 | 'instance_method from Superclass' 8 | end 9 | end 10 | 11 | class Subclass < Superclass 12 | end 13 | 14 | # Subclasses inherit methods from their superclass 15 | Subclass.class_method # => "class_method from Superclass" 16 | Subclass.new.instance_method # => "instance_method from Superclass" 17 | 18 | -------------------------------------------------------------------------------- /session4/1-notes/11-overriding-inherited-methods.rb: -------------------------------------------------------------------------------- 1 | class Superclass 2 | def self.class_method 3 | 'class_method from Superclass' 4 | end 5 | 6 | def instance_method 7 | 'instance_method from Superclass' 8 | end 9 | end 10 | 11 | class Subclass < Superclass 12 | def self.class_method 13 | 'class_method from Subclass' 14 | end 15 | end 16 | 17 | Subclass.class_method # => "class_method from Subclass" 18 | Subclass.new.instance_method # => "instance_method from Superclass" 19 | 20 | -------------------------------------------------------------------------------- /session4/1-notes/12-super-to-invoke-inherited.rb: -------------------------------------------------------------------------------- 1 | # When you override a method, you can call the method 2 | # you're overriding, with the keyword `super`. 3 | class Superclass 4 | def self.class_method 5 | 'class_method from Superclass' 6 | end 7 | end 8 | 9 | class Subclass < Superclass 10 | def self.class_method 11 | super + " | through Subclass" 12 | end 13 | end 14 | 15 | Subclass.class_method # => "class_method from Superclass | through Subclass" 16 | 17 | -------------------------------------------------------------------------------- /session4/1-notes/13-inheritance-example.rb: -------------------------------------------------------------------------------- 1 | # This will be our superclass. There are many kinds of employees but 2 | # they all have wages, and each type makes a certain dollars per hour. 3 | class Employee 4 | class << self 5 | attr_accessor :dollars_per_hour 6 | end 7 | 8 | attr_accessor :hours_worked 9 | 10 | def initialize( hours_worked ) 11 | self.hours_worked = hours_worked 12 | end 13 | 14 | def wages 15 | self.class.dollars_per_hour * hours_worked 16 | end 17 | end 18 | 19 | 20 | # Bill is a clerk, he makes 160 hours * $20 per hour = $3200 21 | class Clerk < Employee 22 | self.dollars_per_hour = 20 23 | end 24 | bill = Clerk.new 160 25 | bill.wages # => 3200 26 | 27 | 28 | # Ayaan is an engineer, she makes 29 | # 160 hours * $30 per hour + $500 per month = $5300 30 | class Engineer < Employee 31 | self.dollars_per_hour = 30 32 | def wages 33 | super + 500 34 | end 35 | end 36 | ayaan = Engineer.new 160 37 | ayaan.wages # => 5300 38 | -------------------------------------------------------------------------------- /session4/1-notes/14-ancestors.rb: -------------------------------------------------------------------------------- 1 | # The chain of superclasses are called ancestors. 2 | class Superclass 3 | end 4 | 5 | class Subclass < Superclass 6 | end 7 | 8 | Subclass.ancestors # => [Subclass, Superclass, Object, Kernel, BasicObject] 9 | Subclass # => Subclass 10 | Subclass.superclass # => Superclass 11 | Superclass.superclass # => Object 12 | Object.superclass # => BasicObject 13 | BasicObject.superclass # => nil 14 | 15 | # Kernel doesn't fit in, that's because it's not a class, 16 | # it's a module. We'll talk about modules next time. 17 | -------------------------------------------------------------------------------- /session4/1-notes/15-exceptions-introduction.rb: -------------------------------------------------------------------------------- 1 | # Errors and Exceptions are used to say "something something happend 2 | # that I don't know how to deal with". They halt evaluation, and 3 | # return to where they were called from, incrementally making their 4 | # way up the stack (the series of methods that were called to get to 5 | # wherever the exception was raised) until they are either either 6 | # rescued, or cause the program to crash. 7 | 8 | # You raise exceptions with the raise method 9 | raise "This will now die!" 10 | # ~> -:9:in `
': This will now die! (RuntimeError) 11 | -------------------------------------------------------------------------------- /session4/1-notes/16-exceptions-rescuing.rb: -------------------------------------------------------------------------------- 1 | def method_with_one_parameter(n) 2 | end 3 | 4 | 5 | # Code that might raise an error goes in begin/rescue/end blocks. 6 | begin 7 | method_with_one_parameter(1,2,3) 8 | # This code won't be executed because it happened after the exception. 9 | 1 + 2 # => 10 | rescue ArgumentError => e 11 | # We've rescued the Error, and are storing it in 12 | # the variable e. Errors are objects just like anything else. 13 | e # => # 14 | e.class # => ArgumentError 15 | e.class.ancestors # => [ArgumentError, StandardError, Exception, Object, Kernel, BasicObject] 16 | end 17 | 18 | 19 | 20 | # You can rescue specific exceptions if you like 21 | begin 22 | method_with_one_parameter(1,2,3) 23 | rescue ZeroDivisionError => e 24 | e # => 25 | rescue ArgumentError => e 26 | e # => # 27 | end 28 | 29 | 30 | begin 31 | 1 / 0 32 | rescue ZeroDivisionError => e 33 | e # => # 34 | rescue ArgumentError => e 35 | e # => 36 | end 37 | 38 | -------------------------------------------------------------------------------- /session4/1-notes/17-raising-your-own.rb: -------------------------------------------------------------------------------- 1 | # You can raise an existing exception by passing it to raise 2 | begin 3 | raise Exception.new("We made this!") 4 | rescue Exception => e 5 | e # => # 6 | end 7 | 8 | 9 | # If you pass a string to raise, it will be a RuntimeError 10 | begin 11 | raise "Fix your shit" 12 | rescue RuntimeError => e 13 | e # => # 14 | end 15 | -------------------------------------------------------------------------------- /session4/3-challenge/2_subclassing_require.rb: -------------------------------------------------------------------------------- 1 | # If you struggle on this question for ~30 minutes and aren't getting anywhere, look at the solutions file, try to understand the code, then close the file, come back here, and try again to solve it. 2 | 3 | # Require the stack code from challenge 1 4 | # The code you added causes it to do this 5 | # 6 | # stack = Stack.new 7 | # stack.push 1 8 | # stack.push 2 9 | # stack # => (2)1) 10 | 11 | 12 | # But sometimes you want it to inspect like an array. 13 | # stack # => [1, 2] 14 | # 15 | # Subclass the Stack class and override its inspect 16 | # so that we can do this: 17 | # 18 | # stack = StackInDisguise.new 19 | # stack.push 1 20 | # stack.push 2 21 | # stack # => [1, 2] 22 | 23 | -------------------------------------------------------------------------------- /session4/3-challenge/3_inject_blocks_enumerable.rb: -------------------------------------------------------------------------------- 1 | # If you struggle on this question for ~30 minutes and aren't getting anywhere, look at the solutions file, try to understand the code, then close the file, come back here, and try again to solve it. 2 | 3 | # You are going to write a method called passthrough 4 | # It receives an enumerable object, and an initial passthrough value, and a block 5 | # 6 | # For each of the elements in the enumerable object, 7 | # it passes them the passthrough value and the element. 8 | # Whatever the block returns, must be passed in as the 9 | # next passthrough value for the next element. 10 | # 11 | # After we go through all the elements, the last passthrough value is returned to the caller 12 | # 13 | # 14 | # EXAMPLE: 15 | # 16 | # passthrough 5..10 , 0 do |sum,num| 17 | # sum + num 18 | # end 19 | # 20 | # This should return 45 in the following manner: 21 | # The first time the block is passed 0 , 5 and it returns 5 22 | # The second time the block is passed 5 , 6 and it returns 11 23 | # The third time the block is passed 11 , 7 and it returns 18 24 | # The fourth time the block is passed 18 , 8 and it returns 26 25 | # The fourth time the block is passed 26 , 9 and it returns 35 26 | # The fourth time the block is passed 35 , 10 and it returns 45 27 | # The method then returns 45 28 | # 29 | -------------------------------------------------------------------------------- /session4/3-challenge/4_oror.rb: -------------------------------------------------------------------------------- 1 | # If you struggle on this question for ~30 minutes and aren't getting anywhere, look at the solutions file, try to understand the code, then close the file, come back here, and try again to solve it. 2 | 3 | # Write a method first_object, that takes three parameters 4 | # and returns the first one that is true. 5 | # 6 | # EXAMPLES: 7 | # first_object 1, nil, nil # => 1 8 | # first_object nil, 1, nil # => 1 9 | # first_object nil, nil, 1 # => 1 10 | # first_object nil, 1, 2 # => 1 11 | # first_object nil, nil, nil # => nil 12 | 13 | def first_object(arg1, arg2, arg3) 14 | 15 | end 16 | -------------------------------------------------------------------------------- /session4/3-challenge/5_file.rb: -------------------------------------------------------------------------------- 1 | # If you struggle on this question for ~30 minutes and aren't getting anywhere, look at the solutions file, try to understand the code, then close the file, come back here, and try again to solve it. 2 | 3 | # you will be given a file name 4 | # inside the file will be a series of numbers 5 | # find the largest number on each line 6 | # return their sum 7 | # 8 | # EXAMPLE 9 | # file: nums.txt 10 | # 406 217 799 116 45 651 808 780 11 | # 205 919 474 567 712 12 | # 776 170 681 86 822 9 100 540 812 13 | # 602 117 181 169 876 336 14 | # 434 165 725 187 974 48 15 | # 16 | # line_sums('nums.txt') # => 808 + 919 + 822 + 876 + 974 # => 4399 17 | 18 | -------------------------------------------------------------------------------- /session4/3-challenge/6_singleton_class_string.rb: -------------------------------------------------------------------------------- 1 | # If you struggle on this question for ~30 minutes and aren't getting anywhere, look at the solutions file, try to understand the code, then close the file, come back here, and try again to solve it. 2 | 3 | # In Ruby on Rails, when a person goes to a URL on your site, your application looks at the url, 4 | # and maps it to a controller method to handle the request 5 | # 6 | # My boss wanted to be able to specify what CSS class the body of the HTML output should have, 7 | # based on which controller method was being accessed. 8 | # It fell to me to provide a method, which, when invoked, would return a String that could handle the request 9 | # 10 | # There are a few nuances, though. 11 | # The String you return must be retained during the object's entire life 12 | # The method must be able to be called multiple times 13 | # The String you return should know how to add new classes: each class is separated by a space 14 | # The only method you need to worry about being invoked is the << method. 15 | # 16 | # EXAMPLE: 17 | # controller = ApplicationController.new 18 | # controller.body_class # => "" 19 | # controller.body_class << 'admin' 20 | # controller.body_class # => "admin" 21 | # controller.body_class << 'category' 22 | # controller.body_class # => "admin category" 23 | # controller.body_class << 'page' << 'order' 24 | # controller.body_class # => "admin category page order" 25 | # 26 | # 27 | # HINT: 28 | # The concat method will do the same thing as the << method 29 | 30 | class ApplicationController 31 | def body_class 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /session4/3-challenge/7_introspection.rb: -------------------------------------------------------------------------------- 1 | # Given an object, return the name of its longest method 2 | # o = Object.new 3 | # def o.this_is_a_really_really_really_really_really_long_method_name 4 | # end 5 | # 6 | # longest_method o # => :this_is_a_really_really_really_really_really_long_method_name 7 | 8 | -------------------------------------------------------------------------------- /session4/3-challenge/8_exceptions.rb: -------------------------------------------------------------------------------- 1 | # If you struggle on this question for ~30 minutes and aren't getting anywhere, look at the solutions file, try to understand the code, then close the file, come back here, and try again to solve it. 2 | 3 | # Write a method that receives a number 1 through 5. 4 | # Depending on the value of the number, it will raise 5 | # some particular type of exception. 6 | # 7 | # HINT: 8 | # All exceptions and errors are descendants of Exception. 9 | # (Exception is listed as an ancestor) 10 | # 11 | # Examples: 12 | # exception_raiser 1 # => # 13 | # exception_raiser 2 # => # 14 | # exception_raiser 3 # => # 15 | # exception_raiser 4 # => # 16 | # exception_raiser 5 # => # 17 | 18 | -------------------------------------------------------------------------------- /session4/3-challenge/9_exceptions.rb: -------------------------------------------------------------------------------- 1 | # If you struggle on this question for ~30 minutes and aren't getting anywhere, look at the solutions file, try to understand the code, then close the file, come back here, and try again to solve it. 2 | 3 | # You need to write a method that will take a person and 4 | # generate their full name. A full name is just a first_name 5 | # and a last_name separated by a space. 6 | # 7 | # Sometimes, though, the code will raise a FirstNameError 8 | # In these cases, just return their last name. 9 | # 10 | # Other times, the code will raise a LastNameError 11 | # In these cases, just return their first name. 12 | # 13 | # And sometimes, it will raise other unexpected errors. 14 | # In these cases, don't do anything, because we don't know 15 | # why that error was raised. 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /session4/4-spec/1.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'Stack#inspect' do 2 | let(:stack) { Stack.new } 3 | 4 | example 'initially is ()' do 5 | expect(stack.inspect).to eq "()" 6 | end 7 | 8 | example 'after pushing 1: (1)' do 9 | stack.push 1 10 | expect(stack.inspect).to eq '(1)' 11 | end 12 | 13 | example 'after pushing a hash: ({1=>2})' do 14 | stack.push({1=>2}) 15 | expect(stack.inspect).to eq '({1=>2})' 16 | end 17 | 18 | example 'after pushing 1, then 2, then 3: (3)2)1)' do 19 | (1..3).each { |i| stack.push i } 20 | expect(stack.inspect).to eq '(3)2)1)' 21 | end 22 | 23 | example 'after pushing 1 through 5: (5)4)3)2)1)' do 24 | (1..5).each { |i| stack.push i } 25 | expect(stack.inspect).to eq "(5)4)3)2)1)" 26 | end 27 | 28 | example 'after pushing 1 through 3, and then /abc/: (/abc/)3)2)1)' do 29 | (1..3).each { |i| stack.push i } 30 | stack.push(/abc/) 31 | expect(stack.inspect).to eq "(/abc/)3)2)1)" 32 | end 33 | 34 | example 'after pushing lotsa stuff: ([1, 2, 3])"abc")true)false)nil)' do 35 | [nil, false, true, "abc", [1,2,3]].each { |e| stack.push e } 36 | expect(stack.inspect).to eq '([1, 2, 3])"abc")true)false)nil)' 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /session4/4-spec/3.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'passthrough' do 2 | it 'returns what is passed in, if the enum is empty' do 3 | result = passthrough([], :passed_in) { |a, b| :from_block } 4 | expect(result).to eq :passed_in 5 | end 6 | 7 | it 'summing 5..10, starting at 0, returns 45' do 8 | result = passthrough(5..10, 0) { |sum, num| sum + num } 9 | expect(result).to eq 45 10 | end 11 | 12 | it 'summing 5..10 from 0 again, but checking params this time' do 13 | expected_params = [ 14 | 0, 5, 15 | 5, 6, 16 | 11, 7, 17 | 18, 8, 18 | 26, 9, 19 | 35, 10, 20 | ] 21 | actual_params = [] 22 | result = passthrough 5..10, 0 do |sum, num| 23 | actual_params << sum << num 24 | sum + num 25 | end 26 | expect(actual_params).to eq expected_params 27 | end 28 | 29 | it '"the fox and the hound ran all around", with words aggregated by length' do 30 | result = passthrough %w(the fox and the hound ran all around), Hash.new do |words, word| 31 | words[word.length] ||= Array.new 32 | words[word.length] << word 33 | words 34 | end 35 | expect(result).to eq 5 => ["hound"], 36 | 6 => ["around"], 37 | 3 => ["the", "fox", "and", "the", "ran", "all"] 38 | end 39 | 40 | it 'passing a hash in, and expanding it to names' do 41 | married_couples = {'Smith' => ['John', 'Sally'], 'Jones' => ['Will', 'Robert']} 42 | people = passthrough married_couples, Array.new do |people, (last_name, first_names)| 43 | full_names = first_names.map { |first_name| "#{first_name} #{last_name}" } 44 | people + full_names 45 | end 46 | expect(people).to eq ["John Smith", "Sally Smith", "Will Jones", "Robert Jones"] 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /session4/4-spec/4.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'first_object' do 2 | def self.assert_first(first, args) 3 | example "first_object(#{args.map(&:inspect).join(", ")}) # => #{first.inspect}" do 4 | obj = first_object(*args) 5 | expect(obj).to eq first 6 | end 7 | end 8 | 9 | assert_first 1, [1, nil, nil] 10 | assert_first 1, [nil, 1, nil] 11 | assert_first 1, [nil, nil, 1] 12 | assert_first 1, [nil, 1, 2] 13 | assert_first nil, [nil, nil, nil] 14 | assert_first nil, [false, false, false] 15 | assert_first true, [false, false, true] 16 | assert_first 5, [5, 4, 3] 17 | assert_first 5, [5, nil, 3] 18 | assert_first 5, [5, 4, nil] 19 | end 20 | -------------------------------------------------------------------------------- /session4/4-spec/5.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | RSpec.describe 'line_sums' do 4 | expected_answers = { 5 | '8.1' => 4399, 6 | '8.2' => 0, 7 | '8.3' => 4399, 8 | '8.4' => 12, 9 | '8.5' => 3, 10 | '8.6' => 5, 11 | '8.7' => 23793343701, 12 | '8.8' => 880754605216, 13 | '8.9' => 2987648672, 14 | } 15 | 16 | template_pattern = File.expand_path "../../resources/*.template", __FILE__ 17 | Dir[template_pattern].each do |template_path| 18 | real_path = template_path.sub /\.template$/, '' 19 | expected_answer = expected_answers.fetch real_path[/(\d+\.\d+$)/] 20 | 21 | example "#{real_path} sums to #{expected_answer}" do 22 | begin 23 | FileUtils.cp template_path, real_path 24 | expect(line_sums real_path).to eq expected_answer 25 | ensure 26 | FileUtils.rm real_path 27 | end 28 | end 29 | 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /session4/4-spec/6.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'ApplicationController#body_class' do 2 | let(:ac) { ApplicationController.new } 3 | 4 | it 'returns the aggregated class in the #body_class method, which starts empty' do 5 | ac = ApplicationController.new.body_class 6 | expect(ac).to eq "" 7 | end 8 | 9 | it 'becomes "admin" after it receives `<< "admin"`' do 10 | bc = ApplicationController.new.body_class 11 | bc << "admin" 12 | expect(bc).to eq "admin" 13 | end 14 | 15 | it 'keeps track of the variable it is using' do 16 | ac.body_class << 'admin' 17 | expect(ac.body_class).to eq 'admin' 18 | end 19 | 20 | it 'has unique state for each instance' do 21 | ac1 = ApplicationController.new 22 | ac1.body_class << "admin" 23 | 24 | ac2 = ApplicationController.new 25 | ac2.body_class << "page" 26 | 27 | expect(ac1.body_class).to eq "admin" 28 | expect(ac2.body_class).to eq "page" 29 | end 30 | 31 | it 'places a space between CSS classes appended to it' do 32 | ac.body_class << 'admin' 33 | ac.body_class << 'category' 34 | expect(ac.body_class).to eq 'admin category' 35 | end 36 | 37 | it 'returns the string when invoking << on the string' do 38 | obj_id = (ac.body_class << 'admin').object_id 39 | expect(obj_id).to eq ac.body_class.object_id 40 | end 41 | 42 | it 'works with multiple CSS classes' do 43 | ac.body_class << 'admin' 44 | ac.body_class << 'category' 45 | ac.body_class << 'page' << 'order' 46 | expect(ac.body_class).to eq 'admin category page order' 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /session4/4-spec/7.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | 3 | RSpec.describe 'longest_method' do 4 | [ 1, 5 | 2, 6 | 2**1000, 7 | "abc", 8 | /abc/, 9 | Object.new, 10 | Object, 11 | Class, 12 | Class.new, 13 | Date.today, 14 | Pathname.new('.'), 15 | Time.now, 16 | Object.new.instance_eval { def this_is_a_really_really_really_really_really_long_method_name; end; self }, 17 | ].each do |object| 18 | # This might be cheating, but I'm hesitant to hard code something in here, 19 | # given that it could change as Ruby changes. 20 | expected = object.methods.max_by(&:length) 21 | it "returns #{expected.inspect} for #{object.inspect}" do 22 | actual = longest_method(object) 23 | expect(actual).to eq expected 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /session4/4-spec/8.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'exception_raiser' do 2 | it 'when given 1, it raises #' do 3 | expect { exception_raiser 1 }.to raise_error(RuntimeError, "No 1s allowed!") 4 | end 5 | 6 | it 'when given 2, it raises #' do 7 | expect { exception_raiser 2 }.to raise_error(ArgumentError, "No 2s allowed!") 8 | end 9 | 10 | it 'when given 3, it raises #' do 11 | expect { exception_raiser 3 }.to raise_error(Exception, "No 3s allowed!") 12 | end 13 | 14 | it 'when given 4, it raises #' do 15 | expect { exception_raiser 4 }.to raise_error(SyntaxError, "No 4s allowed!") 16 | end 17 | 18 | it 'when given 5, it raises #' do 19 | expect { exception_raiser 5 }.to raise_error(RubyKickstartException, "No 5s allowed!") 20 | end 21 | 22 | [-1, 0, "abc", /abc/].each do |object| 23 | it "doesn't raise an error when it receives #{object.inspect}" do 24 | expect { exception_raiser object }.to_not raise_error 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /session4/5-solved/1.rb: -------------------------------------------------------------------------------- 1 | # load the stack code in 2 | require File.expand_path("../../challenge/1_stack_classes_inspect", __FILE__) 3 | 4 | 5 | class Stack 6 | def inspect 7 | current = @head 8 | to_return = "(" 9 | while current 10 | to_return << current.data.inspect 11 | to_return << ")" 12 | current = current.next_node 13 | end 14 | to_return << ")" if to_return == "(" 15 | to_return 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /session4/5-solved/2.rb: -------------------------------------------------------------------------------- 1 | # 1's solution requires the actual file we are interested in 2 | require File.dirname(__FILE__) + "/1" 3 | 4 | class StackInDisguise < Stack 5 | def inspect 6 | ary = [] 7 | current = @head 8 | while current 9 | ary << current.data 10 | current = current.next_node 11 | end 12 | ary.reverse.inspect 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /session4/5-solved/3.rb: -------------------------------------------------------------------------------- 1 | def passthrough(enumerable, to_pass, &block) 2 | enumerable.each do |element| 3 | to_pass = block.call(to_pass, element) 4 | end 5 | to_pass 6 | end 7 | -------------------------------------------------------------------------------- /session4/5-solved/4.rb: -------------------------------------------------------------------------------- 1 | def first_object(a, b, c) 2 | a || b || c || nil 3 | end 4 | -------------------------------------------------------------------------------- /session4/5-solved/5.rb: -------------------------------------------------------------------------------- 1 | def line_sums(filename) 2 | File.readlines(filename).inject 0 do |sum, line| 3 | numbers = line.split.map { |number| number.to_i } 4 | sum + numbers.max 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /session4/5-solved/6.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController 2 | def body_class 3 | return @body_class if @body_class 4 | @body_class = String.new 5 | def @body_class.<<(str) 6 | concat ' ' unless length.zero? 7 | concat str 8 | end 9 | @body_class 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /session4/5-solved/7.rb: -------------------------------------------------------------------------------- 1 | def longest_method(object) 2 | object.methods.max_by { |meth| meth.length } 3 | end 4 | -------------------------------------------------------------------------------- /session4/5-solved/8.rb: -------------------------------------------------------------------------------- 1 | class RubyKickstartException < Exception 2 | end 3 | 4 | def exception_raiser(num) 5 | if num == 1 then raise "No 1s allowed!" 6 | elsif num == 2 then raise ArgumentError, "No 2s allowed!" 7 | elsif num == 3 then raise Exception, "No 3s allowed!" 8 | elsif num == 4 then raise SyntaxError, "No 4s allowed!" 9 | elsif num == 5 then raise RubyKickstartException, "No 5s allowed!" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /session4/5-solved/9.rb: -------------------------------------------------------------------------------- 1 | def full_name(person) 2 | begin 3 | "#{person.first_name} #{person.last_name}" 4 | rescue FirstNameError 5 | person.last_name 6 | rescue LastNameError 7 | person.first_name 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /session4/resources/8.1.template: -------------------------------------------------------------------------------- 1 | 406 217 799 116 45 651 808 780 2 | 205 919 474 567 712 3 | 776 170 681 86 822 9 100 540 812 4 | 602 117 181 169 876 336 5 | 434 165 725 187 974 48 6 | -------------------------------------------------------------------------------- /session5/.rvmrc: -------------------------------------------------------------------------------- 1 | rvm use ruby-1.9.2-p180@cleaned_for_rks_session_5 2 | 3 | -------------------------------------------------------------------------------- /session5/1-notes/01-modules-introduction.rb: -------------------------------------------------------------------------------- 1 | #Watch this video - https://vimeo.com/25294157 - these notes are supplementary as per the last section 2 | 3 | # Modules are just like classes in that they contain methods. But 4 | # unlike classes, you can't instantiate them. Instead, we include 5 | # their methods in some other class, and then its instances get 6 | # the module's methods. 7 | 8 | # A class can only inherit from one other class, but it can include 9 | # as many modules as it likes (this is commonly called a mix-in) 10 | 11 | # Because of this (among other things), mixing modules in is usually 12 | # preferred in the Ruby community, rather than subclassing. 13 | # Now, people usually prefer to get functionality by mixing in a 14 | # module rather than subclassing another class. 15 | 16 | -------------------------------------------------------------------------------- /session5/1-notes/02-modules-including.rb: -------------------------------------------------------------------------------- 1 | # Modules have the feel of a class in that you define methods in them. 2 | # But since they cannot be instantiated, you must declare that the 3 | # methods in the module should be included in a class, and the module 4 | # will be added to the inheritance chain, making its methods available. 5 | module OurModule 6 | def meth 7 | 'method from OurModule' 8 | end 9 | end 10 | 11 | # When we include OurModule in a class, it becomes an ancestor 12 | class OurClass 13 | include OurModule 14 | end 15 | OurClass.ancestors # => [OurClass, OurModule, Object, Kernel, BasicObject] 16 | 17 | # This means its instances can invoke OurModule's methods 18 | OurClass.new.meth # => "meth from M" 19 | 20 | -------------------------------------------------------------------------------- /session5/1-notes/03-modules-extending.rb: -------------------------------------------------------------------------------- 1 | # Sometimes we want to give the module's functionality to just one 2 | # object. In this case, we include it in the object's singleton class. 3 | module OurModule 4 | def meth 5 | 'method from M' 6 | end 7 | end 8 | 9 | obj = Object.new 10 | class << obj 11 | include OurModule 12 | end 13 | obj.singleton_class.ancestors # => [OurModule, Object, Kernel, BasicObject] 14 | obj.meth # => "method from M" 15 | 16 | 17 | # Unfortunately, that's a little bit annoying to write, so there 18 | # is a shortcut syntax. Extending an object with a module is the 19 | # same as including the module in its singleton class. 20 | obj = Object.new 21 | obj.extend OurModule 22 | obj.singleton_class.ancestors # => [OurModule, Object, Kernel, BasicObject] 23 | obj.meth # => "method from M" 24 | 25 | -------------------------------------------------------------------------------- /session5/1-notes/04-modules-example.rb: -------------------------------------------------------------------------------- 1 | # Here is a common example of how we might use modules: 2 | module Threes 3 | def threes_r0 4 | self.select { |i| i % 3 == 0 } 5 | end 6 | 7 | def threes_r1 8 | select { |i| i % 3 == 1 } 9 | end 10 | 11 | def threes_r2 12 | select { |i| i % 3 == 2 } 13 | end 14 | end 15 | 16 | 17 | 18 | sequence = 0...30 19 | sequence.extend Threes 20 | 21 | sequence # => 0...30 22 | 23 | 24 | # Threes is not on our sequence of numbers, but not on any others. 25 | sequence.singleton_class.ancestors # => [Threes, Range, Enumerable, Object, Kernel, BasicObject] 26 | (0...30).singleton_class.ancestors # => [Range, Enumerable, Object, Kernel, BasicObject] 27 | 28 | 29 | # This means we can call it's methods. 30 | sequence.threes_r0 # => [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] 31 | sequence.threes_r1 # => [1, 4, 7, 10, 13, 16, 19, 22, 25, 28] 32 | sequence.threes_r2 # => [2, 5, 8, 11, 14, 17, 20, 23, 26, 29] 33 | 34 | sequence # => 0...30 35 | 0...30 # => 0...30 36 | sequence.methods.grep(/threes/) # => [:threes_r0, :threes_r1, :threes_r2] 37 | (0...30).methods.grep(/threes/) # => [] 38 | 39 | # Questions: Where did the select come from in threes_rn? 40 | # Can you think of another object we could extend with this module? 41 | 42 | -------------------------------------------------------------------------------- /session5/1-notes/05-nesting-classes-and-modules.rb: -------------------------------------------------------------------------------- 1 | # You can declare classes and modules inside of each other. 2 | class A 3 | 4 | class B 5 | end 6 | 7 | module C 8 | module D 9 | class C 10 | def self.deep_in_the_hole 11 | "The further down I go, pulls the strings on my violin bow" 12 | end 13 | end 14 | end 15 | end 16 | 17 | end 18 | 19 | # You can then access them with :: 20 | A # => A 21 | A::B # => A::B 22 | A::C # => A::C 23 | A::C::D # => A::C::D 24 | A::C::D::C # => A::C::D::C 25 | A::C::D::C.deep_in_the_hole # => "The further down I go, pulls the strings on my violin bow" 26 | 27 | 28 | # Note that even though they're named the same, these are different, 29 | # like similarly named files in different directories 30 | A::C == A::C::D::C # => false 31 | -------------------------------------------------------------------------------- /session5/1-notes/06-modules-namespacing.rb: -------------------------------------------------------------------------------- 1 | # A great use for modules is as namespaces: You can do all sorts 2 | # of stuff in a module, and it keeps it contained within that 3 | # module. This prevents conflicts with similarly named things 4 | # in other places. 5 | 6 | # Example: 7 | # Maybe you want to try the same problem several days in a row, 8 | # to see how your approach changes over time. 9 | module Day1Solutions 10 | class MinFinder 11 | def initialize(a, b) 12 | @a = a 13 | @b = b 14 | end 15 | def solve 16 | if @a < @b then @a else @b end 17 | end 18 | end 19 | end 20 | 21 | module Day2Solutions 22 | class MinFinder 23 | def initialize(a, b) 24 | @elements = [a, b] 25 | end 26 | def solve 27 | @elements.min 28 | end 29 | end 30 | end 31 | 32 | day1 = Day1Solutions::MinFinder.new 10, 5 33 | day2 = Day2Solutions::MinFinder.new 10, 5 34 | day1 # => # 35 | day2 # => # 36 | day1.solve # => 5 37 | day2.solve # => 5 38 | 39 | -------------------------------------------------------------------------------- /session5/1-notes/07-extending-main.rb: -------------------------------------------------------------------------------- 1 | # Lets say that we want to escape html output. This prevents someone 2 | # from submitting html to a form and having it mess up our page's 3 | # html when we put it in there gets displayed. Well, there is a method 4 | # to do this in ERB::Util, which we can get from the standard library 5 | require 'erb' 6 | 7 | ERB::Util.h "