Ruby知识积累2

来源:互联网 发布:淘宝子账号登陆不了 编辑:程序博客网 时间:2024/05/17 03:00
  • Block:
    •   Proc.new    my_proc = Proc.new { puts "tweet" }    my_proc.call  lambda    my_proc = lambda { puts "tweet" }    my_proc.call  ->    my_proc = -> { puts "tweet" }    my_proc.call  Parameter:    e.g.      class Tweet        def post(success, error)          if authenticate?(@user, @password)            success.call          else            error.call          end        end      end      tweet = Tweet.new('Ruby Bits!')      success = -> { puts "Sent!" }      error = -> { raise 'Auth Error' }      tweet.post(success, error)    e.g.      tweets = ["First tweet", "Second tweet"]      printer = lambda { |tweet| puts tweet }      tweets.each(&printer) # &操作符将lambda转换为block  block_given?    e.g.      class Timeline        attr_accessor :tweets        def print          if block_given?            tweets.each { |tweet| puts yield tweet }          else            puts tweets.join(', ')          end        end      end      timeline = Timeline.new      timeline.tweets = ["One", "Two"]      timeline.print      timeline.print { |tweet|        "tweet: #{tweet}"      }    e.g.      class Tweet        def initialize          yield self if block_given?        end      end      Tweet.new do |tweet|        tweet.status = "Set in initialize!"        tweet.created_at = Time.now      end  closure(闭包):    def tweet_as(user)      lambda { |tweet| puts "#{user}: #{tweet}" }    end    gregg_tweet = tweet_as("andy")    greeg_tweet.call("Mind blowing!")  Symbol#to_proc    tweets.map { |e| tweet.user  }    tweets.map(&:user)
  • Struct:
    •   e.g.    类:      class Tweet        attr_accessor :user, :status        def initialize(user, status)          @user, @status = user, status        end        def to_s          "#{user}: #{status}"        end      end    结构体:      Tweet = Struct.new(:user, :status) do        def to_s          "#{user}: #{status}"        end      end
  • Alias_method:
    • Bad:    class Timeline      def initialize(tweets = [])        @tweets = tweets      end      def tweets        @tweets      end      def contents        @tweets      end    end  Good:    class Timeline      def initialize(tweets = [])        @tweets = tweets      end      attr_reader :tweets      alias_method :contents, :tweets    end
  • Define_method:
    • e.g.    native:      class Tweet        def draft          @status = :draft        end        def posted          @status = :posted        end        def deleted          @status = :deleted        end      end    change:      class Tweet        status = [:draft, :posted, :deleted]        status.each do |status|          define_method status do            @status = status          end        end      end
  • Send:(常用于访问protected和private方法)
    • e.g.    class Timeline      def initialize(tweets)        @tweets = tweets      end      def contents        @tweets      end      private        def direct_message          #...        end    end    tweets = ['Compiling!', 'Bundling...']    timeline = Timeline.new(tweets)    timeline.contents    timeline.send(:contents)    timeline.send("contents")    timeline.send(:direct_message)    timeline.public_send("direct_message")   # only can access public methods
  • Method:
    • e.g.    class Timeline      def initialize(tweets)        @tweets = tweets      end      def contents        @tweets      end      def show_tweet(index)        puts @tweets[index]      end    end    tweets = ['Compiling!', 'Bundling...']    timeline = Timeline.new(tweets)    content_method = timeline.method(:contents)    content_method.call    show_tweet = timeline.method(:show_tweet)    show_tweet.call(0)    (0..1).each(&show_tweet)      #相当于show_tweet(0)和show_tweet(1)
  • Self:
    • e.g.    puts "Outside the class: #{self}"    # main    class Tweet      puts "Inside the class: #{self}"   # Tweet      def self.find(keyword)        # ...      end    end
  • Class_eval(在指定类中执行):
    • e.g.    class Tweet      attr_accessor :status      attr_reader :created_at      def initialize(status)        @status = status        @created_at = Time.now      end    end    Tweet.class_eval do      attr_accessor :user    end    tweet = Tweet.new("Learning class_eval")    tweet.user = "doit"
  • Create a log_method:
    •   log_method以类名和方法名作为参数,调用class_eval来执行类中的代码。使用alias_method来保存原先的方法,使用define_method来重定义方法,对该方法的调用过程进行记录,使用send来调用原先的方法。  class MethodLogger    def log_method(klass, method_name)      klass.class_eval do        alias_method "#{method_name}_original", method_name        define_method method_name do |*args, &block|          puts "#{Time.now}: Called #{method_name}"          send "#{method_name}_original", *args, &block        end      end    end  end  e.g.    class Tweet      def say_hi        puts "hi"      end    end    logger = MethodLogger.new    logger.log_method(Tweet, :say_hi)    Tweet.new.say_hi
  • Instance_eval:
    •  e.g.    class Tweet      attr_accessor :user, :status    end    tweet = Tweet.new    tweet.instance_eval do      self.status = "Changing the tweet's status"    end  Good:    class Tweet      attr_accessor :user, :status      def initialize        yield self if block_given?      end    end    Tweet.new do |tweet|      tweet.status = "I was set in the initialize block!"      tweet.user = "Gregg"    end  Better:    class Tweet      attr_accessor :user, :status      def initialize(&block)        instance_eval(&block) if block_given?      end    end
  • Method_missing:
    • 当无法找到方法时调用  e.g.    class Tweet      def method_missing(method_name, *args)        logger.warn "You tried to call #{method_name} with these arguments: #{args}"        super   # ruby's default method handling raise a NoMethodError      end    end  e.g.(对一些方法进行委托)    class Tweet      DELEGATED_METHODS = [:username, :avatar]      def initialize(user)        @user = user      end      def method_missing(method_name, *args)        if DELEGATED_METHODS.include?(method_name)          @user.send(method_name, *args)        else          super        end      end    end  e.g.(将未知方法,全部委托到user)    require 'delegate'    class Tweet < SimpleDelegator      def initialize(user)        super(user)      end    end  e.g.    class Tweet      def initialize(text)        @text = text      end      def to_s        @text      end      def method_missing(method_name, *args)        match = method_name.to_s.match(/^hash_(\w+)/)        if match          @text << " #" + match[1]        else          super        end      end    end  e.g.(define_method)    class Tweet      def initialize(text)        @text = text      end      def to_s        @text      end      def method_missing(method_name, *args)        match = method_name.to_s.match(/^hash_(\w+)/)        if match          self.class.class_eval do            define_method(method_name) do              @text << " #" + match[1]            end          end          send(method_name)        else          super        end      end    end
  • Response_to?:
    • e.g.    class Tweet      ...      def respond_to?(method_name)        method_name =~ /^hash_\w+/ ||super      end    end    tweet = Tweet.new    tweet.respond_to?(:to_s)    tweet.respond_to?(:hash_ruby)    tweet.method(:hash_ruby)  # NameError:undefined method
  • Response_to_missing?:(Ruby 1.9.3)
    •   e.g.    class Tweet      ...      def respond_to_missing?(method_name)        method_name =~ /^hash_\w+/ ||super      end    end    tweet = Tweet.new    tweet.method(:hash_ruby)  # return a Method object
  • Implement a simple DSL:
    • DSL:领域专用语言  e.g.    class Tweet      def initialize(user)        @user = user        @tweets = []        @annotations = {}      end      def submit_to_twitter        tweet_text = @tweet.join(' ')        if tweet_text.length <= 140          puts "#{@user}: #{tweet_text}"          puts @annotations.inspect unless @annotations.empty?        else          raise "your tweet is too long."        end      end      def text(str)        @tweet << str        self      end      def mention(*users)        users.each do |user|          @tweet << "@" + user        end        self      end      def hashtag(str)        @tweet << "#" + str        self      end      def link(str)        @tweet << str      end      def method_missing(method, *args)        @annotations[method] = args.join(', ')      end    end    def tweet_as(user, text=nil,&block)      tweet = Tweet.new(user)      tweet.text(text) if text      tweet.instance_eval(&block) if block_given?      tweet.submit_to_twitter    end    tweet_as 'marken' do      mention 'china','usa'      text('I made a DSL!').hashtag('hooray').hashtag('ruby')      link 'http://www.somewhere.com'    end
0 0
原创粉丝点击