a Tour on Ruby and Friends
Minqi Pan (P.S.V.R)
“A Programmer’s Best Friend”
3 Keywords:
   Dynamic...
     Ruby executes at runtime many common behaviors
     that other languages might perform during

   Reflective...
     Ruby can observe (do type introspection) and modify
     its own structure and behavior at runtime.

   Humanity...
     Ruby is designed for programmer productivity and
     fun.
Snippet #1. OO
   # The Greeter class
class Greeter
  def initialize(name)
    @name = name.capitalize
  end
 
  def salute
    puts "Hello #{@name}!"
  end
end
 
# Create a new object
g = Greeter.new("world")
 
Snippet #2.
Everything is an object
 Applying an action on a number...



 5.times do
   print "We *love* Ruby -- it's outrageous!"
 end
Snippet #3. Flexibility
 Essential parts of Ruby can be removed or redefined,
 at will...


           class Numeric
             def plus(x)
               self.+(x)
             end
           end

           y = 5.plus 6
           # y is now equal to 11
Snippet #4. closures
  creating a function together with a referencing
  environment for the non-local variables of that
# In an object instance variable (denoted with '@'), remember
a block.
def remember(&a_block)
  @block = a_block
end

# Invoke the above method, giving it a block which takes a
name.
remember {|name| puts "Hello, #{name}!"}

# When the time is right (for the object) -- call the
closure!
@block.call("Jon")
# => "Hello, Jon!"
Snippet #5. closures (cont.)
  creating a function together with a referencing
  environment for the non-local variables of that

def create_set_and_get(initial_value=0) # Note the default value of 0
  closure_value = initial_value
  return Proc.new {|x| closure_value = x}, Proc.new { closure_value }
end

setter, getter = create_set_and_get   # ie. returns two values
setter.call(21)
getter.call # => 21

#You can also use a parameter variable as a binding for the closure.
#So the above can be rewritten as...

def create_set_and_get(closure_value=0)
  return proc {|x| closure_value = x } , proc { closure_value }
end
Snippet #6. anonymous func
 4 ways to create a function (or a subroutine) defined,
 and possibly called, without being bound to an

proc {|arg| print arg}

Proc.new {|arg| print arg}

lambda {|arg| print arg}

->(arg) {print arg}
Snippet #7. meta-programming
 writing of programs that write or manipulate other
 programs (or themselves) as their data...
 COLORS = { :black     =>   "000",
            :red       =>   "f00",
            :green     =>   "0f0",
            :yellow    =>   "ff0",
            :blue      =>   "00f",
            :magenta   =>   "f0f",
            :cyan      =>   "0ff",
            :white     =>   "fff" }

 class String
   COLORS.each do |color,code|
     define_method "in_#{color}" do
       "<span style="color: ##{code}">#{self}</span>"
     end
   end
 end

                                       "Hello, World!".in_blue
                                       => "<span style="color: #00f">Hello, World!</span>"
Snippet #8. meta-prog (cont)
 specialising the behaviour of methods called on a
 specific object...

 a = 'foo'
 class << a #opens up a’s singleton class (eigenclass)
   def inspect
     '"bar"'
   end
 end
 a.inspect   # => "bar"

 a = 'foo'   # new object, new singleton class
 a.inspect   # => "foo"
                                   "Hello, World!".in_blue
                                   => "<span style="color: #00f">Hello, World!</span>"
Snippet #9. eval
# Defining a class method with instance_eval
Fixnum.instance_eval { def ten; 10; end }
Fixnum.ten #=> 10

# Defining an instance method with class_eval
Fixnum.class_eval { def number; self; end }
7.number #=> 7

Fixnum.instance_eval treats Fixnum as an instance
(an instance of the Class class)

Fixnum.class_eval treats Fixnum as a class and
executes the code in the context of that class
Snippet #10. eval (cont.)
  class BindingTest
   def initialize(n)
    @value = n
   end
  def getBinding
   return binding() # using Kernel#binding
   end
  end
  obj1 = BindingTest.new(10)
  binding1 = obj1.getBinding
  obj2 = BindingTest.new(“Binding Test”)
  binding2 = obj2.getBinding
  puts eval(“@value”, binding1) #=> 10
  puts eval(“@value”, binding2) #=> Binding Test
  puts eval(“@value”) #=> nil
I made this!




(                    )
Yukihiro Matsumoto
“Often people, especially computer engineers, focus on the machines. They
think, "By doing this, the machine will run faster. By doing this, the machine will
run more effectively. By doing this, the machine will something something
something." They are focusing on machines. But in fact we need to focus on
humans, on how humans care about doing programming or operating the
application of the machines. We are the masters. They are the slaves.
 ”
Rails
2 Keywords:
   Convention over Configuration...
      a developer only needs to specify unconventional
      aspects of the application.

   Don't repeat yourself...
      information is located in a single, unambiguous
      place..
how to build a blog engine in
15 minutes with Ruby on Rails
Rails was created in 2003 by
David Heinemeier Hansson
                    I made that!
 In 2005 he was
 recognized by Google
 and O'Reilly with the
 Hacker of the Year
 award for his creation
 of Ruby on Rails.
 Hansson appeared on
 the cover of the July
 2006 issue of Linux
 Journal
