SlideShare una empresa de Scribd logo
1 de 32
Descargar para leer sin conexión
Ruby 
Gotchas 
Last edited 2014-10-05 
by Dave Aronson, 
T. Rex of Codosaurus, LLC
Ruby can be surprising! 
Though "engineered to 
maximize programmer 
happiness", with the 
"principle of least surprise", 
Ruby still has gotchas. 
This presentation will 
proceed from newbie trivial 
gotchas, to more advanced 
and confusing gotchas. 
We = 2 
class Fixnum 
def rb; self; end 
end 
We <3 .rb 
=> true 
But = 3 
still = 1 
perfect = 4 
But - still .rb < perfect 
=> true
Don't quote me on this, but . . . . 
x = 3 
puts 'x = #{x}nx' 
x = #{x}nx 
puts "x = #{x}nx" 
x = 3 
x 
String interpolation 
(including special chars 
like n) fails with 'single' 
quotes -- it requires 
"double" quotes. 
(Just like in most 
languages with string 
interpolation.) 
To avoid: use doubles 
whenever practical.
It's twue! It's twue! 
Only two things are false 
(falsey): false, and nil. 
Everything else is true 
(truthy), even 0 (false in C), 
"" (false in JS), [], etc. 
(Trips up people from C, JS, 
etc. where some of these are 
false.) 
true ? "true" : "false" 
=> "true" 
false ? "true" : "false" 
=> "false" 
nil ? "true" : "false" 
=> "false" 
1 ? "true" : "false" 
=> "true" 
0 ? "true" : "false" 
=> "true" 
"false"? "true" : "false" 
=> "true" 
"" ? "true" : "false" 
=> "true" 
[] ? "true" : "false" 
=> "true"
Hang him in effigy 
(String him up, symbolically) 
Symbols != strings. 
Even if same, printed. 
Remember which one to 
use for what (args). 
Ideally, take either: "Be 
liberal in what you accept, 
and conservative in what 
you send." (Postel's Law) 
str = "string" 
sym = :string 
puts str 
string 
puts sym 
string 
str == sym 
=> false
String... or nothing! 
bash> irb-1.9 
str = "string" 
=> "string" 
str[2] 
=> "r" 
# makes sense. 
bash> irb-1.8 
str = "string" 
=> "string" 
str[2] 
=> 114 
# ??? ascii code! 
str[2..2] 
=> "r" 
# that's better! 
str[2,1] 
=> "r" 
# works too....
Constants Aren't (Part 1/2) 
FOO = 5 
=> 5 
FOO = 7 
(irb):3: warning: already 
initialized constant FOO 
=> 7 
FOO 
=> 7 
(Initial uppercase means 
constant, in Ruby.) 
Try to change a constant. 
Ooooh, you get a 
WARNING! BFD.
Constants Aren't (Part 2/2) 
Even freezing doesn't 
work for Fixnums. 
It does work for arrays 
(sort of) and most other 
objects . . . he said 
foreshadowingly. 
FOO 
=> 7 
FOO.freeze 
=> 7 
FOO += 2 
(irb):5: warning: already 
initialized constant FOO 
=> 9 
FOO 
=> 9
Some are more equal than others 
Effectively: 
== is the usual 
(same value) 
.eql? is value and class 
(1 is Fixnum, 1.0 is Float) 
.equal? is same object 
It's actually much hairier; 
see docs on class Object 
1 == 1.0 
=> true 
1.eql? 1.0 
=> false 
a = "foo" 
b = "foo" 
a == b 
=> true 
a.eql? b 
=> true 
a.equal? b 
=> false 
a.equal? a 
=> true
=== != ==! 
Effectively: 
=== is "case equality", as in 
case statements. A better name 
(IMHO) might be ".describes?", 
or overload ".includes?"! 
Again, it's actually much hairier; 
see the docs on class Object. 
Gets people from languages 
where === is identity, or same 
value and class. 
1 === 1 
=> true 
Fixnum === 1 
=> true 
1 === Fixnum 
=> false 
Class === Class 
Object === Object 
Class === Object 
Object === Class 
=> all true 
Fixnum === Fixnum 
=> false 
(1..3) === 2 
=> true 
2 === (1..3) 
=> false
and != && 
&& has higher precedence 
than =, so 
x = true && false 
means 
x = (true && false) 
and has lower precedence, so 
x = true and false 
means 
(x = true) and false 
Ruby Style Guide: Use && / || 
for boolean expressions, [use] 
and / or for control flow. 
x = true && false 
=> false 
x 
=> false 
# OK so far, but: 
x = true and false 
=> false 
x 
=> true 
Return value is false 
but variable is true! 
Why the mismatch?!
or != || 
|| has higher precedence 
than =, so 
x = false || true 
means 
x = (false || true) 
or has lower precedence so 
x = false or true 
means 
(x = false) or true 
Also, && is higher than ||, 
but and and or are equal, so 
they are evaluated left-to-right! 
x = false || true 
=> true 
x 
=> true 
# OK so far, but: 
x = false or true 
=> true 
x 
=> false 
Return value is true 
but variable is false! 
Why the mismatch?!
Don't be so sensitive! (Part 1/4) 
Whitespace-insensitive? 
NOT ALWAYS! 
With multiple args: 
- No parens, no problem. 
- Parens w/o space, OK. 
- Parens and space, NO! 
Parser thinks it's an 
expression, as one arg, 
but (1, 2) is not a valid 
Ruby expression! 
(All work fine w/ 1 arg.) 
def method(arg1, arg2); end 
method 1, 2 
=> nil 
method(1, 2) 
=> nil 
method (1, 2) 
syntax error, unexpected 
',', expecting ')' 
method (1, 2) 
^
Don't be so sensitive! (Part 2/4) 
def method; 42; end 
num = 21 
method/num 
=> 2 
method / num 
=> 2 
method/ num 
=> 2 
method /num 
SyntaxError: 
unterminated regexp 
"method /num" is an 
unended regex or string! 
Ruby thinks you might be 
giving an argument to 
method meth. 
General principle: use 
BALANCED whitespace; 
both sides or neither.
Don't be so sensitive! (Part 3/4) 
"one -1" makes Ruby 
think you might be giving 
an argument (of -1) to 
method one. (Same for 
+1 . . . or even *1!) 
Again: use BALANCED 
whitespace; both sides or 
neither. 
def one 
1 
end 
one - 1 
=> 0 
one-1 
=> 0 
one- 1 
=> 0 
one -1 
ArgumentError: wrong number 
of arguments (1 for 0)
Don't be so sensitive! (Part 4/4) 
dbl = ->(x) { x * 2 } 
=> #<Proc:... (lambda)> 
dbl = ->x{ x * 2 } 
=> #<Proc:... (lambda)> 
dbl = -> x { x * 2 } 
=> #<Proc:... (lambda)> 
two = -> { 2 } 
=> #<Proc:... (lambda)> 
dbl = -> (x) { x * 2 } 
syntax error, unexpected 
tLPAREN_ARG, expecting 
keyword_do_LAMBDA or tLAMBEG 
two = -> () { 2 } 
same syntax error 
"Stabby" lambdas (1.9+) 
Parentheses optional 
Space before/after args 
without parens, OK. 
Space after parens, OK. 
Again, space before 
parens, NO! 
UPDATE: Fixed in 2.0!
'Ang onto yer @! 
class Foo 
attr_reader :value 
def initialize(v) 
value = v 
end 
def set_val(v) 
@value = v 
end 
end 
f = Foo.new(3) 
f.value 
=> nil # not 3?! 
f.set_val 5 
=> 5 
f.value 
=> 5 
Naked value becomes a 
temporary local variable! 
Solution: remember the @! (Or 
"self.".) 
Gets people from Java/C++, 
not so much Python (which 
needs "self." too). 
"You keep on using that variable. I don't 
think it means what you think it means."
Look out, it’s an @@! 
What the fillintheblank? We didn't 
change Parent’s @@value before 
checking it, nor Child’s at all! 
. . . Or did we? 
@@ variables are shared with 
subclasses -- not just that they 
exist, but the variables 
themselves! Declaring Child’s 
@@value changed Parent’s, and 
inc’ing Parent’s changed Child’s. 
IMHO, best just forget them. 
class Parent 
@@value = 6 
def self.value 
@@value 
end 
def self.inc_value 
@@value += 1 
end 
end 
class Child < Parent 
@@value = 42 
end 
Parent.value 
=> 42 # wtf? 
Parent.inc_value 
Child.value 
=> 43 # wtf?!
With init(ialize) or without it 
class Parent 
def initialize 
puts "Parent init" 
end 
end 
class NoInitChild < Parent 
end 
NoInitChild.new 
Parent init 
class NormalChild < Parent 
def initialize 
puts "NormalChild init" 
end 
end 
NormalChild.new 
"NormalChild init" 
class SuperChild < Parent 
def initialize 
puts "SuperChild" 
super 
puts "init" 
end 
end 
SuperChild.new 
SuperChild 
Parent init 
init 
Parent's initialize runs 
automagically only if child 
has none. Else, parent's 
must be called to run.
Superman vs. the Invisible Man 
Child2.new.add 1, 2, 3, 5 
ArgumentError: wrong 
number of arguments (4 
for 2) 
Child2.new.add 1, 2 
=> 3 
Child4.new.add 1, 2, 3, 5 
=> 11 
super with no arg list 
sends what caller got 
super with explicit args 
sends those args 
to send NO args, use 
empty parens: super() 
class Parent 
def add *args 
args.inject :+ 
end 
end 
class Child2 < Parent 
def add arg1, arg2 
super arg1, arg2 
end 
end 
class Child4 < Parent 
def add a1, a2, a3, a4 
super # no args! 
end 
end
When will it end? (Or start?) 
str = "OnenTwonThree" 
str =~ /^Two$/ 
=> 4 
str =~ /ATwoZ/ 
=> nil 
str =~ /AOne/ 
=> 0 
str =~ /ThreeZ/ 
=> 8 
In "standard" regexps: 
^ is start and $ is end... 
of the whole string. 
Ruby’s regexes default to 
multiline, so: 
^ is start and $ is end... 
of any line! 
A is start and Z is end 
of the whole string. (Or z 
to include any newline… 
which is another gotcha!)
[].any? 
=> false 
[1].any? 
=> true 
[:foo, :bar].any? 
=> true 
# ok so far, BUT: 
[nil].any? 
=> false 
[false].any? 
=> false 
[false, nil].any? 
=> false 
getting .any? 
.any? does not mean 
“any elements?”! 
With block: “do any 
make the block true?” 
Without: “are any truthy?” 
Has implicit block: 
{ |element| element }
Variables declared in blocks 
passed to iterators (e.g., 
times or each) are undefined 
at the top of each iteration! 
Iterators call the block 
repeatedly, so vars are out of 
scope again after each call. 
Built-in looping constructs (e. 
g., while or for) are OK. 
(Or declare vars before block.) 
3.times do |loop_num| 
sum ||= 0 
sum += 1 
puts sum 
end 
111 
for loop_num in 1..3 
sum ||= 0 
sum += 1 
puts sum 
end 
123 
(Un)Def Leppard
Freeze (Ar)ray 
arr = ["one", "two", "three"] 
arr.freeze 
arr << "four" 
RuntimeError: can't modify 
frozen Array 
arr[0] = "eno" 
RuntimeError: can't modify 
frozen Array 
arr[0].object_id 
=> 1234567890 
arr[0].reverse! 
arr 
=> ["eno", "two", "three"] 
arr[0].object_id 
=> 1234567890 
Freezing an array (or a 
hash) freezes it, not the 
items it contains. 
Strings can be modified 
in place. This way, you 
can modify a given slot in 
a frozen Array of Strings.
1 is 1 … and ever more shall be so! 
Changing Fixnum to new 
value means new object. 
They can't be modified in 
place! So, can’t modify a 
frozen Array of Fixnums. 
(Fixnums and Integers 
have no bang-methods to 
demo trying with.) 
BTW: a Fixnum's object_id 
is value * 2 + 1. 
arr = [1, 2, 3, 4] 
arr.freeze 
=> [1, 2, 3, 4] 
arr << 5 
RuntimeError: can't modify 
frozen Array 
arr[0] += 2 
RuntimeError: can't modify 
frozen Array 
1.object_id 
=> 3 
3.object_id 
=> 7
(to! || ! to!) == ? 
str = "foo" 
str.upcase 
=> ”FOO” 
str 
=> ”foo” 
str.upcase! 
=> ”FOO” 
str 
=> ”FOO” 
# Now that it’s already FOO: 
str.upcase! 
=> nil # ?! 
str 
=> ”FOO” 
Well-known semi-gotcha: 
bang versions of methods 
are dangerous; usually 
may modify receiver. 
DO NOT RELY ON THEM 
RETURNING SAME 
VALUE AS NON-BANG 
VERSION! 
Many return nil if no 
change needed!
An Array of New Gotchas 
Initial value given as 
object is same object 
for each slot (if modded 
in place, not reassigned 
as with = or +=). 
Initial value given as 
block gets evaluated 
separately for each slot. 
Use this to create new 
vars for each. 
class Person 
attr_accessor :name 
end 
people = Array.new(3, Person.new) 
people[0].name = "Alice" 
people[1].name = "Bob" 
people[0].name 
=> "Bob" 
# should have been "Alice"! 
people = Array.new(3) { Person.new 
} 
people[0].name = "Alice" 
people[1].name = "Bob" 
people[0].name 
=> "Alice"
Making a Hash of it 
Mostly same problem (and 
solution) as Arrays. 
WARNING: creates new 
object on any access to 
empty slot! May create 
excessive number of new 
objects; ruins checking 
“real” contents or count 
(nil-checking, .size, etc.). 
langs = Hash.new [] 
langs[:jane] << "Java" 
langs[:rachel] << "Ruby" 
langs[:jane] 
=> ["Java", "Ruby"] 
langs[:rachel] 
=> ["Java", "Ruby"] 
langs = Hash.new { |h, k| 
h[k] = [] } 
langs[:jane] << "Java" 
langs[:rachel] << "Ruby" 
langs[:jane] 
=> ["Java"] 
langs[:rachel] 
=> ["Ruby"]
Rescue Me, Throw a Line, I'll Try to Catch It! 
/* JAVA: */ 
try { 
throw new MyException("blah"); 
} catch(MyException e) { 
fix_it(); 
} 
# RUBY: 
index = catch(:idx) { 
arr.each_with_index do |v, i| 
throw :idx, i if v == target 
end 
-1 
} 
begin 
raise MyException.new "blah" 
rescue MyException => e 
fix_it 
end 
In Ruby, throw and catch 
are NOT for exceptions! 
They are advanced flow 
control, to exit deep 
nesting. 
Ruby uses raise and 
rescue for exceptions.
I’m Gonna Getcha Getcha Getcha Getcha! 
- Watch out for these gotchas as you code. 
- If Ruby behaves badly, refer to these slides. 
- Available at http://bit.ly/RubyGotchas 
- If your gotcha isn’t listed, tell me; maybe I’ll add it!
The Someday-Maybe List 
Add gotchas: 
- to_s vs. to_str 
- need to coordinate method_missing and responds_to_missing 
- rescue from a StandardError, not an Exception 
- instance_eval with calls in local scope 
- private data isn’t really, and not at all w/ class methods 
- lambda vs. proc vs. block vs. method vs. Bambi vs. Godzilla 
- attribute=(val) always returns the argument, no matter the code 
- Proxies are always truthy, even if the target is not 
- class Foo::Bar, defined outside Module Foo, won’t see inside Foo 
- in debugging, “next” goes into loops but skips over blocks 
- vars introduced in a loop (not block!) are visible outside it (?) 
- private methods are accessible by the instance, not the whole class 
Rails gotchas? 
Screencast series?
Questions/Contact/Etc. 
questions.any? ; gotchas[:more].any? 
Contact information / shameless plug: 
T.Rex-2015 [at] Codosaur [dot] us 
+1-571-308-6622 
www.Codosaur.us (Codosaurus, LLC main site) 
www.linkedin.com/profile/view?id=719998 
Blog.Codosaur.us (code blog) 
www.Dare2XL.com (excellence blog) 
@davearonson 
AVAILABLE FOR CONSULTING!

