Cheat Sheet速查表
跳转到主要内容

Goby 速查表

本文根据 Devhints / Goby 翻译。代码示例及版本范围沿用原文。原文标注更新日期:2018-12-06。

Goby 的语言设计基于 Ruby 语言,更加精简干练。两者在语法上的差异非常小。

入门

Hello world

hello.gb

class Greet
  attr_accessor :audience, :head, :tail

  def initialize
    @head = "Hello, "
    @tail = "!"
  end

  def name
    audience.name
  end

  def say
    puts head + name + tail
  end
end

module MyName
  attr_reader :name

  def initialize
    @name = self.class.to_s
  end
end

class World
  include MyName
end

greet = Greet.new
greet.audience = World.new
greet.say

然后运行:

$ goby hello.gb
#=> Hello, World!

REPL (igb)

$ goby -i
  • reset: 重置 VM
  • exit: 退出 REPL
  • help: 显示帮助
  • ctrl-c: 取消当前输入的代码块,或退出(在 top 顶层时)

参见 igb 手册与测试脚本. 您可以使用 readline 诸如通过方向键访问命令历史记录等功能。

变量

局部变量

zip101 = "233-7383"
magic_number = 42

应采用“[a-z][a-z0-9_]+”(蛇形命名法,snake_case)。

实例变量

module State
  def initialize(state)
    @state = state      # declaring an instance variable by assignment
  end
  def show
    @state              # accessible from other instance methods
  end
end

state = State.new "success"
state.show
#=> success

应采用“@[a-z][a-z0-9_]+”(蛇形命名法,snake_case)。

多重赋值

# array literal
a, b, c = [1, 2, 3]

# array with '*'
a = [1, 2, 3]
x, y, z = *a

# array literal with '*'
a, b, c = *[1, 2, 3]

# bare assignment: unsupported
a, b, c = 1, 2, 3  #=> unexpected 3 Line: 0

“黑洞”变量(丢弃变量)

# '_' is write-only
a, _ = [1, 2]

类变量

不支持。

全局变量

不支持。

方法定义

方法定义与调用

def foo_bar?(baz)
  if baz == "Hi, Goby!"
    true
  else
    false
  end
end

foo_bar? "Hi, Goby!" #=> true

方法名称应采用“[a-z][a-z0-9_]+\??”(蛇形命名法,snake_case)。仅在没有参数时,可以省略末尾的“()”。!” 不被支持 不被支持.

方法参数的顺序

def foo(normal, default="value", hash={}, ary=[], keyword:, keyword_default:"key", *sprat)
end

如果为参数提供了默认值,则在调用时可以省略该参数。 () 可以省略。方法定义中参数的顺序限制如下:

  1. 普通参数 (例如 a)
  2. 带有默认值的普通参数 (例如 a=1)
  3. 可选参数 (数组或哈希,例如 ary=[] 或 hs={})
  4. 关键字参数 (例如 kwd:)
  5. 带有默认值的关键字参数 (例如 kwd: 1 或 ary: [1,2,3] 或 hsh: {key: "value"})
  6. 不定长参数(splat 参数) (例如 *sp)

否则,将会报错。

关键字参数 (WIP)

def foo(process:, verb: :GET, opt:{ csp: :enabled }, ary: [1, 2, 3])
end

返回值

PI = 3.14
def area(radius)
  radius * PI      # returns the result of evaluation
end

area 6             #=> 18.84

返回多个值

def my_array
  [1, 2, 3]
end

my_array   #=> [1, 2, 3]

实例方法

module Foo
  def bar       # defining instance method
    puts "bar"
  end

  def baz(count, email: "goby@example.com")
    count.times do
      puts email
    end
  end
end

foo = Foo.new
foo.bar     #=> bar
foo.baz(3)  #↓
goby@example.com
goby@example.com
goby@example.com

单例方法 #1

str = "Goby"
def str.foo     #1 singleton method on the object
  self * 2
end

str.foo
#=> GobyGoby

单例方法 #2

module Foo
  def self.bar  #2 singleton method with `self.`
    92
  end
end

单例方法 #3

module Foo
  def Foo.bar   #3 singleton method with a class name (unrecommended)
    88
  end
end

