Ruby 学习(一)

Ruby 学习(一)

前因

为什么要学习Ruby?我们都知道iOS 强大的包管理工具Cocoapods,Cocoapods正是使用Ruby进行编写,那么想要了解Cocoapods内部的实现原理,以及他架构方式,想必我们必须要学习他所使用的语言—即ruby。

初识

Ruby 背景

Ruby 这门语言呢是由日本人松本行弘 在20世纪90年代设计并开发的一种语言。那么Ruby呢,其实是一中完全面向对象的语言,在Ruby 里也是万物皆对象。当然Ruby 和 Python、JavaScript等脚本语言一样,它是一种需要解释的语言(也就是说它不需要进行编译、链接形成可执行二进制文件,而是需要一个解释器去解释执行)。据说火起来其实在2000年以后了(这个我就不知道了….)

Ruby 安装

MacOS 会内置Ruby, 默认Ruby一般版本较低,且不好升级

一般情况下,我们Linux 、MacOs 会采用三种方式安装Ruby:

  • 采用homebrew安装Ruby,brew install ruby, 配置环境变量 ``` echo ‘export PATH=”/usr/local/opt/ruby/bin:$PATH”’ » ~/.zshrc, 但是这是属于自管理ruby版本的方式,不推荐使用

  • 采用 RVM安装, RVM也就是Ruby Version Manager的首字母。可想而知他就是Ruby 版本管理器。

    • 首先需要安装RVM: curl -sSL https://get.rvm.io | bash -s stable --auto-dotfiles ,–auto-dotfiles 其实就是在安装rvm的时候,他会主动将环境变量配置好,不用我们自己在打开.bashrc/.zshrc 配置了。

    • 重启终端 source ~/.zshrc, 输入命令 rvm --verison, 输出正常版本号则安装rvm成功
    • rvm list known 列出已知的所有Ruby版本

    • rvm install 3.1.2 安装制定ruby 版本

      • 可能会出现一个以下错误 :

        Error running '__rvm_make -j12',
        please read /Users/haoyh02/.rvm/log/1704359555_ruby-3.1.2/make.log
        There has been an error while running make. Halting the installation.
        

        通过查看make.log,我们发现报错是发生在openssl@3,大概原因应该就是安装Ruby的时候需要编译用到openssl, 当我们没有指定openssl路径的情况下,它就会默认到/usr/local/Cellar/ 下的openssl使用,但是正常我们使用brew 更新或者安装过openssl的话路径并不在这里,应该在/usr/local/opt/openssl@3 这里。这也就是导致编译的时候openssl的某些方法找不到等等错误

      • 解决版本则是:使用命令 rvm install 3.1.2 --with-openssl-dir=`brew --prefix openssl` | rvm install 3.1.2 --with-openssl-dir='/usr/local/opt/openssl@3'

        :) 这个问题也是让我很长时间找不到问题的原因。

    • 安装Ruby成功后, 使用rvm use 3.1.2 --default, 我们也可以使用rvm use 其他版本切换ruby 版本

    • ruby --verison 查看版本是否是我们安装的版本
  • 采用rbenv 安装,rbenv 是Ruby environment 的缩写,也就是Ruby 环境,同样也是一个Ruby 版本管理器。

    • 安装rbenv : brew install rbenv ruby-build, 当然也可以采用非home brew 手动安装:https://ruby-china.org/wiki/rbenv-guide, 手动安装就不赘述了,麻烦一些。
    • 安装完成后, rbenv install --list 列出可安装的Ruby 版本
    • rbenv install 3.1.2 安装制定ruby 版本
    • rbenv global 3.1.2 全局使用3.1.2的ruby, 类似于rvm use

那不禁就想问:那这三种方式的区别是什么,我们应该用哪一种?

那么对于homebrew 的方式(也就是第一种方式),只能安装一个版本的ruby,如果你多ruby开发,那么这种方式不合适了,因为它并不是ruby 版本管理工具,对吧?

其他两种来说,我也查阅了一些资料,总体来说rvm出来的更早,功能更全,但是rbenv也很好。换言之就是用谁都行,只要你觉得好就好~

所以推荐来说的话,还是使用rvm或者rbenv进行ruby安装以及版本管理~

对于Windows的安装请查阅文档:https://rubyinstaller.cn/ (因为我是Mac, 没有Windows,没有尝试,所以没有发言权😭)

ok,现在来说我们已经拥有基本的开发ruby的条件。

相关概念

对于我刚开始学习的时候,这几个概念也是对我造成了一定的困扰,并且我们要知道以下几个东西会一直陪在我们开发过程中的。所以对于他们的了解,可想而知多重要~

IRb

可交互式Ruby shell, 什么意思呢?就是我们可以直接在终端进行用IRb 命令解释Ruby 代码,举个栗子:

% IRb                       
A gemspec development dependency (bacon, ~> 1.1) is being overridden by a Gemfile dependency (bacon, >= 0).
This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement
3.2.1 :001 > puts "hello world"
hello world
 => nil 
3.2.1 :002 > 

如上,我们在命令行输入IRb后回车,就会进入到可交互shell 编程,我们可以去编写ruby,然后单行解释。

Gem

Gem 相当于是用Ruby 写的三方Gem 库的管理,通过Gem 我们可以安装所有现有的三方gem库。其实三方gem 包管理器。通过gem 可以进行安装gem 包。我们可以通过gem list –local 查看本地安装了的gem 包。其实我们回想一下cocoapods的安装,gem install cocoapods 对吧?所以其实我们的cocoapods他就是一个gem 包。

Bundler

说到bundler 那就不得不提,另外的两个工程里的文件:

Gemfile
Gemfile.lock

看着这两个是否有点感觉好熟悉的样子?想一想我们iOS工程采用Cocoapods管理的时候是否有类似的文件?

是的,我们iOS 工程如果采用Cocoapods管理的话,我们会有Podfile和Podfile.lock。 如果你对这两个文件了解的话,那其实Gemfile Gemfile.lock 也是同样的功能,因为Cocoapods的设计就是从Gem的设计借鉴而来的。

好了,我们还是解释一下这两个文件的作用吧

Gemfile: 同样是用来描述当前包依赖的三方gem包的,如下:

SKIP_UNRELEASED_VERSIONS = false
def cp_gem(name, repo_name, branch = 'master', path: false)
  return gem name if SKIP_UNRELEASED_VERSIONS
  opts = if path
           { :path => "../#{repo_name}" }
         else
           url = "https://github.com/CocoaPods/#{repo_name}.git"
           { :git => url, :branch => branch }
         end
  gem name, opts
end

source 'https://rubygems.org'

gemspec

group :development do
  cp_gem 'claide',                'CLAide'
  cp_gem 'cocoapods-core',        'Core'
  cp_gem 'cocoapods-deintegrate', 'cocoapods-deintegrate'
  cp_gem 'cocoapods-downloader',  'cocoapods-downloader'
end

Gemfile.lock: 如同它的类型名一样,他是用来锁定的,锁定什么?锁定你所依赖的三方gem包的版本的。同样和Podfile.lock一样防止多人开发协作,版本不一致的问题。

OK,那么我们来说一说它与Bundler的关系:

其实Bundler 和 我们Pod 命令很相似,在当前根目录下执行bundler install, 它会进行依赖解析、安装依赖。这是不是就和我们pod install 一样呢?

那么这么看呢?bundler 其实用来工程依赖解析、安装装的,其实具体的安装是通过gem安装的。

这样他们之间的关系是不是更加清晰了~

Rake

当我第一眼看到这个单词,我就想到了Make,但事实上他并不是一个单词,它是一个组合:Ruby Make。

我们在工程里可以看到有一个文件叫Rakefile。那么其实他们是相关联的。

刚才我们提到了Make,这个可不是仅仅是一个词啊,我想到的是C语言的构建工具Make, 同样他也有对应的文件makefile。

也就是说我们可以在Rakefile 定义一些列的任务,相当于任务脚本,执行rake 命令就可以执行任务。

比如CocoaPods工程下的Rakefile为:

# Bootstrap task
#-----------------------------------------------------------------------------#

desc 'Initializes your working copy to run the specs'
task :bootstrap, :use_bundle_dir? do |_, args|
  title 'Environment bootstrap'

  puts 'Updating submodules'
  execute_command 'git submodule update --init --recursive'

  if system('which bundle')
    puts 'Installing gems'
    if args[:use_bundle_dir?]
      execute_command 'env bundle install --path ./travis_bundle_dir'
    else
      execute_command 'env bundle install'
    end
  else
    $stderr.puts "\033[0;31m" \
      "[!] Please install the bundler gem manually:\n" \
      '    $ [sudo] gem install bundler' \
      "\e[0m"
    exit 1
  end
end
....

开发环境

开发环境可以说是我搞的时间最长的一个东西了。你知道如果你用VSCode 打开一个Gem项目,它的所有依赖、类的快速跳转、解释都没有、甚至提示都没有这对于开发来说多痛苦,更对于我想要阅读Cocoapods源码来说多痛苦,更是让我想到了?怎么开发gem 如果我有依赖三方gem。

首先我选择是VSCode Ide,作为开发IDE。其次经过研究,需要安装两个插件Ruby LSP、 Ruby Solargraph。安装了这两个插件按理来说就能实现方法、类跳转、解释。但是实际远比我想的复杂。当我安装了这两个插件之后,用VS code 打开工程,一直报错,错误则是LSP 无法连接服务、Solargraph启动失败等等,对应的VSCode 就不会有任何的解释、提示、跳转。

解决问题的过程总是复杂的、艰难的。最后发现我们需要进行以下几个步骤:

  1. 需要gem install solargraph

  2. 修改插件的设置,将LSP 的 ruby 管理工具改为你使用的,我则是rvm

  3. 增加setting.json 设置

    {
        "solargraph.commandPath": "/Users/haoyh02/.rvm/rubies/ruby-3.2.1/bin/",
        "rubyLsp.rubyVersionManager": "rvm",
        "solargraph.useBundler": true,
        "solargraph.references": true,
        "solargraph.autoformat": true,
        "solargraph.formatting": true
    }
    
  4. 在Gemfile中引用 LSP, Solargraph

    gem 'ruby-lsp'
    gem 'solargraph'
    
  5. 删掉Gemfile.lock, bundler install

  6. 重新打开vsCode, 打开工程即可

总结

兜兜转转,一直在学习的路上,但是新手么,难免会踩坑,当然踩坑也没有更好的方式解决,只能自己查资料、尝试解决。但是解决了就会收获成就感哦。

希望以上的经验可以帮助正在需要了解Ruby, 或者和我一样想要了解Cocoapods底层的朋友一些帮助。

相关文档

Ruby-China

一文搞清rake、Rakefile、gem、gemspec、bundler、bundle、Gemfile的关系

Rakefile

Ruby 教程

rvm 官网

rake github