Your SlideShare is downloading. ×
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Elegant APIs
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Elegant APIs

678

Published on

Some tips and patterns on how to design elegant Ruby APIs

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
678
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
12
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
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

    • 1. Elegant APIsWhy your methodsshould nevergo missingPresented by Andrew Timberlake
    • 2. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    • 3. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    • 4. variable arguments Elegant APIs method_missing blocks instance_eval
    • 5. variable arguments Elegant APIsdef method(arg1) #...end
    • 6. variable arguments Elegant APIsdef method(arg1 = 1) #...end
    • 7. variable arguments Elegant APIsdef method(arg1 = 1, arg2 = 2) #...end
    • 8. variable arguments Elegant APIsdef method(opts = {}) options = {:arg1 => 1, :arg2 => 2}.merge(opts) #...end
    • 9. variable arguments Elegant APIsdef method(opts = {}) options = {:arg1 => 1, :arg2 => 2}.merge(opts) #...endmethod :arg2 => 3
    • 10. variable arguments Elegant APIs#Active RecordUser.create(:first_name => Andrew, :last_name => Timberlake)
    • 11. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    • 12. method_missing Elegant APIs variable arguments blocks instance_eval
    • 13. method_missing Elegant APIscss = CSS::Parser.parse("body { background: #FFF }")body = css[body] http://github.com/andrewtimberlake/css
    • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    • 30. blocks Elegant APIs variable arguments method_missing instance_eval
    • 31. blocks Elegant APIsec2 = Awsum::Ec2.new(123456, 654321)ec2.run_instances ami-123456 http://github.com/internuity/awsum
    • 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. 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. 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. 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. 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. Elegant APIsvariable argumentsmethod_missingblocksinstance_eval
    • 38. instance_eval Elegant APIs variable arguments method_missing blocks
    • 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. 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. 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. instance_eval Elegant APIsec2.region(eu-west).use do run_instancesend http://github.com/internuity/awsum
    • 43. instance_eval Elegant APIsec2.region(eu-west).use do run_instancesendec2.region(eu-west) do run_instancesend http://github.com/internuity/awsum
    • 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. 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. 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. Elegant APIs Inspiration (recommended reading) Ruby Best Practiceshttp://ruby best practices book.comPracticing Ruby newsletter http://letter.ly/practicing-ruby Thanks Gregory Brown
    • 48. Elegant APIs Thank you twitter: @atimberlake email: andrew@andrewtimberlake.com web: http://andrewtimberlake.comcode: http://github.com/andrewtimberlake

    ×