单例方法 #4

module Foo end

def Foo.bar     #4 singleton methods outside the Foo
  9999
end

Foo.bar #=> 9999

属性访问器方法

class Foo
  attr_accessor :bar, :baz

  def initialize
    @bar = 42
    @baz = 99
  end
end

foo = Foo.new

foo.bar = 77
foo.baz = 88

您可以使用以下简写形式在类或模块中声明属性访问器方法:

  • attr_accessor
  • attr_reader
  • attr_writer

私有方法(待实现)

class Foo
  def bar
    42
  end

  def _baz  # leading '_' means private method
    99
  end
end

模块/类定义

模块定义与 include

module Foo
  def foo
    "Foo's instance method"
  end
end

class Bar
  include Foo   # to include Foo
end

Bar.new.foo     #=> Foo's instance method

模块名称应采用“[A-Z][A-Za-z0-9_]+”(大驼峰命名法,UpperCamelCase)。模块无法被继承。

模块定义与 extend

module Foo
  def foo
    "Foo's instance method will be a singleton method"
  end
end

class Bar
  extend Foo   # to extend Foo
end

Bar.foo        #=> Foo's instance method will be a singleton method

extend 即在您的类或模块中,将指定模块内的实例方法用作 单例方法 。

模块实例化

module Foo   #module definition
  def foo
    99
  end
end

Foo.new.foo  #=> 99

实际上,Goby 所指的模块甚至可以是 实例化 通过“new”——例如“Foo.new”.

类定义与继承

class Foo       # class definition
  def bar
    99
  end
end

class Baz < Foo # inheritance
end

Baz.new.bar  #=> 99

类名应采用“[A-Z][A-Za-z0-9]+”(大驼峰命名法,UpperCamelCase)。支持通过“<”进行继承。

常量

HTTP_ERROR_404 = 404
HTTP_ERROR_404 = 500    # error

常量应采用“[A-Z][A-Za-z0-9_]+”(UPPER_SNAKECASE)。常量 不可重入 且其作用域为 全局.

重新定义类/模块

class Foo
  def bar
    99
  end
end

class Foo
  def bar  # redefining is possible
    77
  end
end

命名空间

class Foo
  module Bar
    MAGIC = 99
    def baz
      99
    end
  end
end

Foo::Bar.new.baz     # Use '::' for namespacing
Foo::Bar::MAGIC      # Use '::' for namespacing

加载库

require

require("uri")   # to activate URL class

u = URI.parse("http://example.com")
u.scheme   #=> "http"

require_relative

require_relative("bar")  # loading the local bar.gb

class Foo
  def self.bar(x)
    Bar.foo do |ten|
      x * ten
    end
  end

  def self.baz
    yield(100)
  end
end

字面量

关键字

def, true, false, nil, if, elsif, else, case, when, return, self, end, while, do, yield, get_block, next, class, module, break

字符串字面量

"double quote"
'single quote'

可以使用双引号或单引号。

符号字面量

:symbol           # equivalent to "symbol"
{ symbol: "value" }

Goby 的符号(使用 :)始终为 String 类。

数值字面量

year   =  2018   # Integer
offset = -42     # Integer
PI     = 3.14    # Float
G      = -9.8    # Float

数组字面量

[1, 2, 3, "hello", :goby, { key: "value"}]
[1, 2, [3, 4], 5, 6]

哈希(Hash)字面量

h = { key: "value", key2: "value2" }
h[:key2]   #=> value2

哈希字面量的键应始终为 符号字面量.

范围字面量

(1..10).each do |x|    # '..' represents a range
  puts x*x
end

布尔值与 nil

true       # Boolean class
false      # Boolean class
nil        # Null class

!nil  #=> true

除……之外的任何对象 nil 以及 false 在条件判断中均被视为 true 。

运算符

算术/逻辑/赋值运算符

+           # unary
**          # power
-           # unary
* / %       # multiplication, division, modulus
+ -         # addition, subtraction
!           # logical inversion
> >= < <=   # inequality comparison
== !=       # equality comparison, negative comparison
&&          # logical AND
||          # logical OR
+= -=       # shorthand of addition/subtraction
=           # assignment

*运算符优先级为 TBD

其他运算符

