Ruby 语言

精选 Ruby 语言 常用指令与核心速查备忘单,涵盖高频用法、配置参数与实用技巧。

#入门指南

#安装 (Installation)

# Debian, Ubuntu
$ sudo apt-get install ruby-full
# Windows
$ winget install RubyInstallerTeam.Ruby
$ brew install ruby # macOS
$ docker run -it --rm ruby:latest # Docker

#What is Gemfile and Gemfile.lock

  • Gemfile Is the Bundler (also gem) configuration file that contains the project's gem list (dependencies)
# Specify gem in the Gemfile in the project root directory
ruby '3.1.2'

source 'https://rubygems.org'
gem 'nokogiri'
gem 'rack', '~>3.0.10'
gem 'rspec', :require => 'spec'

Install all gems in Gemfile

$ bundle install

Solve the problem of Gemfile.lock inconsistency between mac for development and linux for production

bundle lock --add-platform x86_64-linux

#安装 (Installation)

$ gem install bundler -v 2.4.20
$ gem install minitest -v 5.22.3

#Update gems using Bundler

# Updating a single gem using Bundler
$ bundle update nokogiri
# Use Bundler to update each gem in the Gemfile
$ bundle update

#代码注释 (Comments)

# This is a single line comments.
=begin
Multi-line
Comment
=end
puts "Hello world!"  # Inline comments for code

#reserved words

Reserved words Description
__ENCODING__ The script encoding of the current file
__LINE__ The line number of this keyword in the current file
__FILE__ The path of the current file
BEGIN Code enclosed in { } is run before the program is run
END Code enclosed in { } is run at the end of the program
alias Create an alias for an existing method, operator, or global variable
and Logical AND operator
begin Begin a block of code
break Terminate a loop
case Compare an expression with matching when clauses, terminated with
end
class Define a class
def define a function/method
defined? Check if a variable or function exist
do Start a block of code, terminated with the
end keyword
else Execute the following code if previous conditions are not met
elsif Alternative condition for if expressions
end End blocks of code starting with keywords like begin, class,def,do,if, etc.
ensure Always execute at the end of a block
false Logical boolean value false
for Start a for loop
if Execute the code block if the condition is true
in Used with for loop
module Define a module
next jump to the point before the evaluation of the loop condition
nil Stand for null, invalid, or always false
not Logical NOT operator
or Logical OR operator
redo Jump back to the loop condition evaluation
rescue Evaluate expressions after an exception is raised
retry Repeat method calls when called outside rescue, jump to the top of the block when called inside rescue
return Return a value from a method or block
self Refer to the current object
super Call the same-named method in the superclass
then Used as a separator withif,unless,when,case,rescue
true Logical boolean value true
undef Undefine methods/functions within the current class
until Execute the code block until the condition is false
when Begin a clause under a case statement
while Execute the code block while the condition is true
yield Execute the code block passed to a method

#Operator

#Logical Operators

  • and
  • or
  • not
  • &&
  • ||
  • !

#Bit operators

  • &
  • |
  • ^
  • ~
  • <<
  • >>

#Arithmetic operators

  • +
  • -
  • *
  • /
  • %
  • **

#Comparison operator

  • ==
  • !=
  • >
  • <
  • >=
  • <=
  • <=>
  • ===
  • eql?
  • equal?

#Operator examples

# Addition
1 + 1   #=> 2
# Subtraction
2 - 1   #=> 1
# Multiplication
2 * 2   #=> 4
# Division
10 / 5  #=> 2
17 / 5    #=> 3, not 3.4
17 / 5.0  #=> 3.4
# Exponentiation
2 ** 2  #=> 4
3 ** 4  #=> 81
# Modulus (remainder of division)
8 % 2   #=> 0  (8 / 2 = 4; no remainder)
10 % 4  #=> 2  (10 / 4 = 2 remainder 2)
a = 10
b = 20
a == b #=> false
a != b #=> true
a > b #=> false
a < b #=> true
a >= b #=> false
a <= b #=> true

# Comparison operators
a <=> b #=> -1
c = 20
c <=> b #=> 0
c <=> a  #=> 1
# Equality used in when clauses for case statements
(1...10) === 5 #=> true
# True if the receiver and the argument have the same type and equal values
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 parallel assignment
a = 10
b = 20
c = 30
a, b, c = 10, 20, 30
# Ruby bitwise operators
a = 60
b = 13
# & Binary AND operator copies a bit to the result if it exists in both operands.
a & b #=> 12
# | Binary OR operator copies a bit if it exists in either operand.
a | b #=> 61
# ^ Binary XOR operator copies a bit if it is set in one operand but not both.
a ^ b #=> 49
# ~ Binary Ones Complement is unary and has the effect of 'flipping' bits.
~a
# << Binary Left Shift Operator. The left operand's value is moved
# left by the number of bits specified by the right operand.
a << 2
# >> Binary Right Shift Operator. The left operand's value is moved
# right by the number of bits specified by the right operand.
a >> 2