“ Flexibility is not free. It’s overrated. And if you trade that
flexibility in for some constraints, you get a lot of complexity
removed from the equation, you get a lot of productivity back
from all the stuff you don’t have to do.”
How many source code does it take
         to make rails?
4 lines

#!/usr/bin/env ruby

if File.exists?(File.join(File.expand_path('../..', __FILE__), '.git'))
  railties_path = File.expand_path('../../railties/lib', __FILE__)
  $:.unshift(railties_path)
end
require "rails/cli"
It’s dependencies that matter
  s.add_dependency('activesupport',    version)
  s.add_dependency('actionpack',       version)
  s.add_dependency('activerecord',     version)
  s.add_dependency('activeresource',   version)
  s.add_dependency('actionmailer',     version)
  s.add_dependency('railties',         version)
  s.add_dependency('bundler',          '~> 1.0')
railties
Rails internals: application bootup, plugins,
generators, and rake tasks.


http://rubygems.org/gems/railties
require 'rails/ruby_version_check'

require 'pathname'

require 'active_support'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/logger'

require 'rails/application'
require 'rails/version'

require 'active_support/railtie'
require 'action_dispatch/railtie'
module Rails
 autoload :Info, 'rails/info'
 autoload :InfoController, 'rails/info_controller'

 class << self
  def application
    @@application ||= nil
  end
  def initialized?
    @@initialized || false
  end
  ...
 end
end
module Rails
 class Application < Engine
  autoload :Bootstrap,     'rails/application/bootstrap'
  autoload :Configuration, 'rails/application/configuration'

 end
end

module Rails
 module Generators
  autoload :Actions,    'rails/generators/actions'
  autoload :ActiveModel, 'rails/generators/active_model'
  ...
 end
end
Railties
Railties is responsible for gluing all frameworks together.
Overall, it:

* handles the bootstrapping process for a Rails application;

* manages the +rails+ command line interface;

* and provides Rails generators core.
activesupport
A toolkit of support libraries and Ruby core extensions extracted
from the Rails framework. Rich support for multibyte strings,
internationalization, time zones, and testing.


http://rubygems.org/gems/activesupport
irb(main):001:0> require 'active_support/all'
=> true
irb(main):002:0> 'person'.pluralize
=> "people"

2.even? # => true

irb(main):004:0> Time.now.in_time_zone('Alaska')
=> Sun, 11 Dec 2011 03:17:21 AKST -09:00
activesupport
Active Support is a collection of utility classes and standard library
extensions that were found useful for the Rails framework. These additions
reside in this package so they can be loaded as needed in Ruby projects
outside of Rails.


of great use to ruby learners!
actionpack
Action Pack is a framework for handling and responding to web
requests. It provides mechanisms for *routing* (mapping
request URLs to actions), defining *controllers* that implement
actions, and generating responses by rendering *views*, which
are templates of various formats. In short, Action Pack provides
the view and controller layers in the MVC paradigm.


http://rubygems.org/gems/actionpack
module ActionController
  class Base < Metal
    abstract!
     ...
  end
end
actionpack
* Action Dispatch, which parses information about the web request, handles
  routing as defined by the user, and does advanced processing related to HTTP
  such as MIME-type negotiation, decoding parameters in POST/PUT bodies,
  handling HTTP caching logic, cookies and sessions.

* Action Controller, which provides a base controller class that can be
  subclassed to implement filters and actions to handle requests. The result
  of an action is typically content generated from views.

* Action View, which handles view template lookup and rendering, and provides
  view helpers that assist when building HTML forms, Atom feeds and more.
  Template formats that Action View handles are ERB (embedded Ruby, typically
  used to inline short Ruby snippets inside HTML), and XML Builder.
activerecord
Active Record connects classes to relational database tables to establish an
almost zero-configuration persistence layer for applications. The library
provides a base class that, when subclassed, sets up a mapping between the new
class and an existing table in the database. In the context of an application,
these classes are commonly referred to as *models*. Models can also be
connected to other models; this is done by defining *associations*.



(c.f. mongoid)
http://rubygems.org/gems/activerecord
module ActiveRecord
  module Associations # :nodoc:
    extend ActiveSupport::Concern
    module ClassMethods
     def has_many
...
activerecord
 Automated mapping between classes and tables, attributes and columns.

 Associations between objects defined by simple class methods.

 Aggregations of value objects.

 Validation rules that can differ for new or existing objects.

 Callbacks available for the entire life cycle (instantiation, saving, destroying, validating, etc.).

 Observers that react to changes in a model.

 Inheritance hierarchies.

 Transactions

 Reflections on columns, associations, and aggregations.

 Database abstraction through simple adapters.

 Logging support

 Database agnostic schema management with Migrations.
activeresource
Active Resource (ARes) connects business objects and
Representational State Transfer (REST)
web services. It implements object-relational mapping for REST
web services to provide transparent
proxying capabilities between a client (ActiveResource) and a
RESTful service (which is provided by Simply RESTful routing
in ActionController::Resources).


http://rubygems.org/gems/activeresource
how it works

Model classes are mapped to remote REST resources
by Active Resource much the same way Active Record
maps model classes to databasetables. When a
request is made to a remote resource, a REST XML
request is generated, transmitted, and the result
received and serialized into a usable Ruby object.
models/product.rb

