`
biyeah
  • 浏览: 200702 次
  • 来自: ...
社区版块
存档分类
最新评论
收藏列表
标题 标签 来源
almost_sinatra.rb ruby
%w.rack tilt backports INT TERM..map{|l|trap(l){$r.stop}rescue require l}
$n=Sinatra=Module.new{extend Rack;a,D,S,$p,q,Application=Rack::Builder.new,Object.method(:define_method),/@@ *([^\n]+)\n(((?!@@)[^\n]*\n)*)/m,4567,a
%w[get post put delete].map{|m|D.(m){|u,&b|a.map(u){run->(e){[200,{"Content-Type"=>"text/html"},[a.instance_eval(&b)]]}}}}
Tilt.mappings.map{|k,v|D.(k){|n,*o|$t||=(h={};File.read(caller[0][/^[^:]+/]).scan(S){|a,b|h[a]=b};h);v[0].new(*o){n.to_s==n ?n:$t[n.to_s]}.render(a,o[0].try(:[],:locals)||{})}}
%w[set enable disable configure helpers use register].map{|m|D.(m){|*_,&b|b.try :[]}};END{Rack::Handler.get("webrick").run(a,Port:$p){|s|$r=s}}
%w[params session].map{|m|D.(m){q.send m}};a.use Rack::Session::Cookie;a.use Rack::Lock
D.(:before){|&b|a.use Rack::Config,&b};before{|e|q=Rack::Request.new e;q.params.dup.map{|k,v|params[k.to_sym]=v}}}
puts "== almost #$n/No Version has taken the stage on #$p for development with backup from Webrick"

https://github.com/rkh/almost-sinatra/blob/master/almost_sinatra.rb
Rails plugin例子 SlowGrowl ror
Rails 3 plugin which surfaces slow code paths in your Rails application by integrating with the new Notifications API in Rails 3 with your system Growl (OSX) or libnotify (Linux) notification service. By default, any activity which takes longer than one second, will generate a growl alert, with the description of the action, time taken, and other meta data. A preview in action:


require 'platform'

SlowGrowl::GEMS.each do |dep|
  require (dep[:require] || dep[:name])
end

module SlowGrowl
  class Railtie < Rails::Railtie
    config.slowgrowl = ActiveSupport::OrderedOptions.new
    config.slowgrowl.warn = 1000    # default slow alert set to 1000ms
    config.slowgrowl.sticky = false # should error warnings be sticky?
    config.slowgrowl.debug = false  # print debug information

    initializer "slowgrowl.initialize" do |app|
      ActiveSupport::Notifications.subscribe do |*args|

        if NOTIFIER
          event = ActiveSupport::Notifications::Event.new(*args)

          sticky = false
          action, type = event.name.split('.')
          alert = case event.duration
            when (0...config.slowgrowl.warn) then
              false
            when (config.slowgrowl.warn..config.slowgrowl.warn*2) then
              :warning
            else
              sticky = config.slowgrowl.sticky
              :error
          end

          begin
            e = event.payload
            message = case type
              when 'action_controller' then
                case action
                  when 'process_action' then
                    # {:controller=>"WidgetsController", :action=>"index", :params=>{"controller"=>"widgets", "action"=>"index"},
                    #  :formats=>[:html], :method=>"GET", :path=>"/widgets", :status=>200, :view_runtime=>52.25706100463867,
                    #  :db_runtime=>0}


                    if e[:exception]
                      "%s#%s.\n\n%s" % [
                        e[:controller], e[:action], e[:exception].join(', ')
                      ]
                    else
                      "%s#%s (%s).\nDB: %.1f, View: %.1f" % [
                        e[:controller], e[:action], e[:status], (e[:db_runtime] || 0), (e[:view_runtime] || 0)
                      ]
                    end

                  else
                    '%s#%s (%s)' % [e[:controller], e[:action], e[:status]]
                end

              when 'action_view' then
                # {:identifier=>"text template", :layout=>nil }
                '%s, layout: %s' % [e[:identifier], e[:layout].nil? ? 'none' : e[:layout]]

              when 'active_record' then
                # {:sql=>"SELECT "widgets".* FROM "widgets", :name=>"Widget Load", :connection_id=>2159415800}
                "%s\n\n%s" % [e[:name], e[:sql].gsub("\n", ' ').squeeze(' ')]
              else
                'Duration: %.1f' % [event.duration] if event.respond_to? :duration
            end

            if alert
              title = "%1.fms - %s : %s" % [event.duration, action.humanize, type.camelize]

              case NOTIFIER
                when :growl
                  if Growl.installed?
                    Growl.send("notify_#{alert}", message, {:title => title, :sticky => sticky})
                  end

                when :libnotify
                  Notify::Notification.new(title, message, nil, nil).show
              end
            end
          rescue Exception => e
            if config.slowgrowl.debug
              puts e
              puts event.inspect
              puts e.backtrace.join("\n")
              puts "-- If you're seeing this, you should probably open a ticket on github :-)"
            end
          end

        end
      end

    end
  end
end
ruby 中的retry ruby
begin
  a = 1 / 0 #connect to mongo #mock
rescue
  i ||= 0
  puts "in rescue i=#{i}"
  i += 1
  if i < 5
    puts "  will retry~"
    retry
  end
  puts "in the end"
end
ruby_proc_lambda区别: ruby
proc:形如proc中的代码在当前方法内,这样这些代码中如果有return,则退出了整个方法
lambda:形如当前方法外的一个方法,return只会返回结果给当前语句,后面的语句继续执行
 
本质上来理解,可以借鉴python的yield执行的细节以及ruby自己lyber
当前语句碰到lambda,会把执行指针指向lambda的block,让出了当前执行context,执行完后再回来;
但proc的block仍会在当前的context中执行,不存在执行context的出让;
 
from http://samdanielson.com/2007/3/19/proc-new-vs-lambda-in-ruby 的一个很好的例子:
 
Ruby代码  
def foo  
  f = Proc.new { return "return from foo from inside proc" }  
  f.call # control leaves foo here  
  return "return from foo"  
end  
  
def bar  
  f = lambda { return "return from lambda" }  
  f.call # control does not leave bar here  
  return "return from bar"  
end  
  
puts foo # prints "return from foo from inside proc"  
puts bar # prints "return from bar"  ruby
class_eval和instance_eval ruby
*1 C.class_eval "eval_str" 等价于在C中放入eval_str这段代码;
     class_eval只有类对象(Class Object)才能执行,普通对象没有这个方法
*2 obj.instance_eval "eval_str" 等价于class << obj eval_str end,也就是在obj的单例类中放入eval_str这段代码
     同时还能访问obj的实例变量!
     instance_eval对任意实例都可以运行
 
 
 
原理简记:
*1 The Module class defines a method named class_eval . (module_eval is a synonym for class_eval .) 
     Class < Module < Object
*2 The Object class defines a method named instance_eval. ruby中都是对象,所以都可以运行哈。
ruby === ruby
在Range中===用于判断等号右边的对象是否包含于等号左边的Range;正则表达式中用于判断一个字符串是否匹配模式,Class定义===来判断一个对象是否为类的实例,Symbol定义===来判断等号两边的符号对象是否相同。
(1..10) === 5 # true: 5属于range 1..10

/\d+/ === "123"  # true: 字符串匹配这个模式
String === "s"   # true: "s" 是一个字符串类的实例
:s === "s"       # true 
minitest ruby
== SYNOPSIS:

Given that you'd like to test the following class:

  class Meme
    def i_can_has_cheezburger?
      "OHAI!"
    end

    def will_it_blend?
      "YES!"
    end
  end

=== Unit tests

  require 'minitest/autorun'

  class TestMeme < MiniTest::Unit::TestCase
    def setup
      @meme = Meme.new
    end

    def test_that_kitty_can_eat
      assert_equal "OHAI!", @meme.i_can_has_cheezburger?
    end

    def test_that_it_will_not_blend
      refute_match /^no/i, @meme.will_it_blend?
    end
  end

=== Specs

  require 'minitest/autorun'

  describe Meme do
    before do
      @meme = Meme.new
    end

    describe "when asked about cheeseburgers" do
      it "must respond positively" do
        @meme.i_can_has_cheezburger?.must_equal "OHAI!"
      end
    end

    describe "when asked about blending possibilities" do
      it "won't say no" do
        @meme.will_it_blend?.wont_match /^no/i
      end
    end
  end

For matchers support check out:
https://github.com/zenspider/minitest-matchers

=== Benchmarks

Add benchmarks to your regular unit tests. If the unit tests fail, the
benchmarks won't run.

  # optionally run benchmarks, good for CI-only work!
  require 'minitest/benchmark' if ENV["BENCH"]

  class TestMeme < MiniTest::Unit::TestCase
    # Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000]
    def bench_my_algorithm
      assert_performance_linear 0.9999 do |n| # n is a range value
        @obj.my_algorithm(n)
      end
    end
  end

Or add them to your specs. If you make benchmarks optional, you'll
need to wrap your benchmarks in a conditional since the methods won't
be defined.

  describe Meme do
    if ENV["BENCH"] then
      bench_performance_linear "my_algorithm", 0.9999 do |n|
        100.times do
          @obj.my_algorithm(n)
        end
      end
    end
  end

outputs something like:

  # Running benchmarks:

  TestBlah	100	1000	10000
  bench_my_algorithm	 0.006167	 0.079279	 0.786993
  bench_other_algorithm	 0.061679	 0.792797	 7.869932

Output is tab-delimited to make it easy to paste into a spreadsheet.

=== Mocks

  class MemeAsker
    def initialize(meme)
      @meme = meme
    end

    def ask(question)
      method = question.tr(" ","_") + "?"
      @meme.send(method)
    end
  end

  require 'minitest/autorun'

  describe MemeAsker do
    before do
      @meme = MiniTest::Mock.new
      @meme_asker = MemeAsker.new @meme
    end

    describe "#ask" do
      describe "when passed an unpunctuated question" do
        it "should invoke the appropriate predicate method on the meme" do
          @meme.expect :will_it_blend?, :return_value
          @meme_asker.ask "will it blend"
          @meme.verify
        end
      end
    end
  end

=== Customizable Test Runner Types:

MiniTest::Unit.runner=(runner) provides an easy way of creating custom
test runners for specialized needs. Justin Weiss provides the
following real-world example to create an alternative to regular
fixture loading:

  class MiniTestWithHooks::Unit < MiniTest::Unit
    def before_suites
    end

    def after_suites
    end

    def _run_suites(suites, type)
      begin
        before_suites
        super(suites, type)
      ensure
        after_suites
      end
    end

    def _run_suite(suite, type)
      begin
        suite.before_suite
        super(suite, type)
      ensure
        suite.after_suite
      end
    end
  end

  module MiniTestWithTransactions
    class Unit < MiniTestWithHooks::Unit
      include TestSetupHelper

      def before_suites
        super
        setup_nested_transactions
        # load any data we want available for all tests
      end

      def after_suites
        teardown_nested_transactions
        super
      end
    end
  end

  MiniTest::Unit.runner = MiniTestWithTransactions::Unit.new
ActiveRecord example ror
require 'active_record'
require 'logger'

ActiveRecord::Base.logger = Logger.new(STDERR)
# ActiveRecord::Base.colorize_logging = false

ActiveRecord::Base.establish_connection(
    :adapter => "sqlite3",
    :database  => ":memory:"
)

ActiveRecord::Schema.define do
    create_table :albums do |table|
        table.column :title, :string
        table.column :performer, :string
    end

    create_table :tracks do |table|
        table.column :album_id, :integer
        table.column :track_number, :integer
        table.column :title, :string
    end
end

class Album < ActiveRecord::Base
    has_many :tracks
end

class Track < ActiveRecord::Base
    belongs_to :album
end

album = Album.create(:title => 'Black and Blue',
    :performer => 'The Rolling Stones')
album.tracks.create(:track_number => 1, :title => 'Hot Stuff')
album.tracks.create(:track_number => 2, :title => 'Hand Of Fate')
album.tracks.create(:track_number => 3, :title => 'Cherry Oh Baby ')
album.tracks.create(:track_number => 4, :title => 'Memory Motel ')
album.tracks.create(:track_number => 5, :title => 'Hey Negrita')
album.tracks.create(:track_number => 6, :title => 'Fool To Cry')
album.tracks.create(:track_number => 7, :title => 'Crazy Mama')
album.tracks.create(:track_number => 8,
    :title => 'Melody (Inspiration By Billy Preston)')

album = Album.create(:title => 'Sticky Fingers',
    :performer => 'The Rolling Stones')
album.tracks.create(:track_number => 1, :title => 'Brown Sugar')
album.tracks.create(:track_number => 2, :title => 'Sway')
album.tracks.create(:track_number => 3, :title => 'Wild Horses')
album.tracks.create(:track_number => 4,
    :title => 'Can\'t You Hear Me Knocking')
album.tracks.create(:track_number => 5, :title => 'You Gotta Move')
album.tracks.create(:track_number => 6, :title => 'Bitch')
album.tracks.create(:track_number => 7, :title => 'I Got The Blues')
album.tracks.create(:track_number => 8, :title => 'Sister Morphine')
album.tracks.create(:track_number => 9, :title => 'Dead Flowers')
album.tracks.create(:track_number => 10, :title => 'Moonlight Mile')

puts Album.find(1).tracks.length
puts Album.find(2).tracks.length

puts Album.find_by_title('Sticky Fingers').title
puts Track.find_by_title('Fool To Cry').album_id
File Access ruby
Introduction

# An IO object being Enumerable, we can use 'each' directly on it
File.open("/usr/local/widgets/data").each { |line|
    puts line if line =~ /blue/
}

logfile = File.new("/var/log/rubylog.txt", "w")
mysub($stdin, logfile)

# The method IO#readline is similar  to IO#gets
# but throws an exception when it reaches EOF
f = File.new("bla.txt")
begin
    while (line = f.readline)
        line.chomp
        $stdout.print line if line =~ /blue/
    end
rescue EOFError
    f.close
end

while $stdin.gets                        # reads from STDIN
    unless (/\d/) 
        $stderr.puts "No digit found."   # writes to STDERR
    end
    puts "Read: #{$_}"                   # writes to STDOUT
end

logfile = File.new("/tmp/log", "w")

logfile.close

# $defout (or its synonym '$>') is the destination of output
# for Kernel#print, Kernel#puts, and family functions
logfile = File.new("log.txt", "w")
old = $defout
$defout = logfile                 # switch to logfile for output
puts "Countdown initiated ..."
$defout = old                     # return to original output
puts "You have 30 seconds to reach minimum safety distance."
Opening a File

source = File.new(path, "r")  # open file "path" for reading only
sink   = File.new(path, "w")  # open file "path" for writing only

source = File.open(path, File::RDONLY)  # open file "path" for reading only
sink   = File.open(path, File::WRONLY)  # open file "path" for writing only

file   = File.open(path, "r+")  # open "path" for reading and writing
file   = File.open(path, flags) # open "path" with the flags "flags" (see examples below for flags)

# open file "path" read only
file   = File.open(path, "r")
file   = File.open(path, File::RDONLY)

# open file "path" write only, create it if it does not exist
# truncate it to zero length if it exists
file   = File.open(path, "w")
file   = File.open(path, File::WRONLY|File::TRUNC|File::CREAT) 
file   = File.open(path, File::WRONLY|File::TRUNC|File::CREAT, 0666)  # with permission 0666

# open file "path" write only, fails if file exists
file   = File.open(path, File::WRONLY|File::EXCL|File::CREAT) 
file   = File.open(path, File::WRONLY|File::EXCL|File::CREAT, 0666) 

# open file "path" for appending
file   = File.open(path, "a")
file   = File.open(path, File::WRONLY|File::APPEND|File::CREAT) 
file   = File.open(path, File::WRONLY|File::APPEND|File::CREAT, 0666) 

# open file "path" for appending only when file exists
file   = File.open(path, File::WRONLY|File::APPEND) 

# open file "path" for reading and writing
file   = File.open(path, "r+")
file   = File.open(path, File::RDWR)

# open file for reading and writing, create a new file if it does not exist
file   = File.open(path, File::RDWR|File::CREAT)
file   = File.open(path, File::RDWR|File::CREAT, 0600)

# open file "path" reading and writing, fails if file exists
file   = File.open(path, File::RDWR|File::EXCL|File::CREAT)
file   = File.open(path, File::RDWR|File::EXCL|File::CREAT, 0600)
Opening Files with Unusual Filenames

# No problem with Ruby since the filename doesn't contain characters with
# special meaning; like Perl's sysopen
File.open(filename, 'r')
Expanding Tildes in Filenames

File.expand_path('~root/tmp')
#=> "/root/tmp"
File.expand_path('~rpcuser')
#=> "/var/lib/nfs"

# To expand ~/.. it explicitely needs the environment variable HOME
File.expand_path('~/tmp')
#=> "/home/gc/tmp"
Making Perl Report Filenames in Errors

# The exception raised in Ruby reports the filename
File.open('afile')
Creating Temporary Files

# Standard Ruby distribution provides the following useful extension
require 'tempfile'
# With the Tempfile class, the file is automatically deleted on garbage
# collection, so you won't need to remove it, later on.
tf = Tempfile.new('tmp')   # a name is required to create the filename

# If you need to pass the filename to an external program you can use
# File#path, but don't forget to File#flush in order to flush anything
# living in some buffer somewhere.
tf.flush
system("/usr/bin/dowhatever #{tf.path}")

fh = Tempfile.new('tmp')
fh.sync = true                # autoflushes
10.times { |i| fh.puts i }
fh.rewind
puts 'Tmp file has: ', fh.readlines
Storing Files Inside Your Program Text

while (DATA.gets) do
    # process the line  
end
__END__
# your data goes here

# __DATA__ doesn't exist in Ruby

# get info about the script (size, date of last modification)
kilosize = DATA.stat.size / 1024
last_modif = DATA.stat.mtime
puts "<P>Script size is #{kilosize}"
puts "<P>Last script update: #{last_modif}"
__END__
# DO NOT REMOVE THE PRECEEDING LINE.
# Everything else in this file will be ignored.
Writing a Filter

while line = gets do
    # do something with line.
end

#  or 
while gets do
    # do something with $_
end

# or more rubyish
$stdin.each do |line|
    # do stuff with line
end


# ARGF may makes this more easy
# this is skipped if ARGV.size==0
ARGV.each do |filename| 
    # closing and exception handling are done by the block
    open(filename) do |fd| 
        fd.each do |line|
            # do stuff with line
        end   
    end rescue abort("can't open %s" % filename)
end

# globbing is done in the Dir module
ARGV = Dir["*.[Cch]"] if ARGV.empty?

# note: optparse is the preferred way to handle this
if (ARGV[0] == '-c')  
    chop_first += 1
    ARGV.shift
end


# processing numerical options
if ARGV[0] =~ /^-(\d+)$/
    columns = $1
    ARGV.shift
end

# again, better to use optparse:
require 'optparse'
nostdout = 0
append = 0
unbuffer = 0
ignore_ints = 0
ARGV.options do |opt|
    opt.on('-n') { nostdout +=1 }
    opt.on('-a') { append   +=1 }
    opt.on('-u') { unbuffer +=1 }
    opt.on('-i') { ignore_ints +=1 }
    opt.parse!
end or abort("usage: " + __FILE__ + " [-ainu] [filenames]")

# no need to do undef $/, we have File.read
str = File.read(ARGV[0])

# again we have File.read
str = File.read(ARGV[0])

# not sure what this should do:
# I believe open the file, print filename, lineno and line:
ARGF.each_with_index do |line, idx|
    print ARGF.filename, ":", idx, ";", line
end

# print all the lines in every file passed via command line that contains login
ARGF.each do |line|
    puts line if line =~ /login/
end
#
# even this would fit
#%ruby -ne "print if /f/" 2.log
#

ARGF.each { |l| puts l.downcase! }

#------------------
#!/usr/bin/ruby -p
# just like perl's -p
$_.downcase!
#

# I don't know who should I trust. 
# perl's version splits on \w+ while python's on \w.

chunks = 0

File.read(ARGV[0]).split.each do |word|
    next if word =~ /^#/
    break if ["__DATA__", "__END__"].member? word
    chunks += 1 
end

print "Found ", chunks, " chunks\n"
Modifying a File in Place with Temporary File

old = File.open(old_file)
new = File.open(new_file, "w")
while old.gets do
    # change $_, then...
    new.print $_
end
old.close
new.close
File.rename(old_file, "old.orig")
File.rename(new_file, old_file)

while old.gets do
    if $. == 20 then # we are at the 20th line
        new.puts "Extra line 1"
        new.puts "Extra line 2"
    end
    new.print $_
end

while old.gets do
    next if 20..30 # skip the 20th line to the 30th
                   # Ruby (and Perl) permit to write if 20..30 
                   # instead of if (20 <= $.) and ($. <= 30)
    new.print $_
end
Modifying a File in Place with -i Switch

#% ruby -i.orig -pe 'FILTER COMMAND' file1 file2 file3 ...
#
#-----------------------------
##!/usr/bin/ruby -i.orig -p
# filter commands go here
#-----------------------------

#% ruby -pi.orig -e 'gsub!(/DATE/){Time.now)'

# effectively becomes:
ARGV << 'I'
oldfile = ""
while gets
    if ARGF.filename != oldfile
        newfile = ARGF.filename
        File.rename(newfile, newfile + ".orig")
        $stdout = File.open(newfile,'w')
        oldfile = newfile
    end
    gsub!(/DATE/){Time.now}
    print 
end
$stdout = STDOUT
#-----------------------------
#% ruby -i.old -pe 'gsub!(%r{\bhisvar\b}, 'hervar')' *.[Cchy]

#-----------------------------
# set up to iterate over the *.c files in the current directory,
# editing in place and saving the old file with a .orig extension
$-i = '.orig'                       # set up -i mode
ARGV.replace(Dir['*.[Cchy]'])
while gets
    if $. == 1
        print "This line should appear at the top of each file\n"
    end
    gsub!(/\b(p)earl\b/i, '\1erl')    # Correct typos, preserving case
    print
    ARGF.close if ARGF.eof
end
Modifying a File in Place Without a Temporary File

File.open('itest', 'r+') do |f|   # open file for update
    lines = f.readlines           # read into array of lines
    lines.each do |it|            # modify lines
        it.gsub!(/foo/, 'QQQ')
    end
    f.pos = 0                     # back to start
    f.print lines                 # write out modified lines
    f.truncate(f.pos)             # truncate to new length
end                               # file is automatically closed
#-----------------------------
File.open('itest', 'r+') do |f|   
    out = ""
    f.each do |line|
        out << line.gsub(/DATE/) {Time.now}
    end
    f.pos = 0                     
    f.print out
    f.truncate(f.pos)             
end
Locking a File

File.open('infile', 'r+') do |f|
    f.flock File::LOCK_EX
    # update file
end
#-----------------------------
File::LOCK_SH     # shared lock (for reading)
File::LOCK_EX     # exclusive lock (for writing)
File::LOCK_NB     # non-blocking request
File::LOCK_UN     # free lock
#-----------------------------
unless f.flock File::LOCK_EX | File::LOCK_NB
    warn "can't get immediate lock: blocking ..."
    f.flock File::LOCK_EX 
end
#-----------------------------
File.open('numfile', File::RDWR|File::CREAT) do |f|
    f.flock(File::LOCK_EX)
    num = f.gets.to_i || 0
    f.pos = 0
    f.truncate 0
    f.puts num + 1q
end
Flushing Output

output_handle.sync = true
# Please note that like in Perl, $stderr is already unbuffered
#-----------------------------
#!/usr/bin/ruby -w
# seeme - demo stdio output buffering
$stdout.sync = ARGV.size > 0
print "Now you don't see it..."
sleep 2
puts "now you do"
#-----------------------------
$stderr.sync = true
afile.sync = false
#-----------------------------
# assume 'remote_con' is an interactive socket handle,
# but 'disk_file' is a handle to a regular file.
remote_con.sync = true       # unbuffer for clarity
disk_file.sync = false       # buffered for speed
#-----------------------------
require 'socket'
sock = TCPSocket.new('www.ruby-lang.org', 80)
sock.sync = true
sock.puts "GET /en/ HTTP/1.0 \n\n"
resp = sock.read
print "DOC IS: #{resp}\n"
Reading from Many Filehandles Without Blocking

#-----------------------------
# assumes fh1, fh2, fh2 are oen IO objects
nfound = select([$stdin, fh1, fh2, fh3], nil, nil, 0)
nfound[0].each do |file|
    case file
        when fh1
            # do something with fh1
        when fh2
            # do something with fh2
        when fh3
            # do something with fh3
    end
end
#-----------------------------
input_files = []
# repeat next line for all in-files to poll
input_files << fh1
if nfound = select(input_files, nil, nil, 0)
    # input ready on files in nfound[0]
end
Doing Non-Blocking I/O

# It throws exception on EOF, instead of sysread, you can use read_nonblock(), too.
begin
   File.open fname, (File::RDONLY | File::NONBLOCK) do |io|
     puts io.sysread(4096) # throws exception
   end
rescue EOFError
rescue IOError => e
   puts e.exception
rescue Errno::ENOENT
   puts "no such file #{fname}"
end

# return nil on EOF
begin
   File.open fname, (File::RDONLY | File::NONBLOCK) do |io|
     puts io.read(4096) # returns nil
   end
rescue Errno::ENOENT
   puts "no such file #{fname}"
end
Determining the Number of Bytes to Read

Storing Filehandles in Variables

# filehandles are normal variables, so they behave properly
def subroutine(fh):
  fh.print "Hello, file"
end

variable = fh
subroutine(variable)
Caching Open Output Filehandles

Printing to Many Filehandles Simultaneously

#----------------------------
filehandles.each do |filehandle|
  filehandle.print stuff_to_print
end
#----------------------------
# NOTE: this is unix specific
IO.popen("tee file1 file2 file3 >/dev/null", "w") do |many|
  many.puts "data"
end
#----------------------------
# (really a Perl issue here, no problem in ruby)
[fh1 fh2 fh3].each {|fh| fh.puts "whatever" }
#----------------------------
# redirect to stdout to use print/puts directly
$stdout = IO.popen("tee file1 file2 file3", "w")
puts "whatever"
$stdout.close
$stdout = STDOUT   # get things back to the way they were
#----------------------------
# create a class/object to encapsulate the behavior in ruby
class MultiDispatcher < BasicObject # inherit from BasicObject in 1.9.x only
 def initialize(targets)
   @targets = targets
 end

 def method_missing(*a,&b)
   @targets.each {|tgt| tgt.send(*a,&b)}
 end
end

md = MultiDispatcher.new [$stdout, $stderr]
4.times {|i| md.printf "%3d\n", i}
md.close



NaiveCampingRoutes ruby
module NaiveCampingRoutes
  extend self
  def R(url)
    route_lookup = routes
    klass = Class.new
    meta = class << klass; self; end
    meta.send(:define_method, :inherited) do |base| #klass类被继承时,触发inherited方法,base为子类
      raise "Already defined" if route_lookup[url]
      route_lookup[url] = base
    end
    klass
  end
  def routes
    @routes ||= {}
  end
  def process(url, params={})
    routes[url].new.get(params)
  end
end
module NaiveCampingRoutes
  class Hello < R '/hello'
    def get(params)
      puts "hello #{params[:name]}"
    end
  end
  class Goodbye < R '/goodbye'
    def get(params)
      puts "goodbye #{params[:name]}"
    end
  end
end
NaiveCampingRoutes.process('/hello', :name => "greg")
NaiveCampingRoutes.process('/goodbye', :name => "joe")
Ruby Pattern Matching ruby http://pleac.sourceforge.net/pleac_ruby/patternmatching.html
Introduction

# The verbose version are match, sub, gsub, sub! and gsub!;
# pattern needs to be a Regexp object; it yields a MatchData
# object.
pattern.match(string)
string.sub(pattern, replacement)
string.gsub(pattern, replacement)
# As usual in Ruby, sub! does the same as sub but also modifies
# the object, the same for gsub!/gsub.

# Sugared syntax yields the position of the match (or nil if no
# match). Note that the object at the right of the operator needs
# not to be a Regexp object (it can be a String). The "dont
# match" operator yields true or false.
meadow =~ /sheep/   # position of the match, nil if no match
meadow !~ /sheep/   # true if doesn't match, false if it does
# There is no sugared version for the substitution

meadow =~ /\bovines?\b/i and print "Here be sheep!"

string = "good food"
string.sub!(/o*/, 'e')

# % echo ababacaca | ruby -ne 'puts $& if /(a|ba|b)+(a|ac)+/'
# ababa

# The "global" (or "multiple") match is handled by String#scan
scan (/(\d+)/) {
    puts "Found number #{$1}"
}

# String#scan yields an Array if not used with a block
numbers = scan(/\d+/)

digits = "123456789"
nonlap = digits.scan(/(\d\d\d)/)
yeslap = digits.scan(/(?=(\d\d\d))/)
puts "Non-overlapping:  #{nonlap.join(' ')}"
puts "Overlapping:      #{yeslap.join(' ')}";
# Non-overlapping:  123 456 789
# Overlapping:      123 234 345 456 567 678 789

string = "And little lambs eat ivy"
string =~ /l[^s]*s/
puts "(#$`) (#$&) (#$')"
# (And ) (little lambs) ( eat ivy)
Copying and Substituting Simultaneously

# Ruby doesn't have the same problem:
dst = src.sub('this', 'that')

progname = $0.sub('^.*/', '')

bindirs = %w(/usr/bin /bin /usr/local/bin)
libdirs = bindirs.map { |l| l.sub('bin', 'lib') }
Matching Letters

Matching Words

/\S+/               # as many non-whitespace bytes as possible
/[A-Za-z'-]+/       # as many letters, apostrophes, and hyphens

/\b([A-Za-z]+)\b/   # usually best
/\s([A-Za-z]+)\s/   # fails at ends or w/ punctuation
Commenting Regular Expressions

require 'socket'
str = 'www.ruby-lang.org and www.rubygarden.org'
re = /
      (               # capture the hostname in $1
        (?:           # these parens for grouping only
          (?! [-_] )  # lookahead for neither underscore nor dash
          [\w-] +     # hostname component
          \.          # and the domain dot
        ) +           # now repeat that whole thing a bunch of times
        [A-Za-z]      # next must be a letter
        [\w-] +       # now trailing domain part
      )               # end of $1 capture
     /x               # /x for nice formatting

str.gsub! re do       # pass a block to execute replacement
    host = TCPsocket.gethostbyname($1)
    "#{$1} [#{host[3]}]"
end

puts str
#-----------------------------
# to match whitespace or #-characters in an extended re you need to escape
# them.

foo = 42
str = 'blah #foo# blah'
str.gsub! %r/       # replace
              \#    #   a pound sign
              (\w+) #   the variable name
              \#    #   another pound sign
          /x do
              eval $1           # with the value of a local variable
          end
puts str  # => blah 42 blah
Finding the Nth Occurrence of a Match

# The 'g' modifier doesn't exist in Ruby, a regexp can't be used
# directly in a while loop; instead, use String#scan { |match| .. } 
fish = 'One fish two fish red fish blue fish'
WANT = 3
count = 0
fish.scan(/(\w+)\s+fish\b/i) {
    if (count += 1) == WANT
        puts "The third fish is a #{$1} one."
    end
}

if fish =~ /(?:\w+\s+fish\s+){2}(\w+)\s+fish/i
    puts "The third fish is a #{$1} one."
end

pond = 'One fish two fish red fish blue fish'
# String#scan without a block gives an array of matches, each match
# being an array of all the specified groups
colors = pond.scan(/(\w+)\s+fish\b/i).flatten  # get all matches
color  = colors[2]                          # then the one we want
# or without a temporary array
color = pond.scan(/(\w+)\s+fish\b/i).flatten[2]  # just grab element 3
puts "The third fish in the pond is #{color}."

count = 0
fishes = 'One fish two fish red fish blue fish'
evens = fishes.scan(/(\w+)\s+fish\b/i).select { (count+=1) % 2 == 0 }
print "Even numbered fish are #{evens.join(' ')}."

count = 0
fishes.gsub(/
   \b               # makes next \w more efficient
   ( \w+ )          # this is what we\'ll be changing
   (
     \s+ fish \b
   )
            /x) {
    if (count += 1) == 4
        'sushi' + $2
    else
        $1 + $2
    end
}

pond = 'One fish two fish red fish blue fish swim here.'
puts "Last fish is #{pond.scan(/\b(\w+)\s+fish\b/i).flatten[-1]}"

/
    A               # find some pattern A
    (?!             # mustn\'t be able to find
        .*          # something
        A           # and A
    )
    $               # through the end of the string
/x

# The "s" perl modifier is "m" in Ruby (not very nice since there is
# also an "m" in perl..)
pond = "One fish two fish red fish blue fish swim here."
if (pond =~ /
                    \b  (  \w+) \s+ fish \b
                (?! .* \b fish \b )
            /mix)
    puts "Last fish is #{$1}."
else
    puts "Failed!"
end
Matching Multiple Lines

#-----------------------------
#!/usr/bin/ruby -w
# killtags - very bad html killer
$/ = nil;                              # each read is whole file
while file = gets() do
    file.gsub!(/<.*?>/m,'');           # strip tags (terribly)
    puts file                          # print file to STDOUT
end
#-----------------------------
#!/usr/bin/ruby -w
#headerfy - change certain chapter headers to html
$/ = ''
while file = gets() do
    pattern = /
                  \A                   # start of record
                  (                    # capture in $1
                      Chapter          # text string
                      \s+              # mandatory whitespace
                      \d+              # decimal number
                      \s*              # optional whitespace
                      :                # a real colon
                      . *              # anything not a newline till end of line
                  )
               /x
    puts file.gsub(pattern,'<H1>\1</H1>')
end
#-----------------------------
#% ruby -00pe "gsub!(/\A(Chapter\s+\d+\s*:.*)/,'<H1>\1</H1>')" datafile

#!/usr/bin/ruby -w
#-----------------------------
for file in ARGV
    file = File.open(ARGV.shift)
    while file.gets('') do             # each read is a paragraph
        print "chunk #{$.} in $ARGV has <<#{$1}>>\n" while /^START(.*?)^END/m
    end                                # /m activates the multiline mode
end
#-----------------------------
Reading Records with a Pattern Separator

#-----------------------------
$/ = nil;
file = File.open("datafile")
chunks = file.gets.split(/pattern/)
#-----------------------------
# .Ch, .Se and .Ss divide chunks of STDIN
chunks = gets(nil).split(/^\.(Ch|Se|Ss)$/)
print "I read #{chunks.size} chunks.\n"
#-----------------------------
Extracting a Range of Lines

while gets
    if ~/BEGIN/ .. ~/END/
        # line falls between BEGIN and END inclusive
    end
end

while gets
    if ($. == firstnum) .. ($. == lastnum)
        # operate between firstnum and lastnum line number
    end
end

# in ruby versions prior to 1.8, the above two conditional
# expressions could be shortened to:
#     if /BEGIN/ .. /END/
# and
#     if firstnum .. lastnum
# but these now only work this way from the command line  

#-----------------------------

while gets
    if ~/BEGIN/ ... ~/END/
        # line falls between BEGIN and END on different lines
    end
end

while gets
    if ($. == first) ... ($. == last)
        # operate between first and last line number on different lines
    end
end

#-----------------------------
# command-line to print lines 15 through 17 inclusive (see below)
ruby -ne 'print if 15 .. 17' datafile

# print out all <XMP> .. </XMP> displays from HTML doc
while gets
    print if ~%r#<XMP>#i .. ~%r#</XMP>#i;
end
    
# same, but as shell command
# ruby -ne 'print if %r#<XMP>#i .. %r#</XMP>#i' document.html
#-----------------------------
# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \
#     print if $top .. $bottom' /etc/passwd                 #  FAILS
# ruby -ne 'BEGIN { $top=3; $bottom=5 }; \
#     print if $. == $top .. $. ==  $bottom' /etc/passwd    # works
# ruby -ne 'print if 3 .. 5' /etc/passwd                    # also works
#-----------------------------
print if ~/begin/ .. ~/end/;
print if ~/begin/ ... ~/end/;
#-----------------------------
while gets
    $in_header = $. == 1  .. ~/^$/ ? true : false
    $in_body   = ~/^$/ .. ARGF.eof ? true : false
end
#-----------------------------
seen = {}
ARGF.each do |line|
    next unless line =~ /^From:?\s/i .. line =~ /^$/;
    line.scan(%r/([^<>(),;\s]+\@[^<>(),;\s]+)/).each do |addr|
        puts addr unless seen[addr]
        seen[addr] ||= 1 
    end
end
Matching Shell Globs as Regular Expressions

def glob2pat(globstr)
    patmap = {
        '*' => '.*',
        '?' => '.',
        '[' => '[',
        ']' => ']',
    }
    globstr.gsub!(/(.)/) { |c| patmap[c] || Regexp::escape(c) }
    '^' + globstr + '$'
end
Speeding Up Interpolated Matches

# avoid interpolating patterns like this if the pattern
# isn't going to change:
pattern = ARGV.shift
ARGF.each do |line|
    print line if line =~ /#{pattern}/
end

# the above creates a new regex each iteration. Instead,
# use the /o modifier so the regex is compiled only once

pattern = ARGV.shift
ARGF.each do |line|
    print line if line =~ /#{pattern}/o
end

#-----------------------------

#!/usr/bin/ruby
# popgrep1 - grep for abbreviations of places that say "pop"
# version 1: slow but obvious way
popstates = %w(CO ON MI WI MN)
ARGF.each do |line|
    popstates.each do |state|
        if line =~ /\b#{state}\b/
            print line
            last
        end
    end
end

#-----------------------------
#!/usr/bin/ruby
# popgrep2 - grep for abbreviations of places that say "pop"
# version 2: eval strings; fast but hard to quote
popstates = %w(CO ON MI WI MN)
code = "ARGF.each do |line|\n"
popstates.each do |state|
    code += "\tif line =~ /\\b#{state}\\b/; print(line); next; end\n"
end
code += "end\n"
print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging
eval code

# CODE IS
# ---
# ARGF.each do |line|
#         if line =~ /\bCO\b/; print(line); next; end
#         if line =~ /\bON\b/; print(line); next; end
#         if line =~ /\bMI\b/; print(line); next; end
#         if line =~ /\bWI\b/; print(line); next; end
#         if line =~ /\bMN\b/; print(line); next; end
# end
# 
# ---

## alternatively, the same idea as above but compiling 
## to a case statement: (not in perlcookbook)
#!/usr/bin/ruby -w
# popgrep2.5 - grep for abbreviations of places that say "pop"
# version 2.5: eval strings; fast but hard to quote
popstates = %w(CO ON MI WI MN)
code = "ARGF.each do |line|\n    case line\n"
popstates.each do |state|
    code += "        when /\\b#{state}\\b/ : print line\n"
end
code += "    end\nend\n"
print "CODE IS\n---\n#{code}\n---\n" if false # turn on for debugging
eval code

# CODE IS
# ---
# ARGF.each do |line|
#     case line
#         when /\bCO\b/ : print line
#         when /\bON\b/ : print line
#         when /\bMI\b/ : print line
#         when /\bWI\b/ : print line
#         when /\bMN\b/ : print line
#     end
# end
# 
# ---

# Note: (above) Ruby 1.8+ allows the 'when EXP : EXPR' on one line
# with the colon separator.

#-----------------------------
#!/usr/bin/ruby
# popgrep3 - grep for abbreviations of places that say "pop"
# version3: build a match_any function
popstates = %w(CO ON MI WI MN)
expr = popstates.map{|e|"line =~ /\\b#{e}\\b/"}.join('||')
eval "def match_any(line); #{expr};end"
ARGF.each do |line|
    print line if match_any(line)
end
#-----------------------------

##  building a match_all function is a trivial
##  substitution of && for ||
##  here is a generalized example:
#!/usr/bin/ruby -w
## grepauth - print lines that mention both foo and bar
class MultiMatch 
    def initialize(*patterns)
        _any = build_match('||',patterns)
        _all = build_match('&&',patterns)
        eval "def match_any(line);#{_any};end\n"
        eval "def match_all(line);#{_all};end\n"
      end
    def build_match(sym,args)
        args.map{|e|"line =~ /#{e}/"}.join(sym)
    end
end

mm = MultiMatch.new('foo','bar')
ARGF.each do |line|
    print line if mm.match_all(line)
end
#-----------------------------

#!/usr/bin/ruby
# popgrep4 - grep for abbreviations of places that say "pop"
# version4: pretty fast, but simple: compile all re's first:
popstates = %w(CO ON MI WI MN)
popstates = popstates.map{|re| %r/\b#{re}\b/}
ARGF.each do |line|
    popstates.each do |state_re|
        if line =~ state_re
            print line
            break
        end
    end
end

## speeds trials on the jargon file(412): 26006 lines, 1.3MB
## popgrep1   => 7.040s
## popgrep2   => 0.656s
## popgrep2.5 => 0.633s
## popgrep3   => 0.675s
## popgrep4   => 1.027s

# unless speed is criticial, the technique in popgrep4 is a
# reasonable balance between speed and logical simplicity.
Testing for a Valid Pattern

begin
    print "Pattern? "
    pat = $stdin.gets.chomp
    Regexp.new(pat)
rescue 
    warn "Invalid Pattern"
    retry
end
Honoring Locale Settings in Regular Expressions

Approximate Matching

# uses the 'amatch' extension found on:
# http://raa.ruby-lang.org/project/amatch/
require 'amatch'
matcher = Amatch.new('balast')
#$relative, $distance = 0, 1
File.open('/usr/share/dict/words').each_line do |line|
    print line if matcher.search(line) <= 1
end
__END__
ballast
ballasts
balustrade
balustrades
blast
blasted
blaster
blasters
blasting
blasts
Matching from Where the Last Pattern Left Off

str.scan(/\G(\d)/).each do |token|
    puts "found #{token}"
end
#-----------------------------
n = "   49 here"
n.gsub!(/\G /,'0')
puts n
#-----------------------------
str = "3,4,5,9,120"
str.scan(/\G,?(\d+)/).each do |num|
    puts "Found number: #{num}"
end
#-----------------------------
# Ruby doesn't have the String.pos or a /c re modifier like Perl 
# But it does have StringScanner in the standard library (strscn)
# which allows similar functionality:

require 'strscan'
text = 'the year 1752 lost 10 days on the 3rd of September'
sc = StringScanner.new(text)
while sc.scan(/.*?(\d+)/)
    print "found: #{sc[1]}\n"   
end
if sc.scan(/\S+/)
    puts "Found #{sc[0]} after last number"
end
#-----------------------------
# assuming continuing from above:
puts "The position in 'text' is: #{sc.pos}"
sc.pos = 30
puts "The position in 'text' is: #{sc.pos}"
Greedy and Non-Greedy Matches

#-----------------------------
# greedy pattern
str.gsub!(/<.*>/m,'')   # not good

# non-greedy (minimal) pattern
str.gsub!(/<.*?>/m,'')   # not great


#-----------------------------
#<b><i>this</i> and <i>that</i> are important</b> Oh, <b><i>me too!</i></b>
#-----------------------------
%r{ <b><i>(.*?)</i></b> }mx
#-----------------------------
%r/BEGIN((?:(?!BEGIN).)*)END/
#-----------------------------
%r{ <b><i>(  (?: (?!</b>|</i>). )*  ) </i></b> }mx
#-----------------------------
%r{ <b><i>(  (?: (?!</[ib]>). )*  ) </i></b> }mx
#-----------------------------
%r{
    <b><i> 
    [^<]*  # stuff not possibly bad, and not possibly the end.
    (?:
 # at this point, we can have '<' if not part of something bad
     (?!  </?[ib]>  )   # what we can't have
     <                  # okay, so match the '<'
     [^<]*              # and continue with more safe stuff
    ) *
    </i></b>
 }mx
Detecting Duplicate Words

#-----------------------------
$/ = ""
ARGF.each do |para|
    para.scan %r/
                  \b     # start at word boundary
                  (\S+)  # find chunk of non-whitespace
                  \b     # until a word boundary
                  (      
                    \s+  # followed by whitespace
                    \1   # and that same chunk again
                    \b   # and a word boundary
                  ) +    # one or more times
                /xi do
        puts "dup word '#{$1}' at paragraph #{$.}" 
    end
end
#-----------------------------
astr = 'nobody'
bstr = 'bodysnatcher'
if "#{astr} #{bstr}" =~ /^(\w+)(\w+) \2(\w+)$/
    print "#{$2} overlaps in #{$1}-#{$2}-#{$3}"
end
#-----------------------------
#!/usr/bin/ruby -w
# prime_pattern -- find prime factors of argument using patterns
ARGV << 180
cap = 'o' * ARGV.shift
while cap =~ /^(oo+?)\1+$/
    print $1.size, " "
    cap.gsub!(/#{$1}/,'o')
end
puts cap.size
#-----------------------------
#diophantine
# solve for 12x + 15y + 16z = 281, maximizing x
if ('o' * 281).match(/^(o*)\1{11}(o*)\2{14}(o*)\3{15}$/)
    x, y, z = $1.size, $2.size, $3.size
    puts "One solution is: x=#{x}; y=#{y}; z=#{z}"
else 
    puts "No solution."
end
#    => One solution is: x=17; y=3; z=2

#-----------------------------
# using different quantifiers:
('o' * 281).match(/^(o+)\1{11}(o+)\2{14}(o+)\3{15}$/)
#    => One solution is: x=17; y=3; z=2

('o' * 281).match(/^(o*?)\1{11}(o*)\2{14}(o*)\3{15}$/)
#    => One solution is: x=0; y=7; z=11

('o' * 281).match(/^(o+?)\1{11}(o*)\2{14}(o*)\3{15}$/)
#    => One solution is: x=1; y=3; z=14
Expressing AND, OR, and NOT in a Single Pattern

# alpha OR beta
%r/alpha|beta/

# alpha AND beta
%r/(?=.*alpha)(?=.*beta)/m

# alpha AND beta,  no overlap
%r/alpha.*beta|beta.*alpha/m

# NOT beta
%r/^(?:(?!beta).)*$/m

# NOT bad BUT good
%r/(?=(?:(?!BAD).)*$)GOOD/m
#-----------------------------

if !(string =~ /pattern/)   # ugly
    something()
end

if string !~ /pattern/   # preferred
    something()
end


#-----------------------------
if string =~ /pat1/  && string =~ /pat2/
    something()
end
#-----------------------------
if string =~ /pat1/ || string =~ /pat2/
    something()
end
#-----------------------------
#!/usr/bin/ruby -w
# minigrep - trivial grep
pat = ARGV.shift
ARGF.each do |line|
    print line if line =~ /#{pat}/o
end
#-----------------------------
 "labelled" =~ /^(?=.*bell)(?=.*lab)/m
#-----------------------------
$string =~ /bell/ && $string =~ /lab/
#-----------------------------
$murray_hill = "blah bell blah "
if $murray_hill =~ %r{
                         ^              # start of string
                        (?=             # zero-width lookahead
                            .*          # any amount of intervening stuff
                            bell        # the desired bell string
                        )               # rewind, since we were only looking
                        (?=             # and do the same thing
                            .*          # any amount of intervening stuff
                            lab         # and the lab part
                        )
                     }mx                # /m means . can match newline

    print "Looks like Bell Labs might be in Murray Hill!\n";
end
#-----------------------------
"labelled" =~ /(?:^.*bell.*lab)|(?:^.*lab.*bell)/
#-----------------------------
$brand = "labelled";
if $brand =~ %r{
                (?:                 # non-capturing grouper
                    ^ .*?           # any amount of stuff at the front
                      bell          # look for a bell
                      .*?           # followed by any amount of anything
                      lab           # look for a lab
                  )                 # end grouper
            |                       # otherwise, try the other direction
                (?:                 # non-capturing grouper
                    ^ .*?           # any amount of stuff at the front
                      lab           # look for a lab
                      .*?           # followed by any amount of anything
                      bell          # followed by a bell
                  )                 # end grouper
            }mx                     # /m means . can match newline
    print "Our brand has bell and lab separate.\n";
end
#-----------------------------
$map =~ /^(?:(?!waldo).)*$/s
#-----------------------------
$map = "the great baldo"
if $map =~ %r{
                ^                   # start of string
                (?:                 # non-capturing grouper
                    (?!             # look ahead negation
                        waldo       # is he ahead of us now?
                    )               # is so, the negation failed
                    .               # any character (cuzza /s)
                ) *                 # repeat that grouping 0 or more
                $                   # through the end of the string
             }mx                    # /m means . can match newline
    print "There's no waldo here!\n";
end
#-----------------------------
 7:15am  up 206 days, 13:30,  4 users,  load average: 1.04, 1.07, 1.04

USER     TTY      FROM              LOGIN@  IDLE   JCPU   PCPU  WHAT

tchrist  tty1                       5:16pm 36days 24:43   0.03s  xinit

tchrist  tty2                       5:19pm  6days  0.43s  0.43s  -tcsh

tchrist  ttyp0    chthon            7:58am  3days 23.44s  0.44s  -tcsh

gnat     ttyS4    coprolith         2:01pm 13:36m  0.30s  0.30s  -tcsh
#-----------------------------
#% w | minigrep '^(?!.*ttyp).*tchrist'
#-----------------------------
%r{
    ^                       # anchored to the start
    (?!                     # zero-width look-ahead assertion
        .*                  # any amount of anything (faster than .*?)
        ttyp                # the string you don't want to find
    )                       # end look-ahead negation; rewind to start
    .*                      # any amount of anything (faster than .*?)
    tchrist                 # now try to find Tom
}x
#-----------------------------
#% w | grep tchrist | grep -v ttyp
#-----------------------------
#% grep -i 'pattern' files
#% minigrep '(?i)pattern' files
#-----------------------------
Matching Multiple-Byte Characters

Matching a Valid Mail Address

#-----------------------------
# basically, the Perl Cookbook categorizes this as an
# unsolvable problem ...
#-----------------------------
1 while addr.gsub!(/\([^()]*\)/,'')
#-----------------------------
Dear someuser@host.com,

Please confirm the mail address you gave us Wed May  6 09:38:41
MDT 1998 by replying to this message.  Include the string
"Rumpelstiltskin" in that reply, but spelled in reverse; that is,
start with "Nik...".  Once this is done, your confirmed address will
be entered into our records.
Matching Abbreviations

ans = $stdin.gets.chomp
re = %r/^#{Regexp.quote(ans)}/
case 
    when "SEND"  =~ re : puts "Action is send"
    when "STOP"  =~ re : puts "Action is stop"
    when "ABORT" =~ re : puts "Action is abort"
    when "EDIT"  =~ re : puts "Action is edit"
end
#-----------------------------
require 'abbrev'
table = Abbrev.abbrev %w-send stop abort edit-
loop do
    print "Action: "
    ans = $stdin.gets.chomp
    puts "Action for #{ans} is #{table[ans.downcase]}"
end


#-----------------------------
# dummy values are defined for 'file', 'PAGER', and
# the 'invoke_editor' and 'deliver_message' methods
# do not do anything interesting in this example.
#!/usr/bin/ruby -w
require 'abbrev'

file = 'pleac_ruby.data'
PAGER = 'less'

def invoke_editor
    puts "invoking editor"
end

def deliver_message
    puts "delivering message"
end

actions = {
    'edit'  => self.method(:invoke_editor),
    'send'  => self.method(:deliver_message),
    'list'  => proc {system(PAGER, file)},
    'abort' => proc {puts "See ya!"; exit},
    ""      => proc {puts "Unknown Command"}
}

dtable = Abbrev.abbrev(actions.keys)
loop do
    print "Action: "
    ans = $stdin.gets.chomp.delete(" \t")
    actions[ dtable[ans.downcase] || "" ].call
end
Program: urlify

#-----------------------------
#% gunzip -c ~/mail/archive.gz | urlify > archive.urlified
#-----------------------------
#% urlify ~/mail/*.inbox > ~/allmail.urlified
#-----------------------------
#!/usr/bin/ruby -w
# urlify - wrap HTML links around URL-like constructs

urls = '(https?|telnet|gopher|file|wais|ftp)';
ltrs = '\w';
gunk = '/#~:.?+=&%@!\-';
punc = '.:?\-';
any  = "#{ltrs}#{gunk}#{punc}";

ARGF.each do |line|
    line.gsub! %r/
        \b                    # start at word boundary
        (                     # begin $1  {
         #{urls}     :        # need resource and a colon
         [#{any}] +?          # followed by on or more
                              #  of any valid character, but
                              #  be conservative and take only
                              #  what you need to....
        )                     # end   $1  }
        (?=                   # look-ahead non-consumptive assertion
         [#{punc}]*           # either 0 or more punctuation
         [^#{any}]            #   followed by a non-url char
         |                    # or else
         $                    #   then end of the string
        )
    /iox do 
        %Q|<A HREF="#{$1}">#{$1}</A>|
    end
    print line
end
Program: tcgrep

Regular Expression Grabbag

%r/^m*(d?c{0,3}|c[dm])(l?x{0,3}|x[lc])(v?i{0,3}|i[vx])$/i
#-----------------------------
str.sub!(/(\S+)(\s+)(\S+)/, '\3\2\1')
#-----------------------------
%r/(\w+)\s*=\s*(.*)\s*$/             # keyword is $1, value is $2
#-----------------------------
%r/.{80,}/
#-----------------------------
%r|(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)|
#-----------------------------
str.gsub!(%r|/usr/bin|,'/usr/local/bin')
#-----------------------------
str.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/){ $1.hex.chr }
#-----------------------------
str.gsub!(%r{
    /\*                    # Match the opening delimiter
    .*?                    # Match a minimal number of characters
    \*/                    # Match the closing delimiter
}xm,'')
#-----------------------------
str.sub!(/^\s+/, '')
str.sub!(/\s+$/, '')

# but really, in Ruby we'd just do:
str.strip!
#-----------------------------
str.gsub!(/\\n/,"\n")
#-----------------------------
str.sub!(/^.*::/, '')
#-----------------------------
%r/^([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])\.
    ([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])$/x
#-----------------------------
str.sub!(%r|^.*/|, '')
#-----------------------------
cols = ( (ENV['TERMCAP'] || " ") =~ /:co#(\d+):/ ) ? $1 : 80;
#-----------------------------
name = " #{$0} #{ARGV}".gsub(%r| /\S+/|, ' ')
#-----------------------------
require 'rbconfig'
include Config
raise "This isn't Linux" unless CONFIG['target_os'] =~ /linux/i;
#-----------------------------
str.gsub!(%r/\n\s+/, ' ')
#-----------------------------
nums = str.scan(/(\d+\.?\d*|\.\d+)/)
#-----------------------------
capwords = str.scan(%r/(\b[^\Wa-z0-9_]+\b)/)
#-----------------------------
lowords = str.scan(%r/(\b[^\WA-Z0-9_]+\b)/)
#-----------------------------
icwords = str.scan(%r/(\b[^\Wa-z0-9_][^\WA-Z0-9_]*\b)/)
#-----------------------------
links = str.scan(%r/<A[^>]+?HREF\s*=\s*["']?([^'" >]+?)[ '"]?>/mi)   #'
#-----------------------------
initial = str =~ /^\S+\s+(\S)\S*\s+\S/ ? $1 : ""
#-----------------------------
str.gsub!(%r/"([^"]*)"/, %q-``\1''-)   #"
#-----------------------------

$/ = ""
sentences = []
ARGF.each do |para|
    para.gsub!(/\n/, ' ')
    para.gsub!(/ {3,}/,'  ')
    sentences << para.scan(/(\S.*?[!?.])(?=  |\Z)/)
end

#-----------------------------
%r/(\d{4})-(\d\d)-(\d\d)/            # YYYY in $1, MM in $2, DD in $3
#-----------------------------
%r/ ^
      (?:
       1 \s (?: \d\d\d \s)?            # 1, or 1 and area code
       |                               # ... or ...
       \(\d\d\d\) \s                   # area code with parens
       |                               # ... or ...
       (?: \+\d\d?\d? \s)?             # optional +country code
       \d\d\d ([\s\-])                 # and area code
      )
      \d\d\d (\s|\1)                   # prefix (and area code separator)
      \d\d\d\d                         # exchange
        $
 /x
#-----------------------------
%r/\boh\s+my\s+gh?o(d(dess(es)?|s?)|odness|sh)\b/i
#-----------------------------
lines = []
lines << $1 while input.sub!(/^([^\012\015]*)(\012\015?|\015\012?)/,'')
Grep in Ruby ruby http://zigzag.github.com/2010/03/31/grep-in-ruby----a-powerful-enumerable-method.html
If you were a Unix shell fan, I bed that the “grep” command would be in your top-used list. But as for the Ruby programming, are you still prefer “grep” to the other methods come with the “Enumerable” module?
Do you know in most of the situation, using “grep” is more handy and powerful than the commonly used “map” or “select” methods? I will try to unveil the power of “grep” method in this post.

First of all, let’s review what “grep” do for an Enumerable object:
(Quoted from the Rdoc document of Ruby)

    enum.grep(pattern)                   => array 
    enum.grep(pattern) {| obj | block }  => array 
    Returns an array of every element in enum for which Pattern === element.
    If the optional block is supplied, each matching element is passed to it,
    and the block's result is stored in the output array.  
Simple enough,right? Here I will show you some convenient use cases:

Simpler select – Filtering by pattern matching rather than giving a block to “select”.
Most of the time, we use the “select” method for filtering the elements in an Enumerable object by giving a block as criterion. Such as using ['a','1','b'].select{|x| /^\d*$/ === x} to filter out the numeric string. But by applying “grep” method with a Regexp pattern instead of a block, we get a shorter version: ['a','1','b'].grep(/^\d*$/). This shortcut not only works for the RegExp pattern matching, But also works for all objects that overwrote the “===” method. Such as “Range” and “Class”. Therefore we can easily filter out elements like:

[1,10,100,1000].grep(1..100) # => [1, 10, 100]
[1,'a',2,'b'].grep(Integer) # => [1,2]
It is very easy to customize your filtering as well, just have you categorization logic defined as case equal(“===”) in your own class, then the instances of that class can be easily filtered out from an Enumerable object using the “grep” method.

Easier transforming using grep with Regexp and $n
It is not uncommon that we need to select some elements from a String collection according to some pattern and want to strip out part of the origin. Like the below example:
Given a String Array like ['hello.rb','world.rb','public.html'], and what we expected is the Ruby files without the extension name like: ['hello','world'].
Without thinking it too much, we can achieve this goal by combining the “select” and “map” methods just like #1 line below. But after we get familiar with the “grep” method and convention of the Regexp, we can have a more compact and elegant expression like #2 line:

['hello.rb','world.rb','public.html'].select{|x|x=~/\.rb/}.map{|x|x[0..-4]}
['hello.rb','world.rb','public.html'].grep(/(.*)\.rb/){$1}
Selective bulk transforming – combination of “select” and “map”
Among the Ruby methods of Enumerable, normally we use “select” for filtering and use “map” for bulk transforming. But as the examples showed before, the “grep” method can act as a combination of those two methods. Here it is called “selective bulk transforming”. A simple example is to pickup the numeric string and transfer them into Integer instances. See the following two versions for comparison:

['a','1','b','2'].select{|x| /^\d*$/ === x}.map{|x| x.to_i}
['a','1','b','2'].grep(/^\d*$/){|x| x.to_i}
Or, even we make them shorter by the &symbol block, the version using “grep” looks more lovely:

['a','1','b','2'].select{|x| /^\d*$/ === x}.map(&:to_i)
['a','1','b','2'].grep(/^\d*$/,&:to_i)
Conclusion
Although the definition and implementation of the “grep” method from Enumerable module is simple, but by combing with other Ruby expression like case equal(“===”), Regexp, and “&symbol” block, It become a very handy and powerful method. Therefore next time when you come across some situation need to use “select + map”, keep “grep” in your mind beforehand.
my vimrc vim
call pathogen#infect()
syntax on
filetype plugin indent on
set cf  " Enable error files & error jumping.
set clipboard+=unnamed  " Yanks go on clipboard instead.
set history=256  " Number of things to remember in history.
set autowrite  " Writes on make/shell commands
set ruler  " Ruler on
set nu  " Line numbers on
set nowrap  " Line wrapping off
set timeoutlen=250  " Time to wait after ESC (default causes an annoying delay)
" colorscheme vividchalk  " Uncomment this to set a default theme
 
" Formatting (some of these are for coding in C and C++)
set ts=2  " Tabs are 2 spaces
set bs=2  " Backspace over everything in insert mode
set shiftwidth=2  " Tabs under smart indent
set nocp incsearch
set cinoptions=:0,p0,t0
set cinwords=if,else,while,do,for,switch,case
set formatoptions=tcqr
set cindent
set autoindent
set smarttab
set expandtab
 
" Visual
set showmatch  " Show matching brackets.
set mat=5  " Bracket blinking.
set list
" Show $ at end of line and trailing space as ~
set lcs=tab:\ \ ,eol:$,trail:~,extends:>,precedes:<
set novisualbell  " No blinking .
set noerrorbells  " No noise.
set laststatus=2  " Always show status line.
 
" gvim specific
set mousehide  " Hide mouse after chars typed
set mouse=a  " Mouse in all modes
if has("gui_running") 
  color molokai
endif
instance_method ruby
defined = User.instance_method(:nothis) rescue false
p defined
#如果String没有nothis方法,则defined=false。否则返回UnboundMethod。
defined = User.instance_method(:length) rescue false
p defined.bind('china').call #=>5
Stubber ruby
#静态生成某个实例的特有方法
class User;end
user = User.new
def user.logged_in?
  true
end

#动态生成
module Stubber
	extend self

	def stubs(method, options={})
		singleton(options[:for]).send(:define_method, method) do |*a|
			options[:returns]
		end
	end

	def singleton obj
		class << obj; self; end
	end
end


user = User.new
Stubber.stubs(:logged_in?, for: user, returns: true)
p user.logged_in? #=> true
p User.new.logged_in? #=>undefined method `logged_in?'
instance_eval ruby
class Peron
	attr_accessor :name
	def initialize name
		@name = name
	end
	def say w
		puts w
	end
end

pp = Peron.new 'war'

pp.instance_eval do
	say 'hello'
	puts @name
end
###另一个例子

pdf = Prawn::Document.new
pdf.text "Hello World"
pdf.render_file "hello.pdf"

#转成

Prawn::Document.generate("hello.pdf") do
  text "Hello World"
end


class Prawn::Document
  def self.generate(file, *args, &block)
    pdf = Prawn::Document.new(*args)
    pdf.instance_eval(&block)
    pdf.render_file(file)
  end
end
#但这种方式对以下例子不适用。

class MyBestFriend
  def initialize
    @first_name = "Paul"
    @last_name = "Mouzas"
  end
  def full_name
    "#{@first_name} #{@last_name}"
  end
  def generate_pdf
    Prawn::Document.generate("friend.pdf") do
      text "My best friend is #{full_name}" #有变量在这里
    end
  end
end
#变通方式
class Prawn::Document
  def self.generate(file, *args, &block)
    pdf = Prawn::Document.new(*args)
    block.arity < 1 ? pdf.instance_eval(&block) : block.call(pdf)
    pdf.render_file(file)
  end
end

class MyOtherBestFriend
  def initialize
    @first_name = "Pete"
    @last_name = "Johansen"
  end
  def full_name
    "#{@first_name} #{@last_name}"
  end
  def generate_pdf
    Prawn::Document.generate("friend.pdf") do |doc| #这里加参数
      doc.text "My best friend is #{full_name}"
    end
  end
end


StringScanner ruby
require 'strscan'
  input = 'ddfaa123foo 123'
  scanner = StringScanner.new(input)
  p scanner.scan(/\d+/)   #=> 从字符串开始的位置匹配,字符串开始不是数字所以为nil
  p scanner.scan_until(/\d+/)   #=> ddfaa123
  p scanner.pre_match #ddfaa
  p scanner.pos #=> 8

def parse_inline_styles(text)
  segments = text.split( %r{(</?.*?>)} ).reject {|x| x.empty? }
  segments.size == 1 ? segments.first : segments
end

p parse_inline_styles 'Hello <indigo>Ch</b>arl</b>ie</indigo>'
#=>["Hello ", "<indigo>", "Ch", "</b>", "arl", "</b>", "ie", "</indigo>"]
ruby元编程 ruby http://deathking.is-programmer.com/posts/24125
反射#kind_of?方法和is_a?方法是同义词
module M; end
class A; include M; end
class B < A; end
class C < B; end
 
b = B.new
b.instance_of? A  #=> false
b.instance_of? B  #=> true
b.instance_of? C  #=> false
b.instance_of? M  #=> false
 
b.kind_of? A      #=> true
b.kind_of? B      #=> true
b.kind_of? C      #=> false
b.kind_of? M      #=> true
B.included_modules #=>[M, Kernel]
B.ancestors #=>[B, A, M, Object, Kernel, BasicObject]

Kernel模块提供的local_variables、global_variables、Object类提供的instance_variab
irb(main):042:0> def i_am_a_temp_method
irb(main):043:1>   temp_var = 1
irb(main):044:1>   puts local_variables
irb(main):045:1> end
=> nil
 
irb(main):046:0> local_variables
=> [:b, :_]
irb(main):047:0> i_am_a_temp_method
temp_var
=> nil
  global_variables方法返回全局变量(Global Variable)。

irb(main):048:0> global_variables
=>[:$;, :$-F, :$@, :$!, :$SAFE, :$~, :$&, :$`, :$', :$+, :$=, :$KCODE, :$-K, :$,, :$/, :$-0, :$\, :$_, :$stdin, :$stdout, :$stderr, :$>, :$<, :$., :$FILENAME,:$-i, :$*, :$?, :$$, :$:, :$-I, :$LOAD_PATH, :$", :$LOADED_FEATURES, :$VERBOSE,:$-v, :$-w, :$-W, :$DEBUG, :$-d, :$0, :$PROGRAM_NAME, :$-p, :$-l, :$-a, :$binding, :$1, :$2, :$3, :$4, :$5, :$6, :$7, :$8, :$9]
les以及Module模块的constants方法,都大有用途。

  local_variables方法以数组的方式(元素是符号,1.9.X特性)返回建立的局部变量,不过受到作用域的限制。

为了做示范,我们得初始化一个实例变量(Instance Variable)。

?
1
2
3
4
5
6
7
irb(main):052:0>class A
irb(main):053:1>  @yet_another_instance_variables = 0
irb(main):054:1>end
=> nil
 
irb(main):055:0>A. instance_variables
=> [:@yet_another_instance_variables]
  反射出类中的常量,以Math模块快速示范:
irb(main):056:0> Math.constants
=> [:PI, :E]
  反射机制还有一个功能,可以列出对象的一些行为(方法),做了一些省略:
irb(main):001:0> 1.methods
=>[:to_s, :-@, :+, :-, :*, :/, :div, :%, :modulo, :divmod, :fdiv, :**, :abs, :magnitude, :==, :<=>, :>, :>=, :<, :<=, :~, :&, :|, :^, :[], :<<, :>>, :to_f, :size, :zero?, :odd?, :even?, :succ, :integer?, :upto, :downto, :times, :next, :pred, :chr, :ord, ...
Object#methods方法用数组的方式返回对象所拥有的方法,包括从祖先那里继承来的方法。而Class#instance_methods则是返回由类实例化的对象能拥有的方法,请与methods方法区分。
instance_methods和methods都可带boolean参数。
irb(main):005:0> Fixnum.instance_methods
=>[:to_s, :-@, :+, :-, :*, :/, :div, :%, :modulo, :divmod, :fdiv, :**, :abs, :magnitude, :==, :<=>, :>, :>=, :<, :<=, :~, :&, :|, :^, :[], :<<, :>>, :to_f, :size, :zero?, :odd?, :even?, :succ, :integer?, :upto, :downto, :times, :next, :pred, :chr, :ord, :to_i, :to_int, :floor, :ceil, :truncate, :round, :numerator, :denominator, :gcd, :lcm, :gcdlcm, ...
 
irb(main):006:0> Fixnum.instance_methods == Fixnum.methods
=> false
  而Object#singleton_methods方法同样以数组的方式返回对象的单例方法(Singleton Method)。

irb(main):007:0> Math.singleton_methods
=> [:atan2, :cos, :sin, :tan, :acos, :asin, :atan, :cosh, :sinh, :tanh, :acosh,:asinh, :atanh, :exp, :log, :log2, :log10, :sqrt, :cbrt, :frexp, :ldexp, :hypot, :erf, :erfc, :gamma, :lgamma]
这些方法,可以在发生NoMethodError后帮助我们调试。

  使用object_id获取对象的一个全局id,可以用于确定对象是不是同一个对象。
Numeric, Integer, Fixnum, Bignum, Float的比较 ruby
cary = [Numeric, Integer, Fixnum, Bignum, Float]
mary = cary.collect {|c| c.instance_methods(false)}
methods = mary.flatten.uniq.sort

methods.each_with_index {|op, i|
  if i % 10 == 0
    heading = sprintf("%12s   %10s %10s %10s %10s %10s",
                "", *cary.collect {|klass| klass.name.center(10)})
    puts heading
    puts "-" * heading.size
  end

  printf("%12s | %10s %10s %10s %10s %10s\n",
    op, *mary.collect {|ms| (ms.member?(op) ? "o" : "-").center(10)})
}

#result
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
           % |     o          -          o          o          o     
           & |     -          -          o          o          -     
           * |     -          -          o          o          o     
          ** |     -          -          o          o          o     
           + |     -          -          o          o          o     
          +@ |     o          -          -          -          -     
           - |     -          -          o          o          o     
          -@ |     o          -          o          o          o     
           / |     -          -          o          o          o     
           < |     -          -          o          o          o     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
          << |     -          -          o          o          -     
          <= |     -          -          o          o          o     
         <=> |     o          -          o          o          o     
          == |     -          -          o          o          o     
         === |     -          -          o          o          o     
           > |     -          -          o          o          o     
          >= |     -          -          o          o          o     
          >> |     -          -          o          o          -     
          [] |     -          -          o          o          -     
           ^ |     -          -          o          o          -     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
         abs |     o          -          o          o          o     
        abs2 |     o          -          -          -          -     
       angle |     o          -          -          -          o     
         arg |     o          -          -          -          o     
        ceil |     o          o          -          -          o     
         chr |     -          o          -          -          -     
      coerce |     o          -          -          o          o     
        conj |     o          -          -          -          -     
   conjugate |     o          -          -          -          -     
 denominator |     o          o          -          -          o     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
         div |     o          -          o          o          -     
      divmod |     o          -          o          o          o     
      downto |     -          o          -          -          -     
        eql? |     o          -          -          o          o     
       even? |     -          o          o          o          -     
        fdiv |     o          -          o          o          o     
     finite? |     -          -          -          -          o     
       floor |     o          o          -          -          o     
         gcd |     -          o          -          -          -     
      gcdlcm |     -          o          -          -          -     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
        hash |     -          -          -          o          o     
           i |     o          -          -          -          -     
        imag |     o          -          -          -          -     
   imaginary |     o          -          -          -          -     
   infinite? |     -          -          -          -          o     
    integer? |     o          o          -          -          -     
         lcm |     -          o          -          -          -     
   magnitude |     o          -          o          o          o     
      modulo |     o          -          o          o          o     
        nan? |     -          -          -          -          o     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
        next |     -          o          -          -          -     
    nonzero? |     o          -          -          -          -     
   numerator |     o          o          -          -          o     
        odd? |     -          o          o          o          -     
         ord |     -          o          -          -          -     
       phase |     o          -          -          -          o     
       polar |     o          -          -          -          -     
        pred |     -          o          -          -          -     
         quo |     o          -          -          -          o     
 rationalize |     -          o          -          -          o     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
        real |     o          -          -          -          -     
       real? |     o          -          -          -          -     
        rect |     o          -          -          -          -     
 rectangular |     o          -          -          -          -     
   remainder |     o          -          -          o          -     
       round |     o          o          -          -          o     
singleton_method_added |     o          -          -          -          -     
        size |     -          -          o          o          -     
        step |     o          -          -          -          -     
        succ |     -          o          o          -          -     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
       times |     -          o          -          -          -     
        to_c |     o          -          -          -          -     
        to_f |     -          -          o          o          o     
        to_i |     -          o          -          -          o     
      to_int |     o          o          -          -          o     
        to_r |     -          o          -          -          o     
        to_s |     -          -          o          o          o     
    truncate |     o          o          -          -          o     
        upto |     -          o          -          -          -     
       zero? |     o          -          o          -          o     
                Numeric    Integer     Fixnum     Bignum     Float   
---------------------------------------------------------------------
           | |     -          -          o          o          -     
           ~ |     -          -          o          o          -     
[Finished]
ruby常用函数 ruby
'must be good'.gsub(/\s+/,'_') #=> must_be_good 查找与替换
#一些全局变量
:$, $LOAD_PATH, __FILE__, ENV, ARGV
require 'rbconfig'
RbConfig::CONFIG #ruby的相关信息
a,b,c = *[1,2,3]#=>a = 1, b = 2, c= 3

__FILE__ == $PROGRAM_NAME #判断当前运行的是不是本程序
 
warn "#{__FILE__}:#{__LINE__}: versio" #当前文件名(路径)与当前行号

#send 与__send__一样,用法
if aobject.respond_to? :somemethod
   anobject.send :somemethod,args, &proc
end
def fun(arg)
  yield arg
end
self.__send__ :fun, 'hello', &lambda{|x| puts x} #=>hello

##########
class Person; end
Person.instance_eval do #instance_eval作用在Class时,是给类添加类方法
  def species; end
end
Person.class_eval do #class_eval只能作用在类上
	def smile; end
end

pa = Person.new
pa.instance_eval do
	def smile; end #instance_eval作用在实例时,给实例添加类方法
end
Person.instance_methods.grep /smile/
##########另一个示例
class Baby
	class_eval <<-RUBY #实例方法
		def smile; end
	RUBY

	instance_eval 'def foo; end' #类方法
end

Baby.new.smile
Baby.foo
DataMapper简单例子 ruby http://datamapper.org/docs/find.html
require 'dm-core'
require  'dm-migrations'

DataMapper::Logger.new($stdout, :debug)
DataMapper.setup :default, 'sqlite::memory'

class Post
	include DataMapper::Resource

	property :id,		Serial
	property :title,	String
	property :body,		Text
	property :created_at,DateTime
end

DataMapper.finalize

DataMapper.auto_migrate!

@post = Post.create(
  :title      => "My first DataMapper post",
  :body       => "A lot of text ...",
  :created_at => Time.now
)
@post.save

p1 = Post.get 1

p p1;

##################22

DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/recall.db")  
  
class Note  
  include DataMapper::Resource  
  property :id, Serial  
  property :content, Text, :required => true  
  property :complete, Boolean, :required => true, :default => false  
  property :created_at, DateTime  
  property :updated_at, DateTime  
end  
  
DataMapper.finalize.auto_upgrade!  
##获取当前目录 Dir.pwd
has_secure_password ror
Adds methods to set and authenticate against a BCrypt password. This mechanism requires you to have a password_digest attribute.

Validations for presence of password, confirmation of password (using a “password_confirmation” attribute) are automatically added. You can add more validations by hand if need be.

Example using Active Record (which automatically includes ActiveModel::SecurePassword):

# Schema: User(name:string, password_digest:string)
class User < ActiveRecord::Base
  has_secure_password
end

user = User.new(:name => "david", :password => "", :password_confirmation => "nomatch")
user.save                                                      # => false, password required
user.password = "mUc3m00RsqyRe"
user.save                                                      # => false, confirmation doesn't match
user.password_confirmation = "mUc3m00RsqyRe"
user.save                                                      # => true
user.authenticate("notright")                                  # => false
user.authenticate("mUc3m00RsqyRe")                             # => user
User.find_by_name("david").try(:authenticate, "notright")      # => nil
User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user

need gem 'bcrypt-ruby', '~> 3.0.0'
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/secure_password.rb
validates.rb ror https://github.com/rails/rails/blob/master/activemodel/lib/active_model/validations/validates.rb
require 'active_support/core_ext/hash/slice'

module ActiveModel

  # == Active Model validates method
  module Validations
    module ClassMethods
      # This method is a shortcut to all default validators and any custom
      # validator classes ending in 'Validator'. Note that Rails default
      # validators can be overridden inside specific classes by creating
      # custom validator classes in their place such as PresenceValidator.
      #
      # Examples of using the default rails validators:
      #
      #   validates :terms, :acceptance => true
      #   validates :password, :confirmation => true
      #   validates :username, :exclusion => { :in => %w(admin superuser) }
      #   validates :email, :format => { :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create }
      #   validates :age, :inclusion => { :in => 0..9 }
      #   validates :first_name, :length => { :maximum => 30 }
      #   validates :age, :numericality => true
      #   validates :username, :presence => true
      #   validates :username, :uniqueness => true
      #
      # The power of the +validates+ method comes when using custom validators
      # and default validators in one call for a given attribute e.g.
      #
      #   class EmailValidator < ActiveModel::EachValidator
      #     def validate_each(record, attribute, value)
      #       record.errors.add attribute, (options[:message] || "is not an email") unless
      #         value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      #     end
      #   end
      #
      #   class Person
      #     include ActiveModel::Validations
      #     attr_accessor :name, :email
      #
      #     validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 }
      #     validates :email, :presence => true, :email => true
      #   end
      #
      # Validator classes may also exist within the class being validated
      # allowing custom modules of validators to be included as needed e.g.
      #
      #   class Film
      #     include ActiveModel::Validations
      #
      #     class TitleValidator < ActiveModel::EachValidator
      #       def validate_each(record, attribute, value)
      #         record.errors.add attribute, "must start with 'the'" unless value =~ /\Athe/i
      #       end
      #     end
      #
      #     validates :name, :title => true
      #   end
      #
      # Additionally validator classes may be in another namespace and still used within any class.
      #
      #   validates :name, :'film/title' => true
      #
      # The validators hash can also handle regular expressions, ranges,
      # arrays and strings in shortcut form, e.g.
      #
      #   validates :email, :format => /@/
      #   validates :gender, :inclusion => %w(male female)
      #   validates :password, :length => 6..20
      #
      # When using shortcut form, ranges and arrays are passed to your
      # validator's initializer as +options[:in]+ while other types including
      # regular expressions and strings are passed as +options[:with]+
      #
      # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ and +:strict+
      # can be given to one specific validator, as a hash:
      #
      #   validates :password, :presence => { :if => :password_required? }, :confirmation => true
      #
      # Or to all at the same time:
      #
      #   validates :password, :presence => true, :confirmation => true, :if => :password_required?
      #
      def validates(*attributes)
        defaults = attributes.extract_options!.dup
        validations = defaults.slice!(*_validates_default_keys)

        raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
        raise ArgumentError, "You need to supply at least one validation" if validations.empty?

        defaults.merge!(:attributes => attributes)

        validations.each do |key, options|
          key = "#{key.to_s.camelize}Validator"

          begin
            validator = key.include?('::') ? key.constantize : const_get(key)
          rescue NameError
            raise ArgumentError, "Unknown validator: '#{key}'"
          end

          validates_with(validator, defaults.merge(_parse_validates_options(options)))
        end
      end

      # This method is used to define validation that can not be corrected by end user
      # and is considered exceptional.
      # So each validator defined with bang or <tt>:strict</tt> option set to <tt>true</tt>
      # will always raise <tt>ActiveModel::InternalValidationFailed</tt> instead of adding error
      # when validation fails
      # See <tt>validates</tt> for more information about validation itself.
      def validates!(*attributes)
        options = attributes.extract_options!
        options[:strict] = true
        validates(*(attributes << options))
      end

    protected

      # When creating custom validators, it might be useful to be able to specify
      # additional default keys. This can be done by overwriting this method.
      def _validates_default_keys
        [ :if, :unless, :on, :allow_blank, :allow_nil , :strict]
      end

      def _parse_validates_options(options) #:nodoc:
        case options
        when TrueClass
          {}
        when Hash
          options
        when Range, Array
          { :in => options }
        else
          { :with => options }
        end
      end
    end
  end
end
Rails源码分析——delegate(转载) ror http://www.cnblogs.com/lwm-1988/archive/2011/08/20/2147395.html
Delegate是一种应用composite来代替extend的机制,可以有效地降低代码的耦合性。
Rails 2.2增加了delegate方法,可以十分方便地实现delegate机制。来看看源码吧:

def delegate(*methods)
  options = methods.pop
  unless options.is_a?(Hash) && to = options[:to]
    raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
  end
 
  if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
    raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
  end
 
  prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"
 
  methods.each do |method|
    module_eval(<<-EOS, "(__DELEGATION__)", 1)
      def #{prefix}#{method}(*args, &block)
        #{to}.__send__(#{method.inspect}, *args, &block)
      end
    EOS
  end
end
delegate方法首先检查传入的参数,正确参数形式为:method1, :method2, ..., :methodN, :to => klass[, :prefix => prefix]
delegate要求参数的最后必须是一个Hash,:to表示需要代理的类,:prefix表示代理的方法是否要加前缀,如果:prefix => true,则代理的方法名为klass_method1, klass_method2, ..., klass_methodN,如果:prefix => prefix (prefix为string),则代理的方法名为prefix_method1, prefix_method2, ..., prefix_methodN。
最终通过module_eval动态生成每个方法定义。通过send方法调用:to类的方法。
来看看调用的例子:
简单的调用:

class Greeter  ActiveRecord::Base
  def hello()   "hello"   end
  def goodbye() "goodbye" end
end
 
class Foo  ActiveRecord::Base
  delegate :hello, :goodbye, :to => :greeter
end
 
Foo.new.hello   # => "hello"
Foo.new.goodbye # => "goodbye"
增加:prefix = true:


class Foo  ActiveRecord::Base
  delegate :hello, :goodbye, :to => :greeter, :prefix => true
end
 
Foo.new.greeter_hello   # => "hello"
Foo.new.greeter_goodbye # => "goodbye"
自定义前缀名:

class Foo  ActiveRecord::Base
  delegate :hello, :goodbye, :to => :greeter, :prefix => :foo
end
 
Foo.new.foo_hello   # => "hello"
Foo.new.foo_goodbye # => "goodbye"


ruby的动态性再一次发挥了强大的功能!
Ruby生成随机字符 ruby
value = ""
 8.times{value  << (65 + rand(25)).chr}

(0...8).map{65.+(rand(25)).chr}.join

(0...50).map{ ('a'..'z').to_a[rand(26)] }.join

o =  [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten;  
string  =  (0..50).map{ o[rand(o.length)]  }.join;

require 'active_support/secure_random'
random_string = ActiveSupport::SecureRandom.hex(16)


rand(36**length).to_s(36)#to_s(36)转成36进制
Builder 插件示例 ruby
require 'builder'
xm = Builder::XmlMarkup.new(:target=>STDOUT, :indent=>2)

xm.em("emphasized")            # => <em>emphasized</em>
xm.em { xm.b("emp & bold") }   # => <em><b>emph & bold</b></em>
xm.a("A Link", "href"=>"http://onestepback.org")
                               # => <a href="http://onestepback.org">A Link</a>
xm.div { xm.br }               # => <div><br/></div>
xm.target("name"=>"compile", "option"=>"fast")
                               # => <target option="fast" name="compile"\>
                               # NOTE: order of attributes is not specified.

xm.instruct!                   # <?xml version="1.0" encoding="UTF-8"?>
xm.html {                      # <html>
  xm.head {                    #   <head>
    xm.title("History")        #     <title>History</title>
  }                            #   </head>
  xm.body {                    #   <body>
    xm.comment! "HI"           #     <!-- HI -->
    xm.h1("Header")            #     <h1>Header</h1>
    xm.p("paragraph")          #     <p>paragraph</p>
  }                            #   </body>
}       
puts xm.target!
ajax_rails31_demo ror https://github.com/samnang/ajax_rails31_demo
##app / controllers / comments_controller.rb 
class CommentsController < ApplicationController
  respond_to :html, :js

  def index
    @comments = Comment.all
  end

  def create
    @comment = Comment.new(params[:comment])

    @comment.save

    respond_with @comment, :location => comments_url
  end

  def destroy
    @comment = Comment.find(params[:id])

    @comment.destroy

    respond_with @comment, :location => comments_url
  end
end
## app / models / comment.rb
class Comment < ActiveRecord::Base
  attr_accessible :name, :content
end
##ajax_rails31_demo / app / views / comments / index.html.erb
<% title "Comments for Ajax in Rails 3.1" %>

<div id="comments_count"><%= comments_count %></div>

<div id="comments">
  <%= render @comments %>
</div>

<h3>Add your comment:</h3>

<%= form_for Comment.new, :remote => true do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :content, "Comment" %><br />
    <%= f.text_area :content, :rows => '12', :cols => 35 %>
  </p>
  <p><%= f.submit %></p>
<% end %>
##ajax_rails31_demo / app / views / comments / _comment.html.erb
<div id=<%= dom_id(comment) %> class="comment">
  <strong><%= comment.name %></strong>
  <em>on <%= comment.created_at.strftime('%b %d, %Y at %I:%M %p') %></em>
  <%= link_to "Remove", comment, :method => :delete, :remote => true %>
  <%= simple_format comment.content %>
</div>
##app/views/comments/destroy.js.coffee
$('#comments_count').html '<%= comments_count %>'

$('#<%= dom_id(@comment) %>')
  .fadeOut ->
    $(this).remove()
##ajax_rails31_demo / app / views / comments / create.js.coffee 
$('<%= escape_javascript(render(:partial => @comment))%>')
  .appendTo('#comments')
  .hide()
  .fadeIn()

$('#new_comment')[0].reset()

$('#comments_count').html '<%= comments_count %>'
Construct Nested Hash in Ruby ruby http://huangzhimin.com/2011/01/18/construct-nested-hash-in-ruby/
normal form:
cache_data = {}
cache_data['a'] ||= {}
cache_data['a']['b'] ||= {}
cache_data['a']['b']['c'] ||= {}
cache_data['a']['b']['c']['d'] ||= {}
cache_data['a']['b']['c']['d'] = something...

other form:

leet = lambda {|hash, key| hash[key] = Hash.new(&leet)}
cache_data = Hash.new(&leet)
cache_data['a']['b']['c']['d'] = 'something'

#=> {"a"=>{"b"=>{"c"=>{"d"=>"something"}}}}
知识点:
1、
Hash.new {|hash, key| block } → new_hash
# While this creates a new default object each time
h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
h["c"]           #=> "Go Fish: c"
h["c"].upcase!   #=> "GO FISH: C"
h["d"]           #=> "Go Fish: d"
h.keys           #=> ["c", "d"]

2、
def fun &b
	b.call
end

fun { p 'hello world'}

b1 = lambda {p 'hello world'}

fun &b1

Simplify render in controllers ror http://rails-bestpractices.com/posts/62-simplify-render-in-controllers
Like simplify render in views, from rails 2.3, we can also simplify render in controllers. Here I will show you the contrast.
Rendering an Action's View

Before
render :action => :edit
render :action => 'edit'
After
render :edit
render 'edit'
Rendering an Action’s Template from Another Controller

Before
render :template => 'books/edit'
After
render 'books/edit'
Rendering an Arbitrary File

Before
render :file => '/path/to/rails/app/views/books/edit'
After
render '/path/to/rails/app/views/books/edit'
Share Simplify render in views ror http://rails-bestpractices.com/posts/61-simplify-render-in-views
render is one of the often used view helpers, we use it to extract sub part view. We can pass object, collection or local variables to the partial views. From rails 2.3, more simplified syntax for render are provided that makes render helper cleaner. Here I will show you the contrast.
Render simple partial

Before
<%= render :partial => 'sidebar' %>
<%= render :partial => 'shared/sidebar' %>
After
<%= render 'sidebar' %>
<%= render 'shared/sidebar' %>
Render partial with object

Before
<%= render :partial => 'posts/post', :object => @post %>
After
<%= render @post %>
Render partial with collection

Before
<%= render :partial => 'post', :collection => @posts %>
After
<%= render @posts %>
Render partial with local variables

Before
<%= render :partial => 'comments/comment', :locals => { :parent => post } %>
After
<%= render 'comments/comment', :parent => post %>
Global site tag (gtag.js) - Google Analytics