# Ruby logical operators
a and b #=> true.
a or b #=> true.
a && b #=> true.
(a || b) #=> true.
!(a && b) #=> false.
not(a && b) #=> false.
# Ruby ternary operator
# ? :
# If condition is true ? Then value X : Otherwise value Y
a == 10 ? puts 'Right' : puts 'Wrong'
# Ruby range operators
# .. Creates a range from the start point to the end point (inclusive)
1..10 #=> Creates a range from 1 to 10 (inclusive of 1 and 10)
# ... Creates an exclusive range from the start point to the end point
1...10 #=> Creates an exclusive range from 1 to 10

#Operator precedence table

From highest to lowest, this is the precedence table for ruby. High precedence operations happen before low precedence operations.

  • !, ~, unary +
  • **
  • unary -
  • *, /, %
  • +, -
  • <<, >>
  • &
  • |, ^
  • , >=, <, <=

  • <=>, ==, ===, !=, =~, !~
  • &&
  • ||
  • .., ...
  • ?, :
  • modifier-rescue
  • =, +=, -=, etc.
  • defined?
  • not
  • or, and
  • modifier-if, modifier-unless, modifier-while, modifier-until
  • { } blocks

#变量声明 (Variables) and scope

- - - -
Name Scope Example Explanation
[a-z] or _ Local count = 10 or _count = 10 Local variables must be initialized
@ Instance variable @id = [] Instance variables have a "nil" value before initialization
@@ Class variable @@name = [] Class variables must be initialized
$ Global variable $version = "0.8.9" Global variables have a "nil" value before initialization
[A-Z] Constant PI = 3.14 Constant variables must be initialized, you can change constants, but you will receive a warning

There are five different types of variables. The first character determines the range To read in deap about variables check User Guide cap 19,20,21,22,23 Pre-Defined Variables and Constants

#Check the scope of a variable

defined? count
"local-variable"
defined? @id
"instance-variable"
defined? @@name
"class variable"
defined? $version
"global-variable"
defined? PI
"constant"

#Data Types

- - - -
Type Example Class Documentation
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 = 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 #

further reading

#Check data type

# Both are synonyms
a = 37
a.kind_of? Integer
# true
a.is_a? Integer
# true

#Symbol

week_days = {sunday: 11, monday: 222}

#Integer useful methods

2.even?
# true
3.even?
# false

#Range

.. Used to create inclusive ranges

range = 1..10
range.to_a
# output => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

... Used to create exclusive ranges

range = 1...10
range.to_a
# output => [1, 2, 3, 4, 5, 6, 7, 8, 9]

some useful methods

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

#Using step in Range

(1..20).step(2) { |number| puts "#{number}"}
# output
# 1
# 3
# 5
# 7
# 9
# 11
# 13
# 15
# 17
# 19

#Ruby Flow control

#if

num = 2
puts 'two' if num == 2

If the condition is true, execute the code

#if elsif else

temp = 19
if temp >= 25
  puts "hot"
elsif temp < 25 && temp >= 18
  puts "normal"
else
  puts "cold"
end
# output => normal

#unless

# Unless contrary to if , evaluates when the statement is false
name = "rob"
# if name != "bob"
unless name == "bob"
  puts "hello stranger"
else
  puts "hello bob"
end
# output => hello stranger
num = 6
puts 'not two' unless num == 2
# output => not two

#case

# case returns the value of the last expression executed
case input
# Check for an integer, 19
when 19
  puts "It's 19"
  # Check for an exact string,“Zaman”
when "Zaman"
  puts "Hi Zaman"
when 7..11
  puts "It's between 7 and 11"
  # Check multiple values, "coffee"
when "tea", "coffee"
  puts "Happy days"
end

#case( short syntax )

case input
  when 19 then puts "It's 19"
end

#case( 可选 failure )

case input
  when 19 then puts "It's 19"
else
  puts "It's not 19"
end

#case( Get return value )

marks = 86
result = case marks
        when 0..49 then "Fail"
        when 50..64 then "Pass"
        when 65..74 then "Credit"
        when 75..84 then "Distinction"
        when 85..100 then "High Distinction"
        else "Invalid marks"
        end

puts result
# High Distinction

#String

#字符串 (Strings) interpolation

name = "World"
puts "Hello #{name}"
puts "The total is #{1+1}"
# "the total is 2"

String interpolation allows you to combine strings together

#Extract substring

string = "abc123"
string[0,3]
# "abc"
string[3,3]
# "123"
string[0..-2]
# "abc12"
#remove or replace the substring
string[0..2] = ""
puts string
# "123"

A substring is a small part of a string, which is useful if you only want that specific part, like the beginning, middle, or end

#Convert a string to lowercase or uppercase

"HELLO World".downcase  # "hello world"
"hello worlD".upcase    # "HELLO WORLD"
"hEllo wOrlD".capitalize # "Hello world"
"hEllo WOrlD".swapcase  # "HeLLO woRLd"

