简单过一下Ruby基础语法

本文首发于我的个人博客: https://by-musi.github.io/


学 web 安全也有段时间了,但我一直都只是在打靶场,实战直接猿形毕露,连个后台都找不到,呜呜。所以,我打算稍微改变下学习方式,目前思路是酱紫的:针对某一课题(最近在看 race conditions)–> 尽可能多、尽可能详细地分析实战案例、CVE --> 挑一些典型的尝试复现 --> 看到新的 vector 及时实践 --> 抽象出通用规律,探索自动化的可能。

不知道这思路好不好使,不过,干就完了!!

在分析过程中碰到好多 Ruby 代码,就简单过了下 Ruby 的基础语法,本文更多的是我学习过程中的记录,方便后续查阅。根据老马的第一性原理,我在学了 Ruby 基础语法之后,rails 应该也没啥问题了,devise 也是手到擒来,漏洞赏金绝对能拿到手软,如果没有,那就是老马有问题! (不是)

话不多说,hacking for fun!

啥时候能挖到我的处女洞啊!!!

参考资料:

输出字符串

括号可加可不加。

# 印出 Hello, World 
print "Hello, World"
# 印出 Hello, World 字樣,换行
puts "Hello, World"
# 印出 "Hello, World" 字樣(含引号),换行
p "Hello, World"

p 'hello world'
p %Q (hello world) # 印出 "hello world",双引号
p %q (hello world) # 印出 'hello world',单引号

字符串中嵌入变量:

name = "Sean"
age = 18
puts "I'm #{name}, and I am #{age} years old" # I'm Sean, and I am 18 years old

