Top Banner
Matthew Mongeau halogenandtoast [email protected]
102

The Art of Ruby

May 27, 2015

Download

Technology

halogenandtoast

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.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 2: The Art of Ruby
Page 3: The Art of Ruby

The Art of Ruby

Page 4: The Art of Ruby

A programmer who subconsciously views himself as an artist will enjoy

what he does and will do it better.

Donald Knuth

Page 5: The Art of Ruby

What is Art?

Page 6: The Art of Ruby

/ä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.

Page 7: The Art of Ruby

/ä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.

Page 8: The Art of Ruby

What is Art

Page 9: The Art of Ruby

It’s beautiful.

What is Art

Page 10: The Art of Ruby

It’s beautiful.It’s creative.

What is Art

Page 11: The Art of Ruby

It’s beautiful.It’s creative.It’s expressive.

What is Art

Page 12: The Art of Ruby

What is Programming

Page 13: The Art of Ruby

The art of writing code.

Page 14: The Art of Ruby

Code is Art

Page 15: The Art of Ruby

It’s beautiful.

Code is Art

Page 16: The Art of Ruby

It’s beautiful.It’s creative.

Code is Art

Page 17: The Art of Ruby

It’s beautiful.It’s creative.It’s expressive.

Code is Art

Page 18: The Art of Ruby

Writing beautiful Code

Page 19: The Art of Ruby

Simplicity

Page 20: The Art of Ruby

Code should be clear

Page 21: The Art of Ruby

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}." endend

Page 22: The Art of Ruby

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}." endend

Page 23: The Art of Ruby

def play puts "Welcome to the guessing game." play_rounds print_resultsend

Extract MethodPattern

Page 24: The Art of Ruby

def play print_header play_rounds print_resultsend

Single Level of Abstraction

Principle

Page 25: The Art of Ruby

Complexity

Page 26: The Art of Ruby

Balance

Page 27: The Art of Ruby

def play_rounds round_count.times do if correct_guess? get_guess @won = true break else puts "Wrong!" end endend

Page 28: The Art of Ruby

def play_rounds @won = round_count.times.detect { play_round }end

def play_round if correct_guess? get_guess true else puts "Wrong!" endend

Page 29: The Art of Ruby

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 endend

Page 30: The Art of Ruby

Constraints

Page 31: The Art of Ruby

The more constraints one imposes, the more one frees one's self.

Igor Stravinsky

Page 32: The Art of Ruby

Code Constraints

Page 33: The Art of Ruby

Code Constraints

5 line methods

Page 34: The Art of Ruby

Code Constraints

5 line methods100 line classes

Page 35: The Art of Ruby

Code Constraints

5 line methods100 line classesNo classes in public methods

Page 36: The Art of Ruby

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}." endend

Page 37: The Art of Ruby

def play print_header play_rounds print_resultsend

Page 38: The Art of Ruby

def play_rounds round_count.times do if correct_guess? get_guess @won = true break else puts "Wrong!" end endend

Page 39: The Art of Ruby

def play_rounds @won = round_count.times.detect { play_round }end

def play_round if correct_guess? get_guess true else puts "Wrong!" endend

Page 40: The Art of Ruby

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 endend

Page 41: The Art of Ruby

Breaking the Rules

Page 42: The Art of Ruby

Pablo

Picasso

Learn the rules like a pro, so you can break

them like an artist.

Page 43: The Art of Ruby

def play_round if correct_guess? get_guess true else puts "Wrong!" endend

Page 44: The Art of Ruby

def play_round if correct_guess? get_guess puts "Correct" true else puts "Wrong!" false endend

Page 45: The Art of Ruby

def play_round if correct_guess? get_guess correct_guess else incorrect_guess endend

def incorrect_guess puts "Wrong!" falseend

def correct_guess puts "Correct" falseend

Page 46: The Art of Ruby

def play_round if correct_guess? get_guess correct_guess else incorrect_guess endend

def incorrect_guess puts "Wrong!" falseend

def correct_guess puts "Correct" falseend

Page 47: The Art of Ruby