#useful methods

Function Name Output Note
length or size "HELLO World".length => 11
"HELLO World".size => 11
Returns the length of the string
reverse "hello worlD".reverse => "Dlrow olleh" Returns the reversed string
include? other_str "hEllo wOrlD".include? "w" => true Returns true if the string or character exists, otherwise returns false
gsub(pattern, replacement) "hEllo wOrlD".gsub(" ", "_") => "hEllo_wOrlD" gsub or global substitute replaces one or more strings with the provided string
gsub(pattern, hash) "organization".gsub("z", 'z' => 's') => "organisation" gsub or global substitute replaces one or more strings with the provided hash
gsub(pattern) "Price of the phone is 1000 AUD".gsub(/\d+/) {\| s\| '$'+s }
"Price of the phone is $1000 AUD"
gsub or global substitute replaces one or more strings with the provided block
strip " hEllo WOrlD ".strip
"hEllo WOrlD"
It will remove (trim) any leading and trailing characters: null (“\x00”), horizontal tab (“\t”), newline (\n), vertical tab (“\v”), form feed (f), carriage return(\r), space (" ")
prepend a = "world" <br> a.prepend("hello ")
"hello world"
Adds the string before another string
insert a = "hello" <br> a.insert(a.length, " world")
"hello world"
Inserts the string at a specific position
start_with? string = "ruby programming"
string.start_with? "ruby"
true
Checks if the string starts with a specific prefix
end_with? string = "ruby programming"
string.end_with? "ruby"
false
Checks if the string ends with a specific prefix
delete_suffix string = "sausage is expensive"
string.delete_suffix(" is expensive")
"sausage"
Deletes the suffix from the string
delete_prefix string = "sausage is expensive"
string.delete_prefix("sausage")
" is expensive"
Deletes the prefix from the string
split string = "a b c d" <br> string.split
["a", "b", "c", "d"]
Converts the string into an array of characters
join arr = ['a', 'b', 'c'] <br> arr.join => "abc" Converts an array into a string
to_i a = "49" <br> a.to_i => 49 Converts the string into an integer
chop "abcd?".chop("?") => "abcd" Deletes the last character from the string
count str = "aaab" <br> str.count("a")
3
Counts the characters in the string
to_f a = "49"
a.to_f
49.0
Converts the string into a floating point number
to_sym a = "key"
a.to_sym
:key
Converts the string into a symbol
match "abcd?".match(/ab/) => #<MatchData "ab"> Converts the pattern into a regular expression and calls its match method on the string
empty? "hello".empty? => false Returns true if the length of the string is zero
squeeze "Booook".squeeze => "Bok" Returns a copy of the string where runs of the same character are replaced by a single character
* puts "Ruby " * 4 => Ruby Ruby Ruby Ruby Returns the concatenation of multiple copies of self
+ "sammy " + "shark" => "sammyshark" Returns the concatenation of self and the given other string
eql? s = 'foo' => true
s.eql?('foo') => true
Returns true if the objects have the same length and content; false otherwise

#Methods

#Declare a method

def method_name(parameter1, parameter2)
    puts "#{parameter1} #{parameter2}"
    parameter1 + parameter2
end

res = method_name(20, 10)
# output => 30
def method_name(parameter1, parameter2)
    puts "#{parameter1} #{parameter2}"
    return parameter1 + parameter2
end
# output => 30
res = method_name(20, 10)
# output => 30
def method_name(parameter1, parameter2)
    puts "#{parameter1} #{parameter2}"
    return parameter1 + parameter2
end
# output => 30

#调用方法 (Call method)

res = method_name(parameter1, parameter2)
# Methods can be called without parentheses
res = method_name parameter1, parameter2

#类方法 (Class method)

类方法是类级别的方法,有多种定义方式

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

#用另一参数作默认值 (Use another parameter as 默认值)

def method_name(num1, num2 = num1)
    return num1 + num2
end
res = method_name(10)
# output => 20

#为方法参数定义默认值 (Define 默认值s for method parameters)

def method_name(parameter1, parameter2, type = "ADD")
    puts "#{parameter1} #{parameter2}"
    return parameter1 + parameter2 if type == "ADD"
    return parameter1 - parameter2 if type == "SUB"
end
res = method_name(20, 10)
# output => 30

#向方法传递可变长参数 (Pass variable length arguments to method parameters)

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)
# output => 15
res = method_name("SUB", *numbers)
# output => -11
# Or you can provide a value like this
res = method_name("ADD", 2, 2, 2, 3, 3, 3)
# output => 15

#修改对象 (Modify object)

a = ["Drama", "Mystery", "Crime",
"Sci-fi", "Disaster", "Thriller"]
a.sort
puts a
# We did not modify the object
# Drama
# Mystery
# Crime
# Sci-fi
# Disaster
# Thriller
a.sort!
puts a
# Modify object
# Crime
# Disaster
# Drama
# Mystery
# Sci-fi
# Thriller