()          # changing priority of interpretation
[]          # array literal
*           # multiple assignment
..          # range

*运算符优先级为 TBD

分隔符

class Foo; end   # ';' to delimit

class Bar end    # recommended

字符串插值(待实现)

puts "Error: #{error_message}"  # double quotation is required

注释

puts "Goby"    # comments

使用注解(annotations)来保持注释简洁。

  • TODO
  • FIXME
  • OPTIMIZE
  • HACK
  • REVIEW

I/O

  • #puts

  • 特殊常量: ARGV, STDIN, STDOUT, STDERR, ENV

支持 Flow 控制。

if, else, elsif

def foo(str)
  if str.size > 10
    puts "too big!"
  elsif str.size < 3
    puts "too short!"
  else
    puts "moderate"
  end
end

then 是 非 支持的。

Break

def foo(tail)
  (5..tail).each do |t|
    if t % 2 == 0 && t % 5 == 0
      puts "ouch!"
      break       # finish the block
    else
      puts t
    end
  end
  puts "out of the block"
end

foo 20
#=> 5 6 7 8 9
#=> ouch!
#=> out of the block

大小写 (Case)

def foo(str)
  case str
  when "Elf"
    puts "You might be Aragorn II!"
  when "Aragorn"
    puts "Long time no see, Aragorn!"
  when "Frodo", "Sam", "Gandalf"
    puts "One of us!"
  else
    puts "You're not yourself"
  end
end

While

decr = 10
while decr do
  if decr < 1
    break
  end
  puts decr
  decr -= 1
end

while、条件语句以及 do/end 代码块(block)均可用于构建循环。

Rescue

建设中。Join #605.

代码块

代码块

def foo(ary: [1, 2, 3])
  ary.each do |s|      # start of the block with |block variable|
    puts s
  end                  # end of the block
end

{ } 不能用于定义代码块。

yield

def foo
  yield(10)  # executes the block given
end

foo do |ten|
  ten + 20
end

代码块对象(Block object)与 call

b = Block.new do
  100
end

b.call  #=> 100

Block.new 可以接收一个代码块,然后 call.

传递代码块

def baz
  1000
end

class Foo
  def exec_block(block)
	block.call
  end

  def baz
    100
  end
end

b = Block.new do
  baz
end

f = Foo.new
f.exec_block(b)

传递带有参数的代码块

b = Block.new do |arg, offset|
  arg + 1000 - offset
end

b.call(49, 500) #=> 549

特殊 get_block 关键字

def bar(block)
  # runs the block object and the block arg simultaneously
  block.call + get_block.call
end

def foo
  bar(get_block) do # passes two blocks to `bar`
    20
  end
end

foo do
  10
end

get_block 它并非方法,而是 关键字 用于将指定的代码块参数获取为代码块对象。通过这种方式,你可以传递或 call 将指定的代码块参数作为代码块对象进行处理。

闭包(Closure)

count = 0          # the declaration is used
b = Block.new do
  count += 1       # the block looks preserving the `count`
end

class Foo
  def bar(blk)
    count = 9      # (does not affect)
    puts blk.call  # local variable is resolved to the one above
  end
end

Foo.new.bar b  #=> 1
Foo.new.bar b  #=> 2
Foo.new.bar b  #=> 3

原生类(主要)

Goby 中最“原生”的类,原则上无法通过 new 进行实例化。

Object

Bar.ancestors
#» [Bar, Foo, Object]
Bar.singleton_class.ancestors
#» [#<Class:Bar>, #<Class:Object>, Class, Object]

Object 实际上仅用于创建单例类(singleton class)。参见 Class.

  • Object.methods: !, !=, ==, block_given?, class, exit, instance_eval, instance_variable_get, instance_variable_set, is_a?, methods, nil?, object_id, puts, raise, require, require_relative, send, singleton_class, sleep, thread, to_s, <, <=, >, >=, ancestors, attr_accessor, attr_reader, attr_writer, extend, include, name, new, superclass

  • Object.new.methods: !, !=, ==, block_given?, class, exit, instance_eval, instance_variable_get, instance_variable_set, is_a?, methods, nil?, object_id, puts, raise, require, require_relative, send, singleton_class, sleep, thread, to_s

