Elegant APIsWhy your methodsshould nevergo missingPresented by Andrew Timberlake
Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
variable arguments   Elegant APIs   method_missing   blocks   instance_eval
variable arguments   Elegant APIsdef method(arg1)  #...end
variable arguments   Elegant APIsdef method(arg1 = 1)  #...end
variable arguments            Elegant APIsdef method(arg1 = 1, arg2 = 2)  #...end
variable arguments                  Elegant APIsdef method(opts = {})  options = {:arg1 => 1,             :arg2 => 2}.merg...
variable arguments                  Elegant APIsdef method(opts = {})  options = {:arg1 => 1,             :arg2 => 2}.merg...
variable arguments                     Elegant APIs#Active RecordUser.create(:first_name => Andrew,            :last_name ...
Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
method_missing     Elegant APIs   variable arguments   blocks   instance_eval
method_missing                            Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]...
method_missing                            Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]...
method_missing                            Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]...
method_missing                            Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]...
method_missing                                  Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css...
method_missing                                  Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css...
method_missing                                  Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css...
method_missing                                  Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css...
method_missing                            Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]...
method_missing                            Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]...
method_missing                            Elegant APIsdef method_missing(method_name, *args, &block)  get(normalize_proper...
method_missing                            Elegant APIsdef respond_to?(method_name, include_private = false)  property_name...
method_missing                            Elegant APIsdef respond_to?(method_name, include_private = false)  property_name...
method_missing                            Elegant APIsdef method_missing(method_name, *args, &block)  property_name = meth...
method_missing                            Elegant APIsdef method_missing(method_name, *args, &block)  property_name = meth...
method_missing                             Elegant APIsdef method_missing(method_name, *args, &block)  property_name = met...
Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
blocks              Elegant APIs   variable arguments   method_missing   instance_eval
blocks                                   Elegant APIsec2 = Awsum::Ec2.new(123456, 654321)ec2.run_instances ami-123456     ...
blocks                                   Elegant APIsec2 = Awsum::Ec2.new(123456, 654321)ec2.run_instances ami-123456regio...
blocks                                      Elegant APIsregion = ec2.region(eu-west)region.run_instances ami-123456region....
blocks                                      Elegant APIsec2.region(eu-west).use do |region|  run_instancesendclass Awsum::...
blocks                                      Elegant APIsec2.region(eu-west).use do |region|  region.run_instances ami-1234...
blocks                                      Elegant APIsec2.region(eu-west).use do |region|  region.run_instances ami-1234...
Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
instance_eval        Elegant APIs    variable arguments    method_missing    blocks
instance_eval                      Elegant APIsec2.region(eu-west).use do  run_instancesendclass Awsum::Ec2::Region  def u...
instance_eval                             Elegant APIsec2.region(eu-west).use do  run_instancesendclass Awsum::Ec2::Region...
instance_eval                             Elegant APIsclass Awsum::Ec2::Region  def use(&block)    if block_given?      be...
instance_eval                      Elegant APIsec2.region(eu-west).use do  run_instancesend                               ...
instance_eval                      Elegant APIsec2.region(eu-west).use do  run_instancesendec2.region(eu-west) do  run_ins...
instance_eval                            Elegant APIsec2.region(eu-west) do  run_instancesenddef region(region_name)  regi...
instance_eval                            Elegant APIsec2.region(eu-west) do  run_instancesenddef region(region_name, &bloc...
instance_eval                            Elegant APIsclass Awsum::Ec2::Region  def method_missing(method_name, *args, &blo...
Elegant APIs     Inspiration     (recommended reading)     Ruby Best Practiceshttp://ruby best practices book.comPracticin...
Elegant APIs                Thank you                  twitter:   @atimberlake  email:   andrew@andrewtimberlake.com      ...
Upcoming SlideShare
Loading in...5
×

Elegant APIs

696

Published on

Some tips and patterns on how to design elegant Ruby APIs

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
696
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
12
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript of "Elegant APIs"

    1. 1. Elegant APIsWhy your methodsshould nevergo missingPresented by Andrew Timberlake
    2. 2. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    3. 3. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    4. 4. variable arguments Elegant APIs method_missing blocks instance_eval
    5. 5. variable arguments Elegant APIsdef method(arg1) #...end
    6. 6. variable arguments Elegant APIsdef method(arg1 = 1) #...end
    7. 7. variable arguments Elegant APIsdef method(arg1 = 1, arg2 = 2) #...end
    8. 8. variable arguments Elegant APIsdef method(opts = {}) options = {:arg1 => 1, :arg2 => 2}.merge(opts) #...end
    9. 9. variable arguments Elegant APIsdef method(opts = {}) options = {:arg1 => 1, :arg2 => 2}.merge(opts) #...endmethod :arg2 => 3
    10. 10. variable arguments Elegant APIs#Active RecordUser.create(:first_name => Andrew, :last_name => Timberlake)
    11. 11. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    12. 12. method_missing Elegant APIs variable arguments blocks instance_eval
    13. 13. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body] http://github.com/andrewtimberlake/css
    14. 14. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]puts body[background] #=> background:#FFF http://github.com/andrewtimberlake/css
    15. 15. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]puts body[background] #=> background:#FFFputs body[:background] #=> background:#FFF http://github.com/andrewtimberlake/css
    16. 16. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]puts body[background] #=> background:#FFFputs body[:background] #=> background:#FFFputs body[background-color] #=> #FFF http://github.com/andrewtimberlake/css
    17. 17. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]puts body[background] #=> background:#FFFputs body[:background] #=> background:#FFFputs body[background-color] #=> #FFFputs body.background #=> background:#FFF http://github.com/andrewtimberlake/css
    18. 18. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]puts body[background] #=> background:#FFFputs body[:background] #=> background:#FFFputs body[background-color] #=> #FFFputs body.background #=> background:#FFFputs body.background_color #=> #FFF http://github.com/andrewtimberlake/css
    19. 19. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]puts body[background] #=> background:#FFFputs body[:background] #=> background:#FFFputs body[background-color] #=> #FFFputs body.background #=> background:#FFFputs body.background_color #=> #FFFputs body.backgroundColor #=> #FFF http://github.com/andrewtimberlake/css
    20. 20. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]puts body[background] #=> background:#FFFputs body[:background] #=> background:#FFFputs body[background-color] #=> #FFFputs body.background #=> background:#FFFputs body.background_color #=> #FFFputs body.backgroundColor #=> #FFFputs body.background.color #=> #FFF http://github.com/andrewtimberlake/css
    21. 21. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]body.background.image = url(image.png) http://github.com/andrewtimberlake/css
    22. 22. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body]body.background.image = url(image.png)puts body.background #=> background:#FFF url(image.png) http://github.com/andrewtimberlake/css
    23. 23. method_missing Elegant APIsdef method_missing(method_name, *args, &block) get(normalize_property_name(method_name.to_s))end http://github.com/andrewtimberlake/css
    24. 24. method_missing Elegant APIsdef respond_to?(method_name, include_private = false) property_name = normalize_property_name(method_name.to_s) default_properties.keys.include?(property_name)end http://github.com/andrewtimberlake/css
    25. 25. method_missing Elegant APIsdef respond_to?(method_name, include_private = false) property_name = normalize_property_name(method_name.to_s) default_properties.keys.include?(property_name) || superend http://github.com/andrewtimberlake/css
    26. 26. method_missing Elegant APIsdef method_missing(method_name, *args, &block) property_name = method_name.to_s if respond_to?(method_name) property_name = normalize_property_name(property_name) get(property_name) endend http://github.com/andrewtimberlake/css
    27. 27. method_missing Elegant APIsdef method_missing(method_name, *args, &block) property_name = method_name.to_s if respond_to?(method_name) property_name = normalize_property_name(property_name) get(property_name) else super endend http://github.com/andrewtimberlake/css
    28. 28. method_missing Elegant APIsdef method_missing(method_name, *args, &block) property_name = method_name.to_s setter = property_name.chomp!(=) if respond_to?(method_name) property_name = normalize_property_name(property_name) if setter @properties[property_name] = ... else get(property_name) end else super endend http://github.com/andrewtimberlake/css
    29. 29. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    30. 30. blocks Elegant APIs variable arguments method_missing instance_eval
    31. 31. blocks Elegant APIsec2 = Awsum::Ec2.new(123456, 654321)ec2.run_instances ami-123456 http://github.com/internuity/awsum
    32. 32. blocks Elegant APIsec2 = Awsum::Ec2.new(123456, 654321)ec2.run_instances ami-123456region = ec2.region(eu-west)region.run_instances ami-123456region.create_volume eu-west-1aregion.allocate_address http://github.com/internuity/awsum
    33. 33. blocks Elegant APIsregion = ec2.region(eu-west)region.run_instances ami-123456region.create_volume eu-west-1aregion.allocate_addressec2.region(eu-west).use do |region| region.run_instances ami-123456 region.create_volume eu-west-1a region.allocate_addressend http://github.com/internuity/awsum
    34. 34. blocks Elegant APIsec2.region(eu-west).use do |region| run_instancesendclass Awsum::Ec2::Region def use(&block) old_host = @ec2.host @ec2.host = end_point yield self ensure @ec2.host = old_host endend http://github.com/internuity/awsum
    35. 35. blocks Elegant APIsec2.region(eu-west).use do |region| region.run_instances ami-123456 region.create_volume eu-west-1a region.allocate_addressend http://github.com/internuity/awsum
    36. 36. blocks Elegant APIsec2.region(eu-west).use do |region| region.run_instances ami-123456 region.create_volume eu-west-1a region.allocate_addressendec2.region(eu-west).use do run_instances ami-123456 create_volume eu-west-1a allocate_addressend http://github.com/internuity/awsum
    37. 37. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    38. 38. instance_eval Elegant APIs variable arguments method_missing blocks
    39. 39. instance_eval Elegant APIsec2.region(eu-west).use do run_instancesendclass Awsum::Ec2::Region def use(&block) old_host = @ec2.host @ec2.host = end_point instance_eval(&block) ensure @ec2.host = old_host endend http://github.com/internuity/awsum
    40. 40. instance_eval Elegant APIsec2.region(eu-west).use do run_instancesendclass Awsum::Ec2::Region def use(&block) old_host = @ec2.host @ec2.host = end_point block.arity < 1 ? instance_eval(&block) : block[self] ensure @ec2.host = old_host endend http://github.com/internuity/awsum
    41. 41. instance_eval Elegant APIsclass Awsum::Ec2::Region def use(&block) if block_given? begin old_host = @ec2.host @ec2.host = end_point block.arity < 1 ? instance_eval(&block) : block[self] ensure @ec2.host = old_host end else @ec2.host = end_point self end endend http://github.com/internuity/awsum
    42. 42. instance_eval Elegant APIsec2.region(eu-west).use do run_instancesend http://github.com/internuity/awsum
    43. 43. instance_eval Elegant APIsec2.region(eu-west).use do run_instancesendec2.region(eu-west) do run_instancesend http://github.com/internuity/awsum
    44. 44. instance_eval Elegant APIsec2.region(eu-west) do run_instancesenddef region(region_name) region = regions(region_name)[0]end http://github.com/internuity/awsum
    45. 45. instance_eval Elegant APIsec2.region(eu-west) do run_instancesenddef region(region_name, &block) region = regions(region_name)[0] if block_given? region.use(&block) else region endend http://github.com/internuity/awsum
    46. 46. instance_eval Elegant APIsclass Awsum::Ec2::Region def method_missing(method_name, *args, &block) use do @ec2.send(method_name, *args, &block) end end def respond_to?(method_name, include_private = false) @ec2.respond_to?(method_name, include_private) || super endend http://github.com/internuity/awsum
    47. 47. Elegant APIs Inspiration (recommended reading) Ruby Best Practiceshttp://ruby best practices book.comPracticing Ruby newsletter http://letter.ly/practicing-ruby Thanks Gregory Brown
    48. 48. Elegant APIs Thank you twitter: @atimberlake email: andrew@andrewtimberlake.com web: http://andrewtimberlake.comcode: http://github.com/andrewtimberlake
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×