若要修改对象本身,在方法后加 !

#布尔方法 (Boolean method)

在 Ruby 中,以问号 (?) 结尾的方法称为布尔方法,返回 truefalse

"some text".nil?
# false
nil.nil?
# true

你也可以自定义布尔方法

def is_vowel?(char)
    ['a','e','i','o','u'].include? char
end
is_vowel? 'a'
# true
is_vowel? 'b'
# false

#代码块

#代码块示例 (Block example)

# return value
def give_me_data
    data = yield
    puts "data = #{data}"
end
give_me_data { "Big data" }
# output => data = Big data

doend(多行)或花括号 {}(单行)之间的代码称为代码块, 并可在两根竖线之间定义多个参数 ( |arg1, arg2|)

#单行代码块 (Single line block)

salary = [399, 234, 566, 533, 233]
salary.each { |s| puts s }
# puts s = block body
# |s| = block arguments

#多行代码块 (Multi-line block)

salary.each do |s|
    a = 10
    res = a * s
    puts res
end
# Block
# a = 10
# res = a * s
# puts res
# block parameters
# |s|

代码块可作为方法参数传入或与方法调用关联;代码块返回最后求值的语句

#隐式传递代码块 (Implicitly passing a block)

def give_me_data
    puts "I am inside give_me_data method"
    yield
    puts "I am back in give_me_data method"
end

give_me_data { puts "Big data" }

# output
# I am inside give_me_data method
# Big data
# I am back in give_me_data method

#多次调用 (Called multiple times)

def give_me_data
    yield
    yield
    yield
end

give_me_data { puts "Big data" }

# output
# Big data
# Big data
# Big data

#带代码块参数调用 (Called with block parameters)

def give_me_data
    yield 10
    yield 100
    yield 30
end

give_me_data { |data| puts "Big data #{data} TB" }

# output
# Big data 10 TB
# Big data 100 TB
# Big data 30 TB

#带多个代码块参数调用 (Called with multiple block parameters)

def give_me_data
    yield "Big data", 10, "TB"
    yield "Big data", 100, "GB"
    yield "Big data", 30, "MB"
end

give_me_data { |text, data, unit| puts "#{text} #{data} #{unit}" }

# output
# Big data 10 TB
# Big data 100 GB
# Big data 30 MB

#代码块会尝试从当前上下文返回 (Block will attempt to return from the current context)

give_me_data
    puts "I'm inside the give_me_data method"
end

def test
  puts "I'm inside the test method"
  give_me_data { return 10 } # Code returns from here
  puts "I am back in test method"
end

return_value = test

# output
# I'm inside the test method
# I'm inside the give_me_data method
# 10

#用 & 参数显式传递代码块 (Pass the block explicitly by using the & parameter)

def give_me_data(&block)
    block.call
    block.call
end

give_me_data { puts "Big data" }

# output
# Big data
# Big data

#检查是否传入代码块 (Check if block is given)

def give_me_data
    yield
end

give_me_data

# output
# LocalJumpError: no block given (yield)

#处理异常并使代码块可选 (Ways to handle exceptions and make blocks 可选)

def give_me_data
    return "no block" unless block_given?
    yield
end

give_me_data { puts "Big data" }
give_me_data

# output
# Big data

#Procs 对象

#Procs 简介 (Procs)

p = Proc.new { puts "Hello World" }

def give_me_data(proc)
    proc.call
end

give_me_data p

# output
# Hello World

proc 类似可存入变量的代码块

#任意参数 (any parameter)

p = Proc.new { |count| "Hello World " * count }

def give_me_data(proc)
    proc.call 5, 2
end

give_me_data p

# output
# ""

#proc 会尝试从当前上下文返回 (proc will attempt to return from the current context)

p = Proc.new { return 10 }
p.call
# output
LocalJumpError: unexpected return

#无法从顶层上下文返回 (Cannot return from top-level context)

def give_me_data
    puts "I'm inside the give_me_data method"
    p = Proc.new { return 10 }
    p.call # Code returns from here
    puts "I am back in give_me_data method"
end

return_value = give_me_data
puts return_value

# output
# I'm inside the give_me_data method
# 10

#Lambdas 表达式

#声明 lambda (Declare a lambda)

l = lambda { puts "Hello World" }
# shorthand
l = -> { puts "Hello World" }
# transfer lambda
l.call
# output => Hello World

调用 lambda 有多种方式

l.()
l[]

#严格参数 (strict arguments)

l = -> (count) { "Hello World " * count }
l.call 5
# output
# ""
l.call 5, 2
# output
wrong number of arguments (given 2, expected 1)

#在代码块中声明 lambda (declare a lambda in block)

def give_me_data
    puts "I am inside give_me_data method"
    l = -> { return 10 }
    l.call
    puts "I am back in give_me_data method"
end

return_value = give_me_data
puts return_value

# output
# I am inside give_me_data method
# I am back in give_me_data method
# nil # because puts return nil