Class

String.ancestors      #=> [String, Object]

Class 以及 Object实际上可以视为相同,在绝大多数情况下无需进行区分。

  • Class.methods: <, <=, >, >=, ancestors, attr_accessor, attr_reader, attr_writer, extend, include, name, new, superclass, !, !=, ==, block_given?, class, exit, instance_eval, instance_variable_get, instance_variable_set, is_a?, methods, nil?, object_id, puts, raise, require, require_relative, send, singleton_class, sleep, thread, to_s

String

puts "Hello" + ' ' + 'world'  #=> Hello world

固定为 UTF-8 ,并支持 mb4。

  • String.methods: fmt,
    • 其余部分: Class.methods
  • "a".methods: !=, *, +, <, <=>, ==, =~, >, [], []=, capitalize, chop, concat, count, delete, downcase, each_byte, each_char, each_line, empty?, end_with?, eql?, fmt, include?, insert, length, ljust, match, new, replace, replace_once, reverse, rjust, size, slice, split, start_with, strip, to_a, to_bytes, to_d, to_f, to_i, to_s, upcase,
    • 其余部分: Object.new.methods

Integer

37037 * 27      #=> 999999
  • Integer.methods:与 Class.methods
  • 1.methods: !=, %, *, **, +, -, /, <, <=, <=>, ==, >, >=, even?, new, next, odd?, pred, ptr, times, to_f, to_float32, to_float64, to_i, to_int, to_int16, to_int32, to_int64, to_int8, to_s, to_uint, to_uint16, to_uint32, to_uint64, to_uint8
    • 其余部分: Object.new.methods

Array

[1, "2", :card, [4, 5], { john: "doe" }]
  • Array.methods:与 Class.methods
  • [1].methods: *, +, [], []=, any?, at, clear, concat, count, delete_at, dig, each, each_index, empty?, first, flatten, include?, join, last, lazy, length, map, new, pop, push, reduce, reverse, reverse_each, rotate, select, shift, to_enum, unshift, values_at
    • 其余部分: Object.new.methods

Hash

h = { key: "value" }
h = { "key": "value" }  #=> error

h["key"]  #=> value
h[:key]   #=> value

哈希字面量(hash literal)中的键应为 符号字面量,而哈希索引既可以是字符串字面量,也可以是符号(symbol)字面量。

  • Hash.methods:与 Class.methods
  • { key: "value" }.methods: [], []=, any?, clear, default, default=, delete, delete_if, dig, each, each_key, each_value, empty?, eql?, fetch, fetch_values, has_key?, has_value?, keys, length, map_values, merge, new, select, sorted_keys, to_a, to_json, to_s, transform_values, values, values_at
    • 其余部分: Object.new.methods

Range

(1..10).each do |i|
  puts i ** 2
end
  • Range.methods:与 Class.methods
  • (1..10).methods: !=, ==, bsearch, each, first, include?, last, lazy, map, new, size, step, to_a, to_enum
    • 其余部分: Object.new.methods

Block

b = Block.new do
  100
end

b.call  #=> 100
  • Block.methods:与 Class.methods
  • (Block.new do end).methods: call
    • 其余部分: Object.new.methods

原生类(次要)

Float

1.1 + 1.1   # => -2.2
2.1 * -2.1  # => -4.41

诸如……之类的浮点数字面量 3.14 或 -273.15. Float 类基于Golang 的 float64 类型。

  • Float.methods:与 Class.methods
  • 3.14.methods: !=, %, *, **, +, -, /, <, <=, <=>, ==, >, >=, new, ptr, to_d, to_i
    • 其余部分: Object.new.methods

Decimal

"3.14".to_d            # => 3.14
"-0.7238943".to_d      # => -0.7238943
"355/113".to_d
# => 3.1415929203539823008849557522123893805309734513274336283185840

a = "16.1".to_d
b = "1.1".to_d
e = "17.2".to_d
a + b # => 0.1
a + b == e # => true

('16.1'.to_d  + "1.1".to_d).to_s #=> 17.2
('16.1'.to_f  + "1.1".to_f).to_s #=> 17.200000000000003