class Product < ActiveResource::Base
 self.site = "http://localhost:3000"
end

models/post.rb

class Post < ActiveRecord::Base
 def product
   @product ||= Product.find(product_id) unless product_id.blank?
 end
end

views/posts/edit.html.erb

<p>
 <%= f.label :product_id %>
 <%= f.collection_select :product_id, Product.find(:all), :id, :name %>
</p>

views/posts/show.html.erb

<% if @post.product %>
 <strong><%=h @post.product.name %></strong>
<% end %>
Philosiphy
 Active Resource attempts to provide a coherent
 wrapper object-relational mapping for REST web
 services. It follows the same philosophy as Active
 Record, in that one of its prime aims is to reduce the
 amount of code needed to map to these resources.
 This is made possible by relying on a number of code-
 and protocol-based conventions that make it easy for
 Active Resourceto infer complex relations and
 structures.
Philosophy (cont.)

class Person < ActiveResource::Base
 self.site = "http://api.people.com:3000/"
end

<->

http://api.people.com:3000/people/
# Expects a response of
  #
  # <person><id type="integer">1</id><attribute1>value1</
attribute1><attribute2>..</attribute2></person>
  #
  # for GET http://api.people.com:3000/people/1.xml
  #
  ryan = Person.find(1)
# <person><first>Ryan</first></person>
#
# is submitted as the body on
#
# POST http://api.people.com:3000/people.xml
#
# when save is called on a new Person object. An empty response is
# is expected with a 'Location' header value:
#
# Response (201): Location: http://api.people.com:3000/people/2
#
ryan = Person.new(:first => 'Ryan')
ryan.new? # => true
ryan.save # => true
ryan.new? # => false
ryan.id # => 2
actionmailer
Action Mailer is a framework for designing email-service layers.
These layers are used to consolidate code for sending out
forgotten passwords, welcome wishes on signup, invoices for
billing, and any other use case that requires a written notification
to either a person or another system.
class Notifier < ActionMailer::Base
 delivers_from 'system@loudthinking.com'

 def welcome(recipient)
  @recipient = recipient
  mail(:to => recipient,
     :subject => "[Signed up] Welcome #{recipient}")
 end
end
message = Notifier.welcome # => Returns a Mail::Message object
message.deliver        # => delivers the email




                           View!

                         Hello there,

                  Mr. <%= @recipient %>

                 Thank you for signing up!
and we get...
Date: Mon, 25 Jan 2010 22:48:09 +1100
From: system@loudthinking.com
To: david@loudthinking.com
Message-ID: <4b5d84f9dd6a5_7380800b81ac29578@void.loudthinking.com.mail>
Subject: [Signed up] Welcome david@loudthinking.com
Mime-Version: 1.0
Content-Type: text/plain;
	 charset="US-ASCII";
Content-Transfer-Encoding: 7bit

Hello there,

Mr. david@loudthinking.com

Thank you for signing up!
why directly calling on the class?
module ActionMailer #:nodoc:
 class Base < AbstractController::Base
  class << self
    def method_missing(method, *args) #:nodoc:
     return super unless respond_to?(method)
     new(method, *args).message
    end
  end
 end
end
Wait! where is activemodel?

 activerecord relies on this!
 activepack also relies on this!!!
 A toolkit for building modeling frameworks like Active
 Record and Active Resource. Rich support for
 attributes, callbacks, validations, observers,
 serialization, internationalization, and testing.
activemodel
  Used to build mongoid,etc
  as long as test is passed, free validation,callbacks,etc
  provided
module ActiveModel
 module Lint
  module Tests
def test_model_naming
 assert model.class.respond_to?(:model_name), "The model should respond to model_name"
 model_name = model.class.model_name
 assert_kind_of String, model_name
 assert_kind_of String, model_name.human
 assert_kind_of String, model_name.singular
 assert_kind_of String, model_name.plural
end

...
end
all those are free
 Add attribute magic to objects

 Callbacks for certain operations

 Tracking value changes

 Adding +errors+ interface to objects

 Model name introspection

 Observer support

 Making objects serializable

 Internationalization (i18n) support

 Validation support

 Custom validators
Other Web Frameworks of Ruby?
Sinatra
small and flexible

NO MVC

"quickly creating web-applications in Ruby with
minimal effort."

                    require 'sinatra'

                    get '/hi' do
                      "Hello World!"
                    end
Nitro
 it does not dictate
 how a web
 application should be
 structured.


<select name="day">
  <option for="day in 1..31" selected_if="day == Time.now.day">#{day}</option>
</select>

                One could use templates with embedded code!