#lambda 从自身返回,类似普通方法 (lambdas are returned from the lambda itself)

l = -> { return 10 }
l.call

# output => 10

#数组

#初始化空数组 (Initialize an empty array)

array = Array.new   #=> []
# or
array = []

#包含不同类型对象的数组 (Array containing objects of different types)

array = [1, "two", 3.0]
#=> [1, "two", 3.0]

#按初始大小与默认对象填充数组 (Fill array with initial size and default objects)

numbers = Array.new(3)
#=> [nil, nil, nil]
numbers = Array.new(3, 7)
#=> [7, 7, 7]
numbers = Array.new(3, true)
#=> [true, true, true]
numbers = []
numbers.fill(7, 0..2)   #=> [7, 7, 7]

#不同哈希组成的数组 (array of different hashes)

array_with_hashes = Array.new(2) { {} } #=> [{}, {}]
array_with_hashes[0][:name] = "Bob"
array_with_hashes[0][:id] = 10          #=> [{:name=>"Bob", :id=>10}, {}]

#二维数组 (Two-dimensional array)

temperature_data = [
              ["A908", 38],
              ["A909", 37],
              ["A910", 38],
          ]
temperature_data[0]    #=> ["A908", 38]
temperature_data[0][0] #=> "A908"
temperature_data[0][1] #=> 38

#数组索引 (array index)

str_array = [
  "This", "is", "a", "small", "array"
]
str_array[0]            #=> "This"
str_array[1]            #=> "is"
str_array[4]            #=> "array"

#负索引 (negative index)

str_array = [
  "This", "is", "a", "small", "array"
]
# Index -1 represents the last element
str_array[-1]        #=> "array"
# Index -2 represents the second to last element
str_array[-2]        #=> "small"
str_array[-6]        #=> nil

#数组方法 at (array method at)

str_array = [
  "This", "is", "a", "small", "array"
]

puts str_array.at(0)      #=> "This"

#范围取值 (Range acquisition)

arr = [1, 2, 3, 4, 5, 6]
arr[100]                  #=> nil
arr[-3]                   #=> 4
arr[2, 3]                 #=> [3, 4, 5]
arr[1..4]                 #=> [2, 3, 4, 5]
arr[1..-3]                #=> [2, 3, 4]

#数组方法 fetch (Array method fetch)

arr = ['a', 'b', 'c', 'd', 'e', 'f']
arr.fetch(100)
#=> IndexError: Index outside array bounds 100:-6...6
arr.fetch(100, "oops")    #=> "oops"

越界时给出默认值

#获取数组元素 (Get array elements)

arr = [1, 2, 3, 4, 5, 6]

arr.first     # first value => 1
arr.last      # last value => 6
# take Returns the first n elements
arr.take(3)   #=> [1, 2, 3]
# drop after n elements have been deleted
arr.drop(3)   #=> [4, 5, 6]

#向数组末尾添加值 push (Add value to end of array push)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.push(11)
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
numbers.push(12, 13, 14)
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

#删除数组末尾值 pop (Delete the value at the end of the array pop)

num_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
num_array.pop             #=> 10
num_array
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

#向数组开头添加值 unshift (Add value to beginning of array unshift)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.unshift(0)
#=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.unshift(-3, -2, -1)
#=> [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

#取出并删除首元素 shift (Retrieve and delete first element shift)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.shift #=> 1
numbers
#=> [2, 3, 4, 5, 6, 7, 8, 9, 10]

#按索引删除元素 delete_at (Remove element at specific index delete_at)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.delete_at(2) #=> 4
numbers
#=> [2, 3, 5, 6, 7, 8, 9, 10]

#删除数组中任意位置的指定元素 (Remove a specific element anywhere in an array)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.delete(2) #=> 2
numbers           #=> [3, 5, 6, 7, 8, 9, 10]

#在给定索引插入值 insert (Insert value at given index insert)

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]

#用代码块填充数组 (A block to fill the array with values)

numbers = Array.new(10) { |n| n = n * 2 }
#=> [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

#更简便地填充数组 (Filling arrays becomes easier)

numbers = Array(100..110)
#=> [100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110]

# Or we can convert the range to an array
(100..110).to_a
#=> [100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110]

#从数组移除 nil (Remove nil value from array)

arr = ['foo', 0, nil, 'bar', 7, nil]
arr.compact  #=> ['foo', 0, 'bar', 7]
arr      #=> ['foo', 0, nil, 'bar', 7, nil]
arr.compact! #=> ['foo', 0, 'bar', 7]
arr      #=> ['foo', 0, 'bar', 7]

#去重 uniq (Remove duplicates uniq)

arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556]
arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]
arr # => [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556]
arr.uniq! #=> [2, 5, 6, 556, 8, 9, 0, 123]
arr #=> [2, 5, 6, 556, 8, 9, 0, 123]

#检查数组是否包含某值 include? (Check if a value exists in an array)

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
planets.include? "Mars"
# output => true
planets.include? "Pluto"
# output => false

