基础概念

def hello 与 def hello?

  • def hello:用于定义普通的方法。在Ruby中,方法名可以以字母、下划线或问号(?)开头,后面可以跟着字母、数字、下划线或问号。def hello定义了一个名为hello的方法,它可以执行一些操作并返回一个值(或者不返回任何值)

    1
    2
    3
    4
    5
    def hello
    puts "Hello, world!"
    end

    hello # 调用hello方法,输出 "Hello, world!"
  • def hello?:用于定义返回布尔值的方法,通常用于表示某种条件或判断的结果

    1
    2
    3
    4
    5
    6
    def even?(number)
    number % 2 == 0
    end

    puts even?(4) # 调用even?方法,输出 true
    puts even?(5) # 调用even?方法,输出 false

关键字

include

  • 在 Ruby 中,include 是一个用于模块和类的方法,用于将模块的方法和常量引入到类中

  • 当一个类使用 include 方法引入一个模块时,该类就可以使用模块中定义的方法和常量。通过 include,模块中的方法和常量成为了类的实例方法和常量

  • 举例

    • 例如,假设有一个名为 ModuleA 的模块和一个名为 ClassB 的类。如果在 ClassB 中使用 include 方法将 ModuleA 引入到类中,那么 ClassB 的实例就可以调用 ModuleA 中定义的方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      module ModuleA
      def hello
      puts "Hello from ModuleA"
      end
      end

      class ClassB
      include ModuleA
      end

      b = ClassB.new
      b.hello
      # 结果 Hello from ModuleA
    • 在这个示例中,ClassB 的实例可以调用 ModuleA 中定义的 hello 方法

  • 需要注意的是,include 方法只能用于引入模块,而不能用于引入其他类。如果需要引入其他类的方法,可以使用 prepend 方法

included

1
2
3
4
5
6
7
module ServiceModeConcern
extend ActiveSupport::Concern

included do |base|
prepend Object.const_get(base.name.split("::").insert(-2, "ServiceMode").join("::")) if AppConfig.service_mode?
end
end
  • 以上代码作用是在模块被包含到其他类中时,根据 AppConfig.service_mode? 的值来动态地插入另一个模块
  • included 方法是 Ruby 中用于在模块中定义的一个回调方法,它会在模块被包含到其他类中时自动执行
  • do |base| 表示 included 方法的块参数,它会接收包含该模块的类作为参数
  • Object.const_get 方法用于获取指定名称的常量,这里传入的参数是一个字符串,它是通过将包含该模块的类名进行修改得到的
  • base.name.split("::").insert(-2, "ServiceMode").join("::") 表示将包含该模块的类名按照 “::” 分隔符进行拆分,然后在倒数第二个位置插入字符串 “ServiceMode”,最后再将拆分后的字符串用 “::” 连接起来
  • prepend 方法是 Ruby 中用于在类或模块中插入方法的方法,它会将指定的模块或类插入到当前类或模块的继承链的顶部。 如果 AppConfig.service_mode? 的返回值为 true,则会将上一步获取到的常量插入到包含该模块的类中

prepend

  • 在 Ruby 中,prepend 是一个用于模块和类的方法,用于在继承链中插入模块或类的方法

  • 当一个模块或类使用 prepend 方法插入到继承链中时,它的方法会优先于继承链中其他模块或类的方法被调用。这意味着,使用 prepend 插入的方法会覆盖继承链中其他模块或类的同名方法

  • 举例

    • 假设有一个名为 ModuleA 的模块和一个名为 ClassB 的类。如果在 ClassB 中使用 prepend 方法将 ModuleA 插入到继承链中,那么 ModuleA 中的方法会优先于 ClassB 中的同名方法被调用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      module ModuleA
      def hello
      puts "Hello from ModuleA"
      end
      end

      class ClassB
      prepend ModuleA

      def hello
      puts "Hello from ClassB"
      end
      end

      b = ClassB.new
      b.hello
      # 结果: Hello from ModuleA
    • 如果使用super,那么class B方法也会被调用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      module ModuleA
      def hello
      puts "Hello from ModuleA"
      super # 新增
      end
      end

      class ClassB
      prepend ModuleA

      def hello
      puts "Hello from ClassB"
      end
      end

      b = ClassB.new
      b.hello
      # 结果: Hello from ModuleA

  • 需要注意的是,prepend 方法只能用于插入模块,而不能用于插入其他类。如果需要插入其他类的方法,可以使用 include 方法

