# Debian, Ubuntu
$ sudo apt-get install ruby-full
# Windows
$ winget install RubyInstallerTeam.Ruby
$ brew install ruby # macOS
$ docker run -it --rm ruby:latest # Docker
$ docker run -it --rm ruby:2.7
使用包管理器安装 rbenv
$ brew install rbenv ruby-build # macOS
# Debian、ubuntu 和其他衍生产品
$ sudo apt install rbenv
使用 rbenv 安装 ruby
# 列出最新的稳定版本
$ rbenv install -l
# 列出所有本地版本
$ rbenv install -L
# 安装 Ruby 版本
$ rbenv install 3.1.2
$ rbenv global 3.1.2 # 为这台机器设置默认Ruby版本
# 或者
$ rbenv local 3.1.2 # 设置此目录的 Ruby 版本
$ rbenv local --unset
$ rbenv version # 显示当前活动的 Ruby 版本
=> 1.9.3-p327 (set by /Users/sam/.rbenv/version)
使用 RVM 安装 ruby
$ curl -sSL https://get.rvm.io | bash -s stable
$ rvm list # Ruby 版本列表
$ rvm install 3.0.1 # 安装 3.0.1
$ rvm use 3.0.1 # 使用 3.0.1
如何安装 ruby gem 管理器, bundler gem
# 访问 bash 以执行以下命令
$ docker run -it --rm ruby:latest bash
$ gem install bundler
$ bundle -v
$ gem update bundler
$ gem uninstall bundler
Gemfile 是 Bundler(也是 gem)的配置文件,其中包含项目的 gem 列表(依赖项)
# 在项目根目录的 Gemfile 中指定 gem
ruby '2.5.6'
source 'https://rubygems.org'
gem 'nokogiri'
gem 'rack', '~>1.1'
gem 'rspec', :require => 'spec'
安装 Gemfile 中的所有 gem
$ bundle install
解决开发用 mac,生产用 linux 出现的 Gemfile.lock 不一致问题
bundle lock --add-platform x86_64-linux
| 保留字 | 描述 |
|---|---|
__ENCODING__ | 当前文件的脚本编码 |
__LINE__ | 当前文件中此关键字的行号 |
__FILE__ | 当前文件的路径 |
BEGIN | 包含在 { } 中的代码在程序运行之前运行 |
END | 包含在 { } 中以在程序结束时运行 |
alias | 为现有方法、运算符、全局变量创建别名 |
and | 逻辑与运算符 |
begin | 开始一段代码 |
break | 终止循环 |
case | 将表达式与匹配的 when 子句进行比较,其中 以 end 结束 |
class | 定义一个类 |
def | 定义函数/方法 |
defined? | 检查某个变量、函数是否存在 |
do | 开始一个代码块并执行块中的代码,以 end关键字结束 |
else | 如果先前的条件不成立,则执行以下代码 |
elsif | if 表达式的替代条件 |
end | 用于结束以 begin、class、def、do、if 等关键字开头的代码块 |
ensure | 总是在块终止时执行 |
false | 逻辑布尔假值 |
for | 开始一个 for 循环 |
if | 如果 if 的条件语句为 true,则执行代码块 |
in | 与 for 循环一起使用 |
module | 定义一个模块 |
next | 跳转到循环条件评估之前的点 |
nil | 为空或无效或始终为假 |
not | 逻辑否定运算符 |
or | 逻辑或运算符 |
redo | 条件循环后跳转 |
rescue | 在引发异常后评估表达式 |
retry | • 在救援之外调用时,重复方法调用 • 在救援内部调用时,跳转到块顶部 |
return | 从方法或代码块返回值 |
self | 当前对象 |
super | 调用超类中的同名方法 |
then | 与 if、unless、when、case、rescue 一起使用的分隔符 |
true | 逻辑布尔真 |
undef | 使当前类中的方法/函数未定义 |
until | 在条件语句为假时执行代码块 |
when | 在 case 语句下开始一个子句 |
while | 执行代码块,直到条件语句变为假 |
yield | 执行传递给方法的代码块 |
andornot&&||!&|^~<<>>+-*/%**==!=><>=<=<=>===eql?equal?# 添加
1 + 1 #=> 2
# 减法
2 - 1 #=> 1
# 乘法
2 * 2 #=> 4
# 分配
10 / 5 #=> 2
17 / 5 #=> 3, not 3.4
17 / 5.0 #=> 3.4
# 指数
2 ** 2 #=> 4
3 ** 4 #=> 81
# 模数(求除法的余数)
8 % 2 #=> 0 (8 / 2 = 4; 没有剩余)
10 % 4 #=> 2 (10 / 4 = 2 余数为 2)
a = 10
b = 20
a == b #=> false
a != b #=> true
a > b #=> false
a < b #=> true
a >= b #=> false
a <= b #=> true
# 比较运算符
a <=> b #=> -1
c = 20
c <=> b #=> 0
c <=> a #=> 1
# 用于测试 case 语句的 when 子句中的相等性
(1...10) === 5 #=> true
# 如果接收者和参数具有相同的类型和相等的值,则为真
1.eql?(1.0) #=> false
c = a + b #=> 30
c += a #=> 40
c -= a #=> 30
c *= a #=> 300
c /= a #=> 30
c %= a #=> 3
c **= a #=> 59049
# Ruby 并行赋值
a = 10
b = 20
c = 30
a, b, c = 10, 20, 30
# Ruby 位运算符
a = 60
b = 13
# & 如果两个操作数中都存在,则二进制 AND 运算符将位复制到结果中。
a & b #=> 12
# | 如果二进制或运算符存在于任一操作数中,则复制一个位。
a | b #=> 61
# ^ 二元异或操作符如果在一个操作数中设置,则复制该位,但不能同时在两个操作数中设置。
a ^ b #=> 49
# ~ 二进制补码运算符是一元的,具有“翻转”位的效果。
~a
# << 二进制左移运算符。 左操作数的值被移动
# 左操作数指定的位数。
a << 2
# >> 二进制右移运算符。 左操作数的值被移动
# 右操作数指定的位数。
a >> 2
# Ruby 逻辑运算符
a and b #=> true.
a or b #=> true.
a && b #=> true.
(a || b) #=> true.
!(a && b) #=> false.
not(a && b) #=> false.
# Ruby 三元运算符
# ? :
# 如果条件为真? 然后值 X :否则值 Y
a == 10 ? puts 'Right' : puts 'Wrong'
# Ruby 范围运算符
# .. 创建从起点到终点的范围(含)
1..10 #=> 创建从 1 到 10 的范围(包括 1 到 10)
# ... 创建一个从起点到终点的范围,不包括在内
1...10 #=> 创建一个从 1 到 10 的独占范围
| 名字 | 说明 |
|---|---|
$! | 异常信息消息。raise 设置此变量 |
$@ | 最后一个异常的回溯,它是 String 的数组,指示调用方法的位置。格式中的元素如:“filename:line”或“filename:line:in `methodname'”(助记符:发生异常的地方) |
$& | 与此范围内最后一次成功的模式匹配匹配的字符串,如果最后一次模式匹配失败,则返回 nil。 (助记符:在某些编辑器中类似于 &)这个变量是只读的 |
$` | 当前范围内最后一次成功的模式匹配所匹配的任何内容之前的字符串,如果最后一次模式匹配失败,则为 nil。 (助记符:` 通常在带引号的字符串之前)此变量是只读的 |
$' | 当前范围内最后一次成功的模式匹配所匹配的字符串后面的字符串,如果最后一次模式匹配失败,则为 nil。 (助记符:' 通常跟在带引号的字符串之后) |
$+ | 最后一个成功的搜索模式匹配的最后一个括号,如果最后一个模式匹配失败,则为 nil。如果您不知道一组替代模式中的哪一个匹配,这很有用。 (助记:积极向上) |
$1, $2... | 包含上一次成功匹配的模式中相应括号集中的子模式,不计算已经退出的嵌套块中匹配的模式,或者如果最后一次模式匹配失败,则为 nil。 (助记符:如 \digit)这些变量都是只读的 |
$~ | 当前范围内最后一个匹配的信息。设置此变量会影响匹配变量,如 $&、$+、$1、$2.. 等。第 n 个子表达式可以通过 $~[nth] 检索。 (助记符:~ 用于匹配)这个变量是局部作用域的 |
$= | 不区分大小写的标志,默认为 nil。 (助记符:= 用于比较) |
$/ | 输入记录分隔符,默认为换行符。像 awk 的 RS 变量一样工作。如果设置为 nil,则将立即读取整个文件。 (助记符:/ 用于在引用诗歌时划定行界) |
$\ | print 和 IO#write 的输出记录分隔符。默认值为无。 (助记符:它就像 /,但它是你从 Ruby 中“返回”的东西) |
$, | 打印的输出字段分隔符。此外,它是 Array#join 的默认分隔符。 (助记符:当您的打印语句中有 , 时打印的内容) |
$; | String#split 的默认分隔符。 |
$. | 读取的最后一个文件的当前输入行号。 |
$< | 由命令行参数或标准输入给出的文件的虚拟连接文件(如果没有提供参数文件)。 $<.file 返回当前文件名。 (助记符:$< 是一个 shell 输入源) |
$> | print 的默认输出,printf。 $stdout 默认情况下。 (助记符:$> 用于 shell 输出) |
$_ | 通过gets或readline输入String的最后一行。如果gets/readline 遇到EOF,它被设置为nil。这个变量是局部作用域的。 (助记符:部分与 Perl 相同) |
$0 | 包含包含正在执行的 Ruby 脚本的文件的名称。在某些操作系统上,分配给 $0 会修改 ps(1) 程序看到的参数区域。作为一种指示当前程序状态的方式,这比隐藏您正在运行的程序更有用。 (助记符:与 sh 和 ksh 相同) |
$* | 为脚本提供的命令行参数。 Ruby 解释器的选项已被删除。 (助记符:与 sh 和 ksh 相同) |
$$ | 运行此脚本的 Ruby 的进程号。(助记符:与贝壳相同) |
$? | 最后执行的子进程的状态。 |
$: | 该数组包含通过 load 或 require 查找 Ruby 脚本和二进制模块的位置列表。 它最初由任何 -I 命令行开关的参数组成,然后是默认的 Ruby 库,probabl "/usr/local/lib/ruby",然后是 ".",表示当前目录 . (助记符:冒号是 PATH 环境变量的分隔符) |
$" | 该数组包含由 require 加载的模块名称。 用于防止 require 两次加载模块。助记符:防止文件被双引号(加载) |
$DEBUG | -d 开关的状态。 |
$FILENAME | 与$<.filename 相同 |
$LOAD_PATH | $: 的别名 |
$stdin | 当前的标准输入 |
$stdout | 当前的标准输出 |
$stderr | 当前标准错误输出 |
$VERBOSE | 详细标志,由 -v 开关设置到 Ruby 解释器 |
| 名字 | 说明 |
|---|---|
TRUE | 典型的真值。在 Ruby 中,所有非 false 值(除了 nil 和 false 之外的所有值)都是 true |
FALSE | 虚假本身 |
NIL | 零本身 |
STDIN | 标准输入。$stdin 默认值 |
STDOUT | 标准输出。$stdout 默认值 |
STDERR | 标准错误输出。$stderr 默认值 |
ENV | 类哈希对象包含当前环境变量。 在 ENV 中设置值会更改子进程的环境 |
ARGF | $< 的别名 |
ARGV | $* 的别名 |
DATA | 脚本的文件对象,就在 END 之后。 除非未从文件中读取脚本,否则未定义 |
VERSION | Ruby 版本字符串 |
RUBY_RELEASE_DATE | 发布日期字符串 |
RUBY_PLATFORM | 平台标识符 |
| 类型 | 示例 | Class | 文档 |
|---|---|---|---|
Integer | a = 17 | a.class > Integer a.class.superclass > Numeric | # |
Float | a = 87.23 | a.class > Float a.class.superclass > Numeric | # |
String | a = "Hello universe" | a.class > String | # |
Array | a = [12, 34] | a.class > Array | # |
Hash | a = {type: "tea", count: 10} | a.class > Hash | # |
Boolean | a = false a = true | a.class > FalseClass a.class > TrueClass | TrueClass FalseClass |
Symbol | a = :status | a.class > Symbol | # |
Range | a = 1..3 | a.class > Range | # |
Nil | a = nil | a.class > NilClass | # |
.. 用于创建包含范围
range = 1..10
range.to_a
# 输出 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
... 用于创建专属范围
range = 1...10
range.to_a
# 输出 => [1, 2, 3, 4, 5, 6, 7, 8, 9]
一些有用的方法
| Method name | Output |
|---|---|
cover? | (1..5).cover?(5) => true |
end | ('a'..'z').end => "z" |
first | (1..5).first => 1 |
first(3) | ('A'..'Z').first(2) => ["A", "B"] |
eql? | ((0..2).eql?(0..5) => false |
# case 返回最后执行的表达式的值
case input
# 检查一个整数,19
when 19
puts "It's 19"
# 检查浮点数,33.3
when 33.3
puts "It's 33.3"
# 检查一个确切的字符串,“Zaman”
when "Zaman"
puts "Hi Zaman"
when 10
puts "It's 10"
# 检查范围
when 7..11
puts "It's between 7 and 11"
# 检查多个值,“咖啡”
when "tea", "coffee"
puts "Happy days"
# 检查正则表达式“aA6”
when /^a[A-Z]+[0-6]+$/
puts "It's a valid match"
# 通过与 String 类“任何字符串”
# 进行比较来检查任何字符串
when String
puts "It's a String"
end
| 函数名称 | Output | Note |
|---|---|---|
| length or size | "HELLO World".length => 11 "HELLO World".size => 11 | 返回字符串的长度 |
| reverse | "hello worlD".reverse => "Dlrow olleh" | 返回反转的字符串 |
| include? other_str | "hEllo wOrlD".include? "w" => true | 如果字符串或字符存在则返回 true,否则返回 false |
| gsub(pattern, replacement) | "hEllo wOrlD".gsub(" ", "_") => "hEllo_wOrlD" | gsub 或全局替换用提供的字符串替换一个或多个字符串 |
| gsub(pattern, hash) | "organization".gsub("z", 'z' => 's') => "organisation" | gsub 或全局替换用提供的哈希替换一个或多个字符串 |
| gsub(pattern) { |match| block} | "Price of the phone is 1000 AUD".gsub(/\d+/) { |s| '$'+s } "Price of the phone is $1000 AUD" | gsub 或全局替换用提供的块替换一个或多个字符串 |
| strip | " hEllo WOrlD ".strip "hEllo WOrlD" | 它将删除(修剪)以下任何前导和尾随字符:null(“\x00”)、水平制表符(“\t”)、换行符(\n)、垂直制表符(“\v”)、换页符(f)、回车(\r)、空格(" ") |
| prepend | a = "world" <br> a.prepend("hello ") "hello world" | 在另一个字符串之前添加字符串 |
| insert | a = "hello" <br> a.insert(a.length, " world") "hello world" | 在特定位置插入字符串 |
| start_with? | string = "ruby programming" string.start_with? "ruby" true | 检查字符串是否以特定前缀开头 |
| end_with? | string = "ruby programming" string.end_with? "ruby" false | 检查字符串是否以特定前缀结尾 |
| delete_suffix | string = "sausage is expensive" string.delete_suffix(" is expensive") "sausage" | 从字符串中删除后缀 |
| delete_prefix | string = "sausage is expensive" string.delete_prefix("sausage") " is expensive" | 从字符串中删除前缀 |
| split | string = "a b c d" <br> string.split ["a", "b", "c", "d"] | 将字符串转换为字符数组 |
| join | arr = ['a', 'b', 'c'] <br> arr.join => "abc" | 将数组转换为字符串 |
| to_i | a = "49" <br> a.to_i => 49 | 将字符串转换为整数 |
| chop | "abcd?".chop("?") => "abcd" | 从字符串中删除最后一个字符 |
| count | str = "aaab" <br> str.count("a") 3 | 计算字符串中的字符 |
| to_f | a = "49" a.to_f 49.0 | 将字符串转换为浮点数 |
| to_sym | a = "key" a.to_sym :key | 将字符串转换为符号 |
| match | "abcd?".match(/ab/) => #<MatchData "ab"> | 将模式转换为正则表达式并在字符串上调用其匹配方法 |
| empty? | "hello".empty? => false | 如果字符串的长度为零,则返回 true |
| squeeze | "Booook".squeeze => "Bok" | 返回字符串的副本,其中相同字符的运行被单个字符替换 |
| * | puts "Ruby " * 4 => Ruby Ruby Ruby Ruby | 返回多个 self 副本的串联 |
| + | "sammy " + "shark" => "sammyshark" | 返回 self 和给定的其他字符串的连接 |
| eql? | s = 'foo' => true s.eql?('foo') => true | 如果对象具有相同的长度和内容,则返回 true;作为自己;否则为假 |
| + | "sammy " + "shark" => "sammyshark" | 返回 self 和给定的其他字符串的连接 |
| + | "sammy " + "shark" => "sammyshark" | 返回 self 和给定的其他字符串的连接 |
类方法是类级别的方法。 有多种定义类方法的方法
class Mobile
def self.ring
"ring ring ring..."
end
end
Mobile.ring
class Mobile
def Mobile.ring
"ring ring ring..."
end
end
Mobile.ring
class Mobile
class << self
def ring
"ring ring ring..."
end
end
end
Mobile.ring
类方法是类对象的实例方法。 当创建一个新类时,“Class”类型的对象被初始化并分配给一个全局常量(在本例中为 Mobile)
Mobile = Class.new do
def self.ring
"ring ring ring..."
end
end
Mobile.ring
Mobile = Class.new
class << Mobile
def ring
"ring ring ring..."
end
end
Mobile.ring
def method_name(type, *values)
return values.reduce(:+) if type == "ADD"
return values.reduce(:-) if type == "SUB"
end
numbers = [2, 2, 2, 3, 3, 3]
res = method_name("ADD", *numbers)
# 输出 => 15
res = method_name("SUB", *numbers)
# 输出 => -11
# 或者您可以提供这样的值
res = method_name("ADD", 2, 2, 2, 3, 3, 3)
# 输出 => 15
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.insert(0, 0)
#=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.insert(0, -3, -2, -1)
#=> [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.insert(-1, 12, 13, 14)
#=> [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]
numbers.insert(-4, 11)
#=> [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
primes = [7, 2, 3, 5]
sorted_primes = primes.sort
puts "#{sorted_primes}"
# 输出 => [2, 3, 5, 7]
or in-place sort
primes = [7, 2, 3, 5]
primes.sort!
puts "#{primes}"
# 输出 => [2, 3, 5, 7]
planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
planets.sort
# 输出
# ["Earth", "Jupiter", "Mars", "Mercury", "Neptune", "Saturn", "Uranus", "Venus"]
planets.sort_by { |p| p }
# 输出
# ["Earth", "Jupiter", "Mars", "Mercury", "Neptune", "Saturn", "Uranus", "Venus"]
planets.sort_by { |p| p.length }
# 输出
# ["Mars", "Earth", "Venus", "Saturn", "Uranus", "Neptune", "Jupiter", "Mercury"]
# 当你有单行块时
salary = [399, 234, 566, 533, 233]
salary.each { |s| puts s }
# 输出
# 399
# 234
# 566
# 533
# 233
当你有一个多行块时,你可以用 do 和 end 替换花括号 {}
salary.each do |s|
a = 10
res = a * s
puts res
end
# 输出
# 3990
# 2340
# 5660
# 5330
# 2330
或者您可以使用大括号 {} 和分号作为分隔符而不是换行符来做同样的事情
salary.each { |s| a = 10 ; res = a * s ; puts res }
colors = [
{color: "red", count: 3}, {color: "red", count: 5}, {color: "black", count: 4}
]
colors.each_with_object(Hash.new(0)) { |color, hash| hash["color_"+color[:color]] = color[:color].upcase; hash["count_"+color[:color]] += color[:count] }
# 输出
{"color_red"=>"RED", "count_red"=>8, "color_black"=>"BLACK", "count_black"=>4}
[1, 2, 3].each_with_object(0) { |number, sum| sum += number}
# 输出
# 0
# 因为0是不可变的,由于初始对象是0,所以方法返回0
numbers = [2, 2, 2, 2, 2]
numbers.inject{ |res, n| res + n }
# 输出是所有数字之和的结果
# 如果不给res设置初始值,则数组的第一个元素作为res的初始值
# 10
# 现在将 res 的值设置为 11
numbers = [2, 2, 2, 2, 2]
numbers.inject(11) { |res, n| res + n }
# so 11 + 2, 13 + 2, 15 + 2, 17 + 2 and 19 + 2
# 21
# using symbol
numbers = [2, 2, 2, 2, 2]
numbers.inject(:+)
# 输出
# 10
使用初始值和符号
numbers = [2, 2, 2, 2, 2]
numbers.inject(11, :+)
# 输出
# 21
& 返回一个新数组,其中包含在数组和数组 other_array 中找到的每个元素;省略重复;使用 eql? 比较项目intersection 返回一个新数组,其中包含在 self 和所有给定数组 other_arrays 中找到的每个元素;省略重复;使用 eql? 比较项目+ 返回一个数组,该数组包含 self 的所有元素,后跟给定数组的所有元素- 返回一个数组,其中包含在给定数组中找不到的所有 self 元素union 返回一个数组,其中包含 self 的所有元素和给定数组的所有元素,已删除重复项difference 返回一个数组,其中包含在任何给定数组中找不到的所有 self 元素product 返回或产生来自 self 和给定数组的所有元素组合[0, 1, 2, 3] & [1, 2] # => [1, 2]
[0, 1, 0, 1] & [0, 1] # => [0, 1]
data = [456, 3000]
retry_count = 0
status = "network failure"
sum = 0
data.each do |d|
if retry_count == 3
status = "connection established"
retry_count = 0
redo
elsif status == "network failure" and retry_count < 5
puts "network failure #{retry_count}"
retry_count += 1
redo
elsif status == "connection established"
puts d
sum += d
end
end
# output of sum
# 3456
class Person
# when you create a new object, it looks for a method named initialize and executes it, like a constructor in java
# def initialize(name, number)
# @name = name
# @number = number
# end
# instance variable
# @name
# class variable
# @@count
# attr_accessor acts as a getter and setter for the following instance attributes
attr_accessor :name, :number
# class variable must be initialized
@@count = 0
def self.count
@@count
end
def self.count=(count)
@@count = count
end
def initialize
@@count += 1
end
end
# create an instance of the Person class
p1 = Person.new
# set attributes of the Person class
p1.name = "Yukihiro Matsumoto"
p1.number = 9999999999
# get attributes of the Person class
puts "#{p1.name}"
puts "#{p1.number}"
puts "#{Person.count}"
# Yukihiro Matsumoto
# 9999999999
# 1
p2 = Person.new
p2.name = "Yukihiro Matsumoto"
p2.number = 9999999999
# get attributes of the Person class
puts "#{p2.name}"
puts "#{p2.number}"
puts "#{Person.count}"
# Yukihiro Matsumoto
# 9999999999
# 2
# set class variable
Person.count = 3
puts "#{Person.count}"
# 3