#获取数组大小 (Get array size)

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
planets.size
# output => 8
planets.length
# output => 8

可用 size 或 length,二者同义

#清空数组 (clear array)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.clear
# output => []

#获取数组首元素 (Get the first element of the array)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers[0]
# or
numbers.first
# output => 1

#获取数组末元素 (Get the last element of the array)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers[-1]
# or
numbers.last
# output => 10

#合并两个数组 (Merge two arrays)

a = ["tom", "mot", "otm"]
b = [2, 3, 5]
a.zip(b)
# output
# [["tom", 2], ["mot", 3], ["otm", 5]]

#数组排序 (Sort array)

primes = [7, 2, 3, 5]
sorted_primes = primes.sort
puts "#{sorted_primes}"
# output => [2, 3, 5, 7]

或就地排序

primes = [7, 2, 3, 5]
primes.sort!
puts "#{primes}"
# output => [2, 3, 5, 7]
planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
planets.sort
# output
# ["Earth", "Jupiter", "Mars", "Mercury", "Neptune", "Saturn", "Uranus", "Venus"]
planets.sort_by { |p| p }
# output
# ["Earth", "Jupiter", "Mars", "Mercury", "Neptune", "Saturn", "Uranus", "Venus"]
planets.sort_by { |p| p.length }
# output
# ["Mars", "Earth", "Venus", "Saturn", "Uranus", "Neptune", "Jupiter", "Mercury"]

#获取数组最大值 (Get maximum value from array)

primes = [7, 2, 3, 5]
primes.max_by { |p| p }
# output => 7

#用范围获取数组元素 (Get array elements using range)

# numbers[start..end], both index are inclusive
puts numbers[0..3]
# 1
# 2
# 3
# 4
# numbers[start..end], end index is exclusive
puts numbers[0...3]
# 1
# 2
# 3
# or numbers[start..length]
puts numbers[0, 1]
# 1

#获取数组前 n 个元素 (Get the first n elements of the array)

primes = [7, 2, 3, 5]
primes.take(3)
# [7, 2, 3]

#访问元素 (access element)

primes = [7, 2, 3, 5]
primes.fetch(3)
# 5
# Fetch will throw an error if the element does not exist
primes.fetch(10)
# (index 10 outside of array bounds: -4...4)
# or get an 默认值
primes.fetch(10, -1)
# -1

#删除前 n 个元素 (Delete first n elements)

primes = [7, 2, 3, 5]
primes.drop(3)
# [5]

#删除首元素 (Delete the first element)

primes = [7, 2, 3, 5]
primes.shift
# [2, 3, 5]

#删除末元素 (Remove last element)

primes = [7, 2, 3, 5]
primes.pop
# [7, 2, 3]

#按索引删除元素 (Delete element with index)

primes = [7, 2, 3, 5]
primes.delete_at(-1)
# [7, 2, 3]

#删除所有出现的元素 (Remove all occurrences of elements)

primes = [7, 2, 3, 5, 5]
primes.delete(5)
# [7, 2, 3]

#each 遍历 (each)

# When you have single line blocks
salary = [399, 234, 566, 533, 233]
salary.each { |s| puts s }
# output
# 399
# 234
# 566
# 533
# 233

多行代码块可用 doend 替代花括号 {}

salary.each do |s|
  a = 10
  res = a * s
  puts res
end
# output
# 3990
# 2340
# 5660
# 5330
# 2330

也可用花括号 {},并以分号代替换行作为分隔

salary.each { |s| a = 10 ; res = a * s ; puts res }

#each_with_index 带索引遍历 (each_with_index)

salary = [399, 234, 566, 533, 233]
salary.each_with_index { |value, index| puts "#{index} #{value}" }
# output
# 0 399
# 1 234
# 2 566
# 3 533
# 4 233

#each_index 索引遍历 (each_index)

salary = [399, 234, 566, 533, 233]
salary.each_index { |i| puts i}
# output
# 0
# 1
# 2
# 3
# 4

#map 映射 (map)

salary = [399, 234, 566, 533, 233]
salary.map { |s|  s * 10  }
# return
# [3990, 2340, 5660, 5330, 2330]
# On the other hand, each returns the original value
salary = [399, 234, 566, 533, 233]
salary.each { |s|  s * 10  }
# return
# [399, 234, 566, 533, 233]

#collect 收集 (collect)

salary = [399, 234, 566, 533, 233]
salary.collect { |s| s > 400 }
# output
# [false, false, true, true, false]

#for 循环 (for)

for value in [2, 3, 5, 7]
    puts value
end

#each_with_object 带对象遍历 (each_with_object)

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] }
# output
{"color_red"=>"RED", "count_red"=>8, "color_black"=>"BLACK", "count_black"=>4}

[1, 2, 3].each_with_object(0) { |number, sum| sum += number}
# output
# 0
# Because 0 is immutable, and since the initial object is 0, the method returns 0

