公司收购了个项目,技术都很老,Web用的Ruby on Rails,前端还在用jQuery,后台定时任务用Java(用的技术也都很老)。自己以前没有接触过Ruby,只是听几个朋友大学里玩过这玩意儿,所以对我来说Ruby就是一门全新的语言。我个人是非常抵触学一门新语言的,Java都还没吃透就并行学Ruby,只会分散深入学习Java的精力。但没办法谁让公司抽到我,还是好好学吧!
1、安装Ruby
Windows上傻瓜式安装Ruby就不赘述了(有RubyInstaller会点下一步就行),其他操作系统都可以用系统相应的包依赖管理器安装Ruby(Linux上的yum、apt-get,Mac上的homebrew)。但是这些包管理器通常只能安装yum源中已有的二进制包,如果你想要的Ruby版本没有在对应操作系统已编译的二进制包,那就只能下载源码自行编译了。虽然通常只需三个命令就能完成编译,但是多个Ruby之间版本的切换也是个问题,这也是小型脚本语言的痛。像Java大版本内不会有语法上改变,小版本也只是修复些bug,切换版本重新编译费时费劲,但Node.js和Ruby这样小巧而且版本间差异相对较大的语言,就需要运行环境的版本管理工具了。
大多数Rubyist都使用Ruby管理工具管理多个Ruby,官方列出来的Ruby管理工具有四个,最常用也是最好用的就是RVM(和Node.js对应有NVM)。安装RVM只需要从https://get.rvm.io
下载一个rvm-installer的Bash脚本即可。ruby-installer
支持默认支持两个版本master
和stable
,需要稳定版直接curl -sSL https://get.rvm.io | bash -s stable
一个管道命令解决。
和
nvm
的$HOME/.nvm
一样rvm
也会在用户目录下创建.rvm
目录保存各个版本的Ruby
安装完RVM后,使用以下命令就可以安装各种版本的Ruby了。
rvm install INTERPRETER[-VERSION] OPTIONS
其中INTERPRETER
指的是不同语言实现的Ruby解释器,没有指定默认就是CRuby,也可以指定Java实现的jruby或.Net实现的ironruby等,使用rvm list known
可以查看可选的Ruby版本。
切换Ruby版本只需用rvm use INTERPRETER[-VERSION]
命令。
2、Ruby周边
gem
RubyGems是Ruby的包管理工具(和Java的Maven,JS的npm类似),从Ruby1.8开始就称为了Ruby默认的包管理工具。使用上和npm大体一致,详情可以参看官方文档
如果说gem是npm的阉割版,bundler就是为了补全被阉割的那部分。gem的.gemspec
虽然定义了包本身的信息,但是不能像npm install
一样安装并管理这个包依赖的其他包。Bundler需要定义一个Gemfile
的文件,这个文件中可以定义应用依赖的gems的兼容版本(和npm的package.json类似)。
所以Bundler官网标题就说Bundler是管理Ruby的gems最好的方式。
Gemfile与.gemspec的区别详请参考这篇文章
Ruby on Rails
Ruby on Rails是一个基于Ruby的MVC框架,和express.js类似,也正是因为这个框架使得默默无闻的Ruby一夜崛起。也是这个框架最早提出Convention Over Configuration的概念,后来其他语言的框架也纷纷效仿,如今口口相传的SpringBoot也深受它的影响。
3、 初学Ruby的20条经验
1、 Ruby和JS、Python一样是解释性脚本语言,使用源文件即可执行,按照惯例源文件以.rb
为后缀。和Python的强制缩进不通,Ruby的缩进并不重要,但是为了代码可读性必须得缩进。
2、 不像JS中0
、undefined
、null
、""
等值都能被转成false,在Ruby中除了false
和nil
这两个保留字,其他全为true。
3、 Ruby方法调用时,括号是可选的。方法中如果没有明确的return
,则返回最后一条语句的结果。
1 | foobar |
详情参考官方文档
4、 Ruby除了支持+
、-
、*
、/
、%
等算数运算符外,还支持**
幂运算符,但是不支持++
、--
运算符。这点和Python一致。在C和Java中%
表示取余操作,但Python和Ruby中%
表示求模运算。
1 | // Java 结果的正负与被除数一致 |
5、 Ruby中一切皆对象,不像Java还有几个基本类型。Ruby中数值类型也是对象。Ruby中Float是双精度浮点型(也就是Java里的Double)。并且Ruby原生就支持BigNum(也就是Java中的BigInteger),所以再也不用担心算数溢出的问题了。并且Ruby 2.4之后Fixnum和Bignum统一为Integer了。
1 | # Before Ruby 2.4 |
有关Fixnum和Bignum更多细节可参考这篇文章,除了Integer和Float这两种常用的数值类型,Numeric还有Rational(有理数)和Complex(复数)两个子类,用处不大这里不过多讨论。
6、 Ruby的变量命名会影响变量的作用域:
局部变量的命名规则和C系列语言命名一样,字母下划线开头数字字母下划线的组合;
使用
local_variables
方法可以查看当前作用域内的局部变量在局部变量的开头加上
@
,表示这个变量是实例对象的属性变量(@sign,@_,@Counter);使用
instance_variables
方法可以查看对象的实例变量在局部变量的开头加上
@@
,表示类变量;使用
class_variables
方法可以查看类变量在局部变量的开头加上
$
,表示全局变量;使用
global_variables
方法可以查看全局变量按照Ruby的约定,全大写的变量是常量,Ruby允许修改常量,但是会报警告。
1
2
3
4
5PI = 3.141592653 # 第一次定义常量
PI = 3.14 # 修改常量
warning: already initialized constant PI
warning: previous definition of PI was here
puts PI # 3.14
7、 Ruby中字符串可以使用单引号也可以使用双引号,但是单引号中只会对\'
和\\
进行转义,双引号中除了会对各种转移字符转义外,还支持变量插值。
1 | puts '\\hello \'\n\' world\\' |
8、 Ruby中每声明一个字符串都会创建一个新的字符串对象,而且在Ruby中要判断两个对象是否是同一个对象不能简单的用==
,对象的.eql?
方法和==
都只会判断对象的内容是否相同,.equal?
方法才能判断是否为同一个对象。
1 | s1 = "hello world" |
9、 Ruby中声明一个字符串数组,可以使用%w
快捷方式:
1 | names1 = [ 'ann', 'richard', 'william', 'susan', 'pat' ] |
更多字符串快捷方式可以参考这篇文章
10、 Java中不支持多行文本字符串,但是JS(反点)和Python(三个连续引号)这些脚本语言中都支持,Ruby中可以使用Here Document。Ruby中追加字符串可以使用<<
操作符。
1 | expected_result = <<HEREDOC |
11、 对象的Mutable和Immutable一直是令人争议的话题,可变意味着不安全难以维护,不可变意味着效率低下。比如在Java、JS和Python中字符串对象都是不可变的,在JS和Python中字符串拼接通常效率极低,在Java中有StringBuilder解决这个问题,但是Ruby为了解决这些问题,在String中提供了两组方法,其中方法名的末尾加上!
表示该方法会修改对象内容。!
符号作为约定被用在了标准库和第三方库中。
1 | a = "hello" |
12、 方法名除了有!
后缀表示会修改对象或入参的内容,Ruby还有?
后缀表示这个方法返回true
或false
,=
后缀表示这个方法是对象属性的setter方法,可以使用赋值运算符修改对象属性。
1 | puts "hello".start_with? "hell" # true |
13、 Ruby内建的正则表达式对象和JS一样,使用/.../
双斜杠创建正则字面量,也可以使用%r{...}
或Regexp的构造函数。
1 | # 和JS不同的是,//斜杠中间可以使用变量插值 |
14、 由于Ruby中每声明一个字符串都会创建一个字符串对象,并且字符串对象是可变的,所以Ruby还提供了一个与字符串类似,但不可变且全局唯一的Symbol类对象。
1 | puts "a".object_id # 70107393092020 |
Symbol包括变量名、方法名、类名,每声明一个变量,方法,类都会在符号表中记录下相应的名字,使用Symbol.all_symbols
方法可以查看当前符号表里所有的符号。
1 | # 不要尝试使用Symbol.all_symbols.include? :new_symbol的方式检测符号是否存在 |
15、 Ruby内建了Array、Hash、Range三种数据结构。可以简单地与Java中的ArrayList、HashMap、Guava中的Range等同。
1 | arr = [0, 1, 2] |
16、 调用一个方法就相当于发一个消息,Ruby的传参还是比较复杂的
1 | my_method(arg1, arg2) |
17、 代码块作为参数是Ruby的一大亮点,也是初学者最看不懂的(说的是自己:anguished:)。在向方法发送消息时,代码块参数始终是最后一个。代码块可以使用do … end或{ … }
1 | my_method do |
更多Ruby函数调用的内容可以参考官方文档
18、 Ruby的控制流语句和C系列语言不同,代码块没有花括号,看到这我觉得Python的语法还是可以的,还有Ruby给它垫底:mask:
1 | def condition(a) |
19、 类的定义,与类的属性
1 | class Greeter |
20、 类的继承和大多数语言一样
1 | class A |
最后吐槽一下:排名低就是有排名低的理由,和排名前十的语言相比感觉还是差了点。