arql 0.3.30 → 0.3.31

Sign up to get free protection for your applications and to get access to all the features.
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