ruby语法 二

299 阅读6分钟

%Q, %q, %W, %w, %x, %s, %i

%Q

# %Q 用于代替双引号字符串,当你需要在字符串里放入很多引号时候, 可以直接用下面方法而不需要在引号前逐个添加反斜杠 (\")
# (...)也可用其他非数字字母的符号或成对的符号代替, 诸如[...], !...!, +...+,{...}, <...>等.
what_frank_said = "hello!"
puts %Q(Joe said: "Frank said: "#{what_frank_said}"") 

#输出结果:
Joe said: "Frank said: "hello!""

%q

# 与`%Q`类似, 但是表示的是单引号字符串
what_frank_said = 'hello!'
puts %q(Joe said: 'Frank said: '#{what_frank_said}' ')

#输出结果:
Joe said: 'Frank said: '#{what_frank_said}' '

%W

# 与`%Q`类似, 但是表示的是单引号字符串
require 'pp'

foo = 'foo'
pp %W(#{foo} Bar Bar\ with\ space) 

#输出结果:
["foo", "Bar", "Bar with space"]

%w

# 用于表示其中元素被单引号括起的数组
require 'pp'

pp %w(eat Bar c d) 

#输出结果:
["eat", "Bar", "c", "d"]

%x

# 使用`方法执行一段shell脚本并返回标准输出内容.
require 'pp'

foo = 'foo'
pp %x(echo foo:#{foo})

#输出结果:
"foo:foo\n"

%s

#用于表示symbol, 但是不会对其中表达式等内容进行转化
require 'pp'

pp %s(foo)

#输出结果:
:foo

%i

# Ruby 2.0 之后引入的语法, 用于生成一个symbol数组
require 'pp'

pp %i[a b c d e]

#输出结果:
[:a, :b, :c, :d, :e]

调用外部可执行文件

exec

#exec('echo hello,`whoami`')
#exec后面 不会被执行 system会执行
#puts '*' * 30

#输出结果:
hello,yutangzhao

system

#返回值true表示成功 false表示失败
pp system('echo hello,`whoami`')
#system后面 不会被执行
puts '*' * 30

pp system('ls xxxx')

#输出结果:
hello,yutangzhao
true
******************************
ls: xxxx: No such file or directory
false
if system('echo hello,`whoami`')
    puts 'success'
else
   put 'faild'
end

#输出结果:
hello,yutangzhao
success

system('echo hello,`whoami`')
pp $?

pp system('ls xxxx')
pp $?
pp $?.exitstatus

if $?.exitstatus.zero?
    puts 'ok'
else
    puts 'faild'
end

##输出结果:
hello,yutangzhao
#<Process::Status: pid 8013 exit 0>
ls: xxxx: No such file or directory
false
#<Process::Status: pid 8016 exit 1>
1
faild

system 高级用法

#方法原形
system([env,],command,[,options])

#configure脚本文件
#!/usr/bin/env ruby

require 'pp'
system('rm -rf out err')
stout = File.open('out','w+')
sterr = File.open('err','w+')
$stdout.reopen(stout)
$stderr.reopen(sterr)

pp "ENV['NAME']: #{ENV['NAME']}"
pp "ENV['AGE']: #{ENV['AGE']}"

puts "ARGV:"
pp ARGV


#注意给configure脚本文件添加可执行权限
chmod a+x configure

#main.rb通过system执行configure脚本
name = 'hanghang'
age = '34'
favors = %W[aaa bb ccc dd]

pp system(
  { 'NAME' => 'zhangsan','AGE' => '34'},
    './configure',
    name, age, *favors
)
p $?

#运行结果:
true
#<Process::Status: pid 10195 exit 0>

#查看out文件
"ENV['NAME']: zhangsan"
"ENV['AGE']: 34"
ARGV:
["hanghang", "34", "aaa", "bb", "ccc", "dd"]

require_relative

run.rb

def run
 puts 'run.rb ----'
end

require 'pp'

require_relative 'run' #相对于当前文件的路径
#require_relative 'yang/run'
#require_relative '../run'

run

#输出结果:
run.rb ----

LOAD_PATH

require 'pp'
#require '/Users/yutangzhao/Desktop/run.rb' #默认做法
$LOAD_PATH.unshift('/Users/yutangzhao/Desktop') #路径添加到load_path中
require 'run'
run
pp '*' * 50

pp $LOAD_PATH

#输出结果:
run.rb ----
"**************************************************"
["/Users/yutangzhao/Desktop",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/site_ruby/2.7.0",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/site_ruby/2.7.0/x86_64-darwin20",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/site_ruby",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/vendor_ruby/2.7.0",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/vendor_ruby/2.7.0/x86_64-darwin20",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/vendor_ruby",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0",
 "/Users/yutangzhao/.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/x86_64-darwin20"]
require 'pp'
#require '/Users/yutangzhao/Movies/Ruby/tool.rb' #默认做法
#require File.expand_path('../tool.rb',__FILE__) #cocoapods做法
load(File.expand_path('../tool.rb',__FILE__))

run

pp '*' * 25 + '打印路径' + '*' * 25

pp File.expand_path('../tool.rb',__FILE__)

#输出结果:
tool.rb ----
"*************************打印路径*************************"
"/Users/yutangzhao/Movies/Ruby/tool.rb"

autoload

#Tool.rb

module Tool
def run
 puts 'module--tool.rb ----'
end
end

===================================
require 'pp'
#autoalod(名字空间:Tool,tool.rb 绝对路径)
autoload(:Tool, File.expand_path('../tool.rb',__FILE__))
include(Tool)

run

self.send(:run)

#输出结果:
module--tool.rb ----
module--tool.rb ----

加载文件方式的区别

#多次require_relative 代码只会初始化一次
require_relative 'tool'
require File.expand_path('../tool',__FILE__)

#需要使用完整的路径名,load 调用一次代码就会执行一次
load File.expand_path('../tool.rb',__FILE__)

#用到的时候才会执行,相当于oc initialize
autoload(:Tool, File.expand_path('../tool.rb',__FILE__))

module

require 'pp'

module AAA
 NAME = 'hanghang'
 AGE = 99

 def run
 puts 'aaa run....'
 end

 def self.sleep
 puts 'aaa sleep...'
 end

#让module中的对象方法,也可以通过module::method方式调用 ,不建议这样做 会破坏module的封装性
 module_function:run
 
 class Dog

 end

 class Cat

 end

 module AAASub
 NAME = 'lisi'
 AGE = 88
 end

end

puts AAA::NAME
puts AAA::AGE

# AAA::run #=> error 只能通过include/extend/prepend 扩展才能使用
AAA::sleep

pp AAA::Dog.new
pp AAA::Cat.new

pp AAA::AAASub::NAME
pp AAA::AAASub::AGE

#输出结果:
hanghang
99
aaa sleep...
#<AAA::Dog:0x00007f90f1132228>
#<AAA::Cat:0x00007f90f11309a0>
"lisi"
88

====================main.rb====================
require_relative 'module'
AAA::run

#输出结果:
aaa run....

module扩展方式

  • include 影响方法查找链顺序
require_relative 'module'

#打印方法查找链
pp self.class.ancestors
include(AAA)
pp self.class.ancestors
eat
#类方法不需要扩展
AAA.sleep
#输出结果:
[Object, PP::ObjectMixin, Kernel, BasicObject]
[Object, AAA, PP::ObjectMixin, Kernel, BasicObject]
aaa eat....
aaa sleep....
  • extend 不影响方法查找链顺序
require_relative 'module'

#打印方法查找链
pp self.class.ancestors
extend(AAA)
eat
pp self.class.ancestors

#输出结果:
[Object, PP::ObjectMixin, Kernel, BasicObject]
aaa eat....
[Object, PP::ObjectMixin, Kernel, BasicObject]

============对象exend(module方法)================

require_relative 'module'

class Person
end

obj = Person.new
#打印方法查找链
pp obj.class.ancestors
obj.extend(AAA)
obj.eat
pp obj.class.ancestors

#输出结果:
[Person, Object, PP::ObjectMixin, Kernel, BasicObject]
aaa eat....
[Person, Object, PP::ObjectMixin, Kernel, BasicObject]


============类exend(module方法)================

require_relative 'module'

class Person
end

#打印方法查找链
pp Person.ancestors
Person.extend(AAA)
Person.eat
pp Person.ancestors

#输出结果:
[Person, Object, PP::ObjectMixin, Kernel, BasicObject]
aaa eat....
[Person, Object, PP::ObjectMixin, Kernel, BasicObject]

  • prepend 只能在类的作用域里扩展
require_relative 'module'

class Person
end

pp Person.ancestors
class Person
   prepend(AAA)
end

Person.new.eat
pp Person.ancestors

#输出结果:
[Person, Object, PP::ObjectMixin, Kernel, BasicObject]
aaa eat....
[AAA, Person, Object, PP::ObjectMixin, Kernel, BasicObject]

注意点: 只有对象方法才可以扩展给外界使用,类方法不需要扩展可以直接使用;ruby本身不支持多继承,可以通过扩展实现多继承的效果

class 与module的关系

class也是module的一种

class Config
    
    def hello(name)
       puts "hello #{name}"
    end
    
    module Mixin
      def xxx_hello(val)
         Config.new.hello(val)
      end
    end
end

class Icon
   include(Config::Mixin)
end
#单列扩展使用,调用会更简洁
Icon.new.xxx_hello('kitty')

#输出结果:
hello kitty

method_missing

class Person
 def self.run
  puts '*' * 50
 end
 
 def eat
  puts '?' * 50
 end
    
 def self.method_missing(method, *args, &block)
     puts "你调用了一个不存在的类方法 #{method}"
 end
 
 def method_missing(method, *args, &block)
     puts "你调用了一个不存在的对象方法 #{method}"
 end
end

Person.haha #类方法
Person.new.sleep #对象方法
#输出结果:
你调用了一个不存在的类方法 haha
你调用了一个不存在的对象方法 sleep

gitlab module定义方式

module Gitlab 
 class Client
    def self.run
     puts 'run.......'
    end 
 end 
end

# 调用类
Gitlab::Client.run

#打开类
module Gitlab 
    class Client
       def self.sleep
        puts 'sleep.......'
       end 
    end 
   end


#gitlab 打开类写法
class Gitlab:: Client
 def self.eat
    puts 'eat.....'
 end
end

  Gitlab::Client.run
  Gitlab::Client.sleep 
  Gitlab::Client.eat

  puts '=' * 50

  module AAA
    module BBB
        module CCC
            module DDD
                class Person
                    def self.jump
                     puts 'jump...'
                    end
                end
            end
        end
    end
end

#module多层嵌套打开方式
class AAA::BBB::CCC::DDD::Person
    def self.fly
     puts 'fly.....'
    end
end

AAA::BBB::CCC::DDD::Person.fly

#输出结果:
run.......
run.......
sleep.......
eat.....
==================================================
fly.....

module的accestor

module Configuration
    #%i 用于生成一个symbol数组
  VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httpparty].freeze
  attr_accessor(*VALID_OPTIONS_KEYS)
end

module Gitlab
    extend Configuration
end

Gitlab.endpoint = 'https://www.baidu.com'
Gitlab.private_token = 'DEDSdddadd'

puts "endpoint: #{Gitlab.endpoint}"
puts "private_token:#{Gitlab.private_token}"

open class

require 'pp'
class String
    def haha
        puts 'haha'
    end
end

"123".haha

#输出结果:
haha

open instance

require 'pp'
class Person
    def run
        puts 'run.....'
    end
end

obj = Person.new
def obj.run
 puts 'hook....'
  super
end

obj.run

puts '='*25 + '原始方法实现' + '='*25

Person.new.run

#输出结果:
yutangzhao@yutangzhaodeMacBook-Pro Ruby % ruby main.rb
hook....
run.....
=========================原始方法实现=========================
run.....

prepend hook

================Animal.rb=====================

class Animal
    def cry
        puts 'cry.....'
    end
end

================main.rb=====================

require 'pp'
require_relative 'animal'

module AnimalPatch
    def cry
        puts 'hook....'
        #调用原始方法
        super
    end
    
end

#打开类
class Animal
    prepend(AnimalPatch)
end

Animal.new.cry

#输出结果:
hook....
cry.....

instance_method hook

================Animal.rb=====================

module Animal
    class Dog
        def run
            puts 'run.....'
        end
    end
end

================main.rb=====================
require 'pp'
require_relative 'animal'

#打开类
module Animal
    class Dog

        origin_run_method = instance_method(:run)
        define_method(:run) do
            puts 'hook....'
            #调用原来的方法
            origin_run_method.bind(self).call
        end

        
    
end
end

Animal::Dog.new.run

#输出结果:
hook....
run.....

DSL

#执行一端ruby代码字符串

eval("def run ; puts 'run ...';end") #=>ruby main.rb
eval("run")

#输出结果:
run ...

spec

================podspec.rb=====================
class Spec
 attr_accessor :name, :version, :license, :summary

 def initialize
    @name = 'tangge'
    @version = '1.2.1'
    @license = 'APCH MTI'
    @summary = 'this is a beautiful vendor'
    
    yield self if block_given?()
 end

end

================ruby.podspec=====================
Spec.new do |s|
    s.name = 'AFNetworking'
    s.version = '4.1.2'
    s.license = 'MIT'
    s.summary = 'A delightful newworking library for Apple platform'
end

================main.rb=====================
#1.导入podspec实体类
require_relative 'podspec'

#2.读取ruby.podspec
str = File.read('ruby.podspec')

#3.解释创建Pod::spec对象
spec = eval(str)

#4.拿到spec对象的各种DSL属性值
puts spec.name
puts spec.version
puts spec.license
puts spec.summary

#输出结果:
AFNetworking
4.1.2
MIT
A delightful newworking library for Apple platform