# Ruby Fundamentals - JS ==> Ruby ## My Focus as a Lecturer Over the next few weeks, my goal is to help you all to practice your technical communication skills. One of the most challenging parts of learning to code is learning to adjust the way you speak to an unfamiliar degree of accuracy and precision. Your ability to think programatically will improve as you practice using terminology to accurately describe what you're doing as you code. I want to help you all add good habits and skills to your toolbox so you are more effective–and happier–problem solvers. ## Questions to Carry around with you as you code - What am I trying to do? - What's happening instead of that? - How can I explain what's happening now? - How can I test my explanation? - Was my explanation correct/complete? When you watch professional athletes, you will see many variations of a pre-shot routine. - A basketball player before shooting a free-throw - A runner before the start of a race - A golfer preparing to tee off - A batter preparing for the pitcher's windup. Whatever the example, the purpose is to develop a set of behaviors that prepare the mind for the task at hand. Approaching programming in the same way can make it a much more enjoyable experience. As you work with me over the next couple of weeks, one of my goals is to share ideas that you can integrate into your routine to develop solid mind patterns that set you up for success. In programming, I see this as a series of questions that you repetitively ask yourself in different situations that move your mind in the directions it needs to go to solve a given type of problem. ## Topics ### Variables In JS we declare variables by using what syntax?: ```js let name = "Dakota" const otherName = "Terry" ``` Pick `let` for something that could change whereas a const is absolute and won't change. In Ruby, declaring variables ```rb name = "Dakota" ``` ```js let name; name = "Dakota" ``` ### Different data types: Array vs Hash - Object (keys and values in pairs) => (Hash in Ruby is the key-value pair data structure) - String - Hash - Boolean - Array - Number (JS) - Integer - Float - Date - DateTime - Symbol (:starts_with_a_colon) #### JS - undefined - null - NaN #### RB - nil | Concept | JS | Ruby | |---|---|---| | Checking Type | `typeof object` | `object.class` | | constructor | uppercase named function that has methods defined on its prototype | class has methods inside of it that all instances can respond to | | Array vs Hash/Obj | pick an array when you want to iterate | in Ruby you can iterate with the same methods over both hashes and arrays | An array of hashes would be a popular data structure. #### Booleans Check for truthiness/falsiness via `!!` If you do `!!object` and get `true` it's truthy, if it's falsey you get `false`. | Concept | JS | Ruby | |---|---|---| | truthiness | everything except for the below | everything but nil and false | | falsiness | null, undefined, false, 0, "", NaN | nil, false | | | | | ### Functions ```js function myFunc() { return "Hi there" } ``` ```rb def my_method "Hi there" end ``` What are the differences here? - ruby version is shorter - use def to define - no more curly braces - end is where our } would have gone - no need to explicitly return - if you don't explicitly return a ruby method will return whatever the last expression inside of the method returns. [] => sqaure brackets {} => curly braces < => angle brackets If we need to iterate over an array, for example, we would call a method and pass in a callback function as an argument: | Concept | JS | Ruby | |---|---|---| | Basic | forEach (returns `undefined`) | each (returns the array you called it on) | | Transforming | map (returns a new array containing return values from your callback function) | map (alias called collect) returns a new array containing return values of the block that you pass to `.map`| | Finding a single match | find returns the element that returns a truthy value for the callback function | find (alias called detect) same but for the block you pass. | | Finding all matches | filter | filter (select is an alias) | ```js function getEpisodes() { return friends["_embedded"]["episodes"] } function getEpisodesInSeason(number) { return getEpisodes().filter(episode => episode.season === number) } ``` The equivalent in ruby: ```rb def get_episodes friends["_embedded"]["episodes"] end def get_episodes_in_season(number) get_episodes.filter do |episode| episode.season == number end end ``` ### Scoping #### Require vs Import When we require one file from another, ruby will run the entire file at that point. This is actually more like a script tag inside of an HTML document in JS than it is like an import. The main reason being–in JS–you need to explicitly `export` from a file, whereas when you `require` (or `require_relative`) the entire file is loaded. Generally, you'll use `require` to load code from other gems/dependencies and you'll use `require_relative` (or later `require_all`) to load your own code. ### Debugging IRB (short for interative Ruby) is the `node` equivalent. You can drop in by typing `irb` in your terminal. You can also do: ```rb require 'irb' IRB.start ``` Which we have in a file called `bin/console`. We'll be using this file to load up all of our code and start up IRB so we can interact with ruby code we've written in our project. If you want to get feedback while you're going without stopping the code from running, the `console.log` equivalent is `puts`. Finally the `pry` gem is your `debugger` equivalent. To use it, you'll need to install the gem and then `require 'pry'` inside of your code. After that, you can drop a `binding.pry` wherever you want to get into that interactive debugging mode. ### Gems installation and use ```bash bundle add pry ``` This will install the Pry gem in your project and also add the latest version to your project's Gemfile. ## Skills ### debug with irb, pry and puts ### become familiar with ruby docs ### write and execute a ruby method ### access nested data from Hashes and Arrays with variable utilization ### read rspec tests ```rb RSpec.describe "favorite_meals" do it "returns a hash containing the team's favorite meals" do expect(favorite_meals).to be_a(Hash) expect(favorite_meals.keys).to eq([:breakfast, :lunch, :dinner]) expect(favorite_meals[:breakfast]).to be_a(Array) expect(favorite_meals[:breakfast].first).to be_a(String) expect(favorite_meals[:lunch]).to be_a(Array) expect(favorite_meals[:lunch].first).to be_a(String) expect(favorite_meals[:dinner]).to be_a(Array) expect(favorite_meals[:dinner].first).to be_a(String) end end ``` Key pieces to note: | Method | Arguments | Purpose | |---|---|---| | describe | A string and a block | Create a group of tests whose output will display together in your terminal under a heading matching the string passed as the first argument. Describe will establish expectations that apply to a particular piece of code. In this case, the `favorite_meals` method. The block passed as the second argument will contain the expectations created using the `it` method. | | it | A string and a block | Create a related group of expectations that will run within the describe block we invoke `it` within. If the expectations are fulfilled, the string will appear in green below the string heading passed to the enclosing `describe` block. | | expect | An object we'd like to establish expectations for | Apply [matchers](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers) to the tested object to verify that it meets our expectations. | ### implement each, map, find, select | Concept | JS | Ruby | |---|---|---| | Basic | forEach (returns undefined) | each (returns original array) | | transforming | map | map (alias called collect) | | searching for one | find | find (alias called detect) | | searching for multiple | filter | filter (select is an alias) | | reducing to a single value | reduce | reduce (alias called inject) |