Más contenido relacionado

La actualidad más candente

Real World Haskell: Lecture 7
Real World Haskell: Lecture 7Real World Haskell: Lecture 7
Real World Haskell: Lecture 7
Bryan O'Sullivan
 
Programming with Java: the Basics
Programming with Java: the BasicsProgramming with Java: the Basics
Programming with Java: the Basics
Jussi Pohjolainen
 

La actualidad más candente (12)

Ruby for Java Developers
Ruby for Java DevelopersRuby for Java Developers
Ruby for Java Developers
 
DEFUN 2008 - Real World Haskell
DEFUN 2008 - Real World HaskellDEFUN 2008 - Real World Haskell
DEFUN 2008 - Real World Haskell
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at Work
 
BayFP: Concurrent and Multicore Haskell
BayFP: Concurrent and Multicore HaskellBayFP: Concurrent and Multicore Haskell
BayFP: Concurrent and Multicore Haskell
 
Protocols with Associated Types, and How They Got That Way
Protocols with Associated Types, and How They Got That WayProtocols with Associated Types, and How They Got That Way
Protocols with Associated Types, and How They Got That Way
 
Idiomatic Javascript (ES5 to ES2015+)
Idiomatic Javascript (ES5 to ES2015+)Idiomatic Javascript (ES5 to ES2015+)
Idiomatic Javascript (ES5 to ES2015+)
 
