- 浏览: 200702 次
- 来自: ...
文章分类
最新评论
-
赤道螞蟻:
如果是數據庫有定時任務,定時更新表的數據。 表中數據變化時,主 ...
用socket.io实现WebSocket的一个简单例子 -
cwalet:
在世界的中心呼喚愛 写道提示找不到 expressnpm in ...
用socket.io实现WebSocket的一个简单例子 -
在世界的中心呼喚愛:
提示找不到 express
用socket.io实现WebSocket的一个简单例子 -
Anleb:
def m1(a)
puts 'invoke m1'
pu ...
Ruby的一些疑问 -
biyeah:
补充,任何类,只要实现to_proc方法,都可以与&结 ...
Ruby的一些疑问
收藏列表
- 全部 [57]
- 默认 [1]
- javascript [2]
- jquery [3]
- ror [12]
- ruby [35]
- vim [1]
- nodejs [1]
- mongdb [1]
- express [1]
- mongoose [1]
- ruby web [2]
标题 | 标签 | 来源 | |
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 %> |