Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
HELLO!!!
ZOMG HAPPY
 SATURDAY!
PEW PEW PEW~!!!
Aaron Patterson
@tenderlove
google 'tenderlove'
      Might be NSFW
AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies.
Enterprise
       Developer
http://github.com/tenderlove/enterprise
ruby core
committer
rails core
committer
rails
committer
My Failures
rails core
committer
rails
committer
Presenting Last
I like Ryan Davis
My Slides Suck
    (Sorry Shane)
minitest
RFC 2119
 common.rspec
No Parens on
Method Definitions
def foo bar, baz
  ...
end
Ruby + JavaScript
Ruby + C
My Failures
  (as a presenter)
Fun
Practical
I am a nerd
I like boring things
2 Presentations
Practical
Fun!
The Fun
Your Guide to
Presentation
 Popularity!
Your Guide to
Presentation
  Notoriety!
•Provocative Title
• Risqué Photos

•Ruby Code?
Provocative Title:
Use Ruby 1.9 like an
     Engineer
Use Ruby 1.9 like a
 SEXY Engineer
Risqué Photos
America's Next Top
      Model
America's Next Top
    Engineer
Confident
Elegant
Sultry
Sexy
Thoughtful
Fierce
Playful
Powerful
Provocative
Ruby Code?
protected

    def method_missing(method, *args, &block)
      if Array.method_defined?(method)
        to_a.send(method, ...
TL;DR
The Practical
Hidden Gems of
   Ruby 1.9
Ruby 1.9 PSA
minitest
require 'minitest/autorun'

class FooTest < MiniTest::Unit::TestCase
  WIN32 = true

 def test_foo
   assert_equal 'foo', ...
require 'minitest/autorun'
Test::Unit::TestCase
           =>
MiniTest::Unit::TestCase
class FooTest < MiniTest::Unit::TestCase
end
assert_not_*
     =>
  refute_*
def test_refutation
  refute_equal 'foo', 'bar'
end
skip
class FooTest < MiniTest::Unit::TestCase
  WIN32 = true

  def test_skip
    skip if WIN32
    assert_equal 'fun!', 'fun!'...
Loaded suite footest
Started
.S.
Finished in 0.000682 seconds.

  1) Skipped:
test_skip(FooTest) [footest.rb:15]:
Skipped,...
randomization
class FailTest < MiniTest::Unit::TestCase
  @@foos = %w{ hello }

 def test_equality
   assert_equal @@foos, %w{ hello }
 ...
Test run options: --seed 31149

Loaded suite failtest
Started
..
Finished in 0.000604 seconds.

2 tests, 2 assertions, 0 f...
Test run options: --seed 29650

Loaded suite failtest
Started
.F
Finished in 0.000637 seconds.

  1) Failure:
test_equalit...
Test run options: --seed 29650

Loaded suite failtest
Started
.F
Finished in 0.000637 seconds.

  1) Failure:
test_equalit...
--seed 29650
-v
ruby failtest.rb --seed 29650 -v
Test run options: --seed 29650 --verbose

Loaded suite failtest
Started
FailTest#test_append: 0.00 s: .
FailTest#test_equa...
Test run options: --seed 29650 --verbose

Loaded suite failtest
Started
FailTest#test_append: 0.00 s: .
FailTest#test_equa...
Test Performance
class FooTest < MiniTest::Unit::TestCase
  def test_foo
    assert_equal 'foo', 'foo'
  end

 def test_refutation
   refut...
class FooTest < MiniTest::Unit::TestCase
  def test_foo
    assert_equal 'foo', 'foo'
  end

 def test_refutation
   refut...
Test run options: --seed 33095 --verbose

Loaded suite footest
Started
FooTest#test_slow: 10.00 s: .
FooTest#test_refutati...
Test run options: --seed 33095 --verbose

Loaded suite footest
Started
FooTest#test_slow: 10.00 s: .
FooTest#test_refutati...
With Rake:
rake test TESTSOPTS='-v'
rspec
describe 'Awesome' do
  describe 'Class' do
    it 'discovers something AMAZING' do
      (10 + 10).must_equal 20
    end
...
rspec
minitest/spec
require 'minitest/spec'
require 'minitest/autorun'
require 'minitest/spec'
require 'minitest/autorun'

describe 'Awesome' do
  describe 'Class' do
    it 'discovers somethin...
ObjectSpace
ObjectSpace.each_object do |obj|
  p obj
end
require 'objspace'

• count_objects_size
• memsize_of
• count_nodes
• count_tdata_objects
count_object_size
require 'objspace'