实验性功能:其大小是任意的,在内部实现上基于 Golang 的 big.Rat 类型。目前十进制字面量表示为 TBD,您可以通过 Decimal 数值,通过 to_d 方法从 Integer/Float/String.

  • Decimal.methods:与 Class.methods
  • (1.1).to_d.methods: !=, *, **, +, -, /, <, <=, <=>, ==, >, >=, denominator, fraction, inverse
    • 其余部分: Object.new.methods

Regexp

a = Regexp.new("orl")
a.match?("Hello World")   #=> true
a.match?("Hello Regexp")  #=> false

b = Regexp.new("😏")
b.match?("🤡 😏 😐")    #=> true
b.match?("😝 😍 😊")    #=> false

c = Regexp.new("居(ら(?=れ)|さ(?=せ)|る|ろ|れ(?=[ばる])|よ|(?=な[いかくけそ]|ま[しすせ]|そう|た|て))")
c.match?("居られればいいのに")  #=> true
c.match?("居ずまいを正す")      #=> false

使用方法 / / (待实现)。

  • Regexp.methods:与 Class.methods
  • Regexp.new("^aa$").methods: ==, match?
    • 其余部分: Object.new.methods

MatchData

# numbered capture
'abcd'.match(Regexp.new('(b.)'))
#=> #<MatchData 0:"bc" 1:"bc">

# named capture
'abcd'.match(Regexp.new('a(?<first>b)(?<second>c)'))
#=> #<MatchData 0:"abc" first:"b" second:"c">

# converting to hash
» 'abcd'.match(Regexp.new('a(?<first>b)(?<second>c)')).to_h
#» { 0: "abc", first: "b", second: "c" }

捕获结果中的数字键实际上是 String class.The 键 0 对应的是匹配到的字符串。

  • MatchData.methods:与 Class.methods
  • 'abcd'.match(Regexp.new('(b.)')).methods: captures, length, new, to_a, to_h
    • 其余部分: Object.new.methods

File

f = File.new("../test_fixtures/file_test/size.gb")
f.name  #=> "../test_fixtures/file_test/size.gb"
  • File.methods: basename, chmod, delete, exist?, extname, join
    • 其余部分: Class.methods
  • File.new.methods: basename, chmod, close, delete, exist?, extname, join, name
    • 其余部分: Object.new.methods

原生类(面向 Golang)

GoMap

h = { foo: "bar" }
m = GoMap.new(h)    # to pass values to Golang's code
h2 = m.to_hash
h2[:foo]   #=> "bar"
  • GoMap.methods:与 Class.methods
  • GoMap.new.methods: get, set, to_hash
    • 其余部分: Object.new.methods

Channel

c = Channel.new

1001.times do |i| # i start from 0 to 1000
  thread do
  	c.deliver(i)
  end
end

r = 0
1001.times do
  r = r + c.receive
end

r #=> 500500

Channel 该类用于持有通道(channel),以便与 #thread配合使用。请参阅 thread.

  • Channel.methods:与 Class.methods
  • Channel.new.methods: close, deliver, new, receive
    • 其余部分: Object.new.methods

枚举器(Enumerator)与惰性求值(lazy)

一个较新的实验性库。

LazyEnumerator

# creating a lazy enumerator
enumerator = LazyEnumerator.new(ArrayEnumerator.new([1, 2, 3])) do |value|
	2 * value
end
result = []

enumerator.each do |value|
	result.push(value)
end

result   #=> [2, 4, 6]

一种简写形式 #lazy 方法也已在 Array 以及 Range 中提供。请参阅下方的“技巧与提示”。

  • LazyEnumerator.methods:与 Class.methods
  • [1, 2].lazy: each, first, has_next?, initialize, map, next
    • 其余部分: Object.new.methods

ArrayEnumerator

iterated_values = []

enumerator = ArrayEnumerator.new([1, 2, 4])

while enumerator.has_next? do
	iterated_values.push(enumerator.next)
end

iterated_values   #=> [1, 2, 4]
  • ArrayEnumerator.methods:与 Class.methods
  • ArrayEnumerator.new([1, 2, 3]).methods: has_next?, initialize, next
    • 其余部分: Object.new.methods

RangeEnumerator

iterated_values = []

enumerator = RangeEnumerator.new((1..4))