Java best practices
Java best practicesJava best practices
Java best practices
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
 
Real World Haskell: Lecture 7
Real World Haskell: Lecture 7Real World Haskell: Lecture 7
Real World Haskell: Lecture 7
 
Java Full Throttle
Java Full ThrottleJava Full Throttle
Java Full Throttle
 
Advanced Python, Part 2
Advanced Python, Part 2Advanced Python, Part 2
Advanced Python, Part 2
 
Programming with Java: the Basics
Programming with Java: the BasicsProgramming with Java: the Basics
Programming with Java: the Basics
 

Similar a Ruby Gotchas

Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technology
ppparthpatel123
 
Slides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersSlides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammers
Giovanni924
 
Ruby introduction part1
Ruby introduction part1Ruby introduction part1
Ruby introduction part1
Brady Cheng
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In Perl
Kang-min Liu
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & Stubs
PatchSpace Ltd
 

Similar a Ruby Gotchas (20)

A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced RubyA limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
 
Ruby from zero to hero
Ruby from zero to heroRuby from zero to hero
Ruby from zero to hero
 
Brogramming - Python, Bash for Data Processing, and Git
Brogramming - Python, Bash for Data Processing, and GitBrogramming - Python, Bash for Data Processing, and Git
Brogramming - Python, Bash for Data Processing, and Git
 