puts %Q(I'm #{name}, and I am #{age} years old) # I'm Sean, and I am 18 years old
puts %q(I'm #{name}, and I am #{age} years old) # 同單引號會失效
say_hi = "hello world"
puts say_hi[0] # => 印出 h
puts say_hi[5] # => 印出 空白 (注意空格也是字元)

say_hi[0..5] = "Hi!" #(把第0位到第5位字元重新指定,中間的..是範圍的用法)
puts say_hi    # => Hi! World

注释

# 這邊被單行註解瞜!!!
# 這邊被單行註解瞜!!!

=begin
這邊是多⾏註解啦!!
這邊是多⾏註解啦!!
 等等。
=end

函数

有时候 () 可加可不加

def hello # def hello()
	puts "hi, 你好啊!"
end

?! 可作为函数命名的一部分,不过只能放在最后面

def double_num?(num)
 return num * 2 # 回傳 num*2 ,可以省略return
end
p double_num?(5) # 印出 10

方法后的 ! 会改变对象原本的值。

list = [1,4,3,2]
p list.sort # 排序但不改變原本陣列,印出[1,2,3,4]
p list # 原本陣列還是印 [1,4,3,2]
p list.sort! # 排序但改變原本陣列 [1,2,3,4]
p list # 原本陣列改成 [1,2,3,4]

列表/数组 array

list = ["apple","bird","哈樓", 1, 2]
list = %w(apple bird 哈樓 1 2) # ["apple","bird","哈樓", "1", "2"] => 此时 "1","2" 是字符串
pokemon = ["皮卡丘","傑尼龜","妙蛙種子","小火龍"]
puts pokemon[0] # 印出 皮卡丘
puts pokemon[1] # 印出 傑尼龜
puts pokemon[-1] # 印出 小火龍
puts pokemon[-2] # 印出 妙蛙種子

# 可以用 first 和 last 取出頭或尾,
puts pokemon.first # 印出 皮卡丘
puts pokemon.last # 印出 小火龍

# length表示陣列的長度
puts pokemon.length # 印出 4
pokemon << '小智' # 在最後⾯加入
puts pokemon.length # 印出 5
pokemon.push('小霞') # 最後面加入
puts pokemon.length # 印出 6
puts pokemon # 經過上面處理印出 皮卡丘, 傑尼龜, 妙蛙種子, 小火龍, 小智, 小霞

话说台湾同胞都喜欢神奇宝贝嘛?!看见好几个了。

map 方法

|x| 代表传递给某个代码块的局部变量。

a = [1,2,3]
p a.map { |x| x*2 }
# 印出 [2, 4, 6]

select 方法

a = [1,2,3,4,5,6,7,8,9,10]
p a.select { |x| x < 5 }
# 印出 [1, 2, 3, 4]

reduce 方法

a = [1,2,3,4,5,6,7,8,9,10]
p a.reduce { |sum, n| sum + n } # p a.sum
# 印出 55

范围 Range

.. 少一点多一点,... 多一点少一点。 emmmm,6,同胞真是太幽默了。

# 少一點多一點 (包含頭尾)
puts (1..10).to_a # 印出 1 ~ 10 [1, 10]

# 多一點少一點 (不含尾)
puts (1...10).to_a # 印出 1 ~ 9 [1, 10)

# * 可以展開範圍
p *1..10 # 依序印出1~10
p [*1..10] # 印出 [1,2,3,4,5,6,7,8,9,10]
# map 對範圍內每個數值做x+1處理後回傳陣列
p [*1..10].map { |x| x+1} # [2,3,4,5,6,7,8,9,10,11]
p (1..10).to_a.map { |x| x+1} # 效果同上

# 字母也可以用大小來判斷呢,想像每個英文字母依照順序是有大小之分,越後面數值越大。 select可以挑選符合條件的元素形成陣列回傳
p ("a".."g").to_a.select { |chars| chars < "c"} # 取出小於"c" 的就會得到 ["a","b"]

哈希 hash

字典?

profile = { :name => 'caishao', :age => 20 } # 旧写法
profile = { name: 'caishao', age: 20 } # 新写法
profile = { name: 'caishao', age: 20 }
puts profile["name"] # nil
puts profile[:name] # caishao
profile.keys #拿取所有key => [:name, :age]
profile.values #拿取所有value => ["caishao", 20]
character[:power] = 100
p character #{:name=>"caishao", :age=>20, :power=>100}
profile = {name: "Sean", age: 25, power:100, ability: "Ruby"}
p profile.length # 4
p profile.size # 4

分支

age = 10
if age >= 0 && age<=10
  puts "小学生" # 年齡>=0 且<=3 就印
elsif age >= 11 && age<=17
  puts "青少年" # 年齡>=11 且<=17 就印
else
  puts "成年" #上述以外的條件都印這個
end

unless = if not

unless age >=18 # unless = if not
  puts "未成年" #如果年齡沒有大於等於18 才印出
end

三目运算

status = (age>=18)? "成年":"未成年" # 三目运算

case when,可使用范围。

age = 20
case age
when 0..10
  puts "小学生"
when 11..17
  puts "青少年"
else
  puts "成年"
end

迭代 Loop and Iteration

for 循环:

names = ["Sean", "Ken", "John", "Tom"]
for name in names
  puts name
end

# 印出"Sean", "Ken", "John", "Tom"

while 循环:

x = 0
while x < 10 #結束條件
  puts x
  x += 1 #改變條件
end
#依序印出 1~9

until 循环,until = while not:

x = 0
until x >= 10 #結束條件
  puts x
  x += 1 #改變條件
end
# 印出1~9 (大於等於10就停止)

loop 循环:

i = 0
loop do
  puts i
  i += 1 # 改變條件
  break if i > 10 # 終止條件
end
# 印出1~9

ruby 中 do-end{} 均可以表示代码块,二者可相互替换。loop 循环可理解为:loop + 代码块

i = 0
loop {
  puts i
  i += 1 # 改變條件
  break if i > 10 # 終止條件
  }
# 印出1~9

ruby 中数字也是对象,可对其使用方法,.times{} .upto() .downto()

#1 .times{} 執行特定次數 (大括號可換用 do...end)
5.times{puts "hello"}
5.times do
  puts "hello"
end # 印出 5次"hello"

#2 .upto() 由小到大(想像.upto後面用小括號接參數)
1.upto(10) do |i|
  puts "hello, ruby #{i}"
end

#3 .downto() 由大到小
10.downto(1) do |i|
  puts "hello, ruby #{i}"
end

迭代:

# each
names = ["Sean", "Ken", "John", "Tom"]
x = 0
names.each do |name|
  puts "#{x} #{name}"
  x += 1
end
# 印出 0 Sean, 1 Ken, 2 John, 3 Tom

# each_with_index ,效果同上
names = ["Sean", "Ken", "John", "Tom"]
x = 0
names.each_with_index do |name, x|
  puts "#{x} #{name}"
  x += 1
end
# 印出 0 Sean, 1 Ken, 2 John, 3 Tom

代码块 block

block 可以传递参数,|n| 代表传递给某个代码块的局部变量。

# test two 方法後面接上block,{}內的判斷就成為最後的回傳
# yield後面帶入的參數會影響下方{}內判斷結果,再回到原本方法去判斷是要印出哪個內容
def test_two
  if yield(2)
    puts "yes, it is 2"
  else
    puts "no, it is not 2"
  end
end

test_two {|n| n == 2 }

执行到 yield(2) 时,会先执行代码块 {|n| n == 2 } 的内容,并将参数 2 传递过去。感觉 yield 其实就是个可传参的代码占位符

do-end{} 的区别:

  1. 优先级不同
  2. 没啥区别了,多行建议用 do-end 单行用 {}
p [*1..10].map { |i| i * 2 }
# => 得到 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] {} 優先度高

p [*1..10].map do |i| i * 2 end
# => 得到 <Enumerator: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:map> do...end 優先度低,
# 可以還原成 (p [*1..10].map) do |i| i * 2 end,括號內先執行完,所以後面的條件沒有被帶入執行。

类 & 对象

#!/usr/bin/env ruby

class MegaGreeter
  attr_accessor :names # 允许使用 mg.names 访问属性 names

  # Create the object
  def initialize(names = "World") # 构造方法
    @names = names
  end

  # Say hi to everybody
  def say_hi
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("each")
      # @names is a list of some kind, iterate!
      @names.each do |name|
        puts "Hello #{name}!"
      end
    else
      puts "Hello #{@names}!"
    end
  end

  # Say bye to everybody
  def say_bye
    if @names.nil?
      puts "..."
    elsif @names.respond_to?("join")
      # Join the list elements with commas
      puts "Goodbye #{@names.join(", ")}.  Come back soon!"
    else
      puts "Goodbye #{@names}.  Come back soon!"
    end
  end
end


# 指明文件执行入口
if __FILE__ == $0 # 类似 python if "__name__" == "__main__":
  mg = MegaGreeter.new
  mg.say_hi
  mg.say_bye

  # Change name to be "Zeke"
  mg.names = "Zeke"
  mg.say_hi
  mg.say_bye

  # Change the name to an array of names
  mg.names = ["Albert", "Brenda", "Charles",
              "Dave", "Engelbert"]
  mg.say_hi
  mg.say_bye

  # Change to nil
  mg.names = nil
  mg.say_hi
  mg.say_bye
end

输出:

Hello World!
Goodbye World.  Come back soon!
Hello Zeke!
Goodbye Zeke.  Come back soon!
Hello Albert!
Hello Brenda!
Hello Charles!
Hello Dave!
Hello Engelbert!
Goodbye Albert, Brenda, Charles, Dave, Engelbert.  Come
back soon!
...
...

实例方法和类别方法:

class Human
  def initialize(name)
    @name = name
  end

  # 实例方法,作用在实例对象上
  def my_name
    puts "I'm #{@name}."
  end

  # 类别方法,作用在类上
  def self.say_hi
    puts "hi 我是類別方法"
  end  
  # class << self
  #   def all
  #   end
  # end
end

Sean = Human.new('Sean')
麥克 = Human.new('麥克')

#實體方法 instance method
Sean.my_name # => I'm Sean.
麥克.my_name # => I'm 麥克.
Human.my_name # => 出錯(NoMethodError)

#類別方法 class method
Human.say_hi # => hi 我是類別方法
Sean.say_hi # => 出錯(NoMethodError),實體沒辦法使用

继承:

class Animal
  def eat(food)
    puts "#{food} 也太好吃了吧!!"
  end
end

class Human < Animal
end

class Dog < Animal
end

模块 module 模组?

代码占位符?相当于把代码块导入类中

# 定義吐司模組
module spinning
  def spin
    puts "我會吐絲啦!"
  end
end

# 引入模組到人類類別
class Human
  include spinning # 引入吐絲模組
end

Sean = Human.new
Sean.spinning # 我會吐絲啦!

Class 与 Module 的区别:

3.1.2 :002 > Class.instance_methods - Module.instance_methods
 => [:allocate, :superclass, :subclasses, :new]

PS: Ruby 确实蛮灵活的,这都能减!!

类 Class 比模块 Module 多了以上四个方法,所以 Module:

  1. 无法创建实例
  2. 无法继承其他 Module
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值