class Guess def initialize actual_number @actual_number = actual_number @guess = get_guess end

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 endend

Extract Class

Pattern

Page 48: The Art of Ruby

def play_round guess = Guess.new(actual_number) puts guess.display_status guess.correct?end

Extract Class

Pattern

Page 49: The Art of Ruby

Extract Method

1

Page 50: The Art of Ruby

Extract Method Extract Class

1 2

Page 51: The Art of Ruby

Extract Method Extract Class Extract Gemor App

1 2 3

Page 52: The Art of Ruby

You Win

Page 53: The Art of Ruby

Performance

Page 54: The Art of Ruby

If you’re willing to restrict the flexibility of your approach, you can almost always do something better.

John Carmack

Page 55: The Art of Ruby
Page 56: The Art of Ruby
Page 57: The Art of Ruby
Page 58: The Art of Ruby

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 endend

class Numeric include Alchemist::Conversionend

Page 59: The Art of Ruby

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 endend

class Numeric include Alchemist::Conversionend

Page 60: The Art of Ruby

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

Page 61: The Art of Ruby

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

Page 62: The Art of Ruby

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

Page 63: The Art of Ruby

def self.prefix_matcher keys = unit_prefixes.keys.map(&:to_s). sort{ |a,b| b.length <=> a.length } %r{^(#{keys.join('|')})?(.+)} end

Page 64: The Art of Ruby

[: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]

Page 65: The Art of Ruby

/^(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)?(.+)/

Page 66: The Art of Ruby

Some people, when confronted with a problem, think "I know, I'll

use regular expressions." Now they have two problems.

Jamie Zawinski

Page 67: The Art of Ruby

I thought

"I know, I'll use regular expressions."

Page 68: The Art of Ruby

I now had two problems

Page 69: The Art of Ruby

but

Page 70: The Art of Ruby

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('|')})?(.+)} endend

Page 71: The Art of Ruby
Page 72: The Art of Ruby

2.0

Page 73: The Art of Ruby

1.9

Page 74: The Art of Ruby

Keep existing interface

Constraints

Page 75: The Art of Ruby

Keep existing interfaceNo method_missing

Constraints

Page 76: The Art of Ruby

Keep existing interfaceNo method_missingIncrease performance

Constraints

Page 77: The Art of Ruby

module Alchemist

def self.setup category = nil if category load_category category else load_all_categories end end

private

def self.load_all_categories library.load_all_categories end

def self.load_category category library.load_category category endend

Page 78: The Art of Ruby

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

Page 79: The Art of Ruby

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

Page 80: The Art of Ruby

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

Page 81: The Art of Ruby

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

Page 82: The Art of Ruby
Page 83: The Art of Ruby

[success_kid.jpg]

Page 84: The Art of Ruby

the c-levelthe c-level#include <ruby.h> #include <string.h>

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]; } } temp[temp_pos] = '\0';

return rb_str_new2(temp);}

void Init_paren_parser() { mParenParser = rb_define_module("ParenParser"); cParser = rb_define_class_under(mParenParser, "Parser", rb_cObject); rb_define_method(cParser, "parse", paren_parser_parse, 1);}

Page 85: The Art of Ruby

How to be an artist

Page 86: The Art of Ruby

Have a toolbox

Page 87: The Art of Ruby

Be inspired by others

Page 88: The Art of Ruby

Surround yourself with talented artists

Page 89: The Art of Ruby

Surround yourself with talented artists

Page 90: The Art of Ruby

Use well known techniques

Page 91: The Art of Ruby

Use well known techniques

Page 92: The Art of Ruby

Measure improvement

Page 93: The Art of Ruby
Page 94: The Art of Ruby
Page 95: The Art of Ruby

PULLREVIEW

Page 96: The Art of Ruby
Page 97: The Art of Ruby

Have feelings

Page 98: The Art of Ruby

Know when to break the rules

Page 99: The Art of Ruby

Have fun.

Page 100: The Art of Ruby

Primelearn.thoughtbot.com/prime

Page 101: The Art of Ruby

THISISMETIS.COM

Page 102: The Art of Ruby

?