zoukankan      html  css  js  c++  java
  • 七周七语言——Ruby

    第一天练习

    puts "Pllease input a number between 0-99"
    a = rand(100)
    b = gets()
    c = b.to_i()
    while c != a
        if c < a
    	    puts "small"
    	else
    	    puts "big"
    	end
    	puts "input again:"
    	b = gets()
        c = b.to_i()
    end
    puts "Bingo"
    

      

    第二天练习

    散列->数组:keys,values, to_a

    练习1,

       a = (1..16).to_a

       使用each

    n = 1
    a.each do |i|
        if n%4 != 0
            print i
            print " "
       else
           puts i
       end
       n = n + 1
    end
    

      使用each_slice    

    a.each_slice(4){|i| p i} 

    练习2

    class Tree
        attr_accessor :children, :node_name
    	
    	def initialize(trees)
    	    @node_name = trees.keys[0]
    		@children = []
    		if trees[@node_name] != nil
    		    @children = trees[@node_name].map {|k,v| Tree.new({k=>v})}
    		end
    	end
    	
    	def visit_all(&block)
    	    visit &block
    		children.each {|c| c.visit_all &block}
    	end
    	
    	def visit(&block)
    	    block.call self
    	end
    end
    
    ruby_tree = Tree.new ({'grandpa' => { 'dad' => {'child 1' => {}, 'child 2' => {} }, 'uncle'=> {'child 3' => {}, 'child 4' => {} } } })
    
    
    puts "Visiting a node"
    ruby_tree.visit {|node| puts node.node_name}
    puts
    
    puts "Visiting entire tree"
    ruby_tree.visit_all {|node| puts node.node_name}
    

    map的使用见http://chrisholtz.com/blog/lets-make-a-ruby-hash-map-method-that-returns-a-hash-instead-of-an-array/

    练习3

    File.open("tree2.rb") do |file|
        file.each_line do |line|
    	         if line =~ /tree/
    			     p "#{file.lineno}: #{line}"
    			 end
    		end
    	end
    

    第三天练习

    module ActsAsCsv
        def self.included(base)
    	    base.extend ClassMethods
    	end
    	
    	module ClassMethods
    	    def acts_as_csv
    		    include InstanceMethods
    		end
    	end
    	
    	module InstanceMethods
    		def read
    		    @csv_contents = []
    			file = File.new(self.class.to_s.downcase + '.txt')
    			@headers = file.gets.chomp.split(', ')
    			
    			file.each do |row|
    				@csv_contents << row.chomp.split(', ')
    			end
    		end
    		
    		attr_accessor :headers, :csv_contents
    		
    		def initialize
    			read
    		end
    		
    		def each
    		    len = @csv_contents.size
    			i = 0
    			while i < len
    			   yield CsvRow.new(@csv_contents[i])
    			   i = i + 1
    			end
    		end
    	end
    end
    
    class RubyCsv 
        include ActsAsCsv
        acts_as_csv
    end
    
    class CsvRow
        attr_accessor :contents
    	
    	def initialize(contents)
    	     @contents = contents[0].split(',')  #contents是一个类似["name, age, phone"]的字符串,所以分割它为数组["name", "age", "phone"]
    	end
    	
    	def method_missing name, *args
    		    numbers = {"one"=>1, "two"=>2, "three"=>3, "four"=>4}  
    			col = numbers[name.to_s].to_i - 1
    			@contents[col]
        end
    	
    	def to_ary
    	   @contents
    	end
    		
    end
    
    
    
    m = RubyCsv.new
    puts m.csv_contents.inspect
    puts
    m.each {|row| puts row}
    puts
    m.each {|row| puts row.two}
    

    值得注意的是,如果没有定义to_ary而定义的是to_s

    def to_s
    	     @contents.join(",  ")
    end
    

    则 

    m.each {|row| puts row}
    

    一句会出现“Can't convert CsvRow to Array(CsvRow#to_ary gives String)”的错误,提示给定String的情况下未定义CsvRow。

    但如果去掉to_ary跟method_missing的定义,只定义to_s,则可以正常输出。

    这是因为:puts默认调用对象的to_ary函数,找不到时才会试着调用to_s。所以只定义to_s的情况下会正常输出。而如果在定义了上述method_missing的情况下再定义to_s,由于优先寻找的是to_ary,它未定义,所以会用method_missing方法来代替它,但这里咱们定义method_missing返回值为String(即@contents[col]),而to_ary的返回值要求是数组,这就是错误“Can't convert CsvRow to Array(CsvRow#to_ary gives String)”出现的原因。

    为了验证这一点,定义to_s函数跟空的method_missing函数,

    class CsvRow
        attr_accessor :contents
    	
    	def initialize(contents)
    	     @contents = contents[0].split(',')  
    	end
    	
    	def method_missing name, *args
    		  		
            end
    		
    	def to_s
    	    @contents.join(', ')
    	end
    end
    

    发现能正常调用to_s打印,说明空的method_missing不会阻止puts继续寻找to_s函数,或者说method_missing返回值为空的情况下,puts会认为to_ary没有找到,进而继续找to_s。

    而如果定义

    def method_missing name, *args
         a = ["b","c"]			
     end
    	
    def to_s
        @contents.join(', ')
    end
    

    则会打印

    b
    c
    

    这是因为method_missing的返回值为数组,满足to_ary返回值要为数组的要求,从而puts直接调用method_missing作为to_ary,不再寻找to_s。

    puts调用to_ary的原因见http://stackoverflow.com/questions/8960685/ruby-why-does-puts-call-to-ary,这个网页还有define_method的几行代码,也值得看。

    一些点:

    •  Ruby是解释型、面向对象、动态类型(类型在运行时而非编译时绑定)的语言,大部分时候表现得像是强类型语言(例外:比如你可以在运行时改变类)。
    • Ruby是纯面向对象语言,比如数字也是FixNum类的对象。Ruby中一切皆对象,而类本身也是对象,所有其他类都是Class类的对象。函数也是对象。
    • 一等对象:可存储于变量或数据结构中;可作为参数传递给函数;可作为返回值从函数返回;可在运行时创建。如C++中的“对象”是一等对象,但函数不是,因为C++中函数无法在运行时创建。
    • 除nil跟false外,其他值都是true,包括0。
    • 鸭子类型:对接口编码,而不对实现编码。比如String、Float类都可以调用to_i。鸭子类型不在乎实际类型(内在实现)可能是什么,只要它像鸭子一样走路,像鸭子一样嘎嘎叫,那它就是只鸭子。尤其注意体会这种思想。
    • 符号与值,比如带冒号的符号“:str”在程序中的标识是唯一的,尽管两个同值字符串在物理上不同(object_id不同),但相同的符号却是同一物理对象(object_id相同)。
    • yield:这个貌似在函数式语言中很重要,尤其是要设计迭代器式的方法时。
    • Ruby命名规范,尼玛不是一般的清晰,举例看看:类以大写字母开头,采用骆驼命名法;类的实例变量(一个对象一个值)前加@,类变量(一个类一个值)前加@@;实例变量和方法以小写字母开头,下划线命名法;条件判断函数后面加"?"。由于标识符不限定只使用“数字、字母、下划线”,命名规范的选择性比类C语言大多了,从而也更清晰多了,比如实例变量加@就比C++中前缀m_啥的强多了,条件判断函数加"?"就比is_、has_、can_等前缀简单清晰多了。
    • Ruby采用模块来解决多重继承的问题,相比于Java用接口来描述,Ruby的这种解决办法相对约束性小,但是更加自由。体会26页to_s定义在类中而不是模块中这一点。
    • 体会mixin的编程方式:先定义类的主要部分,然后用模块添加额外功能,即使用单一继承结合mixin的方式,尽可能合理地把各种行为打包到一起。
    • Ruby中两个重要的mixin,枚举(enumerable)和比较(comparable)。如果想让类可枚举,必须实现 each 方法;如果想让类可比较,必须实现 <=> 操作符。体会这种思想。
    • 开放类:允许你随时改变任何类的定义,常用于给类添加行为,可认为是鸭子类型思想的一种表现。这是一种能力,但注意别滥用,否则带来的坏处比好处多,比如杂乱,甚至毁灭,比如你重定义Class类的new方法。始终铭记:自由越大,责任越重。
    • 开放类的一些用处:修改Ruby让它方便于某个特定领域的编程。
    • method_missing:能力太强大,直接会覆盖诊断信息,不利于错误调试。相关连接:define_method。

    • method_missing建议:慎用,上面那个puts的错误就是因为这个。另一方面,有时候能用它干一些脑洞大开的事情,如XML框架builder允许用户通过 method_missing 方法定义自定义标签,以提供更加美观的语法。

    • Ruby通过模块与类的结合来实现元编程。注意,类也是模块。这个能力很强大,比如可以动态地改变类。有时间可以多学习体会下ActiveRecord。
    • Ruby的一些优点:
      • 鸭子类型思想的尽致应用:根据对象可提供的方法,而不是对象的继承层次,实现了更切合实际的多态设计
      • 模块和开放类的能力
    • Ruby的一些缺点
      • 效率:一个核心的原因——由于允许开放类,一个类任何时候都有可能改变。
      • 扩展性
      • 并发
      • 动态类型带来的限制,如调试的困难等,这是任何事物的一体两面性,对比着看。
    • Ruby应用场景:
      • 适用于要求快速迭代开发的任务
      • 适用于Web开发,得益于Rails框架。
      • 适用与对并发和扩展性要求高的场景。
      • 大型项目慎用,动态语言用在大型项目上确实会感到吃力。
  • 相关阅读:
    原生AJAX基础讲解及兼容处理
    JS子元素oumouseover触发父元素onmouseout
    IE6常见bug
    让IE6支持position:fixed的方法,CSS expression与JavaScript eval讲解
    Alpha通道
    网络游戏开发前的pixel像素画习作
    网络游戏开发其一(游戏美工)
    周内琐记
    地图重置与各项绘图优化
    四足机器人搭建尝试
  • 原文地址:https://www.cnblogs.com/rolling-stone/p/4517148.html
Copyright © 2011-2022 走看看