while enumerator.has_next? do
	iterated_values.push(enumerator.next)
end

iterated_values   #=> [1, 2, 3, 4]
  • RangeEnumerator.methods:与 Class.methods
  • RangeEnumerator.new(1..2).methods: has_next?, initialize, next
    • 其余部分: Object.new.methods

特殊类

Boolean

true.class  #=> Boolean
false.class #=> Boolean

一个专门用于持有 true 以及 false的特殊类。无法被实例化。

Null

nil.class   #=> Null

一个专门用于持有 nil的特殊类。无法被实例化。

Method

(一个特殊的占位类,仅用于存放由 Goby 代码定义的方法。)

Diggable

提供 #dig 方法。目前。 Array 以及 Hash 类的实例可以被 Diggable.

[1, 2].dig(0, 1)  #=> TypeError: Expect target to be Diggable, got Integer

测试框架

Spec

require "spec"

Spec.describe Spec do
  it "fails and exit with code 1" do
	expect(1).to eq(2)
  end
end

Spec.run
  • Spec.methods: describe, describes, instance, run
    • 其余部分: Object.methods
  • Spec.new.methods: describes, initialize, run, session_successful, session_successful=
    • 其余部分: Hash.new.methods

技巧与提示

查看方法

» "string".methods
#» ["!=", "*", "+", "<", "<=>", "==", "=~", ">", "[]", "[]=", "capitalize", "chop", "concat", "count", "delete", "downcase", "each_byte", "each_char", "each_line", "empty?", "end_with?", "eql?", "fmt", "include?", "insert", "length", "ljust", "match", "new", "replace", "replace_once", "reverse", "rjust", "size", "slice", "split", "start_with", "strip", "to_a", "to_bytes", "to_d", "to_f", "to_i", "to_s", "upcase", "!", "block_given?", "class", "exit", "instance_eval", "instance_variable_get", "instance_variable_set", "is_a?", "methods", "nil?", "object_id", "puts", "raise", "require", "require_relative", "send", "singleton_class", "sleep", "thread"]

查看类

» "string".class
#» String

查看单例类

» "moji".singleton_class
#» #<Class:#<String:842352325152>>

» "moji".class.singleton_class
#» #<Class:String>

查看祖先类

» Integer.ancestors
#» [Integer, Object]

» "moji".class.ancestors
#» [String, Object]

查看单例类的祖先类

» "moji".class.singleton_class.ancestors
#» [#<Class:String>, #<Class:Object>, Class, Object]

查看对象的 ID

» "moji".object_id
#» 842352977920

#to_json

h = { a: 1, b: [1, "2", [4, 5, nil]]}
h.to_json         # converts hash to JSON
#=> {"a":1, "b":[1, "2", [4, 5, null]]}

自定义 #to_json

重写 #to_json 在您的类中:

class JobTitle
  def initialize(name)
    @name = name
  end

  def to_json
    { title: @name }.to_json
  end
end

class Person
  def initialize(name, age)
    @name = name
    @age = age
    @job = JobTitle.new("software engineer")
  end

  def to_json
    { name: @name, age: @age, job: @job }.to_json
  end
end

stan = Person.new("Stan", 23)
h = { person: stan }
h.to_json #=> {"person":{"name":"Stan","job":{"title":"software engineer"},"age":23}}

惰性求值(Lazy)枚举

避免 N + 1 查询。

enumerator = [1, 2, 3].lazy.map do |value|
	2 * value
end
result = []

enumerator.each do |value|
	result.push(value)
end

result  #=> [2, 4, 6]

您可以调用 #lazy.map 在 Array, Range上,或者 JSON 对象上。

代码风格

简明风格指南

  • 应使用 UTF-8。
  • 仅使用两个空格 作为一级缩进。
    • 不得使用制表符(Tab)进行缩进。
  • 更多内容,请参考 RuboCop 风格指南 进行实例化。

文档标记法

  • Class#instance_method ——使用 # 在文档中表示实例方法
  • Class.class_method
  • Module.module_method

语法高亮

支持 Vim 和 Sublime Text。目前也可以使用 Ruby 的语法高亮配置。

参考资料

官方

面向 Goby 开发者的阅读材料

JP 资源