ruby1_6up
ruby1_6upruby1_6up
ruby1_6up
 
ruby1_6up
ruby1_6upruby1_6up
ruby1_6up
 
Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technology
 
Ruby Intro {spection}
Ruby Intro {spection}Ruby Intro {spection}
Ruby Intro {spection}
 
Slides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammersSlides chapter3part1 ruby-forjavaprogrammers
Slides chapter3part1 ruby-forjavaprogrammers
 
Ruby introduction part1
Ruby introduction part1Ruby introduction part1
Ruby introduction part1
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
 
Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In Perl
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & Stubs
 
Threequals - Case Equality in Ruby
Threequals - Case Equality in RubyThreequals - Case Equality in Ruby
Threequals - Case Equality in Ruby
 
Ruby Basics
Ruby BasicsRuby Basics
Ruby Basics
 
Ruby_Basic
Ruby_BasicRuby_Basic
Ruby_Basic
 
Short intro to ECMAScript
Short intro to ECMAScriptShort intro to ECMAScript
Short intro to ECMAScript
 
Red Flags in Programming
Red Flags in ProgrammingRed Flags in Programming
Red Flags in Programming
 
Ruby basics
Ruby basicsRuby basics
Ruby basics
 
Introduction to Perl
Introduction to PerlIntroduction to Perl
Introduction to Perl
 