#while 循环 (while)

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
index = 0
while index < planets.size
    puts "#{planets[index]}"
    index += 1
end

a = 1
star = '*'
while a <= 10
    puts star
    star += '*'
    a += 1
end

#do while 循环 (do while)

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
index = 0
loop do
    puts "#{planets[index]}"
    index += 1
    break if planets[index] == "Mars" or index > planets.size
end

#until 循环 (until)

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
index = planets.size - 1
until index < 0
    puts "#{planets[index]}"
    index -= 1
end
a = 1
star = '*'
until star.length > 10
    puts star
    star += '*'
    a += 1
end

#times 次数循环 (times)

10.times { puts "#{rand(1..100)}"}
# output
# will print 10 random numbers

虽然可以这样写,但不代表就应该这样遍历数组

data_sample = [2, 3, 5, 7]
data_sample.size.times { |index| puts "#{data_sample[index]}" }
# output
# 2
# 3
# 5
# 7

#upto 递增 (upto)

data_sample = [2, 3, 5, 7]
0.upto((data_sample.size - 1) / 2) { |index| puts "#{data_sample[index]}" }
# output
# 2
# 3

#downto 递减 (downto)

data_sample = [2, 3, 5, 7]
(data_sample.size - 1).downto(data_sample.size / 2) { |index| puts "#{data_sample[index]}" }
# output
# 7
# 5

#step 步长 (step)

1.step(20, 2) { |number| puts "#{number}"}
# output
# 1
# 3
# 5
# 7
# 9
# 11
# 13
# 15
# 17
# 19

19.step(1, -2) { |number| puts "#{number}"}
# output
# 19
# 17
# 15
# 13
# 11
# 9
# 7
# 5
# 3
# 1

#inject 注入 (inject)

numbers = [2, 2, 2, 2, 2]
numbers.inject{ |res, n| res + n }
# The output is the sum of all numbers
# If no initial value is set for res, the first element of the array is used as the initial value of res.
#10
# Now set the value of res to 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(:+)
# output
# 10

使用初始值与符号

numbers = [2, 2, 2, 2, 2]
numbers.inject(11, :+)
# output
# 21

#reduce 归约 (reduce)

numbers = [2, 2, 2, 2, 2]
numbers.reduce(11, :+)
# output
# 21

#detect 检测 (detect)

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
planets.detect { |name| name.start_with?("E") and name.end_with?("h") }
# output
# Earth
salary = [399, 234, 566, 533, 233]
salary.detect { |s| s > 1000 }
# output
# nil

#find 查找 (find)

planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
planets.find { |name| name.start_with?("E") and name.end_with?("h") }
# output
# Earth

#select 筛选 (select)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.select { |n| n % 2 == 0 }
# Now you have an even array
# [2, 4, 6, 8, 10]
# If there are no values that satisfy your logic, return an empty array
[1, 1, 1].select { |n| n % 2 == 0 }
# no even numbers
# []

#reject 排除 (reject)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.reject { |n| n % 2 == 0 }
# Reject if the number is even, so now we have an odd array
# [1, 3, 5, 7, 9]

#keep_if 条件保留 (keep_if)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.keep_if { |n| n % 2 == 0 }
# numbers Array contains only even numbers
# [2, 4, 6, 8, 10]

#delete_if 条件删除 (delete_if)

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.delete_if { |n| n % 2 == 0 }
# numbers Array contains only odd numbers
# [1, 3, 5, 7, 9]

#drop_while 条件丢弃 (drop_while)

numbers = [1, 2, 3, 1, 2, 3, 0]
numbers.drop_while { |n| n < 3 }
# is 3 less than 3, returns false, so delete 1, 2
# [3, 1, 2, 3, 0]

#reverse_each 反向遍历 (reverse_each)

words = %w[first second third fourth fifth sixth]
str = ""
words.reverse_each {|word| str += "#{word} "}
p str #=> "sixth fifth fourth third second first "

#布尔枚举方法

#布尔枚举方法 (boolean enumerable method)

名称 使用场景
all? 检查是否所有元素都满足条件
any? 检查是否至少有一个元素满足条件
one? 检查是否恰好有一个元素满足条件
none? 检查是否没有任何元素满足条件(与 any? 相反)
empty? 检查对象是否为空
include? 检查对象中是否存在某元素

#all? 全部满足 (all?)

[2, 4, 6, 8, 10].all? { |num| num % 2 == 0 }
# true
[1, 4, 6, 8, 10].all? { |num| num % 2 == 0 }
# false

#any? 任一满足 (any?)

[1, 3, 5, 7, 10].any? { |num| num % 2 == 0 }
# true
[1, 3, 5, 7, 19].any? { |num| num % 2 == 0 }
# false

#one? 恰好一个 (one?)

[1, 3, 2, 5, 7].one? { |num| num % 2 == 0 }
# true
[1, 3, 2, 5, 4].one? { |num| num % 2 == 0 }
# false

#none? 全不满足 (none?)

