arql 0.3.30 → 0.3.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5baf87f0beb5980e412f7c1c6f698b5e20c7bc64736ce2417c9fb41b6b436e63
4
- data.tar.gz: c91e358b60809f044ec1fb345b5c44336ccbb4f1f2708227ccb561d67d284703
3
+ metadata.gz: 0fda37174020852318fc454680c6927e4fd01ef354779e782e596d0af43807e9
4
+ data.tar.gz: b3794fd222fa005419c03b514c3a2d8a4c0ec2dc8db7ea3a4e5ed6304a4146c2
5
5
  SHA512:
6
- metadata.gz: 60c0725447df295df746f3a7bbb9ff7ff8d30272a35fd16f367098ce8cff1d2dbd1a4c44e62eeaabe82301241beb02edf408c5b5f3e8d795ef7c9e6468666229
7
- data.tar.gz: 696903678a8de63f61e0e0bad7f1696ea17e46201c005a4033b1c2da077b1d97dd18e99b78f88fbe9ac7295e2db09b5a71196fb00ecbedaad93eb6a4457103c1
6
+ metadata.gz: 293b549fdbbbd97bd43d3a457325cf88fa8af414f1866918a96bd8b313884c5f7c39a30701571c20e20617e7c68b03b431d8b633a7e2dc09a2a0f6a7db3fc82a
7
+ data.tar.gz: dc4992b8f330b4b1598669cf05987091176d70b56befb70bfffc00ecd94c69d052a3ca4d0c245b748fca02ccfac8776c68fa9bb4f1d3aea1726d1143db6e4ece
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- arql (0.3.30)
4
+ arql (0.3.31)
5
5
  activerecord (>= 6.1.5, < 7.1.0)
6
6
  activesupport (>= 6.1.5, < 7.1.0)
7
7
  caxlsx (~> 3.3.0)
data/README-zh_CN.org CHANGED
@@ -166,6 +166,7 @@
166
166
  6. =ssh.password= : ssh 密码
167
167
  7. =ssh.local_port= : ssh 本地端口
168
168
  8. =singularized_table_names=: 是否使用单数表名,默认为 =false=, 如果为 =false=, 则 =students= 表将定义为 =Student= 模型,如果为 =true=, 则 =students= 表将定义为 =Students= 模型
169
+ 9. =table_name_prefixes=: 表名前缀数组,默认为空数组,如果指定了此项,在生成模型时将忽略这些前缀,例如,如果指定了 =["t_"]=, 则 =t_students= 表将定义为 =Student= 模型
169
170
 
170
171
  **** 配置文件示例
171
172
 
@@ -182,6 +183,7 @@
182
183
  username: root
183
184
  database: blog
184
185
  password:
186
+ table_name_prefixes: ["t_"]
185
187
  socket: /tmp/mysql.sock
186
188
 
187
189
  dev:
@@ -191,6 +193,7 @@
191
193
  username: root
192
194
  password: 123456
193
195
  database: blog
196
+ table_name_prefixes: ["t_"]
194
197
  ssh:
195
198
  host: dev.mycompany.com
196
199
  port: 22
@@ -1075,6 +1078,9 @@
1075
1078
  # Table: sub_order, Column: entry_price (金额)
1076
1079
  #+END_SRC
1077
1080
 
1081
+ *** [[./ruby-guides-for-java-developer-zh_CN.org][给 Java 开发者的 Ruby 入门简明教程]]
1082
+ *** [[./simple-pry-guides-zh_CN.org][简明 Pry 使用指南]]
1083
+ *** [[./simple-active-record-guide-zh_CN.org][简明 ActiveRecord 使用指南]]
1078
1084
  ** 开发
1079
1085
 
1080
1086
  检出代码后,运行 =bin/setup= 安装依赖。你也可以运行 =bin/console= 进入交互式控制台。
data/README.org CHANGED
@@ -175,6 +175,7 @@
175
175
  6. =ssh.password= : ssh password
176
176
  7. =ssh.local_port= : ssh local port
177
177
  8. =singularized_table_names=: Whether to use singular table names, default is =false=, if =false=, the =students= table will be defined as the =Student= model, if =true=, the =students= table will be defined as the =Students= model
178
+ 9. =table_name_prefixes=: An array of table name prefixes, defaults to an empty array. If specified, these prefixes will be ignored when generating models. For example, if =["t_"]= is specified, then the =t_students= table will be defined as the =Student= model
178
179
 
179
180
  **** Example
180
181
 
@@ -190,6 +191,7 @@
190
191
  <<: *default
191
192
  username: root
192
193
  database: blog
194
+ table_name_prefixes: ["t_"]
193
195
  password:
194
196
  socket: /tmp/mysql.sock
195
197
 
@@ -200,6 +202,7 @@
200
202
  username: root
201
203
  password: 123456
202
204
  database: blog
205
+ table_name_prefixes: ["t_"]
203
206
  ssh:
204
207
  host: dev.mycompany.com
205
208
  port: 22
@@ -13,21 +13,51 @@ module Arql::Commands
13
13
  t
14
14
  end
15
15
 
16
- def models_table(regexp)
17
- Terminal::Table.new do |t|
18
- models.each_with_index { |row, idx| t << (row || :separator) if row.nil? ||
19
- regexp.nil? ||
20
- idx.zero? ||
21
- row.any? { |e| e =~ regexp }
22
- }
16
+ def models_table(table_regexp=nil, column_regexp=nil)
17
+ if column_regexp.nil?
18
+ Terminal::Table.new do |t|
19
+ models.each_with_index { |row, idx| t << (row || :separator) if row.nil? ||
20
+ table_regexp.nil? ||
21
+ idx.zero? ||
22
+ row.any? { |e| e =~ table_regexp }
23
+ }
24
+ end
25
+ else
26
+ connection = ::ActiveRecord::Base.connection
27
+ table = Terminal::Table.new do |t|
28
+ t << ['PK', 'Table', 'Model', 'Name', 'SQL Type', 'Ruby Type', 'Limit', 'Precision', 'Scale', 'Default', 'Nullable', 'Comment']
29
+ t << :separator
30
+ Arql::Definition.models.each do |definition|
31
+ model_class = definition[:model]
32
+ matched_columns = model_class.columns.select { |column| column.name =~ column_regexp || column.comment =~ column_regexp }
33
+ next if matched_columns.empty?
34
+ matched_columns.each do |column|
35
+ pk = if [connection.primary_key(definition[:table])].flatten.include?(column.name)
36
+ 'Y'
37
+ else
38
+ ''
39
+ end
40
+ t << [pk, definition[:table], model_class.name, column.name, column.sql_type,
41
+ column.sql_type_metadata.type, column.sql_type_metadata.limit || '',
42
+ column.sql_type_metadata.precision || '', column.sql_type_metadata.scale || '', column.default || '',
43
+ column.null, "#{definition[:comment]} - #{column.comment}"]
44
+ end
45
+ end
46
+ end
47
+ puts table
23
48
  end