Más de Dave Aronson

Más de Dave Aronson (9)

Kill All Mutants! (Intro to Mutation Testing, from Scenic City Summit 2021)
Kill All Mutants! (Intro to Mutation Testing, from Scenic City Summit 2021)Kill All Mutants! (Intro to Mutation Testing, from Scenic City Summit 2021)
Kill All Mutants! (Intro to Mutation Testing, from Scenic City Summit 2021)
 
Write Better Software With ACRUMEN slides from Scenic City Summit 2021
Write Better Software With ACRUMEN slides from Scenic City Summit 2021Write Better Software With ACRUMEN slides from Scenic City Summit 2021
Write Better Software With ACRUMEN slides from Scenic City Summit 2021
 
Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
Kill All Mutants! (Intro to Mutation Testing), Code Europe (Poland), 2021
 
Kill All Mutants KCDC 2021
Kill All Mutants KCDC 2021Kill All Mutants KCDC 2021
Kill All Mutants KCDC 2021
 
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
"Kill All Mutants! (Intro to Mutation Testing)" Slides from NDC Sydney 2020
 
ACRUMEN Slides for DevConf Poland
ACRUMEN Slides for DevConf PolandACRUMEN Slides for DevConf Poland
ACRUMEN Slides for DevConf Poland
 
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
ACRUMEN Slides for Arlington Ruby (Practice for DevConf)
 
ACRUMEN Slides for RubyNation and CapitalGo, 2018
ACRUMEN Slides for RubyNation and CapitalGo, 2018ACRUMEN Slides for RubyNation and CapitalGo, 2018
ACRUMEN Slides for RubyNation and CapitalGo, 2018
 
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
ACRUMEN: Key Aspects of Software Quality (half-hour talk slides)
 

Último

FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
dollysharma2066
 
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ssuser89054b
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
dharasingh5698
 

Último (20)

Unleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapUnleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leap
 
Thermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - VThermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - V
 
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Mahipalpur Delhi Contact Us 8377877756
 
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
(INDIRA) Call Girl Aurangabad Call Now 8617697112 Aurangabad Escorts 24x7
 
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
 
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...Bhosari ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For ...
Bhosari ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For ...
 
