Upcoming SlideShare
×

# The Art of Ruby

564 views
475 views

Published on

The Art of Ruby: The spiritual successor to the Origamist's Ruby

Learn how to write beautiful code and how programming is a form of art.

Published in: Technology
0 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

• Be the first to like this

Views
Total views
564
On SlideShare
0
From Embeds
0
Number of Embeds
18
Actions
Shares
0
1
0
Likes
0
Embeds 0
No embeds

No notes for slide

### The Art of Ruby

1. 1. Matthew Mongeau halogenandtoast goose@thoughtbot.com
2. 2. The Art of Ruby
3. 3. A programmer who subconsciously views himself as an artist will enjoy what he does and will do it better. Donald Knuth
4. 4. What is Art?
5. 5. /ärt/ the expression or application of human creative skill and imagination, typically in a visual form such as painting or sculpture, producing works to be appreciated primarily for their beauty or emotional power.
6. 6. /ärt/ the expression or application of human creative skill and imagination, typically in a visual form such as painting or sculpture, producing works to be appreciated primarily for their beauty or emotional power.
7. 7. What is Art
8. 8. What is Art It’s beautiful.
9. 9. What is Art It’s beautiful. It’s creative.
10. 10. What is Art It’s beautiful. It’s creative. It’s expressive.
11. 11. What is Programming
12. 12. The art of writing code.
13. 13. Code is Art
14. 14. Code is Art It’s beautiful.
15. 15. Code is Art It’s beautiful. It’s creative.
16. 16. Code is Art It’s beautiful. It’s creative. It’s expressive.
17. 17. Writing beautiful Code
18. 18. Simplicity
19. 19. Code should be clear
20. 20. def play puts "Welcome to the guessing game." 3.times do guess = get_guess if won? guess @won = true puts "You win!" break else puts "Wrong!" end end if !@won puts "You lost. The actual number is #{@actual_number}." end end
21. 21. def play puts "Welcome to the guessing game." 3.times do guess = get_guess if won? guess @won = true puts "You win!" break else puts "Wrong!" end end if !@won puts "You lost. The actual number is #{@actual_number}." end end
22. 22. Extract Method Pattern def play puts "Welcome to the guessing game." play_rounds print_results end
23. 23. Single Level of Abstraction Principle def play print_header play_rounds print_results end
24. 24. Complexity
25. 25. Balance
26. 26. def play_rounds round_count.times do if correct_guess? get_guess @won = true break else puts "Wrong!" end end end
27. 27. def play_rounds @won = round_count.times.detect { play_round } end def play_round if correct_guess? get_guess true else puts "Wrong!" end end
28. 28. def play_rounds @won = round_count.times.detect { play_round } end def play_round if correct_guess? get_guess true else puts "Wrong!" # this returns nil which is falsey end end
29. 29. Constraints
30. 30. The more constraints one imposes, the more one frees one's self. Igor Stravinsky
31. 31. Code Constraints
32. 32. Code Constraints 5 line methods
33. 33. Code Constraints 5 line methods 100 line classes
34. 34. Code Constraints 5 line methods 100 line classes No classes in public methods
35. 35. def play puts "Welcome to the guessing game." 3.times do guess = get_guess if won? guess @won = true puts "You win!" break else puts "Wrong!" end end if !@won puts "You lost. The actual number is #{@actual_number}." end end
36. 36. def play print_header play_rounds print_results end
37. 37. def play_rounds round_count.times do if correct_guess? get_guess @won = true break else puts "Wrong!" end end end
38. 38. def play_rounds @won = round_count.times.detect { play_round } end def play_round if correct_guess? get_guess true else puts "Wrong!" end end
39. 39. def play_rounds @won = round_count.times.detect { play_round } end def play_round if correct_guess? get_guess true else puts "Wrong!" # this is still bothering me end end
40. 40. Breaking the Rules
41. 41. Pablo Learn the rules like a pro, so you can break them like an artist. Picasso
42. 42. def play_round if correct_guess? get_guess true else puts "Wrong!" end end
43. 43. def play_round if correct_guess? get_guess puts "Correct" true else puts "Wrong!" false end end
44. 44. def play_round if correct_guess? get_guess correct_guess else incorrect_guess end end def incorrect_guess puts "Wrong!" false end def correct_guess puts "Correct" false end
45. 45. def play_round if correct_guess? get_guess correct_guess else incorrect_guess end end def incorrect_guess puts "Wrong!" false end def correct_guess puts "Correct" false end
46. 46. class Guess def initialize actual_number @actual_number = actual_number @guess = get_guess end Extract Class Pattern def status if correct? "Correct" else "Incorrect" end end def correct? guess == actual_number end private attr_reader :guess, :actual_number def get_guess print "What is your guess: " gets.to_i end end
47. 47. Extract Class Pattern def play_round guess = Guess.new(actual_number) puts guess.display_status guess.correct? end
48. 48. 1 Extract Method
49. 49. 1 2 Extract Method Extract Class
50. 50. 1 2 3 Extract Method Extract Class Extract Gem or App
51. 51. You Win
52. 52. Performance
53. 53. If you’re willing to restrict the ﬂexibility of your approach, you can almost always do something better. John Carmack
54. 54. module Alchemist module Conversion def method_missing unit_name, *args, &block exponent, unit_name = Alchemist.parse_prefix(unit_name) if Alchemist.has_measurement?(unit_name) Alchemist.measurement self, unit_name, exponent else super( unit_name, *args, &block ) end end end end class Numeric include Alchemist::Conversion end
55. 55. module Alchemist module Conversion def method_missing unit_name, *args, &block exponent, unit_name = Alchemist.parse_prefix(unit_name) if Alchemist.has_measurement?(unit_name) Alchemist.measurement self, unit_name, exponent else super( unit_name, *args, &block ) end end end end class Numeric include Alchemist::Conversion end
56. 56. def self.parse_prefix(unit) matches = unit.to_s.match(prefix_matcher) prefix, parsed_unit = matches.captures if prefix && si_units.include?(parsed_unit) value = prefixed_value_for(prefix.to_sym, parsed_unit) [value, parsed_unit.to_sym] else [1, unit] end end
57. 57. def self.parse_prefix(unit) matches = unit.to_s.match(prefix_matcher) prefix, parsed_unit = matches.captures if prefix && si_units.include?(parsed_unit) value = prefixed_value_for(prefix.to_sym, parsed_unit) [value, parsed_unit.to_sym] else [1, unit] end end
58. 58. def self.parse_prefix(unit) matches = unit.to_s.match(prefix_matcher) prefix, parsed_unit = matches.captures if prefix && si_units.include?(parsed_unit) value = prefixed_value_for(prefix.to_sym, parsed_unit) [value, parsed_unit.to_sym] else [1, unit] end end
59. 59. def self.prefix_matcher keys = unit_prefixes.keys.map(&:to_s). sort{ |a,b| b.length <=> a.length } %r{^(#{keys.join('|')})?(.+)} end
60. 60. [:googol, :yotta, :Y, :zetta, :Z, :exa, :E, :peta, :P, :tera, :T, :giga, :G, :mega, :M, :kilo, :k, :hecto, :h, :deca, :da, :deci, :d, :centi, :c, :milli, :m, :micro, :u, :nano, :n, :pico, :p, :femto, :f, :atto, :a, :zepto, :z, :yocto, :y, :kibi, :Ki, :mebi, :Mi, :gibi, :Gi, :tebi, :Ti, :pebi, :Pi, :exbi, :Ei, :zebi, :Zi, :yobi, :Yi]
61. 61. /^(googol|yotta|femto|zetta|zepto|micro| milli|centi|hecto|yocto|exbi|giga|tebi| mega|pebi|kilo|atto|tera|kibi|deca|yobi| deci|pico|nano|gibi|zebi|mebi|peta|exa|Ki| Mi|Gi|Zi|da|Ei|Ti|Pi|Yi|z|a|y|f|p|n|m|c|d| h|k|M|G|T|P|E|Z|Y|u)?(.+)/
62. 62. Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. Jamie Zawinski
63. 63. I thought "I know, I'll use regular expressions."
64. 64. I now had two problems
65. 65. but
66. 66. def self.prefix_matcher @prefix_matcher ||= begin prefix_keys = unit_prefixes.keys.map(&:to_s). sort{ |a,b| b.length <=> a.length } %r{^(#{prefix_keys.join('|')})?(.+)} end end
67. 67. 2.0
68. 68. 1.9
69. 69. Constraints Keep existing interface
70. 70. Constraints Keep existing interface No method_missing
71. 71. Constraints Keep existing interface No method_missing Increase performance
73. 73. module Alchemist class ModuleBuilder def initialize category @category = category end def build Module.new.tap do |category_module| category_module.class_eval %(def self.inspect() "#<Module(#{category})>" end) category_module.class_eval category_methods end end
74. 74. private attr_reader :category def library Alchemist.library end def category_methods unit_names.map do |name| %(define_method("#{name}") { Alchemist.measure self, :#{name} }) + "n" + prefixed_methods(name) end.join("n") end def unit_names library.unit_names(category) end def prefixes_with_value(name) if library.si_units.include?(name.to_s) library.unit_prefixes else [] end end def prefixed_methods(name) prefixes_with_value(name).map do |prefix, value| %(define_method("#{prefix}#{name}") { Alchemist.measure self, :#{name}, #{value} }) end.join("n") end
75. 75. module Alchemist class ModuleBuilder def initialize category @category = category end def build Module.new.tap do |category_module| category_module.class_eval %(def self.inspect() "#<Module(#{category})>" end) category_module.class_eval category_methods end end
76. 76. module Alchemist class ModuleBuilder def initialize category @category = category end def build build_module do |category_module| define_inspect_method(category_module) define_unit_methods(category_module) end end
77. 77. [success_kid.jpg]
78. 78. #include <ruby.h> #include <string.h> the c-level VALUE cParenParser; VALUE paren_parser_parse(VALUE self, VALUE str) { const char *c_str = RSTRING_PTR(str); char *temp = (char *)malloc(sizeof(char) * RSTRING_LEN(str) + 1); int temp_pos = 1; int c_str_pos = 0; temp[0] = c_str[0]; while(c_str[c_str_pos++] != '0') { if(temp_pos > 0 && temp[temp_pos-1] == ')' && c_str[c_str_pos] == '(') { temp_pos--; } else { temp[temp_pos++] = c_str[c_str_pos];
79. 79. How to be an artist
80. 80. Have a toolbox
81. 81. Be inspired by others
82. 82. Surround yourself with talented artists
83. 83. Surround yourself with talented artists
84. 84. Use well known techniques
85. 85. Use well known techniques
86. 86. Measure improvement
87. 87. PULLREVIEW
88. 88. Have feelings
89. 89. Know when to break the rules
90. 90. Have fun.
91. 91. Prime learn.thoughtbot.com/prime
92. 92. THISISMETIS.COM
93. 93. ?