24
49
  end
25
50
  end
26
51
  end
27
52
 
28
- Pry.commands.block_command 'm' do |regexp|
53
+ Pry.commands.block_command 'm' do |arg|
29
54
  puts
30
- puts Models::models_table(regexp.try { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) })
55
+ if arg.start_with?('c=') or arg.start_with?('column=')
56
+ column_regexp = arg.sub(/^c(olumn)?=/, '')
57
+ Models::models_table(nil, column_regexp.try { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) })
58
+ else
59
+ puts Models::models_table(arg.try { |e| e.start_with?('/') ? eval(e) : Regexp.new(e) }, nil)
60
+ end
31
61
  end
32
62
 
33
63
  Pry.commands.alias_command 'l', 'm'
data/lib/arql/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Arql
2
- VERSION = "0.3.30"
2
+ VERSION = "0.3.31"
3
3
  end
@@ -0,0 +1,766 @@
1
+ * Java 开发者的 Ruby 入门简明教程
2
+
3
+ Java 非常成熟,久经检验,且非常快(与那些反对java的人可能还在声称的相反)。但它也非常啰嗦。从 Java 到Ruby,可以预见的
4
+ 是代码规模将大大缩小。你也可以期望使用相对少的时间快速出产原型。
5
+
6
+ ** 相似点 Ruby 与 Java 一样的地方
7
+
8
+ - 垃圾回收器帮你管理内存。
9
+ - 强类型对象。
10
+ - 有 public、 private 和 protected 方法。
11
+ - 拥有嵌入式文档工具(Ruby 的工具叫 rdoc)。rdoc 生成的文档与 javadoc 非常相似。
12
+
13
+ ** 相异点 Ruby 与 Java 不同的地方
14
+
15
+ 一些简单总结:
16
+
17
+ - 你不需要编译你的代码。你只需要直接运行它。
18
+ - 定义像类这样的东西时,可以使用 =end= 关键字,而不使用花括号包裹代码块。
19
+ - 使用 =require= 代替 =import= 。
20
+ - 所有成员变量为私有。在外部,使用方法获取所有你需要的一切。
21
+ - 方法调用的括号通常是可选的,经常被省略。
22
+ - 一切皆对象,包括像 2 和 3.14159 这样的数字。
23
+ - 没有静态类型检查。
24
+ - 变量名只是标签。它们没有相应的类型。
25
+ - 没有类型声明。按需分配变量名,及时可用(如: ~a = [1,2,3]~ 而不是 ~int[] a = {1,2,3};~ )。
26
+ - 没有显式转换。只需要调用方法。代码运行之前,单元测试应该告诉你出现异常。
27
+ - 使用 ~foo = Foo.new("hi")~ 创建新对象,而非 ~Foo foo = new Foo("hi")~ 。
28
+ - 构造器总是命名为“initialize” 而不是类名称。
29
+ - 作为接口的替代,你将获得“混入(mixins)”。
30
+ - 相比 XML,倾向于使用 YAML。
31
+ - =nil= 替代 =null= 。
32
+ - Ruby 对 ~==~ 和 ~equals()~ 的处理方式与 Java 不一样。测试相等性使用 ~==~ (Java 中是 ~equals()~ )。测试是否为同一
33
+ 对象使用 ~equals?()~ (Java 中是 ~==~ )。
34
+ - Ruby 里面调用一个函数或方法,参数两边的圆括号可以省略。如:
35
+ - ~p.say_hello("Hi", "Jack")~ 可以写成 ~p.say_hello "Hi", "Jack"~
36
+ - ~f.close()~ 可以写成 ~f.close~
37
+ - 定义函数或方法时,参数两边的圆括号也可以省略。
38
+ - Ruby 的类可以重新「打开」,即在原有的类定义上追加新的方法或属性、覆盖已有的方法、属性。如:
39
+ #+BEGIN_SRC ruby
40
+ class Person < ActiveRecord::Base # 定义了一个 Person 类,它是 ActiveRecord::Base 的子类
41
+ def say_hello(message, name)
42
+ puts "#{name}, #{message}"
43
+ end
44
+ end
45
+
46
+
47
+ class Person # 重新打开 Person 类,这里添加了一个 sleep 方法,并且 Person 仍然有 say_hello 方法,并且它仍然是 ActiveRecord::Base 的子类
48
+ has_many :books # has_many 是从 ActiveRecord::Base 继承来的类方法(静态方法), 类方法可以直接在类体中调用(就是和定义方法的同一层级),而实例方法则不可以在类体中调用
49
+ def sleep(time_secs)
50
+ ...
51
+ end
52
+ end
53
+ #+END_SRC
54
+
55
+ 下面是更详细的差异的介绍:
56
+
57
+ ** 快速简明教程
58
+
59
+ *** 代码块以 end 关键字结束
60
+
61
+ 不同于 Java,Ruby 使用 =end= 关键字来结束代码块,而不是使用花括号。如:
62
+
63
+ **** 类定义
64
+ #+BEGIN_SRC ruby
65
+ class Person
66
+ def initialize(name)
67
+ @name = name
68
+ end
69
+ end
70
+ #+END_SRC
71
+ **** 函数方法定义
72
+ #+BEGIN_SRC ruby
73
+ def say_hello
74
+ puts "Hello"
75
+ end
76
+ #+END_SRC
77
+ *** 一切皆对象
78
+
79
+ Ruby 中的数字、字符串、数组等都是对象,它们都有自己的方法。如:
80
+
81
+ #+BEGIN_SRC ruby
82
+ 3.times { puts "Hello" } # 输出三次 Hello
83
+ "Hello".length
84
+ [1, 2, 3].reverse
85
+ #+END_SRC
86
+
87
+ *** 基本数据类型
88
+ **** 数值
89
+ #+BEGIN_SRC ruby
90
+ 1 + 2
91
+ 2 * 3
92
+ 10 / 5
93
+ 10 % 3
94
+ #+END_SRC
95
+ **** 字符串
96
+ #+BEGIN_SRC ruby
97
+ "Hello, " + "World"
98
+ "Hello" * 3
99
+ "Hello".length
100
+ "Hello".reverse
101
+ #+END_SRC
102
+
103
+ + 单引号字符串中的特殊字符不会被转义,而双引号字符串中的特殊字符会被转义。如:
104
+ #+BEGIN_SRC ruby
105
+ puts 'Hello\nWorld' # 输出 Hello\nWorld
106
+ puts "Hello\nWorld" # 输出 Hello
107
+ # World
108
+ #+END_SRC
109
+ + 双引号字符串中可以使用 #{} 来插入变量或表达式。如:
110
+ #+BEGIN_SRC ruby
111
+ name = "Jack"
112
+ puts "Hello, #{name}" # 输出 Hello, Jack
113
+ #+END_SRC
114
+
115
+ **** nil
116
+
117
+ Ruby 中的 =nil= 相当于 Java 中的 =null= 。
118
+
119
+ **** Symbol
120
+
121
+ #+BEGIN_SRC ruby
122
+ :name
123
+ #+END_SRC
124
+
125
+ Symbol 是一种特殊的字符串(但Symbok 类的和表示字符串的 String 类没有直接关系),它的值是唯一的。Symbol 通常用来表示一个名字或标识符。
126
+
127
+ **** boolean
128
+
129
+ Ruby 中的 true 和 false 都是对象,它们都是 TrueClass 和 FalseClass 的实例。
130
+
131
+ 在 Ruby 中,除了 false 和 nil 为假,其他值都为真。
132
+
133
+ 在 Ruby 代码中,还经常看到 =if obj.present?= 等方法,这些方法是 Rails 提供的,它们是对 Ruby 的扩
134
+ 展。其中,=obj.present?= 方法会判断 obj 是否为 nil 或空字符串或空数组、空散列
135
+
136
+ **** 数组
137
+
138
+ #+BEGIN_SRC ruby
139
+ [1, 2, 3]
140
+ [1, 2, 3].length
141
+ [1, 2, 3].reverse
142
+ [1, 2, 3] << 4
143
+ #+END_SRC
144
+
145
+ + 数组中的元素可以是不同类型的对象。
146
+ + 数组中的元素可以通过索引访问,索引从 0 开始。
147
+ + 数组中的元素可以通过 << 方法添加到数组的末尾。
148
+ ***** 数组的常用方法
149
+ ****** each
150
+ each 方法用于遍历数组中的元素。如:
151
+ #+BEGIN_SRC ruby
152
+ [1, 2, 3].each { |i| puts i }
153
+ #+END_SRC
154
+ ****** map
155
+ map 方法用于对数组中的每个元素执行块中的操作,返回一个新的数组。如:
156
+ #+BEGIN_SRC ruby
157
+ [1, 2, 3].map { |i| i * 2 }
158
+ #+END_SRC
159
+ ****** select
160
+ select 方法用于从数组中选择满足条件的元素,返回一个新的数组。如:
161
+ #+BEGIN_SRC ruby
162
+ [1, 2, 3].select { |i| i > 1 }
163
+ #+END_SRC
164
+ ****** reduce
165
+ reduce 方法用于对数组中的元素进行累加。如:
166
+ #+BEGIN_SRC ruby
167
+ [1, 2, 3].reduce { |sum, i| sum + i }
168
+ #+END_SRC
169
+ ****** each_with_index
170
+ each_with_index 方法用于遍历数组中的元素,同时获取元素的索引。如:
171
+ #+BEGIN_SRC ruby
172
+ [1, 2, 3].each_with_index { |i, index| puts "#{index}: #{i}" }
173
+ #+END_SRC
174
+
175
+ ****** each_with_object
176
+ each_with_object 方法用于遍历数组中的元素,同时传递一个对象。如:
177
+ #+BEGIN_SRC ruby
178
+ [person1, person2].each_with_object({}) { |person, hash| hash[person.name] = person.age }
179
+ #+END_SRC
180
+ ****** group_by
181
+ group_by 方法用于根据块中的条件对数组中的元素进行分组。如:
182
+ #+BEGIN_SRC ruby
183
+ [person1, person2].group_by { |person| person.gender }
184
+ #+END_SRC
185
+ ****** in_groups
186
+ in_groups 方法用于将数组分成若干组。如:
187
+ #+BEGIN_SRC ruby
188
+ [1, 2, 3, 4, 5].in_groups(2)
189
+ #+END_SRC
190
+ ****** in_groups_of
191
+ in_groups_of 方法用于将数组分成若干组,每组包含指定个数的元素。如:
192
+ #+BEGIN_SRC ruby
193
+ [1, 2, 3, 4, 5].in_groups_of(2)
194
+ #+END_SRC
195
+ **** 哈希
196
+
197
+ 哈希是一种键值对的数据结构,类似于 Java 中的 Map。如:
198
+
199
+ #+BEGIN_SRC ruby
200
+ { "name" => "Jack", "age" => 20 }
201
+ { :name => "Jack", :age => 20 }
202
+ { name: "Jack", age: 20 }
203
+ #+END_SRC
204
+
205
+ 上述代码中:
206
+ 1. 第一行的哈希中的键和值都是字符串。
207
+ 2. 第二行的哈希中的键是 Symbol,值是字符串。
208
+ 3. 第三行的哈希中的键是 Symbol,值是字符串,也就是说在一个哈希中, =key: value= 的形式等价于 ~:key => value~ 的形式。
209
+
210
+ 4. 哈希是一种键值对的集合。
211
+ 5. 哈希中的键和值可以是任意类型的对象。
212
+ 6. 哈希中的键是唯一的。
213
+ ***** 哈希的常用方法
214
+ ****** each
215
+ each 方法用于遍历哈希中的键值对。如:
216
+ #+BEGIN_SRC ruby
217
+ { name: "Jack", age: 20 }.each { |key, value| puts "#{key}: #{value}" }
218
+ #+END_SRC
219
+ ****** map
220
+ map 方法用于对哈希中的每个键值对执行块中的操作,返回一个新的数组。如:
221
+ #+BEGIN_SRC ruby
222
+ { name: "Jack", age: 20 }.map { |key, value| value }
223
+ #+END_SRC
224
+ ****** select
225
+ select 方法用于从哈希中选择满足条件的键值对,返回一个新的哈希。如:
226
+ #+BEGIN_SRC ruby
227
+ { name: "Jack", age: 20 }.select { |key, value| value > 18 }
228
+ #+END_SRC
229
+ ****** keys
230
+ keys 方法用于获取哈希中的所有键。如:
231
+ #+BEGIN_SRC ruby
232
+ { name: "Jack", age: 20 }.keys
233
+ #+END_SRC
234
+ ****** values
235
+ values 方法用于获取哈希中的所有值。如:
236
+ #+BEGIN_SRC ruby
237
+ { name: "Jack", age: 20 }.values
238
+ #+END_SRC
239
+ ****** merge
240
+ merge 方法用于合并两个哈希。如:
241
+ #+BEGIN_SRC ruby
242
+ { name: "Jack" }.merge({ age: 20 })
243
+ #+END_SRC
244
+ ****** merge!
245
+ merge! 方法用于将另一个哈希合并到当前哈希中。如:
246
+ #+BEGIN_SRC ruby
247
+ { name: "Jack" }.merge!({ age: 20 })
248
+ #+END_SRC
249
+ *** 类的基础知识
250
+ **** 初始化函数
251
+
252
+ 初始化函数相当于 Java 中的构造函数,它是在创建对象时自动调用的函数。在 Ruby 中,初始化函数的名字是 =initialize=
253
+
254
+ #+BEGIN_SRC ruby
255
+ class Person
256
+ def initialize(name, age)
257
+ @name = name
258
+ @age = age
259
+ end
260
+ end
261
+ #+END_SRC
262
+ **** 属性和 getter/setter
263
+
264
+ 上例中的 =@name= 和 =@age= 是 Person 类的属性,它们是实例变量,只能在类的内部访问。如果要在类的外部访问这两个属性,需要提供 getter 和 setter 方法。如:
265
+
266
+ #+BEGIN_SRC ruby
267
+ class Person
268
+ def initialize(name, age)
269
+ @name = name
270
+ @age = age
271
+ end
272
+
273
+ def name
274
+ @name
275
+ end
276
+
277
+ def name=(name)
278
+ @name = name
279
+ end
280
+ end
281
+
282
+ p = Person.new("Jack", 20)
283
+ puts p.name # 这是调用 getter 方法, 而不是直接访问实例变量
284
+ p.name = "Tom" # 这是调用 setter 方法, 而不是直接设置实例变量
285
+ #+END_SRC
286
+
287
+ 上述代码中, =name= 方法是 getter 方法, =name= 方法是 setter 方法。Ruby 提供了一种更简洁的方式来定义 getter 和 setter 方法,如:
288
+
289
+ #+BEGIN_SRC ruby
290
+ class Person
291
+ attr_accessor :name
292
+
293
+ def initialize(name, age)
294
+ @name = name
295
+ @age = age
296
+ end
297
+ end
298
+ #+END_SRC
299
+
300
+ 如果只需要 getter 方法,可以使用 =attr= 活 =attr_reader= 方法;如果只需要 setter 方法,可以使用 =attr_writer= 方法。
301
+
302
+ #+BEGIN_SRC ruby
303
+ class Person
304
+ attr :name
305
+ attr_writer :name
306
+
307
+ def initialize(name, age)
308
+ @name = name
309
+ @age = age
310
+ end
311
+ end
312
+ #+END_SRC
313
+
314
+ **** 继承
315
+
316
+ 和 Java 一样,Ruby 也是只支持单继承的。Ruby 使用 =<= 操作符来表示继承关系。如:
317
+
318
+ #+BEGIN_SRC ruby
319
+ class Person
320
+ def initialize(name, age)
321
+ @name = name
322
+ @age = age
323
+ end
324
+ end
325
+
326
+ class Student < Person
327
+ def initialize(name, age, school)
328
+ super(name, age)
329
+ @school = school
330
+ end
331
+ end
332
+ #+END_SRC
333
+
334
+ **** 静态方法
335
+
336
+ Ruby 中的静态方法使用 =self= 关键字来定义。如:
337
+
338
+ #+BEGIN_SRC ruby
339
+ class Person
340
+ def initialize(name, age)
341
+ @name = name
342
+ @age = age
343
+ end
344
+
345
+ def self.say_hello
346
+ puts "Hello"
347
+ end
348
+ end
349
+ #+END_SRC
350
+
351
+ 上述代码中, =say_hello= 是一个静态方法,可以通过 Person 类直接调用。 还有另一种常用的定义静态方法的方式,如:
352
+
353
+ #+BEGIN_SRC ruby
354
+ class Person
355
+ def initialize(name, age)
356
+ @name = name
357
+ @age = age
358
+ end
359
+
360
+ class << self
361
+ def say_hello
362
+ puts "Hello"
363
+ end
364
+ end
365
+ end
366
+ #+END_SRC
367
+
368
+ *** 类可以重新打开
369
+
370
+ Ruby 的类可以重新「打开」,即在原有的类定义上追加新的方法或属性、覆盖已有的方法、属性。如:
371
+
372
+ #+BEGIN_SRC ruby
373
+ class Person < ActiveRecord::Base # 定义了一个 Person 类,它是 ActiveRecord::Base 的子类
374
+ def say_hello(message, name)
375
+ puts "#{name}, #{message}"
376
+ end
377
+ end
378
+
379
+
380
+ class Person # 重新打开 Person 类,这里添加了一个 sleep 方法,并且 Person 仍然有 say_hello 方法,并且它仍然是 ActiveRecord::Base 的子类
381
+ has_many :books # has_many 是从 ActiveRecord::Base 继承来的类方法(静态方法), 类方法可以直接在类体中调用(就是和定义方法的同一层级),而实例方法则不可以在类体中调用
382
+ def sleep(time_secs)
383
+ ...
384
+ end
385
+ end
386
+ #+END_SRC
387
+
388
+ *** 混入和 Enumerable
389
+
390
+ Ruby 虽然和 Java 一样只支持单继承,但是 Ruby 提供了一种叫做「混入」的机制,可以在类中引入模块(module),从而实现多继承的效果。如:
391
+
392
+ #+BEGIN_SRC ruby
393
+ module MyModule
394
+ def say_hello
395
+ puts "Hello"
396
+ end
397
+ end
398
+
399
+ class Person
400
+ def xxx
401
+ end
402
+ end
403
+
404
+ class Student < Person
405
+ include MyModule
406
+ end
407
+ #+END_SRC
408
+
409
+ 现在 Student 类既继承了 Person 类的 xxx 方法,又引入了 MyModule 模块的 say_hello 方法。
410
+
411
+ 因为模块(module关键字定义的部分)和类不同的是,模块不能被实例化,也就是不能创建模块的对象。所以混入模块,只会继承模块的方法,而不会继承模块的属性,从而避免了多继承的问题。
412
+
413
+ Ruby 标准库中的 Enumerable 模块就是一个很好的例子。Enumerable 模块提供了很多方法,如 =each=、=map=、=select=、=reject=、=detect=、=sort= 等,这些方法可以被任何实现了 =each= 方法的类包含进来,从而实现了类似于 Java 中的 Collection 接口的效果。如:
414
+
415
+ #+BEGIN_SRC ruby
416
+ class MyCollection
417
+ include Enumerable
418
+ def each
419
+ ...
420
+ end
421
+ end
422
+ #+END_SRC
423
+
424
+ 现在 MyCollection 类就可以像数组一样使用 =map=、=select=、=reject=、=detect=、=sort= 等方法了。而数组实际上也是实现了 =each= 方法并混入了 Enumerable 模块的类。
425
+
426
+ *** Kernel 模块
427
+
428
+ Ruby 中的 Kernel 模块是一个特殊的模块,它包含了很多常用的方法,这些方法可以直接在任何地方调用,而不需要通过模块名或类名来调用。如:
429
+
430
+ #+BEGIN_SRC ruby
431
+ puts "Hello"
432
+ sleep 1
433
+ #+END_SRC
434
+
435
+ 上述代码中的 =puts= 和 =sleep= 方法都是 Kernel 模块中的方法,可以直接调用。
436
+
437
+ 事实上,Ruby 中的很多方法都是定义在 Kernel 模块中的,这是因为 Ruby 中的所有类都是 Object 类的子类,而 Object 类又混入了 Kernel 模块,所以所有的类都可以直接调用 Kernel 模块中的方法。
438
+
439
+ 如果你希望定义一个全局方法,可以直接定义在 Kernel 模块中,这样就可以在任何地方调用了。如:
440
+
441
+ #+BEGIN_SRC ruby
442
+ module Kernel
443
+ def say_hello
444
+ puts "Hello"
445
+ end
446
+ end
447
+
448
+ say_hello
449
+ #+END_SRC
450
+
451
+ *** Block 和 Proc
452
+
453
+ Java 8 中引入了 Lambda 表达式,Ruby 中的 Block 和 Proc 与之类似,都是相当于一个函数对象。
454
+
455
+ **** Block
456
+
457
+ Block 并不是一个对象,而是一段代码块,是原生的语法元素、可以在方法调用时传递给方法。如:
458
+
459
+ #+BEGIN_SRC ruby
460
+ def say_hello
461
+ puts "Hello"
462
+ yield if block_given? # block_given? 用于判断在调用这个函数时,是否使用了 block, yield 会执行传递给 say_hello 方法的 Block
463
+ end
464
+
465
+ say_hello # 输出 "Hello"
466
+
467
+ say_hello do
468
+ puts "World"
469
+ end # 输出 "Hello" 和 "World"
470
+ #+END_SRC
471
+
472
+ 也可以使用 花括号 代替 do/end:
473
+
474
+ #+BEGIN_SRC ruby
475
+ say_hello { puts "World" } # 输出 "Hello" 和 "World"
476
+ #+END_SRC
477
+
478
+ **** Proc
479
+
480
+ proc 看起来和 Block 类似,但是 proc 是一个对象,可以赋值给变量,也可以作为参数传递给方法。如:
481
+
482
+ #+BEGIN_SRC ruby
483
+ my_proc = Proc.new { puts "Hello" }
484
+ my_proc.call # 输出 "Hello"
485
+
486
+ def say_hello(block)
487
+ block.call
488
+ end
489
+
490
+ say_hello(my_proc) # 输出 "Hello"
491
+ #+END_SRC
492
+
493
+ ***** 将 Block 转换为 Proc
494
+
495
+ 有时候我们需要将 Block 转换为 Proc 对象,可以使用 & 符号:
496
+
497
+ #+BEGIN_SRC ruby
498
+ def say_hello(&blk)
499
+ blk.call
500
+ end
501
+
502
+ say_hello { puts "Hello" } # 输出 "Hello"
503
+ #+END_SRC
504
+
505
+ 上面的代码中,&blk 会将传递给 say_hello 方法的 Block 转换为 Proc 对象。
506
+
507
+
508
+ ***** 其他定义 Proc 的方式
509
+ ****** lambda
510
+
511
+ lambda 是 Proc 的一种特殊形式,可以使用 lambda 方法定义一个 Proc 对象:
512
+
513
+ #+BEGIN_SRC ruby
514
+ my_proc = lambda { puts "Hello" }
515
+ my_proc.call # 输出 "Hello"
516
+ #+END_SRC
517
+
518
+ lambda 定义的 Proc 和普通的 Proc 的区别在于,lambda 会检查传递给它的参数个数是否正确,而普通的 Proc 不会。如:
519
+
520
+ #+BEGIN_SRC ruby
521
+ my_proc = Proc.new { |a, b| puts a + b }
522
+ my_proc.call(1) # 输出 1
523
+
524
+ my_proc = lambda { |a, b| puts a + b }
525
+ my_proc.call(1) # 报错
526
+ ****** ->
527
+
528
+ -> 是 lambda 的一种简写形式,可以用来定义一个 Proc 对象:
529
+
530
+ #+BEGIN_SRC ruby
531
+ my_proc = -> { puts "Hello" }
532
+ my_proc.call # 输出 "Hello"
533
+ #+END_SRC
534
+ ***** =&:my_method=
535
+
536
+ 有时候我们会看到这样的写法:
537
+
538
+ #+BEGIN_SRC ruby
539
+ p1 = Person.new
540
+ p2 = Person.new
541
+
542
+ [p1, p2].each(&:say_hello)
543
+ #+END_SRC
544
+
545
+ 这里的 =&:say_hello= 实际上是将 =:say_hello= Symbol对象转换为 Proc 对象,然后传递给 each 方法。这种写法等价于:
546
+
547
+ #+BEGIN_SRC ruby
548
+ [p1, p2].each { |p| p.say_hello }
549
+ #+END_SRC
550
+
551
+ 这种用法看起来很像 Java 8 中的方法引用,但实际上是 Ruby 的一个语法糖。
552
+
553
+ 那么这是如何将 Symbol 对象转换为 Proc 对象呢?实际上 =&= 后面跟一个对象,就是调用这个对象的 =to_proc= 方法,将其转换为 Proc 对象。如:
554
+
555
+ =&:say_hello= 就是将调用 =:say_hello= 这个 Symbol 对象的 to_proc 方法,而 Symbol 的 =to_proc= 方法是这样定义的:
556
+
557
+ #+BEGIN_SRC ruby
558
+ class Symbol
559
+ def to_proc
560
+ Proc.new { |obj, *args| obj.send(self, *args) }
561
+ end
562
+ end
563
+ #+END_SRC
564
+
565
+ *** 元编程
566
+
567
+ 元编程是指在运行时动态地创建类和方法,或者修改现有类和方法的技术。Ruby 是一种动态语言,非常适合进行元编程。
568
+
569
+ 可以理解为有点像 Java 中的反射机制,但是 Ruby 的元编程更加强大和灵活。
570
+
571
+ Ruby 提供了一些方法来动态地定义类和方法,如 =method_missing=, =define_method=, =class_eval=, =instance_eval= 等。
572
+
573
+ 通过元编程,我们可以实现很多功能,如动态地创建类和方法,动态地修改类和方法,动态地调用方法等。
574
+
575
+ 虽然你在编码时有可能不会用到元编程,但是了解元编程的原理和技术,可以帮助你更好地理解 Rails 等 Ruby 库或者框架的特性和机制。
576
+
577
+ 更多关于元编程的内容,可以参考 「Ruby 元编程」 这本书。
578
+
579
+ **** =method_missing=
580
+
581
+ =method_missing= 是 Ruby 中一个非常重要的方法,当调用一个对象不存在的方法时,Ruby 会调用这个对象的 =method_missing= 方法。
582
+
583
+ 通过重写 =method_missing= 方法,我们可以实现很多功能,如动态地创建方法,动态地调用方法等。
584
+
585
+ 例如,我们可以定义一个类,当调用这个类的不存在的方法时,输出方法名:
586
+
587
+ #+BEGIN_SRC ruby
588
+ class MyClass
589
+ def method_missing(name, *args)
590
+ puts "You called #{name} with #{args.inspect}"
591
+ end
592
+ end
593
+
594
+ obj = MyClass.new
595
+ obj.hello(1, 2, 3) # 输出 "You called hello with [1, 2, 3]"
596
+ #+END_SRC
597
+
598
+ 那么 =method_missing= 方法有哪些实际用途呢?考虑我们定义一个 ActiveRecord 模型:
599
+
600
+ #+BEGIN_SRC ruby
601
+ class User < ActiveRecord::Base
602
+ end
603
+ #+END_SRC
604
+
605
+ ActiveRecord 库会根据约定的命名规则,将 User 类和数据库中的 users 表对应起来,当我们调用 User 类的一些方法:
606
+
607
+ #+BEGIN_SRC ruby
608
+ user = User.find(1)
609
+ user.username = "Tom"
610
+ #+END_SRC
611
+
612
+ 那么 =user.username= setter 方法是如何实现的呢?如果我们是 ActiveRecord 库的作者,我们就可以使用 =method_missing= 方法来实现这些方法:
613
+
614
+ #+BEGIN_SRC ruby
615
+ class ActiveRecord::Base
616
+ def method_missing(name, *args)
617
+ if db_columns.include_by_name?(name) # 判断数据库中是否有这个字段
618
+ db_columns.write_by_column_name(name, args.first) # 写入数据库
619
+ else
620
+ super # 调用父类的 method_missing 方法
621
+ end
622
+ end
623
+ end
624
+ #+END_SRC
625
+
626
+ **** =define_method=
627
+
628
+ =define_method= 方法可以动态地定义方法,它接受一个方法名和一个块,然后定义一个方法。
629
+
630
+ 例如,我们可以定义一个类,动态地定义一个方法:
631
+
632
+ #+BEGIN_SRC ruby
633
+ class MyClass
634
+ define_method :hello do |name|
635
+ puts "Hello, #{name}!"
636
+ end
637
+ end
638
+
639
+ obj = MyClass.new
640
+ obj.hello("Tom") # 输出 "Hello, Tom!"
641
+ #+END_SRC
642
+
643
+ 和 =method_missing= 方法不同, =define_method= 方法是在类对象上调用的,而且定义好之后,这个方法就会一直存在,直到这个类被销毁。而 =method_missing= 方法是在实例对象上调用的,
644
+ 并且每次调用不存在的方法时,都会调用 =method_missing= 方法。
645
+
646
+ 在 =method_missing= 的那个示例中,考虑到性能问题,不希望每次调用 ~user.username=~ 的时候都调用 =method_missing= 方法,我们可以使用 =define_method= 方法来定义这个方法:
647
+
648
+ #+BEGIN_SRC ruby
649
+ class ActiveRecord::Base
650
+ def method_missing(name, *args)
651
+ if db_columns.include_by_name?(name) # 判断数据库中是否有这个字段
652
+ self.class.send(:define_method, name) do |value|
653
+ db_columns.write_by_column_name(name, value) # 写入数据库
654
+ end
655
+ send(name, args.first) # 调用刚刚定义的方法, 而且这样一来,下次调用这个方法就不会再调用 method_missing 方法了
656
+ else
657
+ super # 调用父类的 method_missing 方法
658
+ end
659
+ end
660
+ end
661
+ #+END_SRC
662
+
663
+ **** =class_eval=
664
+
665
+ =class_eval= 方法可以动态地定义类的方法,它接受一个字符串作为参数,然后定义一个方法。
666
+
667
+ 例如,我们可以定义一个类,动态地定义一个方法:
668
+
669
+ #+BEGIN_SRC ruby
670
+ class MyClass
671
+ class_eval %{
672
+ def hello(name)
673
+ puts "Hello, \#{name}!"
674
+ end
675
+ }
676
+ end
677
+
678
+ obj = MyClass.new
679
+ obj.hello("Tom") # 输出 "Hello, Tom!"
680
+ #+END_SRC
681
+
682
+ **** =instance_eval=
683
+
684
+ =instance_eval= 方法可以动态地定义实例对象的方法,它接受一个字符串作为参数,然后定义一个方法。
685
+
686
+ 例如,我们可以定义一个类,动态地定义一个方法:
687
+
688
+ #+BEGIN_SRC ruby
689
+ class MyClass
690
+ def initialize(name)
691
+ @name = name
692
+ end
693
+ end
694
+
695
+ obj = MyClass.new("Tom")
696
+ obj.instance_eval %{
697
+ def hello
698
+ puts "Hello, \#{@name}!"
699
+ end
700
+ }
701
+
702
+ obj.hello # 输出 "Hello, Tom!"
703
+
704
+ obj2 = MyClass.new("Jerry")
705
+ obj2.hello # 报错, 因为 obj2 没有定义 hello 方法, 请自行搜索学习 Ruby 中的 singleton class 的概念
706
+ #+END_SRC
707
+
708
+ **** =instance_exec=
709
+
710
+ =instance_exec= 方法和 =instance_eval= 方法类似,但是它可以接受块作为参数。
711
+
712
+ 例如,我们可以定义一个类,动态地定义一个方法:
713
+
714
+ #+BEGIN_SRC ruby
715
+ class MyClass
716
+ def initialize(name)
717
+ @name = name
718
+ end
719
+ end
720
+
721
+ obj = MyClass.new("Tom")
722
+ obj.instance_exec("Jerry") do |name|
723
+ puts "Hello, #{name}!"
724
+ end # 输出 "Hello, Jerry!", 这里定义的仍然是一个 singleton method
725
+ #+end_src
726
+
727
+
728
+ 还可以借助 =instance_exec= 方法来动态定义一个普通的实例方法:
729
+
730
+ #+BEGIN_SRC ruby
731
+ class MyClass
732
+ def initialize(name)
733
+ @name = name
734
+ end
735
+ end
736
+
737
+ MyClass.instance_exec do
738
+ define_method :hello do
739
+ puts "Hello, #{@name}!"
740
+ end
741
+ end
742
+
743
+ obj = MyClass.new("Tom")
744
+ obj.hello # 输出 "Hello, Tom!"
745
+ #+END_SRC
746
+
747
+
748
+
749
+
750
+ **** =Class.new=
751
+
752
+ 示例:
753
+
754
+ #+BEGIN_SRC ruby
755
+ Employee = Class.new(Person) do
756
+ def hello
757
+ ...
758
+ end
759
+ end
760
+
761
+ e = Employee.new
762
+ e.hello
763
+ #+END_SRC
764
+
765
+ Person 成为 Employee 的父类
766
+
@@ -0,0 +1,83 @@
1
+ * ActiveRecord 简明教程
2
+
3
+ ActiveRecord 是 Rails 中的 ORM 框架,它将数据库表映射到 Ruby 对象,让我们可以通过 Ruby 对象来操作数据库。
4
+
5
+
6
+ ** 定义模型类
7
+
8
+ 模型类是继承自 ActiveRecord::Base 的类,它们是数据库中的表在 Ruby 语言中的映射。
9
+
10
+ #+BEGIN_SRC ruby
11
+ class User < ActiveRecord::Base
12
+ end
13
+ #+END_SRC
14
+
15
+ 而 User 对象的属性和数据库表的字段的对应关系,是 ActiveRecord 根据数据库中的表信息,自动完成的。
16
+
17
+ 在 Arql 中,模型类的定义是 Arql 根据数据库表的表信息自动生成的,所以我们不需要像这里一样手动定义模型类。
18
+
19
+ ** 定义关联关系
20
+
21
+ 在 ActiveRecord 中,我们可以通过 has_many, belongs_to, has_one 等方法来定义模型类之间的关联关系。
22
+
23
+ - =has_many= 表明此表是一对多关系的“一”方
24
+ - =has_one= 表明此表是一对一关系的属主
25
+ - =belongs_to= 表明此表是一对多或一对一关系的从属方
26
+ - =has_and_belongs_to_many= 表明此表是多对多关系的其中一方
27
+
28
+
29
+ 使用 Arql 查询数据库时,我们希望也可以通过定义好的关联关系来查询数据。
30
+
31
+ 例如,我们有两个模型类 User 和 Post,User 有多个 Post,Post 属于一个 User, 如果我们希望查询张三的所有文章,
32
+
33
+ 在不使用关联关系的情况下,我们需要这样查询:
34
+
35
+ #+BEGIN_SRC ruby
36
+ user = User.find_by(name: '张三')
37
+ posts = Post.where(user_id: user.id)
38
+ #+END_SRC
39
+
40
+ 而如果我们定义了关联关系,我们可以这样查询:
41
+
42
+ #+BEGIN_SRC ruby
43
+ user = User.find_by(name: '张三')
44
+ posts = user.posts
45
+ #+END_SRC
46
+
47
+ 关联关系是在模型类中定义的,而 Arql 中模型类是 Arql 替我们自动生成的,那么我们要在哪里定义关联关系呢?
48
+
49
+ 别忘了 Ruby 的类是可以重新打开的,我们可以在 Arql 中重新打开模型类,定义关联关系:
50
+
51
+ #+BEGIN_SRC ruby
52
+ class User < ActiveRecord::Base
53
+ has_many :posts
54
+ end
55
+ #+END_SRC
56
+
57
+ 像 has_many, belongs_to, has_one 这样的方法,ActiveRecord 会根据默认的规则,来关联关系关联到的是哪个表的哪个字段。这也就是 Rails 中所谓的约定大于配置的体现。
58
+
59
+ 使用 Arql 查询既有系统的数据库时,数据库中的表、字段名称往往不符合 Rails 的规则约定,这时我们可以通过传递参数来指定关联关系的关联字段:
60
+
61
+ #+BEGIN_SRC ruby
62
+ class User < ActiveRecord::Base
63
+ has_many :posts, foreign_key: 'author_id', class_name: 'Article', primary_key: 'uid'
64
+ end
65
+ #+END_SRC
66
+
67
+ =has_many=, =belongs_to=, =has_one= 方法常用的参数如下:
68
+
69
+ - =class_name=: 表明此关联关系对应的对方的 Model 类名
70
+ - =foreign_key=: 表明此关联关系中,从属表一侧的关联字段名
71
+ - =primary_key=: 表明此关联关系中,属主表一侧的关联字段名
72
+ - =join_table=: 在多对多关系中,表明关联两个表的中间表名
73
+ - =association_foreign_key=: 在多对多关系中,表明对方 Model 在中间表中的关联字段名
74
+
75
+ ** 简单 CRUD
76
+
77
+ 参考:https://guides.rubyonrails.org/active_record_querying.html
78
+
79
+ ** 参考
80
+
81
+ - https://guides.rubyonrails.org/active_record_basics.html
82
+ - https://guides.rubyonrails.org/active_record_querying.html
83
+ - https://guides.rubyonrails.org/association_basics.html
@@ -0,0 +1,114 @@
1
+ * Pry 简明教程
2
+
3
+ ** Pry 是什么?
4
+
5
+ 和 Python 一样,Ruby 也有自己的 REPL 工具,叫做 irb(Interactive Ruby)。
6
+
7
+ Pry 是另外一个功能更加强大的 Ruby REPL 工具,它可以让你在 Ruby REPL 中做很多事情,比如查看源码、查看文档、调试等等。
8
+
9
+ Arql 的主要功能就是基于 Pry 实现的,所以你可以把 Pry 当做 Arql 的一个子集。Pry 的命令和功能在 Arql 中都是可以使用的。而且 Arql 还提供了一些额外的 Pry 命令。
10
+
11
+
12
+ 当然也可以单独安装和使用 Pry。
13
+
14
+
15
+ ** 单独安装 Pry
16
+
17
+ #+BEGIN_EXAMPLE
18
+ $ gem install pry
19
+ #+END_EXAMPLE
20
+
21
+ Pry 本身也支持扩展,你可以安装一些 Pry 的插件,比如 pry-doc、pry-byebug 等等。
22
+
23
+ #+BEGIN_EXAMPLE
24
+ $ gem install pry-doc
25
+ $ gem install pry-byebug
26
+ #+END_EXAMPLE
27
+
28
+
29
+ ** 单独使用 Pry
30
+
31
+ #+BEGIN_EXAMPLE
32
+ $ pry
33
+ #+END_EXAMPLE
34
+
35
+
36
+ ** 常用的 Pry 命令
37
+
38
+
39
+ *** 查看帮助
40
+
41
+ #+BEGIN_EXAMPLE
42
+ [1] pry(main)> help
43
+ #+END_EXAMPLE
44
+
45
+
46
+ *** 查看变量
47
+
48
+ #+BEGIN_EXAMPLE
49
+ [2] pry(main)> ls
50
+ #+END_EXAMPLE
51
+
52
+
53
+ *** 查看一个实例方法的源码
54
+
55
+ #+BEGIN_EXAMPLE
56
+ [3] pry(main)> show-source ActiveRecord::Base#save
57
+ #+END_EXAMPLE
58
+
59
+
60
+ *** 查看一个实例方法的文档
61
+
62
+ #+BEGIN_EXAMPLE
63
+ [4] pry(main)> show-doc ActiveRecord::Base#save
64
+ #+END_EXAMPLE
65
+
66
+
67
+ *** 查看一个类的的源码
68
+
69
+ #+BEGIN_EXAMPLE
70
+ [5] pry(main)> show-source ActiveRecord::Base
71
+ #+END_EXAMPLE
72
+
73
+
74
+ *** 查看一个类的文档
75
+
76
+ #+BEGIN_EXAMPLE
77
+ [6] pry(main)> show-doc ActiveRecord::Base
78
+ #+END_EXAMPLE
79
+
80
+
81
+ *** 在 Pry 中直接修改代码
82
+
83
+ 你甚至可以在 Pry 中用 edit 命令直接修改代码,然后 Pry 会自动保存修改后的代码到一个临时文件中,然后你可以在 Pry 中直接调用修改后的代码。
84
+
85
+ #+BEGIN_EXAMPLE
86
+ [7] pry(main)> edit ActiveRecord::Base#save
87
+ #+END_EXAMPLE
88
+
89
+ ** 分号
90
+
91
+ 在 Ruby 语言中, 行尾的分号是可以省略的。
92
+
93
+
94
+ Pry 中每次执行一个 Ruby 表达式,都会自动打印出这个表达式的值:
95
+
96
+ #+BEGIN_EXAMPLE
97
+ [7] pry(main)> user.posts = Post.all
98
+ => [#<Post id: 1, title: "Hello World", content: "Hello World", created_at: "2016 -12-12 12:12:12", updated_at: "2016-12-12 12:12:12">,
99
+ #<Post id: 2, title: "Hello Ruby", content: "Hello Ruby", created_at: "2016-12-12 12:12:12", updated_at: "2016-12-12 12:12:12">,
100
+ ... ...]
101
+ #+END_EXAMPLE
102
+
103
+ 这是通过调用 Ruby 的 表达式的值对象的 inspect 方法 (Object#inspect 方法)实现的。如果你不想打印出这个值,可以在表达式后面加上分号:
104
+
105
+ #+BEGIN_EXAMPLE
106
+ [8] pry(main)> user.posts = Post.all;
107
+ #+END_EXAMPLE
108
+
109
+ 我们知道在 ActiveRecord 中,像 =User.where(gender: 'Male')= 这样的表达式,返回结果是一个 ActiveRecord::Relation 对象,而不是一个数组。
110
+ 这样设计的目的是为了支持 Lazy Loading,只有在需要的时候才会去执行 SQL 查询。但是当我们在 Pry 中直接对 =User.where(gender: 'Male')= 的时候,却发现
111
+ 它立即执行了 SQL 查询,并且输出的是一个数组对象;这就是因为 Pry 在打印对象的时候,会调用对象的 inspect 方法,而 ActiveRecord::Relation 对象的 inspect 方法
112
+ 会立即执行 SQL 查询并返回一个数组对象。如果你不想立即执行 SQL 查询,就可以在表达式后面加上分号。
113
+
114
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.30
4
+ version: 0.3.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Liu Xiang
@@ -360,6 +360,9 @@ files:
360
360
  - lib/arql/version.rb
361
361
  - oss-files-zh_CN.org
362
362
  - oss-files.org
363
+ - ruby-guides-for-java-developer-zh_CN.org
364
+ - simple-active-record-guide-zh_CN.org
365
+ - simple-pry-guides-zh_CN.org
363
366
  - sql-log-zh_CN.org
364
367
  - sql-log.org
365
368
  homepage: https://github.com/lululau/arql