(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7
(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7
(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
The Most Attractive Pune Call Girls Budhwar Peth 8250192130 Will You Miss Thi...
 
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
Online banking management system project.pdf
Online banking management system project.pdfOnline banking management system project.pdf
Online banking management system project.pdf
 
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
(INDIRA) Call Girl Bhosari Call Now 8617697112 Bhosari Escorts 24x7
 
Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01
 
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghly
 
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdfONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
 
Double Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torqueDouble Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torque
 

Ruby Gotchas

  • 1. Ruby Gotchas Last edited 2014-10-05 by Dave Aronson, T. Rex of Codosaurus, LLC
  • 2. Ruby can be surprising! Though "engineered to maximize programmer happiness", with the "principle of least surprise", Ruby still has gotchas. This presentation will proceed from newbie trivial gotchas, to more advanced and confusing gotchas. We = 2 class Fixnum def rb; self; end end We <3 .rb => true But = 3 still = 1 perfect = 4 But - still .rb < perfect => true
  • 3. Don't quote me on this, but . . . . x = 3 puts 'x = #{x}nx' x = #{x}nx puts "x = #{x}nx" x = 3 x String interpolation (including special chars like n) fails with 'single' quotes -- it requires "double" quotes. (Just like in most languages with string interpolation.) To avoid: use doubles whenever practical.
  • 4. It's twue! It's twue! Only two things are false (falsey): false, and nil. Everything else is true (truthy), even 0 (false in C), "" (false in JS), [], etc. (Trips up people from C, JS, etc. where some of these are false.) true ? "true" : "false" => "true" false ? "true" : "false" => "false" nil ? "true" : "false" => "false" 1 ? "true" : "false" => "true" 0 ? "true" : "false" => "true" "false"? "true" : "false" => "true" "" ? "true" : "false" => "true" [] ? "true" : "false" => "true"
  • 5. Hang him in effigy (String him up, symbolically) Symbols != strings. Even if same, printed. Remember which one to use for what (args). Ideally, take either: "Be liberal in what you accept, and conservative in what you send." (Postel's Law) str = "string" sym = :string puts str string puts sym string str == sym => false
  • 6. String... or nothing! bash> irb-1.9 str = "string" => "string" str[2] => "r" # makes sense. bash> irb-1.8 str = "string" => "string" str[2] => 114 # ??? ascii code! str[2..2] => "r" # that's better! str[2,1] => "r" # works too....
  • 7. Constants Aren't (Part 1/2) FOO = 5 => 5 FOO = 7 (irb):3: warning: already initialized constant FOO => 7 FOO => 7 (Initial uppercase means constant, in Ruby.) Try to change a constant. Ooooh, you get a WARNING! BFD.
  • 8. Constants Aren't (Part 2/2) Even freezing doesn't work for Fixnums. It does work for arrays (sort of) and most other objects . . . he said foreshadowingly. FOO => 7 FOO.freeze => 7 FOO += 2 (irb):5: warning: already initialized constant FOO => 9 FOO => 9
  • 9. Some are more equal than others Effectively: == is the usual (same value) .eql? is value and class (1 is Fixnum, 1.0 is Float) .equal? is same object It's actually much hairier; see docs on class Object 1 == 1.0 => true 1.eql? 1.0 => false a = "foo" b = "foo" a == b => true a.eql? b => true a.equal? b => false a.equal? a => true
  • 10. === != ==! Effectively: === is "case equality", as in case statements. A better name (IMHO) might be ".describes?", or overload ".includes?"! Again, it's actually much hairier; see the docs on class Object. Gets people from languages where === is identity, or same value and class. 1 === 1 => true Fixnum === 1 => true 1 === Fixnum => false Class === Class Object === Object Class === Object Object === Class => all true Fixnum === Fixnum => false (1..3) === 2 => true 2 === (1..3) => false
  • 11. and != && && has higher precedence than =, so x = true && false means x = (true && false) and has lower precedence, so x = true and false means (x = true) and false Ruby Style Guide: Use && / || for boolean expressions, [use] and / or for control flow. x = true && false => false x => false # OK so far, but: x = true and false => false x => true Return value is false but variable is true! Why the mismatch?!
  • 12. or != || || has higher precedence than =, so x = false || true means x = (false || true) or has lower precedence so x = false or true means (x = false) or true Also, && is higher than ||, but and and or are equal, so they are evaluated left-to-right! x = false || true => true x => true # OK so far, but: x = false or true => true x => false Return value is true but variable is false! Why the mismatch?!
  • 13. Don't be so sensitive! (Part 1/4) Whitespace-insensitive? NOT ALWAYS! With multiple args: - No parens, no problem. - Parens w/o space, OK. - Parens and space, NO! Parser thinks it's an expression, as one arg, but (1, 2) is not a valid Ruby expression! (All work fine w/ 1 arg.) def method(arg1, arg2); end method 1, 2 => nil method(1, 2) => nil method (1, 2) syntax error, unexpected ',', expecting ')' method (1, 2) ^
  • 14. Don't be so sensitive! (Part 2/4) def method; 42; end num = 21 method/num => 2 method / num => 2 method/ num => 2 method /num SyntaxError: unterminated regexp "method /num" is an unended regex or string! Ruby thinks you might be giving an argument to method meth. General principle: use BALANCED whitespace; both sides or neither.
  • 15. Don't be so sensitive! (Part 3/4) "one -1" makes Ruby think you might be giving an argument (of -1) to method one. (Same for +1 . . . or even *1!) Again: use BALANCED whitespace; both sides or neither. def one 1 end one - 1 => 0 one-1 => 0 one- 1 => 0 one -1 ArgumentError: wrong number of arguments (1 for 0)
  • 16. Don't be so sensitive! (Part 4/4) dbl = ->(x) { x * 2 } => #<Proc:... (lambda)> dbl = ->x{ x * 2 } => #<Proc:... (lambda)> dbl = -> x { x * 2 } => #<Proc:... (lambda)> two = -> { 2 } => #<Proc:... (lambda)> dbl = -> (x) { x * 2 } syntax error, unexpected tLPAREN_ARG, expecting keyword_do_LAMBDA or tLAMBEG two = -> () { 2 } same syntax error "Stabby" lambdas (1.9+) Parentheses optional Space before/after args without parens, OK. Space after parens, OK. Again, space before parens, NO! UPDATE: Fixed in 2.0!
  • 17. 'Ang onto yer @! class Foo attr_reader :value def initialize(v) value = v end def set_val(v) @value = v end end f = Foo.new(3) f.value => nil # not 3?! f.set_val 5 => 5 f.value => 5 Naked value becomes a temporary local variable! Solution: remember the @! (Or "self.".) Gets people from Java/C++, not so much Python (which needs "self." too). "You keep on using that variable. I don't think it means what you think it means."
  • 18. Look out, it’s an @@! What the fillintheblank? We didn't change Parent’s @@value before checking it, nor Child’s at all! . . . Or did we? @@ variables are shared with subclasses -- not just that they exist, but the variables themselves! Declaring Child’s @@value changed Parent’s, and inc’ing Parent’s changed Child’s. IMHO, best just forget them. class Parent @@value = 6 def self.value @@value end def self.inc_value @@value += 1 end end class Child < Parent @@value = 42 end Parent.value => 42 # wtf? Parent.inc_value Child.value => 43 # wtf?!
  • 19. With init(ialize) or without it class Parent def initialize puts "Parent init" end end class NoInitChild < Parent end NoInitChild.new Parent init class NormalChild < Parent def initialize puts "NormalChild init" end end NormalChild.new "NormalChild init" class SuperChild < Parent def initialize puts "SuperChild" super puts "init" end end SuperChild.new SuperChild Parent init init Parent's initialize runs automagically only if child has none. Else, parent's must be called to run.
  • 20. Superman vs. the Invisible Man Child2.new.add 1, 2, 3, 5 ArgumentError: wrong number of arguments (4 for 2) Child2.new.add 1, 2 => 3 Child4.new.add 1, 2, 3, 5 => 11 super with no arg list sends what caller got super with explicit args sends those args to send NO args, use empty parens: super() class Parent def add *args args.inject :+ end end class Child2 < Parent def add arg1, arg2 super arg1, arg2 end end class Child4 < Parent def add a1, a2, a3, a4 super # no args! end end
  • 21. When will it end? (Or start?) str = "OnenTwonThree" str =~ /^Two$/ => 4 str =~ /ATwoZ/ => nil str =~ /AOne/ => 0 str =~ /ThreeZ/ => 8 In "standard" regexps: ^ is start and $ is end... of the whole string. Ruby’s regexes default to multiline, so: ^ is start and $ is end... of any line! A is start and Z is end of the whole string. (Or z to include any newline… which is another gotcha!)
  • 22. [].any? => false [1].any? => true [:foo, :bar].any? => true # ok so far, BUT: [nil].any? => false [false].any? => false [false, nil].any? => false getting .any? .any? does not mean “any elements?”! With block: “do any make the block true?” Without: “are any truthy?” Has implicit block: { |element| element }
  • 23. Variables declared in blocks passed to iterators (e.g., times or each) are undefined at the top of each iteration! Iterators call the block repeatedly, so vars are out of scope again after each call. Built-in looping constructs (e. g., while or for) are OK. (Or declare vars before block.) 3.times do |loop_num| sum ||= 0 sum += 1 puts sum end 111 for loop_num in 1..3 sum ||= 0 sum += 1 puts sum end 123 (Un)Def Leppard
  • 24. Freeze (Ar)ray arr = ["one", "two", "three"] arr.freeze arr << "four" RuntimeError: can't modify frozen Array arr[0] = "eno" RuntimeError: can't modify frozen Array arr[0].object_id => 1234567890 arr[0].reverse! arr => ["eno", "two", "three"] arr[0].object_id => 1234567890 Freezing an array (or a hash) freezes it, not the items it contains. Strings can be modified in place. This way, you can modify a given slot in a frozen Array of Strings.
  • 25. 1 is 1 … and ever more shall be so! Changing Fixnum to new value means new object. They can't be modified in place! So, can’t modify a frozen Array of Fixnums. (Fixnums and Integers have no bang-methods to demo trying with.) BTW: a Fixnum's object_id is value * 2 + 1. arr = [1, 2, 3, 4] arr.freeze => [1, 2, 3, 4] arr << 5 RuntimeError: can't modify frozen Array arr[0] += 2 RuntimeError: can't modify frozen Array 1.object_id => 3 3.object_id => 7
  • 26. (to! || ! to!) == ? str = "foo" str.upcase => ”FOO” str => ”foo” str.upcase! => ”FOO” str => ”FOO” # Now that it’s already FOO: str.upcase! => nil # ?! str => ”FOO” Well-known semi-gotcha: bang versions of methods are dangerous; usually may modify receiver. DO NOT RELY ON THEM RETURNING SAME VALUE AS NON-BANG VERSION! Many return nil if no change needed!
  • 27. An Array of New Gotchas Initial value given as object is same object for each slot (if modded in place, not reassigned as with = or +=). Initial value given as block gets evaluated separately for each slot. Use this to create new vars for each. class Person attr_accessor :name end people = Array.new(3, Person.new) people[0].name = "Alice" people[1].name = "Bob" people[0].name => "Bob" # should have been "Alice"! people = Array.new(3) { Person.new } people[0].name = "Alice" people[1].name = "Bob" people[0].name => "Alice"
  • 28. Making a Hash of it Mostly same problem (and solution) as Arrays. WARNING: creates new object on any access to empty slot! May create excessive number of new objects; ruins checking “real” contents or count (nil-checking, .size, etc.). langs = Hash.new [] langs[:jane] << "Java" langs[:rachel] << "Ruby" langs[:jane] => ["Java", "Ruby"] langs[:rachel] => ["Java", "Ruby"] langs = Hash.new { |h, k| h[k] = [] } langs[:jane] << "Java" langs[:rachel] << "Ruby" langs[:jane] => ["Java"] langs[:rachel] => ["Ruby"]
  • 29. Rescue Me, Throw a Line, I'll Try to Catch It! /* JAVA: */ try { throw new MyException("blah"); } catch(MyException e) { fix_it(); } # RUBY: index = catch(:idx) { arr.each_with_index do |v, i| throw :idx, i if v == target end -1 } begin raise MyException.new "blah" rescue MyException => e fix_it end In Ruby, throw and catch are NOT for exceptions! They are advanced flow control, to exit deep nesting. Ruby uses raise and rescue for exceptions.
  • 30. I’m Gonna Getcha Getcha Getcha Getcha! - Watch out for these gotchas as you code. - If Ruby behaves badly, refer to these slides. - Available at http://bit.ly/RubyGotchas - If your gotcha isn’t listed, tell me; maybe I’ll add it!
  • 31. The Someday-Maybe List Add gotchas: - to_s vs. to_str - need to coordinate method_missing and responds_to_missing - rescue from a StandardError, not an Exception - instance_eval with calls in local scope - private data isn’t really, and not at all w/ class methods - lambda vs. proc vs. block vs. method vs. Bambi vs. Godzilla - attribute=(val) always returns the argument, no matter the code - Proxies are always truthy, even if the target is not - class Foo::Bar, defined outside Module Foo, won’t see inside Foo - in debugging, “next” goes into loops but skips over blocks - vars introduced in a loop (not block!) are visible outside it (?) - private methods are accessible by the instance, not the whole class Rails gotchas? Screencast series?
  • 32. Questions/Contact/Etc. questions.any? ; gotchas[:more].any? Contact information / shameless plug: T.Rex-2015 [at] Codosaur [dot] us +1-571-308-6622 www.Codosaur.us (Codosaurus, LLC main site) www.linkedin.com/profile/view?id=719998 Blog.Codosaur.us (code blog) www.Dare2XL.com (excellence blog) @davearonson AVAILABLE FOR CONSULTING!