designing rub yap is

Upload: marinescus-catalinux

Post on 08-Apr-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/7/2019 Designing Rub Yap Is

    1/141

    Designing BeautifulRuby APIs

    [email protected]/4/25 & 6/26

    RubyConf Taiwan & RubyConf China

    V.2

    mailto:[email protected]:[email protected]
  • 8/7/2019 Designing Rub Yap Is

    2/141

    About Me

    a.k.a. ihower http://ihower.tw

    http://twitter.com/ihower Rails Developer since 2006 The Organizer of Ruby Taiwan Community http://ruby.tw http://rubyconf.tw

    http://rubyconf.tw/http://ruby.tw/http://twitter.com/ihowerhttp://ihower.tw/bloghttp://rubyconf.tw/http://rubyconf.tw/http://ruby.tw/http://ruby.tw/http://twitter.com/ihowerhttp://twitter.com/ihowerhttp://ihower.tw/bloghttp://ihower.tw/blog
  • 8/7/2019 Designing Rub Yap Is

    3/141

    Ruby Taiwan

  • 8/7/2019 Designing Rub Yap Is

    4/141

    RubyConf Taiwan 2010

  • 8/7/2019 Designing Rub Yap Is

    5/141

  • 8/7/2019 Designing Rub Yap Is

    6/141

    Define beautiful

    Readable: easy to understand Efficient: easy to write

    Flexible: easy to extend

  • 8/7/2019 Designing Rub Yap Is

    7/141

    1.Argument Processing

  • 8/7/2019 Designing Rub Yap Is

    8/141

    Pseudo-Keyword

    Argumentsdef blah(options)

    puts options[:foo] puts options[:bar]end

    blah(:foo => "test", :bar => "test")

  • 8/7/2019 Designing Rub Yap Is

    9/141

    Treating Arguments as

    an Arradef sum(*args) puts args[0] puts args[1] puts args[2] puts args[3]end

    sum(1,2,3)

    # 1# 2# 3# nil

  • 8/7/2019 Designing Rub Yap Is

    10/141

    # USAGE-1 without block 'posts'%>

    # USAGE-2 with block 'posts'do %>

    Posts list

    Rails helper usage

    example

  • 8/7/2019 Designing Rub Yap Is

    11/141

    # Rails3's source code

    def link_to(*args, &block) ifblock_given?

    options = args.first || {}html_options = args.second

    link_to(capture(&block), options, html_options) else

    name = args[0]options = args[1] || {}

    html_options = args[2]

    html_options = convert_options_to_data_attributes(options, html_options)url = url_for(options)

    if html_options

    html_options = html_options.stringify_keyshref = html_options['href']

    tag_options = tag_options(html_options) else

    tag_options = nil end

    href_attr = "href=\"#{url}\""unless href

    "#{ERB::Util.h(name || url)}".html_safe end

    end

  • 8/7/2019 Designing Rub Yap Is

    12/141

    ActiveSupport#extract_options!extract hash from *args

    def foobar(*args)options = args.extract_options!

    end

    foobar(1, 2)# options is {}

    foobar(1, 2, :a => :b)# options is { :a => :b }

  • 8/7/2019 Designing Rub Yap Is

    13/141

    2.Code Blocks

  • 8/7/2019 Designing Rub Yap Is

    14/141

    A trivial example 1def call_block puts"start" yield(" foobar") puts"end"end

    call_block do |str| puts" here" puts str puts" here"end

    # start# here# foobar# here# end

  • 8/7/2019 Designing Rub Yap Is

    15/141

    A trivial example 2def call_block(&block) puts"start"block.call("foobar")

    puts"end"end

    call_block do |str| puts"here" puts str puts"here"end

    # start# here# foobar# here# end

  • 8/7/2019 Designing Rub Yap Is

    16/141

    pre- and Post-processing

    usage examplef = File.open("myfile.txt", 'w')f.write("Lorem ipsum dolor sit amet")

    f.write("Lorem ipsum dolor sit amet")f.close

    # using blockFile.open("myfile.txt", 'w') do |f|

    f.write("Lorem ipsum dolor sit amet")f.write("Lorem ipsum dolor sit amet")

    end

  • 8/7/2019 Designing Rub Yap Is

    17/141

    pre- and Post-

    processing# without code blockdef send_message(msg)

    socket = TCPSocket.new(@ip, @port) # Pre-socket.puts(msg)response = socket.gets

    ensuresocket.close # Post-

    endend

  • 8/7/2019 Designing Rub Yap Is

    18/141

    # with code blockdef send_message(msg)

    connection do |socket|socket.puts("foobar")socket.gets

    endend

    def connectionsocket = TCPSocket.new(@ip, @port) # Pre-

    yield(socket) ensure

    socket.close # Post-

    endend

  • 8/7/2019 Designing Rub Yap Is

    19/141

    Dynamic CallbacksSinatra usage example

    get '/posts'do #.. show something .. end

    post '/posts'do #.. create something .. end

    put '/posts/:id'do #.. update something .. end

    delete '/posts/:id'do #.. annihilate something .. end

  • 8/7/2019 Designing Rub Yap Is

    20/141

    Dynamic Callbacksserver = Server.new

    server.handle(/hello/) do puts"Hello at #{Time.now}"end

    server.handle(/goodbye/) do puts"goodbye at #{Time.now}"end

    server.execute("/hello")# Hello at Wed Apr 21 17:33:31 +0800 2010server.execute("/goodbye")# goodbye at Wed Apr 21 17:33:42 +0800 2010

  • 8/7/2019 Designing Rub Yap Is

    21/141

    class Serverdef initialize

    @handlers = {} enddef handle(pattern, &block)

    @handlers[pattern] = block end

    def execute(url) @handlers.each do |pattern, block| if match = url.match(pattern)

    block.call break end end endend

  • 8/7/2019 Designing Rub Yap Is

    22/141

    Self Yieldgemspec example

    # using blockGem::Specification.new do |s|s.name = "foobar"

    s.version = "1.1.1" #...end

    spec = Gem::Specification.newspec.name = "foobar"spec.version = "1.1.1"

  • 8/7/2019 Designing Rub Yap Is

    23/141

    class Gem::Specification def initialize name = nil, version = nil

    # ... yieldselfifblock_given? # ... endend

    Self Yieldgemspec example

  • 8/7/2019 Designing Rub Yap Is

    24/141

    3.Module

  • 8/7/2019 Designing Rub Yap Is

    25/141

    A trivial examplemodule Mixin def foo puts"foo" end

    end

    class A include Mixinend

    A.new.foo # foo

  • 8/7/2019 Designing Rub Yap Is

    26/141

    obj.extend(Mod)Implementing class behavior

    module Mixin def foo

    puts"foo" endend

    A.extend(Mixin)

    A.foo # class method

    class A extend Mixinend

    the same as

    class

  • 8/7/2019 Designing Rub Yap Is

    27/141

    obj.extend(Mod)Implementing per-object behavior

    module Mixin def foo puts"foo"

    endend

    a = "test"a.extend(Mixin)a.foo # foo

    b = "demo"b.foo # NoMethodError

    class

  • 8/7/2019 Designing Rub Yap Is

    28/141

  • 8/7/2019 Designing Rub Yap Is

    29/141

  • 8/7/2019 Designing Rub Yap Is

    30/141

    module Mixin

    # self.included is a hook method defself.included(base)

    base.extend(ClassMethods) enddef foo

    puts"foo" end

    module ClassMethods

    def bar puts"bar" end endend

    class MyClass include Mixinend

    mod le Mi in

  • 8/7/2019 Designing Rub Yap Is

    31/141

    module Mixindefself.included(base)base.extend(ClassMethods)base.send(:include, InstanceMethods)

    endmodule InstanceMethods

    def foo puts"foo" end endmodule ClassMethods

    def bar puts"bar"

    end endend

    class MyClass include Mixin

    end

  • 8/7/2019 Designing Rub Yap Is

    32/141

    4.method_missing?

  • 8/7/2019 Designing Rub Yap Is

    33/141

    class Person < ActiveRecord::Baseend

    p1 = Person.find_by_name("ihower")p2 = Person.find_by_email("[email protected]")

    ActiveRecord example

  • 8/7/2019 Designing Rub Yap Is

    34/141

  • 8/7/2019 Designing Rub Yap Is

    35/141

    class Car def go(place) puts"go to #{place}"

    enddef method_missing(name, *args)

    if name.to_s =~ /^go_to_(.*)/go($1)

    else

    super end endend

    car = Car.new

    car.go_to_taipei# go to taipei

    car.blah # NoMethodError: undefined method `blah`

  • 8/7/2019 Designing Rub Yap Is

    36/141

    Dont abuse method

    missing method_missing? is slow only use it when you can not define

    method in advance

    Meta-programming can define methodsdynamically

  • 8/7/2019 Designing Rub Yap Is

    37/141

  • 8/7/2019 Designing Rub Yap Is

    38/141

  • 8/7/2019 Designing Rub Yap Is

    39/141

  • 8/7/2019 Designing Rub Yap Is

    40/141

    5.const_missing

  • 8/7/2019 Designing Rub Yap Is

    41/141

  • 8/7/2019 Designing Rub Yap Is

    42/141

    classModuleoriginal_c_m = instance_method(:const_missing)

    define_method(:const_missing) do |name|

    if name.to_s =~ /^U([0-9a-fA-F]{4})$/

    [$1.to_i(16)].pack("U*") else

    original_c_m.bind(self).call(name) end endend

    puts U0123 # puts U9999 #

    Global constant

  • 8/7/2019 Designing Rub Yap Is

    43/141

    Localized constant(you can use super here)

    class Color

    defself.const_missing(name) if name.to_s =~ /[a-zA-Z]/

    const_set(name, new)

    else super end endend

    Color::RED#Color::GREEN#

  • 8/7/2019 Designing Rub Yap Is

    44/141

    6.Methods chaining

  • 8/7/2019 Designing Rub Yap Is

    45/141

  • 8/7/2019 Designing Rub Yap Is

    46/141

  • 8/7/2019 Designing Rub Yap Is

    47/141

    Object#tapRuby 1.8.7 later

    puts"dog".reverse.tap{ |o| puts"reversed: #{o}" } # return original object.upcase

    # output

    reversed: godGOD

  • 8/7/2019 Designing Rub Yap Is

    48/141

  • 8/7/2019 Designing Rub Yap Is

    49/141

  • 8/7/2019 Designing Rub Yap Is

    50/141

    NilClass#try example

    person = Person.find_by_email(params[:email])# but we don't know @person exists or not

    # Without try@person ? @person.name : nil# With [email protected](:name)

  • 8/7/2019 Designing Rub Yap Is

    51/141

    classNilClass def try(*args)

    nil endend

  • 8/7/2019 Designing Rub Yap Is

    52/141

  • 8/7/2019 Designing Rub Yap Is

    53/141

    classNumeric

    KILOBYTE = 1024MEGABYTE = KILOBYTE * 1024

    GIGABYTE = MEGABYTE * 1024

    def bytes self

    end alias:byte:bytes

    def kilobytes

    self * KILOBYTE end

    alias:kilobyte:kilobytes

    def megabytes self * MEGABYTE

    end alias:megabyte:megabytes

    def gigabytes

    self * GIGABYTE end

    alias:gigabyte:gigabytes

    end

  • 8/7/2019 Designing Rub Yap Is

    54/141

    classObject

  • 8/7/2019 Designing Rub Yap Is

    55/141

    def blank?

    respond_to?(:empty?) ? empty? : !self end

    def present?!blank? end

    end

    classNilClass

    def blank? true

    endend

    classFalseClass

    def blank? true

    endend

    classTrueClass

    def blank? false

    end

    end

  • 8/7/2019 Designing Rub Yap Is

    56/141

    lf

  • 8/7/2019 Designing Rub Yap Is

    57/141

    self

    current ob ectclass Demo

    putsself# Demo

    def blah

    putsself# object

    [1,2,3].each do |i|

    putsself# object end

    end

    class AnotherDemo putsself# Demo::AnotherDemo

    endend

  • 8/7/2019 Designing Rub Yap Is

    58/141

    Everything in Ruby is

    ob ect, even class.

  • 8/7/2019 Designing Rub Yap Is

    59/141

    Ruby Object Model

    class Aend

    class B < Aend

    obj = B.new

    obj.class# B

    B.superclass # AB.class# Class

    obj B

    Object

    Class

    A

    class class

    super

    super

    class object is an object

  • 8/7/2019 Designing Rub Yap Is

    60/141

    class object is an object

    of the class Class

    obj B

    Object

    Class

    A

    class class

    super

    super

    class

    class

    class

    class Aend

    class B < Aend

    obj = B.new

    obj.class# B

    B.superclass # AB.class# Class

  • 8/7/2019 Designing Rub Yap Is

    61/141

    module

    obj D

    A

    MixinB,C

    class

    super

    super

    class Aend

    module Bend

    module Cend

    class D < A

    include B include Cend

    h l ?

  • 8/7/2019 Designing Rub Yap Is

    62/141

    class A def foo endend

    obj1 = A.newobj2 = A.new

    whats metaclass?

    obj2

    Object

    A

    class

    super

    obj2 class

    metaclass

  • 8/7/2019 Designing Rub Yap Is

    63/141

    obj2

    Object

    A

    class

    super

    obj2s

    metaclass

    obj2 class

    super

    class A def foo endend

    obj1 = A.newobj2 = A.new

    def obj2.bar # only obj2 has bar method,# called singleton method

    end

    # another wayclass

  • 8/7/2019 Designing Rub Yap Is

    64/141

    AAs

    metaclass

    super

    Class

    classB

    class

    class A # way1

    defself.foo end# way2

    class

  • 8/7/2019 Designing Rub Yap Is

    65/141

    classClass def blah puts"all class has blah class method" end

    end

    class Aend

    A.blah # all class has blah class methodString.blah # all class has blah class method

    If we define method

    inside class Class

    th d d fi iti ( t l )

  • 8/7/2019 Designing Rub Yap Is

    66/141

    method definition(current class)"def" defines instance method for current class

    class Demo# the current class is Demo

    def foo puts"foo" endend

    Demo.new.foo # foo

  • 8/7/2019 Designing Rub Yap Is

    67/141

  • 8/7/2019 Designing Rub Yap Is

    68/141

  • 8/7/2019 Designing Rub Yap Is

    69/141

  • 8/7/2019 Designing Rub Yap Is

    70/141

  • 8/7/2019 Designing Rub Yap Is

    71/141

    Meta-programmingHow to write code to write code?

  • 8/7/2019 Designing Rub Yap Is

    72/141

    Two types of meta-

    programming Code Generation (Not talk about it today)

    eg. Rails scaffold Reflection

    eg. Class Macro (talk later)

  • 8/7/2019 Designing Rub Yap Is

    73/141

    Specifically, How to write amethod to define method?

    class Demo

  • 8/7/2019 Designing Rub Yap Is

    74/141

    class Demo

    # the current class is Demo

    def define_blah1 # the current class is Demo

    def blah1 puts"blah1"

    end end

    defself.define_blah2

    # the current class is Demo (the same as above)

    def blah2puts"blah2"

    end

    end

    end

    Demo.new.blah1 # NoMethodError: undefined method `blah1'Demo.new.define_blah1

    Demo.new.blah1 # blah1

    Demo.new.blah2 # NoMethodError: undefined method `blah2'Demo.define_blah2

    Demo.new.blah2 #blah2

  • 8/7/2019 Designing Rub Yap Is

    75/141

    class Demo

  • 8/7/2019 Designing Rub Yap Is

    76/141

    def define_blah1

    # self is Demo's instance defself.blah1

    puts"blah1"# define singleton method end

    end

    defself.define_blah2 #self is Demo

    defself.blah2 puts"blah2"# define singleton method (class method)

    end end

    end

    a = Demo.new

    a.define_blah1

    a.blah1 # blah1Demo.new.blah1 # NoMethodError: undefined method `blah1'

    Demo.new.blah2 # NoMethodError: undefined method `blah2'Demo.define_blah2

    Demo.blah2 #blah2

  • 8/7/2019 Designing Rub Yap Is

    77/141

    Not useful really, we

    need more dynamicpower

  • 8/7/2019 Designing Rub Yap Is

    78/141

    The key of power isvariable sco e!!

  • 8/7/2019 Designing Rub Yap Is

    79/141

    module MyDemovar = 1

    class Demovar = 2

    def foovar = 3

    end

    end

    end

    { {{Variable scope

  • 8/7/2019 Designing Rub Yap Is

    80/141

    block variable scope

    var1 = "foo"

    [1,2,3].each do |i| puts var

    var1 = "bar"var2 = "baz"

    end

    puts var1 # foo

    puts var2 # NameError: undefined local variable or method

  • 8/7/2019 Designing Rub Yap Is

    81/141

  • 8/7/2019 Designing Rub Yap Is

    82/141

  • 8/7/2019 Designing Rub Yap Is

    83/141

    classClass

    def define_more_methods # define instance methods

    ["aaa", "bbb", "ccc"].each do |name|define_method(name) do

    puts name.upcase end

    end

    # define class methods

    class

  • 8/7/2019 Designing Rub Yap Is

    84/141

    odu e

    module ClassMethods def define_more_methods

    # define instance methods["aaa", "bbb", "ccc"].each do |name|

    define_method(name) doputs name.upcase

    end end

    # define class methods

    class

  • 8/7/2019 Designing Rub Yap Is

    85/141

    So we maybe need those methods

  • 8/7/2019 Designing Rub Yap Is

    86/141

    So we maybe need those methodsinside define_method:

    (because the scope is not changed)

    Object#instance_variable_get

    Object#instance_variable_set Object#remove_instance_variable

    Module#class_variable_get

    Module#class_variable_set Module#remove_class_variable

  • 8/7/2019 Designing Rub Yap Is

    87/141

    Not dynamic enough?Because class

  • 8/7/2019 Designing Rub Yap Is

    88/141

    we need even moredynamic power

  • 8/7/2019 Designing Rub Yap Is

    89/141

  • 8/7/2019 Designing Rub Yap Is

    90/141

  • 8/7/2019 Designing Rub Yap Is

    91/141

    But how to define

    singleton method usingclass_eval and

    define_method?

  • 8/7/2019 Designing Rub Yap Is

    92/141

  • 8/7/2019 Designing Rub Yap Is

    93/141

  • 8/7/2019 Designing Rub Yap Is

    94/141

    instance eval for any

  • 8/7/2019 Designing Rub Yap Is

    95/141

    instance_eval for any

    ob ectobj = "blah"obj.instance_eval do putsself# obj

    # the current class is obj's metaclass

    def foo puts"foo" endend

    obj.foo # singleton method

    h b l b ?

  • 8/7/2019 Designing Rub Yap Is

    96/141

    how about class object?

    String.instance_eval do putsself# String# the current class is String's metaclass

    def foo puts"bar" endendString.foo # singleton method (class method)

  • 8/7/2019 Designing Rub Yap Is

    97/141

  • 8/7/2019 Designing Rub Yap Is

    98/141

    8. Class Macro(Rubys declarative style)

    A i R d l

  • 8/7/2019 Designing Rub Yap Is

    99/141

    ActiveRecord example

    class User < ActiveRecord::Basevalidates_presence_of :login

    validates_length_of :login, :within => 3..40validates_presence_of :email

    belongs_to :grouphas_many :posts

    end

    Class Bodies Arent

  • 8/7/2019 Designing Rub Yap Is

    100/141

    Class Bodies Aren t

    S ecialclass Demoa = 1

    puts a

    defself.say puts"blah" endsay # you can execute class method in class body

    end

    # 1# blah

    Memorize example

  • 8/7/2019 Designing Rub Yap Is

    101/141

    Memorize example

    class Account

    def calculate @calculate ||= begin sleep10# expensive calculation 5

    end endend

    a = Account.newa.caculate # need waiting 10s to get 5a.caculate # 5a.caculate # 5a.caculate # 5

    memoize method

  • 8/7/2019 Designing Rub Yap Is

    102/141

    memoize methodclass Accountdef calculate

    sleep2# expensive calculation 5

    end

    memoize :calculateend

    a = Account.newa.calculate # need waiting 10s to get 5a.calculate # 5

  • 8/7/2019 Designing Rub Yap Is

    103/141

  • 8/7/2019 Designing Rub Yap Is

    104/141

  • 8/7/2019 Designing Rub Yap Is

    105/141

  • 8/7/2019 Designing Rub Yap Is

    106/141

    9.instance_evalDSL calls it create implicit context

    R k l

  • 8/7/2019 Designing Rub Yap Is

    107/141

    Rack example

    Rack::Builder.new douse Some::Middleware, param

    use Some::Other::Middlewarerun Application end

    How is instance eval

  • 8/7/2019 Designing Rub Yap Is

    108/141

    How is instance_eval

    doing? It changes the self (current object) to

    caller Any object can call instance_eval (unlike

    class_eval)

    t i i l l

  • 8/7/2019 Designing Rub Yap Is

    109/141

    a trivial exampleclass Demo def initialize @a = 99 endend

    foo = Demo.new

    foo.instance_eval doputs self # foo instance

    puts@a# 99

    end

  • 8/7/2019 Designing Rub Yap Is

    110/141

  • 8/7/2019 Designing Rub Yap Is

    111/141

  • 8/7/2019 Designing Rub Yap Is

    112/141

    10.Class.new

  • 8/7/2019 Designing Rub Yap Is

    113/141

  • 8/7/2019 Designing Rub Yap Is

    114/141

  • 8/7/2019 Designing Rub Yap Is

    115/141

  • 8/7/2019 Designing Rub Yap Is

    116/141

  • 8/7/2019 Designing Rub Yap Is

    117/141

    Parameterized

  • 8/7/2019 Designing Rub Yap Is

    118/141

    subclassing exampledef Person(name) if name == "ihower" Class.new do def message puts"good"

    end end else Class.new do def message

    puts"bad" end end endend

  • 8/7/2019 Designing Rub Yap Is

    119/141

  • 8/7/2019 Designing Rub Yap Is

    120/141

    Conclusion

  • 8/7/2019 Designing Rub Yap Is

    121/141

    Story 1:

    DSL or NoDSL by Jos Valim

    at Euruko 2010http://blog.plataformatec.com.br/2010/06/dsl-or-nodsl-at-euruko-2010/

    a DSL

    http://blog.plataformatec.com.br/2010/06/dsl-or-nodsl-at-euruko-2010/http://blog.plataformatec.com.br/2010/06/dsl-or-nodsl-at-euruko-2010/
  • 8/7/2019 Designing Rub Yap Is

    122/141

    class ContactForm < MailForm::Baseto "[email protected]"from "contact_form@app_name.com"subject "Contact form"

    attributes :name, :email, :messageend

    ContactForm.new(params[:contact_form]).deliver

    a DSL

  • 8/7/2019 Designing Rub Yap Is

    123/141

  • 8/7/2019 Designing Rub Yap Is

    124/141

    Other examples

  • 8/7/2019 Designing Rub Yap Is

    125/141

    Other examples

    Rake v.s. Thor

    RSpec v.s. Unit::test

  • 8/7/2019 Designing Rub Yap Is

    126/141

  • 8/7/2019 Designing Rub Yap Is

    127/141

  • 8/7/2019 Designing Rub Yap Is

    128/141

  • 8/7/2019 Designing Rub Yap Is

    129/141

    Story 2:

    Rails 2 to 3API changes

    Routesnice DSL

  • 8/7/2019 Designing Rub Yap Is

    130/141

    nice DSL

    # Rails 2

    map.resources :people, :member => { :dashboard => :get, :resend => :post, :upload => :put } do |people|

    people.resource :avatraend

    # Rails 3resources :peopledo

    resource :avatarmember do

    get :dashboard

    post :resendput :upload

    endend

    AR queries (1)

  • 8/7/2019 Designing Rub Yap Is

    131/141

    AR queries (1)method chaining

    # Rails 2users = User.find(:all, :conditions => { :name =>'ihower' }, :limit => 10, :order => 'age')

    # Rails 3users = User.where(:name => 'ihower').limit(20).order('age')

  • 8/7/2019 Designing Rub Yap Is

    132/141

    AR queries (2)

  • 8/7/2019 Designing Rub Yap Is

    133/141

    # Rails 3users = User

    users = users.some_scope if params[:some]users = users.where( :name => params[:name] ) if params[:name]

    users = users.where( :age => params[:age] ) if params[:age]users = users.order( params[:sort] || "id" )

    q ( )Unify finders, named_scope, with_scope to Relation

    AR queries (3)

  • 8/7/2019 Designing Rub Yap Is

    134/141

    # Rails 3class Product < ActiveRecord::Base

    scope :discontinued, where(:discontinued => true)scope :cheaper_than, lambda { |price| where("price < ?", price) }

    end

    # Rails 3, prefer this way more

    class Product < ActiveRecord::Base

    scope :discontinued, where(:discontinued => true)

    defself.cheaper_than(price)

    where("price < ?", price)end

    end

    Using class methods instead of scopes when you need lambda

  • 8/7/2019 Designing Rub Yap Is

    135/141

    AR validation (2)

  • 8/7/2019 Designing Rub Yap Is

    136/141

    ( )custom validator

    # Rails 3

    class User < ActiveRecord::Basevalidates :email, :presence => true,

    :uniqueness => true,:email_format => true

    end

    class EmailFormatValidator < ActiveModel::EachValidatordef validate_each(object, attribute, value)

    unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/iobject.errors[attribute]

  • 8/7/2019 Designing Rub Yap Is

    137/141

    ActionMailer# Rails 2class UserMailer < ActionMailer::Base

    def signup(user)recipients user.emailfrom '[email protected]'

    body :name => user.namesubject "Signup"

    end

    end

    UserMailer.deliver_registration_confirmation(@user)

    ActionMailer

  • 8/7/2019 Designing Rub Yap Is

    138/141

    ActionMailer# Rails 3class UserMailer < ActionMailer::Base

    default :from => "[email protected]"

    def signup(user) @name = user.namemail(:to => user.email, :subject => "Signup" )

    end

    end

    UserMailer.registration_confirmation(@user).deliver

  • 8/7/2019 Designing Rub Yap Is

    139/141

    I think its a Ruby APIsparadigm shift

    Apparently, Rails is the most successful Ruby open source codebasewhich you can learn from.

    References

    http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/
  • 8/7/2019 Designing Rub Yap Is

    140/141

    References

    Ruby Best Practices, OReilly The Ruby Object Model and Metaprogrammin, Pragmatic Programming Ruby 1.9, Pragmatic

    Metaprogramming Ruby, Pragmatic Advanced Rails, OReilly The Building Blocks of Ruby

    http://yehudakatz.com/2010/02/07/the-building-blocks-of-ruby/

    The Importance of Executable Class Bodieshttp://yehudakatz.com/2009/06/04/the-importance-of-executable-class-bodies/

    Metaprogramming in Ruby: Its All About the Selfhttp://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/

    Three implicit contexts in Rubyhttp://yugui.jp/articles/846

    http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/http://yehudakatz.com/2010/02/07/the-building-blocks-of-ruby/http://yugui.jp/articles/846http://yugui.jp/articles/846http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/http://yehudakatz.com/2010/02/07/the-building-blocks-of-ruby/http://yehudakatz.com/2010/02/07/the-building-blocks-of-ruby/
  • 8/7/2019 Designing Rub Yap Is

    141/141