Launch School 100 and 101
Kernel.gets().chomp()
#gets returns the standard (user) input as a string, and #chomp removes the newline from end of the string.
Peer scopes do not conflict: Peer blocks cannot reference variables initialized in other blocks.
2.times do a = 'hi' puts a #=> "hihi" end loop do puts a #=> NameError: undefined local variable or method `a' for main:Object break end puts a # => NameError: undefined local variable or method `a' for main:Object
An object cannot be assigned to another object
5 = 4 SyntaxError: (irb):1: syntax error, unexpected '=', expecting end-of-input
If both variables point to the same object, and the object is mutated, both variables will point to the same mutated object
>> greeting.upcase! => "HELLO" >> whazzup => "HELLO" >> greeting.object_id => 70101471431160 >> whazzup.object_id => 70101471431160
pass by reference of the value
A combination of behaviours from both "pass by reference" as well as "pass by value", such that destructive method mutates an object; non-destructive, not.
Hash
A dictionary-like collection of unique keys and their values. Also called an associative array. Allows you to use any object type.
collection
A grouping of some variable number of data items (possibly zero) that have some shared significance to the problem being solved and need to be operated upon together in some controlled fashion.
Class
A library of methods that can be instantiated, hold its state, keep track of instance variables, be duplicated
Module
A library of methods that can never be instantiated.
method
A procedure associated with an object class.
variable
A reference to an object in memory. Multiple variables can reference the same object.
lexical scope
A variable may be called only from within the block of code in which it is defined.
object
A variable, a data structure, or a function, and as such, is a location in memory having a value and possibly referenced by an identifier.
local variable
Accessible only within the method.
Kernel.puts() == puts
All code not in a separate class is an instance of Object; the Kernel module is automatically loaded by Object
mutable object
An object that can be modified without creating a new object.
immutable object
An object that cannot be modified; at best, a new object can be created and a variable bound thereto by assignment.
Array
An ordered, integer-indexed collections of any object
code smell
Any symptom in the source code of a program that possibly indicates a deeper problem
String.concat
Appends the given object to str. If the object is an Integer, it is considered as a codepoint, and is converted to a character before concatenation. Concat can take multiple arguments. All the arguments are concatenated in order. Destructive.
operator = 1
Assignment of the integer '1' to the variable 'operator'. Will always return true.
assignment
Binding an object to a variable by means of '='.
variable types
CONSTANT, $global_variable, @@class_variable, @instance_variable, local_variable
method invocation
Calling a method, either defined by the Ruby Cope API or Standard Library or defined by means of 'def'
Hash#each
Calls block once for each key in hsh, passing the key-value pair as parameters. If no block is given, an enumerator is returned instead.
Array#each
Calls the given block once for each element in self, passing that element as a parameter. Returns the original array itself. If no block is given, an Enumerator is returned.
Array#map
Creates a new array containing the values returned by the block. If no block is given, an Enumerator is returned instead.
Hash#select
Creates a new hash containing entries for which the Hash block returns true. If no block is given, an enumerator is returned instead.
CONSTANT_VARIABLE
Declared in UPPERCASE. Used for storing data that never needs to change. If changed, Ruby will throw a warning. Cannot be declared by a #method a definition. Available throughout the application's scope.
$global_variable
Declared with $. Available throughout the entire app, overriding all scope boundaries.
@instance_variable
Declared with @. Available throughout the current instance of the parent class. Can cross some scope bounderies.
@@class_variable
Declared with @@. Accessible by instances of the class, as well as the class itself. Used to declare a variable related to the class, but each instance uses the same value for said variable. Can be altered by using a Class or instance_method definition.
a variable's scope in Ruby
Defined by a 'block'
variable's scope
Determines where in a program a variable is available for use
saved_number ||= num
EITHER saved_number OR saved_number = num
if operator == '1'
Equality comparison between the variable 'operator' and the string '1'. Will return either 'true' or 'false'.
#puts
Equivalent to $stdout.puts(obj, ...)
Array#select
Evaluates the return value of the block, and returns a new array containing all elements of ary for which the given ary block returns a true value. If no block is given, an Enumerator is returned instead.
Axiom of truthiness in Ruby
Everything is truthy except 'nil' and 'false'
A CONSTANT in the outer scope is accessible from within a block
FAVORITE_COLOR = 'taupe' 1.times do puts "I love #{FAVORITE_COLOR}!" # => I love taupe! end
key distingushing factor for considering whether {} or 'do/end' is a block
If the {} or 'do/end' immediately follows a method invocation
Fixnum is an immutable object
If you set x = 7 You can't modify that 7 to be anything different. You can change the variable, x, to be something else, but that seven will stay the same
method definition
In Ruby, creating a method using the 'def' keyword
Enumerator#each
Iterates over the block according to how this Enumerator was constructed. If no block and no arguments are given, returns self.
trapping an error
Let's trace the code backwards... In this case, the make method returns the correct value but the model method does not. Based on these observations, we know that the bug in this code originates from the model method.
#extend Module
Makes all the Module's methods class methods (as each one prepended with #self)
#include Module
Makes all the Module's methods instance methods
Literals
Numbers, Strings, Arrays, Hashes, etc
if user_input #=> true if user_input == true #=> true
Owing to the axiom of truthiness in Ruby, an expression that is not 'false' automatically returns 'true'.
Array#inspect
Prints the array as [el, el] rather than each el to a new line
^\d+$
Regex: "start of line, any digit, one or more, end of line"
^\d*\.?\d*$
Regex: "start of line, any digit, zero or more, full stop, zero or one, any digit, zero or more, end of line
#gets
Returns (and assigns to $_) the next line from the list of files in ARGV (or $*), or from standard input if no files are present on the command line. Returns nil at end of file.
#chomp
Returns a new String with the given record separator removed from the end of str (if present). If $/ has not been changed from the default Ruby record separator, then chomp also removes carriage return characters (that is it will remove \n, \r, and \r\n). If $/ is an empty string, it will remove all trailing newlines from the string.
Enumerable#map
Returns a new array with the results of running block once for every element in enum. If no block is given, an enumerator is returned instead.
String#to_f
Returns the result of interpreting leading characters in str as a floating point number. Extraneous characters past the end of a valid number are ignored. If there is not a valid number at the start of str, 0.0 is returned. This method never raises an exception.
String#to_i
Returns the result of interpreting leading characters in str as an integer base base (between 2 and 36). Extraneous characters past the end of a valid number are ignored. If there is not a valid number at the start of str, 0 is returned. This method never raises an exception when base is valid.
def append(s) s << '*' end t = 'abc' append(t) #=> "prints abc*" t #=> "abc*"
The String object 'abc' is mutable. You can reasonably say that 't' is modified by #append since t is passed by reference to #append where it is bound to variable 's'. When 's' is modified by append, it modifies the same object referenced by 't', so upon return from the method, 't' still refers to the original (albeit modified) String object.
mutability
The attribute of an object being changeable.
def increment(a) a = a + 1 end b = 3 b.object_id #=> 7 increment(b).object_id #=> 9 b.object_id #=> 7
The numeric object 3 is immutable. You can reasonably say that b is not modified by #increment since b is passed by value to #increment where it is bound to variable 'a'. Even though 'a' is set to 4 inside the method, and returned to the caller, the original object referenced by 'b' is untouched.
Golden rule of assignment in Ruby
The object originally referenced by the target variable is never modified.
Local variables that are not initialized inside a method definition must be passed in as parameters.
The only variables a method definition has access to must be passed into the method definition.
scope
The range within the code that the variable may be called
A CONSTANT in the outer scope is accessible from within a method definition
USERNAME = 'Batman' def authenticate puts "Logging in #{USERNAME}" end authenticate # => Logging in Batman
CamelCase
Use when naming Classes
UPPERCASE
Use when naming a CONSTANT
snake_case
Use when naming a variable, method, etc, except a RubyClass or CONSTANT
variable shadowing
When the variable inside the inner scope over-rides the same variable in the outer scope; using the same variable name inside and outside a given scope
definition of a variable's scope
Where the variable is initialized or created
#map block has access to 'a' but cannot mutate it; #map can use the value of 'a' to transform the array.
a = "hello" #=> "hello" [1,2,3].map { |n| a } #=> ["hello", "hello", "hello"] a #=> "hello" a.object_id #=> 47288571430860 [1,2,3].map { |n| a.upcase }[1] #=> "HELLO" [1,2,3].map { |n| a.upcase }[1].object_id #=> 47288571253340
A mutable object retains its object_id.
a = %w(a b c) a.object_id #=> 47146666517420 a[1] = '_' #=> ["a", "_", "c"] a #=> ["a", "_", "c"] a.object_id #=> 47146666517420
A method definition has no access to local variables in another scope
a = 'hi' def some_method puts a end # invoke the method some_method # => # => NameError: undefined local variable or method `a' for main:Object
an outer scope variable is both accessible and mutable from the inner scope
a = 1 loop do puts a a = a + 1 break end puts a #=> 2
Nested blocks follow the same rules of inner and outer scoped variables
a = 1 #=> first level variable loop do #=> second level b = 2 loop do #=> third level c = 3 puts a # => 1 puts b # => 2 puts c # => 3 break end puts a # => 1 puts b # => 2 puts c # => NameError break end puts a # => 1 puts b # => NameError puts c
block
a piece of code following a method invocation, usually delimited by either {} or do/end
'if' expressions can return a value
answer = if true 'yes' else 'no' end Kernel.puts(answer) # => yes
'each do/end' creates a new inner, i.e. is a block
arr = [1, 2, 3] arr.each do a = 5 # a is initialized end a #=> undefined local variable or method 'b' for main:Object
'for... do/end' does not create a new inner scope
arr = [1, 2, 3] for i in arr do a = 5 # a is initialized end a #=> 5
reassignment to an Array is not destructive
def add_name(arr, name) arr = arr + [name] end names = ['bob', 'kim'] add_name(names, 'jim') => ["bob", "kim", "jim"] irb(main):006:0> puts names.inspect ["bob", "kim"] => nil irb(main):007:0> puts names bob kim => nil irb(main):008:0> names => ["bob", "kim"] irb(main):009:0>
pass by reference example
def append(s) s << '*' end t = 'abc' append(t) #=> "prints abc*" t #=> "abc*"
block not executed
def greetings puts "Goodbye" end word = "Hello" greetings do puts word end # Outputs 'Goodbye'
block executed with #yield
def greetings yield puts "Goodbye" end word = "Hello" greetings do puts word end # Outputs 'Hello' # Outputs 'Goodbye'
parameter 'str' not used
def greetings(str) puts "Goodbye" end word = "Hello" greetings(word) # Outputs 'Goodbye'
pass by value example
def increment(a) a = a + 1 end b = 3 b.object_id #=> 7 increment(b).object_id #=> 9 b.object_id #=> 7
Rules of scope for a method invocation with a block remain in full effect inside a method definition
def some_method a = 1 5.times do puts a b = 2 end puts a puts b end some_method # => NameError: undefined local variable or method `b' for main:Object
'loop do ... end' does not take a parameter
for |param| in a
A different object can be assigned to a variable. If the first object is assigned to another variable, its assignment remains unchanged.
greeting #=> "Hello" greeting.object_id == whazzup.object_id #=> true greeting = "Dude" #=> "Dude" greeting.object_id == whazzup.object_id #=> false
Both variables point to the same object
greeting = "Hello" #=> "Hello" whazzup = greeting #=> "Hello" greeting.object_id == whazzup.object_id #=> true
Control Expressions
if, unless, while, until, for, break, next, redo
A CONSTANT in the inner scope is accessible from the outside scope
loop do MY_TEAM = "Phoenix Suns" break end puts MY_TEAM # => Phoenix Suns
an inner scope variable is neither accessible nor mutable from the outer scope
loop do puts a a = a + 1 break end #=> NameError: undefined local variable or method `a' for main:Object
block definition in Ruby
method invocation followed by {} or 'do...end'
The variable 'n' in the 'times' block prevents changes to the variable 'n' in the outer scope.
n = 10 #=> 10 1.times do |n| n = 11 end => 1 n => 10
The variable 'n' in the 'each' block shadows the variable 'n' in the outer scope.
n = 10 #=> 10 [1,2,3].each do |n| p n end 1 2 3 #=> [1, 2, 3]
A different immutable object can be assigned to a variable, but the object itself does not change.
n = 3 n.object_id #=> 7 n = 2 * number #=> 6 n.object_id #=> 13
some_variable = 3 if some_variable = 2 puts "some_variable is 2" else puts "some_variable is not 2" end #=> "some variable is 2"
This bug is due to the assignment of an integer to the variable (which always returns true) rather than a comparison of the variable to the integer.
pass by value strategy
To make a copy of method arguments and pass those copies to the method — the original objects cannot be modified.
pass by reference strategy
To refer directly to the original method argument object, provided that said object is mutable.