[1, 3, 5, 7, 9].none? { |num| num % 2 == 0 }
# true
[2, 3, 5, 7, 9].none? { |num| num % 2 == 0 }
# false

#empty? 是否为空 (empty?)

[].empty?
# true
[1, 3, 5, 7, 9].empty?
# false

#组合方法

#组合方法 (Combination method)

  • & 返回新数组,包含 array 与 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]

#intersection 交集 (intersection)

[0, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3])
# => [0, 1]
[0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3])
# => [0, 1]

#+ 连接 (+)

a = [0, 1] + [2, 3]
a # => [0, 1, 2, 3]

#- 差集 (-)

[0, 1, 1, 2, 1, 1, 3, 1, 1] - [1]
# => [0, 2, 3]
[0, 1, 2, 3] - [3, 0]
# => [1, 2]
[0, 1, 2] - [4]
# => [0, 1, 2]

#union 并集 (union)

[0, 1, 2, 3].union([4, 5], [6, 7])
# => [0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 1].union([2, 1], [3, 1])
# => [0, 1, 2, 3]
[0, 1, 2, 3].union([3, 2], [1, 0])
# => [0, 1, 2, 3]

#difference 差集 (difference)

[0, 1, 1, 2, 1, 1, 3, 1, 1].difference([1])
# => [0, 2, 3]
[0, 1, 2, 3].difference([3, 0], [1, 3])
# => [2]
[0, 1, 2].difference([4])
# => [0, 1, 2]

#product 笛卡尔积 (product)

a = [0, 1, 2]
a1 = [3, 4]
p = a.product(a1)
p.size # => 6 # a.size * a1.size
p # => [[0, 3], [0, 4], [1, 3], [1, 4], [2, 3], [2, 4]]

#循环

#while 循环 (while loop)

# variable count
count = 4
# using while loop
# here conditional is count i.e. 4
while count >= 1
  # statements to be executed
  puts "Ruby Cheatsheet"
  count = count - 1
  # while loop ends here
end

output

Ruby Cheatsheet
Ruby Cheatsheet
Ruby Cheatsheet
Ruby Cheatsheet

#for 循环 (for loop)

# loop using range as expression
text = "Ruby Cheatsheet"
# using for loop with the range
for count in 1..5 do
  puts text
end

output

Ruby Cheatsheet
Ruby Cheatsheet
Ruby Cheatsheet
Ruby Cheatsheet
Ruby Cheatsheet

#do..while 循环 (do..while loop)

# starting of do..while loop
loop do
  puts "Ruby Cheatsheet"
  val = '7'
  # using boolean expressions
  if val == '7'
    break
  end
  # ending of ruby do..while loop
end

output

Ruby Cheatsheet

#until 循环 (until loop)

var = 7
# here do is 可选
until var == 11 do
  # code to be executed
  puts var * 10
  var = var + 1
  # here loop ends
end

output

70
80
90
100

#跳出循环 (Break out of loop)

salary = [399, 234, 566, 533, 233]
salary.each do |s|
  break if s == 566
  puts s
end
# output
# 399
# 234

使用 break 关键字

#循环内跳过 (skip within loop)

salary = [399, 234, 566, 533, 233]
salary.each do |s|
  next if s == 533
  puts s
end
# output
# 399
# 234
# 566
# 233

使用 next 关键字

#重复当前迭代 (Repeat current iteration)

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

#重新开始循环 (Start the cycle again)

numbers = [2, 2, 44, 44]
sum = 0
begin
    numbers.each do |s|
        if rand(1..10) == 5
            puts "hi 5, let's do it again!"
            sum = 0
            raise "hi 5"
        end
        puts s
        sum += s
    end
rescue
    retry
end

#

#类示例 (Classes Example)

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
# 
# 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
# 
# 2
# set class variable
Person.count = 3
puts "#{Person.count}"
# 3

#继承类 (Inherit a class)

class Person
    attr_accessor :name, :number
end
# Inherit methods and properties from parent class using < symbol
class Student < Person
    attr_accessor :id
end
s = Student.new
s.name = "James Bond"
s.number = 700
s.id = 678
puts "#{p.name}"
James Bond
puts "#{p.number}"
700
puts "#{p.id}"
678

#检查实例类型 (Check instance type)

class Vehicle; end
class Car < Vehicle; end
class Audi < Car; end
car = Car.new
car.instance_of? Vehicle
false
car.instance_of? Car
true
car.instance_of? Audi
false
a = 7
a.instance_of? Integer
true
a.instance_of? Numeric
false

当对象是给定类的实例(而非其子类或父类实例)时返回 true

#打印类的全部方法名 (Print all method names of a class)

puts (String.methods).sort
# Exclude methods inherited from Object class
puts (String.methods - Object.public_instance_methods).sort

#检查类是否有指定方法 (Check if a class has a specific method)

String.respond_to?(:prepend)
true
String.respond_to?(:append)
false

#🔗 参考资源