hash = {}
ObjectSpace.count_objects_size(hash)
p hash # =>
{:T_CLASS=>291520, :T_MOD...
count_object_size
require 'objspace'

hash = {}
ObjectSpace.count_objects_size(hash)
p hash # =>
{:T_CLASS=>291520, :T_MOD...
memsize_of


require 'objspace'
require 'fiddle'

cl = Fiddle::Closure.new(0, [1])
p ObjectSpace.memsize_of(cl) # => 232
memsize_of


require 'objspace'
require 'fiddle'

cl = Fiddle::Closure.new(0, [1])
p ObjectSpace.memsize_of(cl) # => 232
Implementation
struct rb_data_type_struct

struct rb_data_type_struct {
    const char *wrap_struct_name;
    struct {
   void (*dmark)(v...
struct rb_data_type_struct

struct rb_data_type_struct {
    const char *wrap_struct_name;
    struct {
   void (*dmark)(v...
static size_t my_memsize(const void *p) {
    return 10;
}

const rb_data_type_t my_data_type = {
    "my_extension",
    ...
count_nodes


require 'objspace'

p ObjectSpace.count_nodes #=>
{:NODE_SCOPE=>50, :NODE_BLOCK=>168,
:NODE_IF=>27, :NODE_IT...
count_nodes


require 'objspace'

p ObjectSpace.count_nodes #=>
{:NODE_SCOPE=>50, :NODE_BLOCK=>168,
:NODE_IF=>27, :NODE_IT...
count_nodes

require 'objspace'

10.times do
  p ObjectSpace.count_nodes[:NODE_IF]
  eval 'if true; end'
end
$ ruby objectspace.rb
27
28
29
30
31
32
33
34
35
36
$
count_tdata_objects

require 'objspace'

p ObjectSpace.count_tdata_objects # =>
{RubyVM::InstructionSequence=>64,
false=>1...
count_tdata_objects

require 'objspace'

p ObjectSpace.count_tdata_objects # =>
{RubyVM::InstructionSequence=>64,
false=>1...
count_tdata_objects


require 'objspace'
require 'fiddle'

10.times do
  Fiddle::Closure.new(0, [1])
  p ObjectSpace.count...
$ ruby objectspace.rb
1
2
3
4
5
6
7
8
9
10
$
Fiddle
libffi wrapper
fiddle + dl
Fiddle


• Function calls
• Closure allocation
DL


• dlopen() wrapper
• memory management
Calling Functions
• Open dynamic library
• Locate function pointer
• Wrap function pointer
• Call function
Wrapping "sin"
require 'fiddle'

libm = DL.dlopen('libm.dylib')

function = Fiddle::Function.new(
  libm['sin'],
  [Fiddle...
Wrapping "sin"
require 'fiddle'

libm = DL.dlopen('libm.dylib')

function = Fiddle::Function.new(
  libm['sin'],
  [Fiddle...
Wrapping "sin"
require 'fiddle'

libm = DL.dlopen('libm.dylib')

function = Fiddle::Function.new(
  libm['sin'],
  [Fiddle...
Wrapping "sin"
require 'fiddle'

libm = DL.dlopen('libm.dylib')

function = Fiddle::Function.new(
  libm['sin'],
  [Fiddle...
Wrapping "sin"
require 'fiddle'

libm = DL.dlopen('libm.dylib')

function = Fiddle::Function.new(
  libm['sin'],
  [Fiddle...
Creating Closures
double (func *)(double)
require 'fiddle'

class MySin < Fiddle::Closure
  def call number
    Math.sin(number)
  end
end

function = MySin.new(
  ...
require 'fiddle'

class MySin < Fiddle::Closure
  def call(number)
    Math.sin(number)
  end
end

function = MySin.new(
 ...
require 'fiddle'

class MySin < Fiddle::Closure
  def call(number)
    Math.sin(number)
  end
end

function = MySin.new(
 ...
require 'fiddle'

class MySin < Fiddle::Closure
  def call(number)
    Math.sin(number)
  end
end

function = MySin.new(
 ...
Using our Closure
class MySin < Fiddle::Closure
  def call number
    Math.sin(number)
  end
end

function = MySin.new(
  Fiddle::TYPE_DOUBL...
class MySin < Fiddle::Closure
  def call number
    Math.sin(number)
  end
end

function = MySin.new(
  Fiddle::TYPE_DOUBL...
Fiddle Masquerade
ruby-ffi code
module Tidy
  extend FFI::Library

 ffi_lib "libtidy.dylib"

  attach_function   :tidyFileExists, [:string], ...
In terms of Fiddle
module FFI
  module Library
    TYPE_MAP = {
      :string => DL::TYPE_VOIDP,
      :pointer => DL::TYPE_VOIDP,
    }

   ...
ruby-ffi code
module Tidy
  extend FFI::Library

 ffi_lib "libtidy.dylib"

  attach_function   :tidyFileExists, [:string], ...
Fiddle code
module Tidy
  extend FFI::Library

 ffi_lib "libtidy.dylib"

  attach_function   :tidyFileExists, [:string], :...
Psych
YAML Parser

• 1.9.2 and up
• Wraps libyaml
• Replaces Syck
• Opt-in
Opt-in Process
$ irb
irb(main):001:0>   require 'yaml'
=> true
irb(main):002:0>   YAML::ENGINE.syck?
=> true
irb(main):003...
require 'psych'
Parsing & Dumping

require 'psych'

Psych.load('--- hello world!') # => 'hello world!'
Psych.dump('hello world!')     # =>...
JSON

Psych.load("['hello', 'world!']n")
  # => ["hello", "world!"]

Psych.to_json(%w{ hello world! })
  # => "['hello', '...
JSON Disclaimer
Evented Parsing
Evented Parsing
class MyHandler < Psych::Handler
  def start_sequence(*args)
    puts "open ["
  end

  def end_sequence(*...
Evented Parsing


parser = Psych::Parser.new(MyHandler.new)
parser.parse(StringIO.new("['foo', 'bar']"))
Evented Parsing

$ ruby yml.rb
open [
foo
bar
close ]
$
Psych::Parser#parse(io_or_string)
Evented Emitting
(the hard way)
Psych::Emitter

emitter = Psych::Emitter.new($stdout)

emitter.start_stream(Psych::Parser::UTF8)
emitter.start_document([]...
---
- 'hello   world'
- 'hello   world'
- 'hello   world'
- 'hello   world'
- 'hello   world'
- 'hello   world'
- 'hello  ...
Read
Psych::Handler
Streamed Emitting
(the easy way)
Psych::Stream

emitter = Psych::Stream.new($stdout)
emitter.start
emitter.push %w{ one two }
emitter.push %w{ three four }...
Psych::Stream

emitter = Psych::Stream.new($stdout)
emitter.start
emitter.push %w{ one two }
emitter.push %w{ three four }...
Psych::Stream
$ ruby yml.rb
---
- one
- two
...
---
- three
- four
...
Problem?
Streaming JSON
Psych::Stream


emitter = Psych::Stream.new($stdout)
emitter.start
emitter.push %w{ one two }
emitter.push %w{ three four ...
Psych::JSON::Stream


emitter = Psych::JSON::Stream.new($stdout)
emitter.start
emitter.push %w{ one two }
emitter.push %w{...
Psych::JSON::Stream


emitter = Psych::JSON::Stream.new($stdout)
emitter.start
emitter.push %w{ one two }
emitter.push %w{...
Psych::JSON::Stream


--- ['one', 'two']
...
--- ['three', 'four']
...
Uses?
More Info
THE END
Questions?
Coverage
Methods


• Coverage.start
• Coverage.result
a.rb
###
# It's my class!
class Foo
  def initialize
    @thought = 0
    10.times {
      @thought += 1 # thinking
    }
...
a.rb
###
# It's my class!
class Foo
  def initialize
    @thought = 0
    10.times {
      @thought += 1 # thinking
    }
...
a.rb
###
# It's my class!
class Foo
  def initialize
    @thought = 0
    10.times {
      @thought += 1 # thinking
    }
...
a.rb
###
# It's my class!
class Foo
  def initialize
    @thought = 0
    10.times {
      @thought += 1 # thinking
    }
...
require 'coverage'

Coverage.start
require 'a'
p Coverage.result
require 'coverage'

Coverage.start
require 'a'
p Coverage.result
Coverage.result


{"/Users/apatterson/git/code/a.rb"=>[nil,
nil, 1, 1, 1, 1, 10, nil, nil, nil, 1, 1, 1,
nil, 0, nil, nil,...
We've Learned
We've Learned

• Lines executed
We've Learned

• Lines executed
• # times a line was executed
We've Learned

• Lines executed
• # times a line was executed
• Lines that can't be executed
We can deduce
We can deduce


• Coverage
We can deduce


• Coverage
• Hotspots (code heatmap)
SimpleCov
http://github.com/colszowka/simplecov
Read More Here!
   http://bit.ly/19coverage
Hidden Gems of Ruby 1.9
Hidden Gems of Ruby 1.9
Upcoming SlideShare
Loading in …5
×

of

Hidden Gems of Ruby 1.9 Slide 1 Hidden Gems of Ruby 1.9 Slide 2 Hidden Gems of Ruby 1.9 Slide 3 Hidden Gems of Ruby 1.9 Slide 4 Hidden Gems of Ruby 1.9 Slide 5 Hidden Gems of Ruby 1.9 Slide 6 Hidden Gems of Ruby 1.9 Slide 7 Hidden Gems of Ruby 1.9 Slide 8 Hidden Gems of Ruby 1.9 Slide 9 Hidden Gems of Ruby 1.9 Slide 10 Hidden Gems of Ruby 1.9 Slide 11 Hidden Gems of Ruby 1.9 Slide 12 Hidden Gems of Ruby 1.9 Slide 13 Hidden Gems of Ruby 1.9 Slide 14 Hidden Gems of Ruby 1.9 Slide 15 Hidden Gems of Ruby 1.9 Slide 16 Hidden Gems of Ruby 1.9 Slide 17 Hidden Gems of Ruby 1.9 Slide 18 Hidden Gems of Ruby 1.9 Slide 19 Hidden Gems of Ruby 1.9 Slide 20 Hidden Gems of Ruby 1.9 Slide 21 Hidden Gems of Ruby 1.9 Slide 22 Hidden Gems of Ruby 1.9 Slide 23 Hidden Gems of Ruby 1.9 Slide 24 Hidden Gems of Ruby 1.9 Slide 25 Hidden Gems of Ruby 1.9 Slide 26 Hidden Gems of Ruby 1.9 Slide 27 Hidden Gems of Ruby 1.9 Slide 28 Hidden Gems of Ruby 1.9 Slide 29 Hidden Gems of Ruby 1.9 Slide 30 Hidden Gems of Ruby 1.9 Slide 31 Hidden Gems of Ruby 1.9 Slide 32 Hidden Gems of Ruby 1.9 Slide 33 Hidden Gems of Ruby 1.9 Slide 34 Hidden Gems of Ruby 1.9 Slide 35 Hidden Gems of Ruby 1.9 Slide 36 Hidden Gems of Ruby 1.9 Slide 37 Hidden Gems of Ruby 1.9 Slide 38 Hidden Gems of Ruby 1.9 Slide 39 Hidden Gems of Ruby 1.9 Slide 40 Hidden Gems of Ruby 1.9 Slide 41 Hidden Gems of Ruby 1.9 Slide 42 Hidden Gems of Ruby 1.9 Slide 43 Hidden Gems of Ruby 1.9 Slide 44 Hidden Gems of Ruby 1.9 Slide 45 Hidden Gems of Ruby 1.9 Slide 46 Hidden Gems of Ruby 1.9 Slide 47 Hidden Gems of Ruby 1.9 Slide 48 Hidden Gems of Ruby 1.9 Slide 49 Hidden Gems of Ruby 1.9 Slide 50 Hidden Gems of Ruby 1.9 Slide 51 Hidden Gems of Ruby 1.9 Slide 52 Hidden Gems of Ruby 1.9 Slide 53 Hidden Gems of Ruby 1.9 Slide 54 Hidden Gems of Ruby 1.9 Slide 55 Hidden Gems of Ruby 1.9 Slide 56 Hidden Gems of Ruby 1.9 Slide 57 Hidden Gems of Ruby 1.9 Slide 58 Hidden Gems of Ruby 1.9 Slide 59 Hidden Gems of Ruby 1.9 Slide 60 Hidden Gems of Ruby 1.9 Slide 61 Hidden Gems of Ruby 1.9 Slide 62 Hidden Gems of Ruby 1.9 Slide 63 Hidden Gems of Ruby 1.9 Slide 64 Hidden Gems of Ruby 1.9 Slide 65 Hidden Gems of Ruby 1.9 Slide 66 Hidden Gems of Ruby 1.9 Slide 67 Hidden Gems of Ruby 1.9 Slide 68 Hidden Gems of Ruby 1.9 Slide 69 Hidden Gems of Ruby 1.9 Slide 70 Hidden Gems of Ruby 1.9 Slide 71 Hidden Gems of Ruby 1.9 Slide 72 Hidden Gems of Ruby 1.9 Slide 73 Hidden Gems of Ruby 1.9 Slide 74 Hidden Gems of Ruby 1.9 Slide 75 Hidden Gems of Ruby 1.9 Slide 76 Hidden Gems of Ruby 1.9 Slide 77 Hidden Gems of Ruby 1.9 Slide 78 Hidden Gems of Ruby 1.9 Slide 79 Hidden Gems of Ruby 1.9 Slide 80 Hidden Gems of Ruby 1.9 Slide 81 Hidden Gems of Ruby 1.9 Slide 82 Hidden Gems of Ruby 1.9 Slide 83 Hidden Gems of Ruby 1.9 Slide 84 Hidden Gems of Ruby 1.9 Slide 85 Hidden Gems of Ruby 1.9 Slide 86 Hidden Gems of Ruby 1.9 Slide 87 Hidden Gems of Ruby 1.9 Slide 88 Hidden Gems of Ruby 1.9 Slide 89 Hidden Gems of Ruby 1.9 Slide 90 Hidden Gems of Ruby 1.9 Slide 91 Hidden Gems of Ruby 1.9 Slide 92 Hidden Gems of Ruby 1.9 Slide 93 Hidden Gems of Ruby 1.9 Slide 94 Hidden Gems of Ruby 1.9 Slide 95 Hidden Gems of Ruby 1.9 Slide 96 Hidden Gems of Ruby 1.9 Slide 97 Hidden Gems of Ruby 1.9 Slide 98 Hidden Gems of Ruby 1.9 Slide 99 Hidden Gems of Ruby 1.9 Slide 100 Hidden Gems of Ruby 1.9 Slide 101 Hidden Gems of Ruby 1.9 Slide 102 Hidden Gems of Ruby 1.9 Slide 103 Hidden Gems of Ruby 1.9 Slide 104 Hidden Gems of Ruby 1.9 Slide 105 Hidden Gems of Ruby 1.9 Slide 106 Hidden Gems of Ruby 1.9 Slide 107 Hidden Gems of Ruby 1.9 Slide 108 Hidden Gems of Ruby 1.9 Slide 109 Hidden Gems of Ruby 1.9 Slide 110 Hidden Gems of Ruby 1.9 Slide 111 Hidden Gems of Ruby 1.9 Slide 112 Hidden Gems of Ruby 1.9 Slide 113 Hidden Gems of Ruby 1.9 Slide 114 Hidden Gems of Ruby 1.9 Slide 115 Hidden Gems of Ruby 1.9 Slide 116 Hidden Gems of Ruby 1.9 Slide 117 Hidden Gems of Ruby 1.9 Slide 118 Hidden Gems of Ruby 1.9 Slide 119 Hidden Gems of Ruby 1.9 Slide 120 Hidden Gems of Ruby 1.9 Slide 121 Hidden Gems of Ruby 1.9 Slide 122 Hidden Gems of Ruby 1.9 Slide 123 Hidden Gems of Ruby 1.9 Slide 124 Hidden Gems of Ruby 1.9 Slide 125 Hidden Gems of Ruby 1.9 Slide 126 Hidden Gems of Ruby 1.9 Slide 127 Hidden Gems of Ruby 1.9 Slide 128 Hidden Gems of Ruby 1.9 Slide 129 Hidden Gems of Ruby 1.9 Slide 130 Hidden Gems of Ruby 1.9 Slide 131 Hidden Gems of Ruby 1.9 Slide 132 Hidden Gems of Ruby 1.9 Slide 133 Hidden Gems of Ruby 1.9 Slide 134 Hidden Gems of Ruby 1.9 Slide 135 Hidden Gems of Ruby 1.9 Slide 136 Hidden Gems of Ruby 1.9 Slide 137 Hidden Gems of Ruby 1.9 Slide 138 Hidden Gems of Ruby 1.9 Slide 139 Hidden Gems of Ruby 1.9 Slide 140 Hidden Gems of Ruby 1.9 Slide 141 Hidden Gems of Ruby 1.9 Slide 142 Hidden Gems of Ruby 1.9 Slide 143 Hidden Gems of Ruby 1.9 Slide 144 Hidden Gems of Ruby 1.9 Slide 145 Hidden Gems of Ruby 1.9 Slide 146 Hidden Gems of Ruby 1.9 Slide 147 Hidden Gems of Ruby 1.9 Slide 148 Hidden Gems of Ruby 1.9 Slide 149 Hidden Gems of Ruby 1.9 Slide 150 Hidden Gems of Ruby 1.9 Slide 151 Hidden Gems of Ruby 1.9 Slide 152 Hidden Gems of Ruby 1.9 Slide 153 Hidden Gems of Ruby 1.9 Slide 154 Hidden Gems of Ruby 1.9 Slide 155 Hidden Gems of Ruby 1.9 Slide 156 Hidden Gems of Ruby 1.9 Slide 157 Hidden Gems of Ruby 1.9 Slide 158 Hidden Gems of Ruby 1.9 Slide 159 Hidden Gems of Ruby 1.9 Slide 160 Hidden Gems of Ruby 1.9 Slide 161 Hidden Gems of Ruby 1.9 Slide 162 Hidden Gems of Ruby 1.9 Slide 163 Hidden Gems of Ruby 1.9 Slide 164 Hidden Gems of Ruby 1.9 Slide 165 Hidden Gems of Ruby 1.9 Slide 166 Hidden Gems of Ruby 1.9 Slide 167 Hidden Gems of Ruby 1.9 Slide 168 Hidden Gems of Ruby 1.9 Slide 169 Hidden Gems of Ruby 1.9 Slide 170 Hidden Gems of Ruby 1.9 Slide 171 Hidden Gems of Ruby 1.9 Slide 172 Hidden Gems of Ruby 1.9 Slide 173 Hidden Gems of Ruby 1.9 Slide 174 Hidden Gems of Ruby 1.9 Slide 175 Hidden Gems of Ruby 1.9 Slide 176 Hidden Gems of Ruby 1.9 Slide 177 Hidden Gems of Ruby 1.9 Slide 178 Hidden Gems of Ruby 1.9 Slide 179 Hidden Gems of Ruby 1.9 Slide 180 Hidden Gems of Ruby 1.9 Slide 181 Hidden Gems of Ruby 1.9 Slide 182 Hidden Gems of Ruby 1.9 Slide 183 Hidden Gems of Ruby 1.9 Slide 184 Hidden Gems of Ruby 1.9 Slide 185 Hidden Gems of Ruby 1.9 Slide 186 Hidden Gems of Ruby 1.9 Slide 187
Upcoming SlideShare
Nordic Ruby 2011
Next
Download to read offline and view in fullscreen.

13 Likes

Share

Download to read offline

Hidden Gems of Ruby 1.9

Download to read offline

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Hidden Gems of Ruby 1.9

  1. 1. HELLO!!!
  2. 2. ZOMG HAPPY SATURDAY!
  3. 3. PEW PEW PEW~!!!
  4. 4. Aaron Patterson
  5. 5. @tenderlove
  6. 6. google 'tenderlove' Might be NSFW
  7. 7. AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies.
  8. 8. Enterprise Developer http://github.com/tenderlove/enterprise
  9. 9. ruby core committer
  10. 10. rails core committer
  11. 11. rails committer
  12. 12. My Failures
  13. 13. rails core committer
  14. 14. rails committer
  15. 15. Presenting Last
  16. 16. I like Ryan Davis
  17. 17. My Slides Suck (Sorry Shane)
  18. 18. minitest
  19. 19. RFC 2119 common.rspec
  20. 20. No Parens on Method Definitions
  21. 21. def foo bar, baz ... end
  22. 22. Ruby + JavaScript
  23. 23. Ruby + C
  24. 24. My Failures (as a presenter)
  25. 25. Fun
  26. 26. Practical
  27. 27. I am a nerd
  28. 28. I like boring things
  29. 29. 2 Presentations
  30. 30. Practical
  31. 31. Fun!
  32. 32. The Fun
  33. 33. Your Guide to Presentation Popularity!
  34. 34. Your Guide to Presentation Notoriety!
  35. 35. •Provocative Title • Risqué Photos •Ruby Code?
  36. 36. Provocative Title:
  37. 37. Use Ruby 1.9 like an Engineer
  38. 38. Use Ruby 1.9 like a SEXY Engineer
  39. 39. Risqué Photos
  40. 40. America's Next Top Model
  41. 41. America's Next Top Engineer
  42. 42. Confident
  43. 43. Elegant
  44. 44. Sultry
  45. 45. Sexy
  46. 46. Thoughtful
  47. 47. Fierce
  48. 48. Playful
  49. 49. Powerful
  50. 50. Provocative
  51. 51. Ruby Code?
  52. 52. protected def method_missing(method, *args, &block) if Array.method_defined?(method) to_a.send(method, *args, &block) elsif @klass.scopes[method] merge(@klass.send(method, *args, &block)) elsif @klass.respond_to?(method) scoping { @klass.send(method, *args, &block) } elsif arel.respond_to?(method) arel.send(method, *args, &block) elsif match = DynamicFinderMatch.match(method) attributes = match.attribute_names super unless @klass.send(:all_attributes_exists?, attributes) if match.finder? find_by_attributes(match, attributes, *args) elsif match.instantiator? find_or_instantiator_by_attributes(match, attributes, *args, &block) end else super end end private def references_eager_loaded_tables? # always convert table names to downcase as in Oracle quoted table names are in uppercase joined_tables = (tables_in_string(arel.joins(arel)) + [table.name, table.table_alias]).compact.map{ |t| t.downcase }.uniq (tables_in_string(to_sql) - joined_tables).any? end
  53. 53. TL;DR
  54. 54. The Practical
  55. 55. Hidden Gems of Ruby 1.9
  56. 56. Ruby 1.9 PSA
  57. 57. minitest
  58. 58. require 'minitest/autorun' class FooTest < MiniTest::Unit::TestCase WIN32 = true def test_foo assert_equal 'foo', 'foo' end def test_refutation refute_equal 'foo', 'bar' end def test_skip return skip if WIN32 assert_equal 'fun!', 'fun!' end end
  59. 59. require 'minitest/autorun'
  60. 60. Test::Unit::TestCase => MiniTest::Unit::TestCase
  61. 61. class FooTest < MiniTest::Unit::TestCase end
  62. 62. assert_not_* => refute_*
  63. 63. def test_refutation refute_equal 'foo', 'bar' end
  64. 64. skip
  65. 65. class FooTest < MiniTest::Unit::TestCase WIN32 = true def test_skip skip if WIN32 assert_equal 'fun!', 'fun!' end end
  66. 66. Loaded suite footest Started .S. Finished in 0.000682 seconds. 1) Skipped: test_skip(FooTest) [footest.rb:15]: Skipped, no message given 3 tests, 2 assertions, 0 failures, 0 errors, 1 skips
  67. 67. randomization
  68. 68. class FailTest < MiniTest::Unit::TestCase @@foos = %w{ hello } def test_equality assert_equal @@foos, %w{ hello } end def test_append @@foos << "world" assert_equal @@foos, %w{ hello world } end end
  69. 69. Test run options: --seed 31149 Loaded suite failtest Started .. Finished in 0.000604 seconds. 2 tests, 2 assertions, 0 failures, 0 errors, 0 skips Test run options: --seed 31149
  70. 70. Test run options: --seed 29650 Loaded suite failtest Started .F Finished in 0.000637 seconds. 1) Failure: test_equality(FailTest) [failtest.rb:7]: Expected ["hello", "world"], not ["hello"]. 2 tests, 2 assertions, 1 failures, 0 errors, 0 skips Test run options: --seed 29650
  71. 71. Test run options: --seed 29650 Loaded suite failtest Started .F Finished in 0.000637 seconds. 1) Failure: test_equality(FailTest) [failtest.rb:7]: Expected ["hello", "world"], not ["hello"]. 2 tests, 2 assertions, 1 failures, 0 errors, 0 skips Test run options: --seed 29650
  72. 72. --seed 29650
  73. 73. -v
  74. 74. ruby failtest.rb --seed 29650 -v
  75. 75. Test run options: --seed 29650 --verbose Loaded suite failtest Started FailTest#test_append: 0.00 s: . FailTest#test_equality: 0.00 s: F Finished in 0.000735 seconds. 1) Failure: test_equality(FailTest) [failtest.rb:7]: Expected ["hello", "world"], not ["hello"]. 2 tests, 2 assertions, 1 failures, 0 errors, 0 skips Test run options: --seed 29650 --verbose
  76. 76. Test run options: --seed 29650 --verbose Loaded suite failtest Started FailTest#test_append: 0.00 s: . FailTest#test_equality: 0.00 s: F Finished in 0.000735 seconds. 1) Failure: test_equality(FailTest) [failtest.rb:7]: Expected ["hello", "world"], not ["hello"]. 2 tests, 2 assertions, 1 failures, 0 errors, 0 skips Test run options: --seed 29650 --verbose
  77. 77. Test Performance
  78. 78. class FooTest < MiniTest::Unit::TestCase def test_foo assert_equal 'foo', 'foo' end def test_refutation refute_equal 'foo', 'bar' end def test_slow sleep 10 end end
  79. 79. class FooTest < MiniTest::Unit::TestCase def test_foo assert_equal 'foo', 'foo' end def test_refutation refute_equal 'foo', 'bar' end def test_slow sleep 10 end end
  80. 80. Test run options: --seed 33095 --verbose Loaded suite footest Started FooTest#test_slow: 10.00 s: . FooTest#test_refutation: 0.00 s: . FooTest#test_foo: 0.00 s: . Finished in 10.001114 seconds. 3 tests, 2 assertions, 0 failures, 0 errors, 0 skips Test run options: --seed 33095 --verbose
  81. 81. Test run options: --seed 33095 --verbose Loaded suite footest Started FooTest#test_slow: 10.00 s: . FooTest#test_refutation: 0.00 s: . FooTest#test_foo: 0.00 s: . Finished in 10.001114 seconds. 3 tests, 2 assertions, 0 failures, 0 errors, 0 skips Test run options: --seed 33095 --verbose
  82. 82. With Rake:
  83. 83. rake test TESTSOPTS='-v'
  84. 84. rspec
  85. 85. describe 'Awesome' do describe 'Class' do it 'discovers something AMAZING' do (10 + 10).must_equal 20 end it 'matches something AMAZING' do "vuvuzela".must_match /vuvu/ end it 'raises something AMAZING' do lambda { raise }.must_raise(RuntimeError) end end end
  86. 86. rspec
  87. 87. minitest/spec
  88. 88. require 'minitest/spec' require 'minitest/autorun'
  89. 89. require 'minitest/spec' require 'minitest/autorun' describe 'Awesome' do describe 'Class' do it 'discovers something AMAZING' do (10 + 10).must_equal 20 end it 'matches something AMAZING' do "vuvuzela".must_match /vuvu/ end it 'must raise something' do lambda { raise }.must_raise(RuntimeError) end end end
  90. 90. ObjectSpace
  91. 91. ObjectSpace.each_object do |obj| p obj end
  92. 92. require 'objspace' • count_objects_size • memsize_of • count_nodes • count_tdata_objects
  93. 93. count_object_size require 'objspace' hash = {} ObjectSpace.count_objects_size(hash) p hash # => {:T_CLASS=>291520, :T_MODULE=>42512, :T_STRING=>26133, :T_REGEXP=>11501, :T_ARRAY=>5896, :T_HASH=>1088, :T_FILE=>9056, :T_DATA=>1144348, :TOTAL=>1532054}
  94. 94. count_object_size require 'objspace' hash = {} ObjectSpace.count_objects_size(hash) p hash # => {:T_CLASS=>291520, :T_MODULE=>42512, :T_STRING=>26133, :T_REGEXP=>11501, :T_ARRAY=>5896, :T_HASH=>1088, :T_FILE=>9056, :T_DATA=>1144348, :TOTAL=>1532054}
  95. 95. memsize_of require 'objspace' require 'fiddle' cl = Fiddle::Closure.new(0, [1]) p ObjectSpace.memsize_of(cl) # => 232
  96. 96. memsize_of require 'objspace' require 'fiddle' cl = Fiddle::Closure.new(0, [1]) p ObjectSpace.memsize_of(cl) # => 232
  97. 97. Implementation
  98. 98. struct rb_data_type_struct struct rb_data_type_struct { const char *wrap_struct_name; struct { void (*dmark)(void*); void (*dfree)(void*); size_t (*dsize)(const void *); void *reserved[2]; /* For future extension. This array *must* be filled with ZERO. */ } function; const rb_data_type_t *parent; void *data; /* This area can be used for any purpose by a programmer who define the type. */ };
  99. 99. struct rb_data_type_struct struct rb_data_type_struct { const char *wrap_struct_name; struct { void (*dmark)(void*); void (*dfree)(void*); size_t (*dsize)(const void *); void *reserved[2]; /* For future extension. This array *must* be filled with ZERO. */ } function; const rb_data_type_t *parent; void *data; /* This area can be used for any purpose by a programmer who define the type. */ };
  100. 100. static size_t my_memsize(const void *p) { return 10; } const rb_data_type_t my_data_type = { "my_extension", {NULL, NULL, my_memsize,}, }; static VALUE allocate(VALUE klass) { struct something * cif; return TypedData_Make_Struct( klass, something, &my_data_type, cif); }
  101. 101. count_nodes require 'objspace' p ObjectSpace.count_nodes #=> {:NODE_SCOPE=>50, :NODE_BLOCK=>168, :NODE_IF=>27, :NODE_ITER=>7, ... }
  102. 102. count_nodes require 'objspace' p ObjectSpace.count_nodes #=> {:NODE_SCOPE=>50, :NODE_BLOCK=>168, :NODE_IF=>27, :NODE_ITER=>7, ... }
  103. 103. count_nodes require 'objspace' 10.times do p ObjectSpace.count_nodes[:NODE_IF] eval 'if true; end' end
  104. 104. $ ruby objectspace.rb 27 28 29 30 31 32 33 34 35 36 $
  105. 105. count_tdata_objects require 'objspace' p ObjectSpace.count_tdata_objects # => {RubyVM::InstructionSequence=>64, false=>13, ... }
  106. 106. count_tdata_objects require 'objspace' p ObjectSpace.count_tdata_objects # => {RubyVM::InstructionSequence=>64, false=>13, ... }
  107. 107. count_tdata_objects require 'objspace' require 'fiddle' 10.times do Fiddle::Closure.new(0, [1]) p ObjectSpace.count_tdata_objects[Fiddle::Closure] end
  108. 108. $ ruby objectspace.rb 1 2 3 4 5 6 7 8 9 10 $
  109. 109. Fiddle
  110. 110. libffi wrapper
  111. 111. fiddle + dl
  112. 112. Fiddle • Function calls • Closure allocation
  113. 113. DL • dlopen() wrapper • memory management
  114. 114. Calling Functions
  115. 115. • Open dynamic library • Locate function pointer • Wrap function pointer • Call function
  116. 116. Wrapping "sin" require 'fiddle' libm = DL.dlopen('libm.dylib') function = Fiddle::Function.new( libm['sin'], [Fiddle::TYPE_DOUBLE], Fiddle::TYPE_DOUBLE ) puts function.call(90 * Math::PI / 180)
  117. 117. Wrapping "sin" require 'fiddle' libm = DL.dlopen('libm.dylib') function = Fiddle::Function.new( libm['sin'], [Fiddle::TYPE_DOUBLE], Fiddle::TYPE_DOUBLE ) puts function.call(90 * Math::PI / 180)
  118. 118. Wrapping "sin" require 'fiddle' libm = DL.dlopen('libm.dylib') function = Fiddle::Function.new( libm['sin'], [Fiddle::TYPE_DOUBLE], Fiddle::TYPE_DOUBLE ) puts function.call(90 * Math::PI / 180)
  119. 119. Wrapping "sin" require 'fiddle' libm = DL.dlopen('libm.dylib') function = Fiddle::Function.new( libm['sin'], [Fiddle::TYPE_DOUBLE], Fiddle::TYPE_DOUBLE ) puts function.call(90 * Math::PI / 180)
  120. 120. Wrapping "sin" require 'fiddle' libm = DL.dlopen('libm.dylib') function = Fiddle::Function.new( libm['sin'], [Fiddle::TYPE_DOUBLE], Fiddle::TYPE_DOUBLE ) puts function.call(90 * Math::PI / 180)
  121. 121. Creating Closures
  122. 122. double (func *)(double)
  123. 123. require 'fiddle' class MySin < Fiddle::Closure def call number Math.sin(number) end end function = MySin.new( Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE] ) puts function.call(90 * Math::PI / 180)
  124. 124. require 'fiddle' class MySin < Fiddle::Closure def call(number) Math.sin(number) end end function = MySin.new( Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE] ) puts function.call(90 * Math::PI / 180)
  125. 125. require 'fiddle' class MySin < Fiddle::Closure def call(number) Math.sin(number) end end function = MySin.new( Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE] ) puts function.call(90 * Math::PI / 180)
  126. 126. require 'fiddle' class MySin < Fiddle::Closure def call(number) Math.sin(number) end end function = MySin.new( Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE] ) puts function.call(90 * Math::PI / 180)
  127. 127. Using our Closure
  128. 128. class MySin < Fiddle::Closure def call number Math.sin(number) end end function = MySin.new( Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE] ) cfunc = Fiddle::Function.new( function, [Fiddle::TYPE_DOUBLE], Fiddle::TYPE_DOUBLE ) puts cfunc.call(90 * Math::PI / 180)
  129. 129. class MySin < Fiddle::Closure def call number Math.sin(number) end end function = MySin.new( Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE] ) cfunc = Fiddle::Function.new( function, [Fiddle::TYPE_DOUBLE], Fiddle::TYPE_DOUBLE ) puts cfunc.call(90 * Math::PI / 180)
  130. 130. Fiddle Masquerade
  131. 131. ruby-ffi code module Tidy extend FFI::Library ffi_lib "libtidy.dylib" attach_function :tidyFileExists, [:string], :int attach_function :tidyCreate, [], :pointer attach_function :tidyParseString, [:pointer, :string], :int attach_function :tidySaveStdout, [:pointer], :int end tdoc = Tidy.tidyCreate Tidy.tidyParseString tdoc, "<title>Foo</title" Tidy.tidySaveStdout tdoc
  132. 132. In terms of Fiddle
  133. 133. module FFI module Library TYPE_MAP = { :string => DL::TYPE_VOIDP, :pointer => DL::TYPE_VOIDP, } DL.constants.each do |const| next unless const.to_s =~ /^TYPE_/ name = const.to_s.split('_', 2).last.downcase.to_sym TYPE_MAP[name] = DL.const_get(const) end def ffi_lib(lib) @lib = DL::Handle.new lib end def attach_function(name, args, ret) func = Fiddle::Function.new( @lib[name.to_s], args.map { |x| TYPE_MAP[x] }, TYPE_MAP[ret] ) define_singleton_method(name) { |*args| func.call(*args) } end end end
  134. 134. ruby-ffi code module Tidy extend FFI::Library ffi_lib "libtidy.dylib" attach_function :tidyFileExists, [:string], :int attach_function :tidyCreate, [], :pointer attach_function :tidyParseString, [:pointer, :string], :int attach_function :tidySaveStdout, [:pointer], :int end tdoc = Tidy.tidyCreate Tidy.tidyParseString tdoc, "<title>Foo</title" Tidy.tidySaveStdout tdoc
  135. 135. Fiddle code module Tidy extend FFI::Library ffi_lib "libtidy.dylib" attach_function :tidyFileExists, [:string], :int attach_function :tidyCreate, [], :pointer attach_function :tidyParseString, [:pointer, :string], :int attach_function :tidySaveStdout, [:pointer], :int end tdoc = Tidy.tidyCreate Tidy.tidyParseString tdoc, "<title>Foo</title" Tidy.tidySaveStdout tdoc
  136. 136. Psych
  137. 137. YAML Parser • 1.9.2 and up • Wraps libyaml • Replaces Syck • Opt-in
  138. 138. Opt-in Process $ irb irb(main):001:0> require 'yaml' => true irb(main):002:0> YAML::ENGINE.syck? => true irb(main):003:0> YAML::ENGINE.yamler = 'psych' => "psych" irb(main):004:0> YAML::ENGINE.syck? => false irb(main):005:0>
  139. 139. require 'psych'
  140. 140. Parsing & Dumping require 'psych' Psych.load('--- hello world!') # => 'hello world!' Psych.dump('hello world!') # => '--- hello world!' 'hello world!'.to_yaml # => '--- hello world!'
  141. 141. JSON Psych.load("['hello', 'world!']n") # => ["hello", "world!"] Psych.to_json(%w{ hello world! }) # => "['hello', 'world!']n"
  142. 142. JSON Disclaimer
  143. 143. Evented Parsing
  144. 144. Evented Parsing class MyHandler < Psych::Handler def start_sequence(*args) puts "open [" end def end_sequence(*args) puts "close ]" end def scalar(value, anchor, tag, plain, quoted, style) puts value end end
  145. 145. Evented Parsing parser = Psych::Parser.new(MyHandler.new) parser.parse(StringIO.new("['foo', 'bar']"))
  146. 146. Evented Parsing $ ruby yml.rb open [ foo bar close ] $
  147. 147. Psych::Parser#parse(io_or_string)
  148. 148. Evented Emitting
  149. 149. (the hard way)
  150. 150. Psych::Emitter emitter = Psych::Emitter.new($stdout) emitter.start_stream(Psych::Parser::UTF8) emitter.start_document([], [], false) emitter.start_sequence(nil, nil, false, 1) 10.times { emitter.scalar('hello world', nil, nil, false, true, 1) } emitter.end_sequence emitter.end_document true emitter.end_stream
  151. 151. --- - 'hello world' - 'hello world' - 'hello world' - 'hello world' - 'hello world' - 'hello world' - 'hello world' - 'hello world' - 'hello world' - 'hello world'
  152. 152. Read Psych::Handler
  153. 153. Streamed Emitting
  154. 154. (the easy way)
  155. 155. Psych::Stream emitter = Psych::Stream.new($stdout) emitter.start emitter.push %w{ one two } emitter.push %w{ three four } emitter.finish
  156. 156. Psych::Stream emitter = Psych::Stream.new($stdout) emitter.start emitter.push %w{ one two } emitter.push %w{ three four } emitter.finish
  157. 157. Psych::Stream $ ruby yml.rb --- - one - two ... --- - three - four ...
  158. 158. Problem?
  159. 159. Streaming JSON
  160. 160. Psych::Stream emitter = Psych::Stream.new($stdout) emitter.start emitter.push %w{ one two } emitter.push %w{ three four } emitter.finish
  161. 161. Psych::JSON::Stream emitter = Psych::JSON::Stream.new($stdout) emitter.start emitter.push %w{ one two } emitter.push %w{ three four } emitter.finish
  162. 162. Psych::JSON::Stream emitter = Psych::JSON::Stream.new($stdout) emitter.start emitter.push %w{ one two } emitter.push %w{ three four } emitter.finish
  163. 163. Psych::JSON::Stream --- ['one', 'two'] ... --- ['three', 'four'] ...
  164. 164. Uses?
  165. 165. More Info
  166. 166. THE END
  167. 167. Questions?
  168. 168. Coverage
  169. 169. Methods • Coverage.start • Coverage.result
  170. 170. a.rb ### # It's my class! class Foo def initialize @thought = 0 10.times { @thought += 1 # thinking } end def rested? if @thought > 8 false else true end end end Foo.new.rested?
  171. 171. a.rb ### # It's my class! class Foo def initialize @thought = 0 10.times { @thought += 1 # thinking } end def rested? if @thought > 8 false else true end end end Foo.new.rested?
  172. 172. a.rb ### # It's my class! class Foo def initialize @thought = 0 10.times { @thought += 1 # thinking } end def rested? if @thought > 8 false else true end end end Foo.new.rested?
  173. 173. a.rb ### # It's my class! class Foo def initialize @thought = 0 10.times { @thought += 1 # thinking } end def rested? if @thought > 8 false else true end end end Foo.new.rested?
  174. 174. require 'coverage' Coverage.start require 'a' p Coverage.result
  175. 175. require 'coverage' Coverage.start require 'a' p Coverage.result
  176. 176. Coverage.result {"/Users/apatterson/git/code/a.rb"=>[nil, nil, 1, 1, 1, 1, 10, nil, nil, nil, 1, 1, 1, nil, 0, nil, nil, nil, nil, 1]}
  177. 177. We've Learned
  178. 178. We've Learned • Lines executed
  179. 179. We've Learned • Lines executed • # times a line was executed
  180. 180. We've Learned • Lines executed • # times a line was executed • Lines that can't be executed
  181. 181. We can deduce
  182. 182. We can deduce • Coverage
  183. 183. We can deduce • Coverage • Hotspots (code heatmap)
  184. 184. SimpleCov http://github.com/colszowka/simplecov
  185. 185. Read More Here! http://bit.ly/19coverage
  • dennisdashkevich1

    Nov. 29, 2016
  • DavidLin2

    Dec. 30, 2012
  • xds2000

    Mar. 5, 2012
  • elvuel

    Oct. 8, 2011
  • zhesto

    Aug. 9, 2011
  • metafoo

    Dec. 28, 2010
  • GauravGiri

    Nov. 19, 2010
  • x777

    Nov. 17, 2010
  • creatop

    Sep. 23, 2010
  • ivanoats

    Sep. 21, 2010
  • anildigital

    Sep. 20, 2010
  • PacoGuzman

    Sep. 20, 2010
  • fallenexile

    Sep. 20, 2010

Views

Total views

9,963

On Slideshare

0

From embeds

0

Number of embeds

16

Actions

Downloads

91

Shares

0

Comments

0

Likes

13

×