-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrb_learning_notes.rb
More file actions
executable file
·371 lines (262 loc) · 8.25 KB
/
rb_learning_notes.rb
File metadata and controls
executable file
·371 lines (262 loc) · 8.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
#!/usr/bin/env ruby
#-----------------------
# everything is object
# 点号之前的东西称为接收者,点号后面的名字是被调用的方法
# 方法通过向对象发送消息来唤起调用
def hello(name)
"Hello, #{name.capitalize}"
end
puts hello('levin')
puts 'levin'.length
puts -8.abs
puts 'levin'.index('v')
#-----------------------
# array literal
words_array = ['cat', 'dog']
puts words_array
words_array = %w{cat dog}
puts words_array
#-----------------------
# hash literal
# 此处和php数组一样的结构
words_hash = {
'a' => 'hello',
'b' => 'world',
}
puts words_hash
#-----------------------
# control structures
if 5 < 3
puts 'ret 1'
elsif 5.nil?
puts 'ret 2'
else
puts 'ret 3'
end
puts 'hello' if 1 #类似python
square = 2
square = square*square while square < 100
puts square
#-----------------------
# regex
if 'ruby' =~ /r\w*y/
puts 'match'
end
puts 'python'.sub(/python/, 'ruby')
puts 'pythonpython'.gsub(/python/, 'ruby')
#-----------------------
# block yield
# 迭代器反复调用block中的代码。迭代数组的each等方法中肯定使用了yield
def call_block
yield('hello')
end
call_block { | word | puts word } #两个竖线为管道符
words_array.each { | word | puts word }
5.times { print '*' }
3.upto(6) { |i| print i }
('a'..'e').each { |char| print char }
print "\n"
def fib_up_to(max)
i1, i2 = 1, 1 #并行赋值
while i1 < max
yield i1
i1, i2 = i2, i1+i2
end
end
fib_up_to(1000) { |f| print f, ' ' }
a = [1, 2]
b = 'cat'
a.each { |b| c = b * a[1] } #此时迭代器将a中的每个值依次传入block,
#上面的b变量将被赋值,最后一次赋值是2,所以下面的b等于2
#不过需要注意的是ruby2.0.0版本已将b变量归为block内部变量
puts b #=>2 why?为什么b等于2,ruby2.0.0版本等于cat保持不变
puts defined?(c)
puts [1, 2, 'a', 'b'].collect { |x| x.succ } #=>[2, 3, "b", "c"] collect将数组元素传递给block,block返回的结果被用来生成一个新的数组。succ为后继的意思
#f = File.open('rb_learning_notes.rb')
#f.each do |line|
# puts line
#end
#f.close
puts [1, 2, 3, 4].inject { |sum, ele| sum+ele } #=>10
puts [1, 2, 3, 4].inject { |product, ele| product*ele } #=>24
class File #其实File类的open方法已经支持了事务block,让文件管理自己的生命周期
def File.open_and_process(*args)
ret = f = File.open(*args)
if block_given?
ret = yield f
f.close
end
return ret
end
end
#File.open_and_process('rb_learning_notes.rb', 'r') do |f|
# while line = f.gets
# puts line
# end
#end
def block_proc(&action) #在最后一个形参前面加上&符号,调用此函数时,函数会自动寻找block并转化为Proc类的对象传给此参数
action
end
g = block_proc { |n| puts "hi, #{n}" }
g.call('levin')
def block_proc(times)
lambda { |n| puts "hi, #{n*times}" } #lambda函数可以将block转换为Proc类的对象
end
g = block_proc(2)
g.call('levin')
#-----------------------
# printf
printf("\nNum: %3.2f, String: %s\n", 237844.248, 'hello')
#-----------------------
# class object
# 创建对象时首先在内存中保存未初始化的对象,然后调用对象的initialize方法
# @符号开头的变量为实例变量,每个对象都有实例变量的拷贝
# 子类继承方法时,应该是增量,而不是直接检验或使用父类的实例变量(低耦合)
class Song
attr_reader :name, :artist, :duration
attr_writer :duration
@@play_count = 0
def initialize(name, artist, duration)
@name = name
@artist = artist
@duration = duration
@play_count = 0
end
def to_s
"#@name, #@artist (#@duration)"
end
def play
@@play_count += 1
@play_count += 1
"#@play_count plays, total #@@play_count plays"
end
public :to_s, :play
end
song = Song.new('ruby', 'ruby song', 240)
puts song.inspect
puts song.to_s
class OKSong < Song
attr_reader :lyrics
def initialize(name, artist, duration, lyrics)
super(name, artist, duration)
@lyrics = lyrics
end
def to_s
super + " lyrics: #@lyrics"
end
end
song = OKSong.new('ruby', 'ruby song', 240, 'ruby song lyrics')
puts song.inspect
puts song.to_s
puts song.name
puts song.lyrics
puts song.duration
song.duration = 301
puts song.duration
puts song.play
puts song.play
class SongList
MAX_TIME = 300
def SongList.is_too_long(song) #如果没加类名前缀,直接调用将提示没有这个方法
return song.duration > MAX_TIME
end
end
puts SongList.is_too_long(song)
#-----------------------
# variables
# 变量本身不是对象,变量是对象的引用,对象一般存在于heap中
# 变量可以通过freeze方法阻止被改动
a = 'Tim'
b = a
a[0] = 'J'
puts a
puts b
a = 'Tim'
b = a.dup
a[0] = 'J'
puts a
puts b
#-----------------------
# Array 数组
# 使用[start, count]来访问数组
# 使用[start..end]或[start...end]访问数组,两个点表示包含end元素,三个点不包含end元素
a = ['a', 'b', 'c', 'd', 'e']
puts a[1, 2]
puts a[1..2]
puts a[1...2]
a[1] = [1, 2] #=>["a", [1, 2], "c", "d", "e"]
a[1, 2] = 'cat' #=>["a", "cat", "d", "e"]
a[1, 0] = 'dog' #=>["a", "dog", "cat", "d", "e"]
a[1, 1] = ['b', 'c'] #=>["a", "b", "c", "cat", "d", "e"]
a[3..3] = [] #=>["a", "b", "c", "d", "e"]
a[7..8] = 'x', 'y' #=>["a", "b", "c", "d", "e", nil, nil, "x", "y"]
#-----------------------
# Numbers 数字
# 数字的前导0代表八进制,0d代表十进制,0x代表十六进制,0b代表二进制,数字间的下划线会被忽略掉
num = 81
6.times do
puts "#{num.class}: #{num}"
num *= num
end
#-----------------------
# String 字符串
# 字符串字面量是处于分界符之间的字符序列
puts "now is #{def the(a)
'the '+a
end
the('time')
} for all good coders."
puts %q/good time/
puts %Q^good time^
puts %Q{hi, #{'j'*2}} #分界符可以是任何一个非字母数字的单字节字符
print <<EOF
ggg
acc
EOF
#使用 - 可以缩进编排终结符
print <<-string1, <<-string2
ggx
string1
gyut
string2
#String.chomp 去掉结尾的换行符
#String.split 分割字符串成数组
#String.squeeze 去除重复字符,如果加了感叹号在方法后面,那么直接对对象进行修改,例如String.squeeze!
#String.scan 匹配某正则并返回
#-----------------------
# Range 区间
# 实现succ和<=>方法的对象才能作为区间,<=>为太空船操作符,它比较两个值,根据第一个值是否大于、等于、小于第二个值返回+1、0、-1
# 使用===可以检测某个值是否在区间的间隔内
puts ('bar'..'bat').to_a
digits = 0..9
puts digits.include?(5)
puts digits.min
puts digits.max
puts digits.reject { |i| i < 5 } #排除小于5的元素
puts digits === 3.1415926
#-----------------------
# Regexp 正则表达式
puts 'ruby' =~ /r.*y/ #=>0 返回初次匹配成功的位置
puts 'ruby' !~ /r.*y/ #=>false =~为肯定匹配操作符,!~为否定匹配操作符
#$&被赋值为匹配的字符串,$`被赋值为匹配字符之前的字符串,$'被赋值为匹配字符之后的字符串
'ruby' =~ /u/
puts "#{$`}<<#{$&}>>#{$'}"
#POSIX字符类
/[:alnum:]/ #字母和数字
/[:alpha:]/ #字母
/[:blank:]/ #空格和制表符
/[:cntrl:]/ #控制字符
/[:digit:]/ #数字
/[:xdigit:]/ #16进制数字
/[:graph:]/ #除了空格的可打印字符
/[:print:]/ #任何可打印字符,包括空格
/[:lower:]/ #小写字母
/[:upper:]/ #大写字母
/[:punct:]/ #除了空格字母数字的可打印字符
/[:space:]/ #\s
'rubby' =~ /(\w)\1/ #=>2 在模式内部,\1指的是第一个组的匹配,\2指的是第二个组的匹配,\&指已匹配的字符串,\+指最后一组的匹配,\` 指匹配前的字符串,\'指匹配后的字符串,在block中这些会失效,应该使用$1等来代替,所有的$变量被保存到了线程局部变量中,用$~访问
#基于模式的替换
a = 'levin';
#! represent mutator
a.sub!(/^./) { |r| r.upcase } #=>Levin
'1:2'.sub!(/(.+):(.+)/, '\2:\1') #=>2:1