Camping
Camping is a web
application framework
written in Ruby which
consistently stays under
4kb - the complete
source code can be
viewed on a single page.
require "uri";require "rack";class Object;def meta_def m,&b;(class<<self;self
end).send:define_method,m,&b end end;module Camping;C=self;S=IO.read(__FILE__
)rescue nil;P="<h1>Camping Problem!</h1><h2>%s</h2>";U=Rack::Utils;O={};Apps=[]
class H<Hash;def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.
to_s]:super end;undef id,type if ??==63 end;class Cookies<H;attr_accessor :_p;
def _n;@n||={}end;alias :_s :[]=;def set k,v,o={};_s(j=k.to_s,v);_n[j]=
{:value=>v,:path=>_p}.update o;end;def []=(k,v)set(k,v,v.is_a?(Hash)?v:{})end
end;module Helpers;def R c,*g;p,h=
/(.+?)/,g.grep(Hash);g-=h;raise"bad route"unless u=c.urls.find{|x|break x if
x.scan(p).size==g.size&&/^#{x}/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a.
to_param rescue a))}.gsub(/(.)/){$1})};h.any?? u+"?"+U.build_query(h[0]):u
end;def / p;p[0]==?/?@root+p :p end;def URL c='/',*a;c=R(c,*a) if c.respond_to?(
:urls);c=self/c;c=@request.url[/.{8,}?(?=/|$)/]+c if c[0]==?/;URI c end end
module Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status,
:headers,:body;T={};L=:layout;def lookup n;T.fetch(n.to_sym){|k|t=Views.
method_defined?(k)||(t=O[:_t].keys.grep(/^#{n}./)[0]and Template[t].new{
O[:_t][t]})||(f=Dir[[O[:views]||"views","#{n}.*"]*'/'][0])&&Template.
new(f,O[f[/.(w+)$/,1].to_sym]||{});O[:dynamic_templates]?t:T[k]=t} end
def render v,*a,&b;if t=lookup(v);r,@_r=@_r,o=Hash===a[-1]?a.pop: {};s=(t==true)?mab{
send v,*a,&b}: t.render(self,o[:locals]||{},&b);s=render(L,o.merge(L=>false)){s
}if o[L]or o[L].nil?&&lookup(L)&&!r&&v.to_s[0]!=?_;s;else;raise"no template: #{v}"
end;end;def mab &b;(@mab||=Mab.new({},self)).capture(&b) end;def r s,b,h={};b,h=
h,b if Hash===b;@status=s;@headers.merge!(h);@body=b end;def redirect *a;r 302,
'','Location'=>URL(*a).to_s end;def r404 p;P%"#{p} not found"end;def r500 k,m,e
raise e end;def r501 m;P%"#{m.upcase} not implemented"end;def serve(p,c)
(t=Rack::Mime.mime_type p[/..*$/],nil)&&@headers["Content-Type"]=t;c;end;def to_a;@env[
'rack.session']=Hash[@state];r=Rack::Response.new(@body,@status,@headers)
@cookies._n.each{|k,v|r.set_cookie k,v};r.to_a end;def initialize env,m
r=@request=Rack:: Request.new(@env=env);@root,@input,@cookies,@state,@headers,
@status,@method=r.script_name.sub(//$/,''),n(r.params),Cookies[r.cookies],
H[r.session.to_hash],{},m=~/r(d+)/?$1.to_i: 200,m;@cookies._p=self/"/" end
def n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=
n(v);m}: h end;def service *a;r=catch(:halt){send(@method,*a)};@body||=r;self
end end;module Controllers;@r=[];class<<self;def R *u;r=@r;Class.
new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def D p,m,e;p='/'if
!p||!p[0];(a=O[:_t].find{|n,_|n==p}) and return [I,:serve,*a]
@r.map{|k|k.urls.map{|x|return(k.method_defined? m)?[k,m,*$~[1..-1]]:
[I, 'r501',m]if p=~/^#{x}/?$/}};[I,'r404',p] end;N=H.new{|_,x|x.downcase}.
merge!("N"=>'(d+)',"X"=>'([^/]+)',"Index"=>'');def M;def M;end;constants.
map{|c|k=const_get(c);k.send:include,C,X,Base,Helpers,Models
@r=[k]+@r if @r-[k]==@r;k.meta_def(:urls){["/#{c.to_s.scan(/.[^A-Z]*/).map(&
N.method(:[]))*'/'}"]}if !k.respond_to?:urls}end end;I=R()end;X=
Controllers;class<<self;def
goes m;Apps<<a=eval(S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING);caller[0]=~/:/
IO.read(a.set:__FILE__,$`)=~/^__END__/&&(b=$'.split /^@@s*(.+?)s*r?n/m).shift rescue nil
a.set :_t,H[*b||[]];end;def call e;X.M
p=e['PATH_INFO']=U.unescape(e['PATH_INFO']);k,m,*a=X.D p,e['REQUEST_METHOD'].
downcase,e;k.new(e,m).service(*a).to_a;rescue;r500(:I,k,m,$!,:env=>e).to_a end
def method_missing m,c,*a;X.M;h=Hash===a[-1]?a.pop: {};e=H[Rack::MockRequest.
env_for('',h.delete(:env)||{})];k=X.const_get(c).new(e,m.to_s);h.each{|i,v|k.
send"#{i}=",v};k.service(*a) end;def use*a,&b;m=a.shift.new(method(:call),*a,&b)
meta_def(:call){|e|m.call(e)}end;def options;O end;def set k,v;O[k]=v end end
module Views;include X,Helpers end;module Models;autoload:Base,'camping/ar'
Helpers.send:include,X,self end;autoload:Mab,'camping/mab'
autoload:Template,'camping/template';C end
== A Camping Skeleton                             module Blog::Views
                                                    def layout
A skeletal Camping blog could look like this:
                                                      html do
  require 'camping'                                     head { title "My Blog" }
                                                        body do
  Camping.goes :Blog
                                                          h1 "My Blog"
  module Blog::Models                                     self << yield
    class Post < Base; belongs_to :user; end            end
    class Comment < Base; belongs_to :user; end       end
    class User < Base; end
  end                                               end

  module Blog::Controllers                          def index
    class Index
                                                      @posts.each do |post|
      def get
        @posts = Post.find :all                         h1 post.title
        render :index                                 end
      end                                           end
    end
  end
                                                  end
Further Research
http://www.ruby-lang.org/
http://www.rubyonrails.org/
http://www.railscasts.com/
Thank you!

A tour on ruby and friends

  • 1.
    a Tour onRuby and Friends Minqi Pan (P.S.V.R)
  • 2.
    “A Programmer’s BestFriend” 3 Keywords: Dynamic... Ruby executes at runtime many common behaviors that other languages might perform during Reflective... Ruby can observe (do type introspection) and modify its own structure and behavior at runtime. Humanity... Ruby is designed for programmer productivity and fun.
  • 3.
    Snippet #1. OO # The Greeter class class Greeter   def initialize(name)     @name = name.capitalize   end     def salute     puts "Hello #{@name}!"   end end   # Create a new object g = Greeter.new("world")  
  • 4.
    Snippet #2. Everything isan object Applying an action on a number... 5.times do print "We *love* Ruby -- it's outrageous!" end
  • 5.
    Snippet #3. Flexibility Essential parts of Ruby can be removed or redefined, at will... class Numeric   def plus(x)     self.+(x)   end end y = 5.plus 6 # y is now equal to 11
  • 6.
    Snippet #4. closures creating a function together with a referencing environment for the non-local variables of that # In an object instance variable (denoted with '@'), remember a block. def remember(&a_block) @block = a_block end # Invoke the above method, giving it a block which takes a name. remember {|name| puts "Hello, #{name}!"} # When the time is right (for the object) -- call the closure! @block.call("Jon") # => "Hello, Jon!"
  • 7.
    Snippet #5. closures(cont.) creating a function together with a referencing environment for the non-local variables of that def create_set_and_get(initial_value=0) # Note the default value of 0 closure_value = initial_value return Proc.new {|x| closure_value = x}, Proc.new { closure_value } end setter, getter = create_set_and_get # ie. returns two values setter.call(21) getter.call # => 21 #You can also use a parameter variable as a binding for the closure. #So the above can be rewritten as... def create_set_and_get(closure_value=0) return proc {|x| closure_value = x } , proc { closure_value } end
  • 8.
    Snippet #6. anonymousfunc 4 ways to create a function (or a subroutine) defined, and possibly called, without being bound to an proc {|arg| print arg} Proc.new {|arg| print arg} lambda {|arg| print arg} ->(arg) {print arg}
  • 9.
    Snippet #7. meta-programming writing of programs that write or manipulate other programs (or themselves) as their data... COLORS = { :black => "000", :red => "f00", :green => "0f0", :yellow => "ff0", :blue => "00f", :magenta => "f0f", :cyan => "0ff", :white => "fff" } class String COLORS.each do |color,code| define_method "in_#{color}" do "<span style="color: ##{code}">#{self}</span>" end end end "Hello, World!".in_blue => "<span style="color: #00f">Hello, World!</span>"
  • 10.
    Snippet #8. meta-prog(cont) specialising the behaviour of methods called on a specific object... a = 'foo' class << a #opens up a’s singleton class (eigenclass)   def inspect     '"bar"'   end end a.inspect   # => "bar" a = 'foo'   # new object, new singleton class a.inspect   # => "foo" "Hello, World!".in_blue => "<span style="color: #00f">Hello, World!</span>"
  • 11.
    Snippet #9. eval #Defining a class method with instance_eval Fixnum.instance_eval { def ten; 10; end } Fixnum.ten #=> 10 # Defining an instance method with class_eval Fixnum.class_eval { def number; self; end } 7.number #=> 7 Fixnum.instance_eval treats Fixnum as an instance (an instance of the Class class) Fixnum.class_eval treats Fixnum as a class and executes the code in the context of that class
  • 12.
    Snippet #10. eval(cont.) class BindingTest def initialize(n) @value = n end def getBinding return binding() # using Kernel#binding end end obj1 = BindingTest.new(10) binding1 = obj1.getBinding obj2 = BindingTest.new(“Binding Test”) binding2 = obj2.getBinding puts eval(“@value”, binding1) #=> 10 puts eval(“@value”, binding2) #=> Binding Test puts eval(“@value”) #=> nil
  • 13.
    I made this! ( ) Yukihiro Matsumoto
  • 14.
    “Often people, especiallycomputer engineers, focus on the machines. They think, "By doing this, the machine will run faster. By doing this, the machine will run more effectively. By doing this, the machine will something something something." They are focusing on machines. But in fact we need to focus on humans, on how humans care about doing programming or operating the application of the machines. We are the masters. They are the slaves. ”
  • 15.
    Rails 2 Keywords: Convention over Configuration... a developer only needs to specify unconventional aspects of the application. Don't repeat yourself... information is located in a single, unambiguous place..
  • 16.
    how to builda blog engine in 15 minutes with Ruby on Rails
  • 17.
    Rails was createdin 2003 by David Heinemeier Hansson I made that! In 2005 he was recognized by Google and O'Reilly with the Hacker of the Year award for his creation of Ruby on Rails. Hansson appeared on the cover of the July 2006 issue of Linux Journal
  • 18.
    “ Flexibility isnot free. It’s overrated. And if you trade that flexibility in for some constraints, you get a lot of complexity removed from the equation, you get a lot of productivity back from all the stuff you don’t have to do.”
  • 19.
    How many sourcecode does it take to make rails?
  • 20.
    4 lines #!/usr/bin/env ruby ifFile.exists?(File.join(File.expand_path('../..', __FILE__), '.git')) railties_path = File.expand_path('../../railties/lib', __FILE__) $:.unshift(railties_path) end require "rails/cli"
  • 21.
    It’s dependencies thatmatter   s.add_dependency('activesupport', version)   s.add_dependency('actionpack', version)   s.add_dependency('activerecord', version)   s.add_dependency('activeresource', version)   s.add_dependency('actionmailer', version)   s.add_dependency('railties', version)   s.add_dependency('bundler', '~> 1.0')
  • 22.
    railties Rails internals: applicationbootup, plugins, generators, and rake tasks. http://rubygems.org/gems/railties
  • 23.
    require 'rails/ruby_version_check' require 'pathname' require'active_support' require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/logger' require 'rails/application' require 'rails/version' require 'active_support/railtie' require 'action_dispatch/railtie'
  • 24.
    module Rails autoload:Info, 'rails/info' autoload :InfoController, 'rails/info_controller' class << self def application @@application ||= nil end def initialized? @@initialized || false end ... end end
  • 25.
    module Rails classApplication < Engine autoload :Bootstrap, 'rails/application/bootstrap' autoload :Configuration, 'rails/application/configuration' end end module Rails module Generators autoload :Actions, 'rails/generators/actions' autoload :ActiveModel, 'rails/generators/active_model' ... end end
  • 26.
    Railties Railties is responsiblefor gluing all frameworks together. Overall, it: * handles the bootstrapping process for a Rails application; * manages the +rails+ command line interface; * and provides Rails generators core.
  • 27.
    activesupport A toolkit ofsupport libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing. http://rubygems.org/gems/activesupport
  • 29.
    irb(main):001:0> require 'active_support/all' =>true irb(main):002:0> 'person'.pluralize => "people" 2.even? # => true irb(main):004:0> Time.now.in_time_zone('Alaska') => Sun, 11 Dec 2011 03:17:21 AKST -09:00
  • 30.
    activesupport Active Support isa collection of utility classes and standard library extensions that were found useful for the Rails framework. These additions reside in this package so they can be loaded as needed in Ruby projects outside of Rails. of great use to ruby learners!
  • 31.
    actionpack Action Pack isa framework for handling and responding to web requests. It provides mechanisms for *routing* (mapping request URLs to actions), defining *controllers* that implement actions, and generating responses by rendering *views*, which are templates of various formats. In short, Action Pack provides the view and controller layers in the MVC paradigm. http://rubygems.org/gems/actionpack
  • 32.
    module ActionController class Base < Metal abstract! ... end end
  • 34.
    actionpack * Action Dispatch,which parses information about the web request, handles routing as defined by the user, and does advanced processing related to HTTP such as MIME-type negotiation, decoding parameters in POST/PUT bodies, handling HTTP caching logic, cookies and sessions. * Action Controller, which provides a base controller class that can be subclassed to implement filters and actions to handle requests. The result of an action is typically content generated from views. * Action View, which handles view template lookup and rendering, and provides view helpers that assist when building HTML forms, Atom feeds and more. Template formats that Action View handles are ERB (embedded Ruby, typically used to inline short Ruby snippets inside HTML), and XML Builder.
  • 35.
    activerecord Active Record connectsclasses to relational database tables to establish an almost zero-configuration persistence layer for applications. The library provides a base class that, when subclassed, sets up a mapping between the new class and an existing table in the database. In the context of an application, these classes are commonly referred to as *models*. Models can also be connected to other models; this is done by defining *associations*. (c.f. mongoid) http://rubygems.org/gems/activerecord
  • 36.
    module ActiveRecord module Associations # :nodoc: extend ActiveSupport::Concern module ClassMethods def has_many ...
  • 37.
    activerecord Automated mappingbetween classes and tables, attributes and columns. Associations between objects defined by simple class methods. Aggregations of value objects. Validation rules that can differ for new or existing objects. Callbacks available for the entire life cycle (instantiation, saving, destroying, validating, etc.). Observers that react to changes in a model. Inheritance hierarchies. Transactions Reflections on columns, associations, and aggregations. Database abstraction through simple adapters. Logging support Database agnostic schema management with Migrations.
  • 38.
    activeresource Active Resource (ARes)connects business objects and Representational State Transfer (REST) web services. It implements object-relational mapping for REST web services to provide transparent proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing in ActionController::Resources). http://rubygems.org/gems/activeresource
  • 39.
    how it works Modelclasses are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to databasetables. When a request is made to a remote resource, a REST XML request is generated, transmitted, and the result received and serialized into a usable Ruby object.
  • 40.
    models/product.rb class Product <ActiveResource::Base self.site = "http://localhost:3000" end models/post.rb class Post < ActiveRecord::Base def product @product ||= Product.find(product_id) unless product_id.blank? end end views/posts/edit.html.erb <p> <%= f.label :product_id %> <%= f.collection_select :product_id, Product.find(:all), :id, :name %> </p> views/posts/show.html.erb <% if @post.product %> <strong><%=h @post.product.name %></strong> <% end %>
  • 41.
    Philosiphy Active Resourceattempts to provide a coherent wrapper object-relational mapping for REST web services. It follows the same philosophy as Active Record, in that one of its prime aims is to reduce the amount of code needed to map to these resources. This is made possible by relying on a number of code- and protocol-based conventions that make it easy for Active Resourceto infer complex relations and structures.
  • 42.
    Philosophy (cont.) class Person< ActiveResource::Base self.site = "http://api.people.com:3000/" end <-> http://api.people.com:3000/people/
  • 43.
    # Expects aresponse of # # <person><id type="integer">1</id><attribute1>value1</ attribute1><attribute2>..</attribute2></person> # # for GET http://api.people.com:3000/people/1.xml # ryan = Person.find(1)
  • 44.
    # <person><first>Ryan</first></person> # # issubmitted as the body on # # POST http://api.people.com:3000/people.xml # # when save is called on a new Person object. An empty response is # is expected with a 'Location' header value: # # Response (201): Location: http://api.people.com:3000/people/2 # ryan = Person.new(:first => 'Ryan') ryan.new? # => true ryan.save # => true ryan.new? # => false ryan.id # => 2
  • 45.
    actionmailer Action Mailer isa framework for designing email-service layers. These layers are used to consolidate code for sending out forgotten passwords, welcome wishes on signup, invoices for billing, and any other use case that requires a written notification to either a person or another system.
  • 46.
    class Notifier <ActionMailer::Base delivers_from 'system@loudthinking.com' def welcome(recipient) @recipient = recipient mail(:to => recipient, :subject => "[Signed up] Welcome #{recipient}") end end
  • 47.
    message = Notifier.welcome# => Returns a Mail::Message object message.deliver # => delivers the email View! Hello there, Mr. <%= @recipient %> Thank you for signing up!
  • 48.
    and we get... Date:Mon, 25 Jan 2010 22:48:09 +1100 From: system@loudthinking.com To: david@loudthinking.com Message-ID: <4b5d84f9dd6a5_7380800b81ac29578@void.loudthinking.com.mail> Subject: [Signed up] Welcome david@loudthinking.com Mime-Version: 1.0 Content-Type: text/plain; charset="US-ASCII"; Content-Transfer-Encoding: 7bit Hello there, Mr. david@loudthinking.com Thank you for signing up!
  • 49.
    why directly callingon the class? module ActionMailer #:nodoc: class Base < AbstractController::Base class << self def method_missing(method, *args) #:nodoc: return super unless respond_to?(method) new(method, *args).message end end end end
  • 50.
    Wait! where isactivemodel? activerecord relies on this! activepack also relies on this!!! A toolkit for building modeling frameworks like Active Record and Active Resource. Rich support for attributes, callbacks, validations, observers, serialization, internationalization, and testing.
  • 51.
    activemodel Usedto build mongoid,etc as long as test is passed, free validation,callbacks,etc provided module ActiveModel module Lint module Tests def test_model_naming assert model.class.respond_to?(:model_name), "The model should respond to model_name" model_name = model.class.model_name assert_kind_of String, model_name assert_kind_of String, model_name.human assert_kind_of String, model_name.singular assert_kind_of String, model_name.plural end ... end
  • 52.
    all those arefree Add attribute magic to objects Callbacks for certain operations Tracking value changes Adding +errors+ interface to objects Model name introspection Observer support Making objects serializable Internationalization (i18n) support Validation support Custom validators
  • 53.
  • 55.
    Sinatra small and flexible NOMVC "quickly creating web-applications in Ruby with minimal effort." require 'sinatra' get '/hi' do "Hello World!" end
  • 56.
    Nitro it doesnot dictate how a web application should be structured. <select name="day"> <option for="day in 1..31" selected_if="day == Time.now.day">#{day}</option> </select> One could use templates with embedded code!
  • 57.
    Camping Camping is aweb application framework written in Ruby which consistently stays under 4kb - the complete source code can be viewed on a single page.
  • 58.
    require "uri";require "rack";classObject;def meta_def m,&b;(class<<self;self end).send:define_method,m,&b end end;module Camping;C=self;S=IO.read(__FILE__ )rescue nil;P="<h1>Camping Problem!</h1><h2>%s</h2>";U=Rack::Utils;O={};Apps=[] class H<Hash;def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m. to_s]:super end;undef id,type if ??==63 end;class Cookies<H;attr_accessor :_p; def _n;@n||={}end;alias :_s :[]=;def set k,v,o={};_s(j=k.to_s,v);_n[j]= {:value=>v,:path=>_p}.update o;end;def []=(k,v)set(k,v,v.is_a?(Hash)?v:{})end end;module Helpers;def R c,*g;p,h= /(.+?)/,g.grep(Hash);g-=h;raise"bad route"unless u=c.urls.find{|x|break x if x.scan(p).size==g.size&&/^#{x}/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a. to_param rescue a))}.gsub(/(.)/){$1})};h.any?? u+"?"+U.build_query(h[0]):u end;def / p;p[0]==?/?@root+p :p end;def URL c='/',*a;c=R(c,*a) if c.respond_to?( :urls);c=self/c;c=@request.url[/.{8,}?(?=/|$)/]+c if c[0]==?/;URI c end end module Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status, :headers,:body;T={};L=:layout;def lookup n;T.fetch(n.to_sym){|k|t=Views. method_defined?(k)||(t=O[:_t].keys.grep(/^#{n}./)[0]and Template[t].new{ O[:_t][t]})||(f=Dir[[O[:views]||"views","#{n}.*"]*'/'][0])&&Template. new(f,O[f[/.(w+)$/,1].to_sym]||{});O[:dynamic_templates]?t:T[k]=t} end def render v,*a,&b;if t=lookup(v);r,@_r=@_r,o=Hash===a[-1]?a.pop: {};s=(t==true)?mab{ send v,*a,&b}: t.render(self,o[:locals]||{},&b);s=render(L,o.merge(L=>false)){s }if o[L]or o[L].nil?&&lookup(L)&&!r&&v.to_s[0]!=?_;s;else;raise"no template: #{v}" end;end;def mab &b;(@mab||=Mab.new({},self)).capture(&b) end;def r s,b,h={};b,h= h,b if Hash===b;@status=s;@headers.merge!(h);@body=b end;def redirect *a;r 302, '','Location'=>URL(*a).to_s end;def r404 p;P%"#{p} not found"end;def r500 k,m,e raise e end;def r501 m;P%"#{m.upcase} not implemented"end;def serve(p,c) (t=Rack::Mime.mime_type p[/..*$/],nil)&&@headers["Content-Type"]=t;c;end;def to_a;@env[ 'rack.session']=Hash[@state];r=Rack::Response.new(@body,@status,@headers) @cookies._n.each{|k,v|r.set_cookie k,v};r.to_a end;def initialize env,m r=@request=Rack:: Request.new(@env=env);@root,@input,@cookies,@state,@headers, @status,@method=r.script_name.sub(//$/,''),n(r.params),Cookies[r.cookies], H[r.session.to_hash],{},m=~/r(d+)/?$1.to_i: 200,m;@cookies._p=self/"/" end def n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]= n(v);m}: h end;def service *a;r=catch(:halt){send(@method,*a)};@body||=r;self end end;module Controllers;@r=[];class<<self;def R *u;r=@r;Class. new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def D p,m,e;p='/'if !p||!p[0];(a=O[:_t].find{|n,_|n==p}) and return [I,:serve,*a] @r.map{|k|k.urls.map{|x|return(k.method_defined? m)?[k,m,*$~[1..-1]]: [I, 'r501',m]if p=~/^#{x}/?$/}};[I,'r404',p] end;N=H.new{|_,x|x.downcase}. merge!("N"=>'(d+)',"X"=>'([^/]+)',"Index"=>'');def M;def M;end;constants. map{|c|k=const_get(c);k.send:include,C,X,Base,Helpers,Models @r=[k]+@r if @r-[k]==@r;k.meta_def(:urls){["/#{c.to_s.scan(/.[^A-Z]*/).map(& N.method(:[]))*'/'}"]}if !k.respond_to?:urls}end end;I=R()end;X= Controllers;class<<self;def goes m;Apps<<a=eval(S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING);caller[0]=~/:/ IO.read(a.set:__FILE__,$`)=~/^__END__/&&(b=$'.split /^@@s*(.+?)s*r?n/m).shift rescue nil a.set :_t,H[*b||[]];end;def call e;X.M p=e['PATH_INFO']=U.unescape(e['PATH_INFO']);k,m,*a=X.D p,e['REQUEST_METHOD']. downcase,e;k.new(e,m).service(*a).to_a;rescue;r500(:I,k,m,$!,:env=>e).to_a end def method_missing m,c,*a;X.M;h=Hash===a[-1]?a.pop: {};e=H[Rack::MockRequest. env_for('',h.delete(:env)||{})];k=X.const_get(c).new(e,m.to_s);h.each{|i,v|k. send"#{i}=",v};k.service(*a) end;def use*a,&b;m=a.shift.new(method(:call),*a,&b) meta_def(:call){|e|m.call(e)}end;def options;O end;def set k,v;O[k]=v end end module Views;include X,Helpers end;module Models;autoload:Base,'camping/ar' Helpers.send:include,X,self end;autoload:Mab,'camping/mab' autoload:Template,'camping/template';C end
  • 59.
    == A CampingSkeleton module Blog::Views def layout A skeletal Camping blog could look like this: html do require 'camping' head { title "My Blog" } body do Camping.goes :Blog h1 "My Blog" module Blog::Models self << yield class Post < Base; belongs_to :user; end end class Comment < Base; belongs_to :user; end end class User < Base; end end end module Blog::Controllers def index class Index @posts.each do |post| def get @posts = Post.find :all h1 post.title render :index end end end end end end
  • 60.
  • 61.