super

  • 最后一行调用super目的是为了重写new方法后,能正确调用initialize方法

    It should also be noted that this overridden new method calls super on the last line which in turn calls Class#new. This makes sure that Ruby’s semantics of new method are preserved. This will make sure that DeprecationProxy.newwill call initialize method of DeprecationProxy after the overridden newmethod is executed.

  • 此外在使用了includeprepend发生函数重载时,可以继续调用被重载的函数

attr_reader

  • attr_reader是Ruby中的一个方法,用于自动生成实例变量的读取器方法

  • attr_reader :source, :credentials, :repo_contents_path, :options为例,在给定的代码中,attr_reader用于生成以下实例变量的读取器方法

    • source
    • credentials
    • repo_contents_path
    • options
  • 这意味着在使用attr_reader后,可以通过实例对象调用这些变量的读取器方法来获取它们的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyClass
attr_reader :source, :credentials, :repo_contents_path, :options

def initialize(source, credentials, repo_contents_path, options)
@source = source
@credentials = credentials
@repo_contents_path = repo_contents_path
@options = options
end
end

obj = MyClass.new("example", "password", "/path/to/repo", { option1: true, option2: false })

puts obj.source # 输出:example
puts obj.credentials # 输出:password
puts obj.repo_contents_path # 输出:/path/to/repo
puts obj.options # 输出:{ option1: true, option2: false }

ruby on rails

rails db:migrate

  • rails db:migrate 是一个 Rails 命令,用于执行数据库迁移操作
  • 数据库迁移是一种用于管理数据库结构变化的技术。通过使用迁移文件,您可以创建、修改或删除数据库表、列、索引等。每个迁移文件都对应一个特定的数据库操作
  • 当您运行 rails db:migrate 命令时,Rails 将检查数据库迁移历史记录表(通常是 schema_migrations 表)以确定哪些迁移文件尚未应用到数据库中。然后,它将按顺序执行这些尚未应用的迁移文件,将数据库结构更新到最新状态
  • 在执行 rails db:migrate 命令之前,请确保已经配置好数据库连接,并且迁移文件已经创建并位于db/migrate 目录下
  • 需要注意的是,rails db:migrate 是一个有副作用的命令,会直接修改数据库结构。在执行之前,请确保已经备份了重要的数据,并且明确了迁移操作的影响

rails background_tasks:run_post_deploy_tasks

  • rails background_tasks:run_post_deploy_tasks 是一个自定义的 Rails 命令,用于在部署后运行一些后台任务
  • 后台任务位置
    1. 打开您的 Rails 应用程序的代码目录
    2. 导航到 lib/tasks 目录。这个目录通常用于存放自定义的任务文件
    3. lib/tasks 目录下查找名为 background_tasks.rake 或类似命名的文件。这个文件通常包含定义后台任务的代码
    4. 打开 background_tasks.rake 文件,查看其中的任务定义。您可以搜索 namespacetask 关键字,以找到相关的任务定义
    5. 在任务定义中,您可以查看任务的具体实现逻辑,包括任务的名称、描述、依赖关系和执行代码
    6. 如果您无法在 lib/tasks 目录中找到相关的任务文件,您还可以尝试在其他目录中搜索,例如 app/jobs 目录(用于存放后台任务类)或 config 目录(用于存放自定义的任务配置)

注意点

  1. ruby定义的函数中,最后一行作为函数返回值,不要在最后一行输出日志,会导致外层接收值为空,导致逻辑错误

参考