-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
1698 lines (1236 loc) · 84.4 KB
/
atom.xml
File metadata and controls
1698 lines (1236 loc) · 84.4 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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[余瓞归的博客]]></title>
<link href="./atom.xml" rel="self"/>
<link href="./"/>
<updated>2017-04-11T11:45:20+08:00</updated>
<id>./</id>
<author>
<name><![CDATA[]]></name>
</author>
<generator uri="http://www.mweb.im">MWeb</generator>
<entry>
<title type="html"><![CDATA[春天到了,最喜欢油菜花开]]></title>
<link href="./14915616638277.html"/>
<updated>2017-04-07T18:41:03+08:00</updated>
<id>./14915616638277.html</id>
<content type="html"><![CDATA[
<p>春天到了,很喜欢金灿灿油菜花,站在一大片一大片的花丛中,如同徜徉在金色的海洋。回忆起小的时候,花比人高,拖着书包走在开满油菜花的田间小路上开心的上学去,闭上眼似乎还能闻见淡淡的花香。</p>
<p>天气暖和了,也该出门走走,结束宅男的生活了。</p>
<p><img src="media/14915616638277/14918808316312.jpg" alt=""/></p>
<span id="more"></span><!-- more -->
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Jenkins集成Ruby on Rails单元测试]]></title>
<link href="./14913797670808.html"/>
<updated>2017-04-05T16:09:27+08:00</updated>
<id>./14913797670808.html</id>
<content type="html"><![CDATA[
<p>Jenkins集成Rails单元测试关键是安装ruby环境,jenkins可以通过插件安装ruby运行环境,但是安装的ruby版本是j-ruby,和我们使用的标准ruby有一定区别不推荐安装。<br/>
我们需要通过ruby版本控制工具安装rvm或者rbenv安装需要的ruby版本。这里选择rvm来安装。</p>
<span id="more"></span><!-- more -->
<h2 id="toc_0">安装rvm</h2>
<p>我们只需要为jekins用户安装rvm, 不推荐安装全局的, 运行下面的命令安装:</p>
<pre><code> sudo su -lp jenkins
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | bash -s stable
echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"' >> ~/.bash_profile
</code></pre>
<p>测试rvm是否安装成功</p>
<pre><code> type rvm | head -1 # 返回 'rvm is a function' 表示安装成功
</code></pre>
<p>最后,配置一些必要的参数</p>
<pre><code> rvm_install_on_use_flag=1
rvm_project_rvmrc=1
rvm_gemset_create_on_use_flag=1
</code></pre>
<h3 id="toc_1">配置jenkins为rails项目添加执行脚本</h3>
<p>添加一个普通的jenkins任务,在'Execute Shell Script'部分做如下设置:</p>
<pre><code> #!/bin/bash
source "$HOME/.rvm/scripts/rvm"
# Use the correct ruby
[[ -s ".rvmrc" ]] && source .rvmrc
# Set "fail on error" in bash
set -e
# Do any setup
# e.g. possibly do 'rake db:migrate db:test:prepare' here
bundle install
rake db:test:prepare
# Finally, run your tests
rake
</code></pre>
<h3 id="toc_2">为rails项目配置数据库</h3>
<p>如果之前没有为rails项目配置数据库,上面的脚本执行build会出错,我们可以在workspace下面设置数据库。</p>
<pre><code> sudo su -lp jenkins
cd /var/lib/jenkins/workspace/Project_name
vi config/database.yml #设置你的development和test数据库
</code></pre>
<p>上面步骤完成之后,就可以成功build一个ROR项目,执行包括单元测试和其他的各种rake任务了。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Jenkins与Gitlab集成]]></title>
<link href="./14910403462980.html"/>
<updated>2017-04-01T17:52:26+08:00</updated>
<id>./14910403462980.html</id>
<content type="html"><![CDATA[
<p>Jenkins和Gitlab集成主要目的是将Jenkins作为Gitlab持续集成工具,版本库有提交或者合并时能够触发Jenkins自动build</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">版本要求</h3>
<p>Jenkins集成Gitlab是用过gitlab-plugin来实现,因此对jenkins和gitlab有版本要求</p>
<p>jenkins > 1.568 <br/>
gitlab 7.14.x 或者 8.1.x,不支持8.0.x</p>
<h3 id="toc_1">gitlab-plugin介绍</h3>
<p>插件为jekins提供了gitlab-webhook以及gitlab-ci相应的功能,相关的接口如下:</p>
<pre><code>/project/PROJECT_NAME/builds/COMMIT_SHA1/status.json 返回COMMIT_SHA1版本号对应的build状态,在gitlab merge/request页面显示
/project/PROJECT_NAME/builds/status.png?ref=BRANCH_NAME 显示分支build状态的图标,"sucess", "pending", "failed"
/project/PROJECT_NAME/builds/status.png?sha1=COMMIT_SHA1 返回COMMIT_SHA1的build状态图标
/project/PROJECT_NAME/builds/COMMIT_SHA1 跳转到对应COMMIT_SHA1版本的build状态页面,
/project/PROJECT_NAME/commits/COMMIT_SHA1 跳转到对应COMMIT_SHA1版本的build状态页面,
/project/PROJECT_NAME?ref=BRANCH_NAME 跳转到对应BRANCH_NAME版本的build状态页面,
/project/PROJECT_NAME 触发jenkins自动build的接口,要传递必要的参数
</code></pre>
<p>插件内置build参数, 可以在初始化构建参数时添加:</p>
<pre><code>gitlabSourceBranch merge/request的源分支
gitlabTargetBranch merge/request的目标分支
gitlabSourceRepoURL
gitlabSourceRepoName
gitlabMergeRequestTitle
gitlabMergeRequestId
gitlabMergeRequestAssignee
gitlabUserName
gitlabUserEmail
gitlabBranch Gitlab push代码的分支可以用于shell script
gitlabActionType Gitlab操作类型PUSH或MERGE可以用于shell script
</code></pre>
<p>以上参数在gitlab 触发webhooks的时候会传递过来,同时我们也可以在构建jekins任务时设置默认值</p>
<h3 id="toc_2">配置jenkins</h3>
<p>基本设置<br/><br/>
1.升级jenkins, 目前使用的1.47版本会遇到克隆版本会报错,升级到最新1.643可以配置成功<br/><br/>
2.安装gitlab-plugin插件,同时会一同安装插件依赖git-client和git<br/><br/>
3.为jenkins生成一个能访问gitlab的ssh密钥对,切换到jenkins用户将密钥对至于.ssh目录,其中公钥将用于gitlab设置deploy key </p>
<p>添加构建项目<br/><br/>
4.添加构建项目(构建一个自由风格的软件项目), 设置项目名<br/><br/>
5.在源码管理部分: </p>
<pre><code>选择git
Repository URL设置gitlab项目地址,如:git@your.gitlab.server:group/repo_name.git
高级设置, Name设置为origin
Branch Specifier: origin/${gitlabSourceBranch}
源码库浏览器:gitlab
URL: http://your.gitlab.server
Version: gitlab版本号,如:1.11.0
Additional Behaviours:
点击'Add', 选择‘Merge before build’
Name of the repository:origin
Branch to merge to: ${gitlabTargetBranch}
构建触发器:
勾选'Build when a change is pushed to GitLab'
保存设置
</code></pre>
<p>6.设置gitlab回调接口,用于在build完成将结果通知到gitlab </p>
<pre><code>进入全局系统管理
Gitlab部分
Gitlab host URL: http://your.gitlab.server
API Token: 设置gitlab的api访问token(admin用户才有)
</code></pre>
<h3 id="toc_3">Gitlab配置</h3>
<p>Gitlab相对于jenkins配置要简单很多,主要是为jenkins要访问的项目配置gitlab-ci以及webhook</p>
<p>1.设置项目deploy key, 将jenkins用户目录下面的公钥设置在这里即可<br/><br/>
2.设置gitlab ci </p>
<pre><code>在项目设置里,点击'Services'
点击'GitLab CI', 勾选'Active'
Trigger栏,勾选'Push events'和'Tag push events'
Token, 随便填写一个字符串
Project url:填写jenkins api地址,http://JENKINS_URL/project/PROJECT_NAME
</code></pre>
<p>3.设置gitlab webhook</p>
<pre><code> 点击'Web hooks', 输入地址:http://JENKINS_URL/project/PROJECT_NAME
然后勾选'Merge Request event'
</code></pre>
<p>注意,gitlab ci和webhook都要设置才行</p>
<p>以上设置完成之后,往gitlab里push代码或者建立Merge Request就会自动build相应的jekins任务了</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Linux的文件链接]]></title>
<link href="./14913797760241.html"/>
<updated>2017-04-05T16:09:36+08:00</updated>
<id>./14913797760241.html</id>
<content type="html"><![CDATA[
<p>链接Linux文件系统中非常重要的一个概念,在这里探讨Linux文件系统中的硬链接和软连接,以帮助我们更好的理解和正确使用硬链接和软连接。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">什么是Inode?</h3>
<p>涉及到文件相关知识,indoe必须了解。文件系统中的索引节点index node 又称 inode。所有文件都有文件名与数据,linux中称之为用户数据 (user data) 与元数据 (metadata)。用户数据也可以称之为文件数据块 (data block)记录文件真实内容的地方,而元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息;inode也是元数据的一部分,在linux中inode是文件的唯一标识而非文件名,系统或程序通过 inode 号寻找正确的文件数据块。而文件名只是为了方便人们记忆和使用。</p>
<p>Inode示意图:<br/>
<img src="media/14913797760241/inode01.jpg" alt="Inode示意图"/></p>
<h3 id="toc_1">Linux一切皆为文件</h3>
<p>Linux中为解决信息能独立于进程之外被长期存储引入了文件,文件作为进程创建信息的逻辑单元可被多个进程并发使用,磁盘上的文本与图像、鼠标与键盘等输入设备及网络交互等 I/O 操作设计了一组通用 API,使他们被处理时均可统一使用字节流方式。也就是说, 系统中除进程之外的一切皆是文件!</p>
<h3 id="toc_2">硬链接与软链接</h3>
<p>有时候我们的文件需要共享不可能每个要用的地方都拷贝一份,链接就是为了解决这个问题。在Linux中链接分为硬链接(hard link)和软链接(soft link), 创建链接的方法为:</p>
<p>硬链接</p>
<pre><code> link file_a file_b
ln file_a file_b
</code></pre>
<p>软链接</p>
<pre><code> link -s file_a file_b
ln -s file_a file_b
</code></pre>
<p>那么,硬链接和软连接有什么区别呢?</p>
<p>硬链接可以理解为对一个inode取多个不同的别名,如果一个inode对应多个文件名那么这个文件之间就是硬链接。通俗讲,硬链接是一个文件的别名,他们具有相同的inode号。<br/><br/>
软链接*是一个普通的文件,只是数据内容存放的是指向另一文件的路径名。它有着自己的 inode 号以及用户数据块。</p>
<p>硬链接和软连接示意图:<br/>
<img src="media/14913797760241/inode02.jpg" alt="硬链接和软连接示意图"/></p>
<p>硬链接存在以下几点特性: </p>
<ol>
<li>文件有相同的 inode 和数据内容;</li>
<li>只能对已存在的文件进行创建;<br/></li>
<li>不能交叉文件系统进行硬链接的创建,例如,nfs和ext3;<br/></li>
<li>不能对目录进行创建,只可对文件创建;<br/></li>
<li>删除一个硬链接文件并不影响其他有相同 inode 号的文件。<br/></li>
</ol>
<p>软链接的特性: </p>
<ol>
<li>软链接有自己的文件属性及权限等;<br/></li>
<li>可对不存在的文件或目录创建软链接;<br/></li>
<li>软链接可交叉文件系统;<br/></li>
<li>软链接可对文件或目录创建;<br/></li>
<li>创建软链接时,链接计数不会增加;<br/></li>
<li>删除软链接并不影响被指向的文件,但若被指向的原文件被删除,链接失效,但是原文件重新创建之后软链接又可以继续使用。<br/></li>
</ol>
<p>以上就是硬链接和软链接的相同点和区别,可以看出导致这些不同的根本原因是软连接是一个独立的文件而硬链接只是一个别名。所以,我们在使用的时候也要区别对待。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[为什么你的代码如此难以理解]]></title>
<link href="./14913797809069.html"/>
<updated>2017-04-05T16:09:40+08:00</updated>
<id>./14913797809069.html</id>
<content type="html"><![CDATA[
<p>无意间读了一篇博客<a href="https://medium.com/on-coding/why-your-code-is-so-hard-to-understand-83057c115a2b">《Why your code is so hard to understand》</a> 恰好最近遇到这些问题,引起了一些思考和共鸣。作为工程师你是如何看待代码的好与坏?该文章中提到的几点我觉得特别有道理,如,过度复杂的心智模型(overly complex mental models),从语义模型到代码的糟糕转化(poor translation of semantic models into code)和隐晦的用法(obscured usage)等等。今天我结合自己的工作谈谈看法。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">过度复杂的心智模型</h3>
<p>说到模型,程序员最熟悉不过了,一个功能完成往往要经历很多个模型的建模,但是这里心智模型(mental model)估计大家很少遇到。简单的说就是根据已有的知识和经验产生对事物的主观认识,从而形成一个对事物运行发展的预测。通俗一点,你‘希望’事物如何发展,这个不是一个心智模型,但是你‘认为’事物将如何发展,这个就是你的心智模型。因此,拥有一个好的心智模型将会对事物的发展做出准确的判断。我们通常说‘眼光好’,‘有远见’,‘运筹帷幄之中,决胜千里之外’,就是形容心智模型比常人精确的人。详见<a href="http://baike.baidu.com/view/2333986.htm?fr=aladdin">百度百科</a>解释。</p>
<p>对于我们编写代码心智模型是你对需求的第一认知,举例说明一下,例如我们需要实现一个用户登录功能,你最先想到的是什么?你第一反应就是输入用户名和密码,校验密码正确以后保存用户状态,没错,这就是你的心智模型。想过没有,对于一个第一次接触互联网的人来说他认为用户登录又该是什么样的呢?而为什么当你很开心的进入编码时,另外一个程序员会告诉你要限制用户密码输错的次数,同事密码不要明文存在数据库和日志中,而你完全没有想到这些?这些就是每一个人的心智模型不一样,导致的不一样的结果。</p>
<p>那么,怎样才能让我们的心智模型足够精准呢?</p>
<p>我认为两点很重要:</p>
<ol>
<li>不断的完善自己的知识结构。我们看不到过苹果的抛物线,但是一个学习过牛顿定律的高中生很快就会在脑海中推断出抛物线形状。</li>
<li>着手实现之前多和身边的人讨论。这是一个自我修正很弥补的过程,站在众人的肩膀上或者三人行必有我师,无论你怎么说都行。</li>
</ol>
<p>心智模型是我们实现某项事情的最先的一步,但是又会受到以往的经验和获得的信息的影响,所以我们要尽可能的让我们的心智模型更加精准,让我们变得更有远见,眼光更好。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[提高你水平git命令]]></title>
<link href="./14913797844730.html"/>
<updated>2017-04-05T16:09:44+08:00</updated>
<id>./14913797844730.html</id>
<content type="html"><![CDATA[
<p>我们在使用Git常用的add, commit和merge等命令来处理我们日常的工作。本文介绍几个不常用,但是能给你带来极大的效率提高同时也能让你Git水平提高一个档次。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">git blame [file_name]</h3>
<p>查看当前file_name文件中的每一行的修改记录。这个在我们想知道某一行是由谁最后一次修改时特别有用, 当你代码出了问题可以快速揪出那个坑人同伴。实用指数5星。</p>
<p>{% highlight ruby linenos %}</p>
<p>git blame Gemfile</p>
<p><sup>0a57942</sup> (rubyrock 2012-07-31 09:46:47 +0800 1) source '<a href="http://ruby.taobao.org">http://ruby.taobao.org</a>'<br/>
0f727cfd (ShiningRay 2014-05-16 14:59:10 +0800 2) source '<a href="http://boohee:boohee0690@gems.boohee.cn">http://boohee:boohee0690@gems.boohee.cn</a>'<br/>
<sup>0a57942</sup> (rubyrock 2012-07-31 09:46:47 +0800 3) <br/>
3556c391 (vincent 2013-10-16 19:13:20 +0800 4) gem 'rails', '3.2.14'<br/>
<sup>0a57942</sup> (rubyrock 2012-07-31 09:46:47 +0800 5) gem 'mysql2'<br/>
ec26bb30 (zhouguangming 2013-01-04 17:23:54 +0800 6) gem 'sqlite3'<br/>
<sup>0a57942</sup> (rubyrock 2012-07-31 09:46:47 +0800 7) <br/>
2421794e (vincent 2013-10-17 14:55:53 +0800 8) # Sunspot. Full-text search engine<br/>
<sup>0a57942</sup> (rubyrock 2012-07-31 09:46:47 +0800 9) gem 'sunspot_rails'<br/>
d4327102 (zhouguangming 2012-07-31 08:43:59 +0800 10) gem 'sunspot_solr', '1.3.2'<br/>
45ec2a81 (vincent 2014-09-10 23:35:53 +0800 11) gem 'progress_bar', require: false</p>
<p>....</p>
<p>{% endhighlight %}</p>
<h3 id="toc_1">git log --oneline, --graph, --all</h3>
<p>我回顾历史时候常用git log。这个是按照提交顺序来排列显示你一些基本信息,你可以试试添加以下几个参数:</p>
<p>--oneline, 以极简的形式只显示commit的hash号和message<br/><br/>
--graph, 以图形树显示历史,SourceTree控们试着换换口味啦<br/><br/>
--all, 显示全部分支历史,不止当前分支哦 </p>
<p>最后,以上三个可以一起组合使用。</p>
<pre><code class="language-ruby">
* 64bb1b1 清理掉ifood星级计算和星级标签中对ifood_menu_materials和ifood_upload_menu_materials的关联
* bb9d626 去掉ifood model中ifood_menu_material, ifood_upload_menu_materials关联
* 8527d02 修改ifood_menu_material, ifood_upload_material
| * 2f4ba29 导入food_meal数据
| * 470322e Refactor: meal_time to meals_order, meal_kind to meals_kind.
| * 83afd02 增加 food_meal,用于存储食物的餐别meal_time和餐类 meal_kind.
| * 37a05a1 Merge branch 'master' of git.boohee.cn:ruby/ifood
| |\
| | | * ba30fa8 WIP on hotfix/remove-duplicated-models: 26f481d Merge branch 'hotfix/remove-duplicated-models' of git.
| | | |\
| |_|/ /
|/| | |
| | | * 211cda6 index on hotfix/remove-duplicated-models: 26f481d Merge branch 'hotfix/remove-duplicated-models' of git.
| |_|/
|/| |
* | | 26f481d Merge branch 'hotfix/remove-duplicated-models' of git.boohee.cn:ruby/ifood into hotfix/remove-duplicated
|\ \ \
| * | | 4798136 移除IfoodMenuMaterial关联
* | | | 567d5e8 移除IfoodMenuMaterial关联
|/ / /
* | | b7ca53f remove binding.pry in qa
* | | a9bb314 Remove IFoodUnit
* | | 65a3fc5 Merge branch 'master' of git.boohee.cn:ruby/ifood into hotfix/remove-duplicated-models
|\ \ \
| | |/
| |/|
| * | 2d60cef Merge branch 'master' of git.boohee.cn:ruby/ifood
| |\ \
| * | | 7950470 Update new relic licence key
:
</code></pre>
<h3 id="toc_2">git reflog</h3>
<p>有时候我们迫不得已使用了git reset --hard,然后你马上意识到你丢失所有的提交。如果你还想在看看怎么办呢?那就使用git reflog吧。请记住Git是不会丢失任何一个commit信息的。</p>
<h3 id="toc_3">git add -p [file_name]</h3>
<p>设想一下,我们为一个文件写了好几个方法。但是有的还没有完全写好,我们只想提交已经写好的部分。怎么办?用git add -p filename, 可以互交是的提交一个文件的部分改动。</p>
<p>同时还有git add -i 也是互交试添加缓存,很好实用的。</p>
<h3 id="toc_4">git rebase -i HEAD~[number_of_commits]</h3>
<p>有没有想过一个功能可能存在多个提交,在最后上线前我们想这多个commit合并成一个。那就用rebase吧。</p>
<pre><code>git rebase -i HEAD~4
</code></pre>
<p>将从HEAD之前的4次提交合并成一个</p>
<h3 id="toc_5">git fsck --lost-found</h3>
<p>有些时候我们的commit可能没有任何的分支名或者tag指向它,到时我们查看历史记录是找不到塔,造成丢失commit的假象。我们可以用git fsck --lost-found快速找回。</p>
<pre><code>git fsck --lost-found
Checking object directories: 100% (256/256), done.
Checking objects: 100% (8924/8924), done.
dangling blob fc81f3f48b7d8298d9624c2f210a41d9eb8edaf8
dangling blob 6b5c1ba9a16089f04a71c4b691bc00a1c6f3310f
dangling commit 3ce4507cec2d6c0e83c263500759a55156d57876
</code></pre>
<h3 id="toc_6">git cherry-pick</h3>
<p>这个是我最喜欢的命令了,git cherry-pick [commit-hash], 可以将其他分支的单次commit合并到当前分支,而不是整个分支合并,也不会扰乱当前分支,酷毙了。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[字符编码]]></title>
<link href="./14913797880850.html"/>
<updated>2017-04-05T16:09:48+08:00</updated>
<id>./14913797880850.html</id>
<content type="html"><![CDATA[
<p>乱码是我们在使用计算机(不止编程)中经常遇到,如,网页显示乱码,Linux文本文件到Windows中乱码。最近花时间研究了一番,在这里做个总结。</p>
<span id="more"></span><!-- more -->
<p>字符编码就是要将字符转换为计算机里的二进制信息存储,当我们需要的时候读取的时候通过该编码方式将二进制转换为人能看懂的有意义的信息。字符编码需要经历一下几个过程:</p>
<p>1.字符表(Character repertoire):知道一个系统需要支持哪些字符,比如,英文,中文日文和拉丁符号。<br/><br/>
2.编码字符集(CCS:Coded Character Set):给字符表里的抽象字符编上一个数字,也就是字符集合到一个整数集合的映射。也就是给每一个要用到字符一个唯一的编号,这个是将字符到数字的一一映射。其中unicode就是这一层的,unicode是一个字符集。<br/><br/>
3.字符编码表(CEF:Character Encoding Form):将字符集里字符对应的整数转换成有限长度的二进制位,便于计算机使用一定长度的二进制形式表示该整数。其中,utf-8, utf-16就是这个层面的。<br/><br/>
4.字符编码方案(CES:Character Encoding Scheme):对于CEF得到的二进制值具体如何在计算机中进行存储,传输。因为存在大端小端的问题,这就会跟具体的操作系统相关了。这种解决方案称为字符编码方案。 </p>
<p><em>ASCII</em><br/><br/>
这个不用说是做早的字符编码方式,用1个字节表示128个英文字符95个可打印字符和33个控制字符,ASCII用7位来表示128个字符的8位用来奇偶校验。</p>
<p><em>EASCII</em><br/><br/>
随着计算机的发展到欧洲,128个字符已经不能满足使用了。于是人们就想到还有的8位没有用上,于是将第8位也用上总共字符集就翻倍了变成256,这个编码规则也常被称为EASCII。EASCII基本解决了整个西欧的字符编码问题。</p>
<p><em>中文编码</em><br/><br/>
中国的汉字数量远远超过ASCII码数量,有10万之多。1个字节最多只能表示256个字符,这个时候需要一种编码来解决中文字符,GB2312就是解决这个问题的。GB2312使用2个字节来编码汉字和符号,同时兼容ASCII码(ASCII还是一个字节存储)。中文编码还有BIG5, GBK和GB18030。他们的关系如下:</p>
<p>GB2312<br/><br/>
描述:国家简体中文字符集<br/><br/>
字节数:可变字节,ASCII用1个字节,汉字2字节<br/><br/>
范围:能表示7445个符号,包含6753个汉字<br/><br/>
兼容性: 兼容ASCII </p>
<p>BIG5<br/><br/>
描述:统一繁体字符集<br/><br/>
字节数:2字节<br/><br/>
范围:能表示21886个符号<br/><br/>
兼容性: 兼容ASCII,但与GB2312冲突 </p>
<p>GBK<br/><br/>
描述:GB2312扩展,加入对繁体字的支持<br/><br/>
字节数:2字节<br/><br/>
范围:能表示21886个符号<br/><br/>
兼容性: 兼容GB2312 </p>
<p>GB18030<br/><br/>
描述:中日韩文字编码<br/><br/>
字节数:可变字节,1字节表示ASCII, 2字节和4字节<br/><br/>
范围:能表示27484个符号<br/><br/>
兼容性: 兼容GB2312 </p>
<p><em>Unicode编码字符集</em><br/><br/>
针对不同的语言采用不同的编码,有可能导致冲突与不兼容性,unicode统一编码世界所有的字符。Unicode字符集涵盖了目前人类使用的所有字符,并为每个字符进行统一编号,分配唯一的字符码(Code Point)。Unicode字符集将所有字符按照使用上的频繁度划分为17个层面(Plane),每个层面上有216=65536个字符码空间。</p>
<p><em>Unicode编码字符集的实现方式</em><br/><br/>
我们有了统一编码,但是怎样将Unicode编码存储到计算机里的呢?目前这种实现方式有utf-8, utf-16,utf-32和BOM。其中 utf-16是以2个字节存储utf-32是以4个字节存储,这样一来就有一个不好的地方,如ASCII字符本来是1个字节就够了,分配2个或4个字符会导致占用很多空间,导致普通文本的体积变大。这个时候utf-8恰好解决这个问题,utf-8以可变长度字节数来存储。</p>
<p><em>utf-16、utf-32</em><br/><br/>
utf(Unicode Transformation Format), 是规定如何将字符集里字符对应的整数转换成有限长度的二进制位以便存储。utf-16采用2个字节存贮unicode字符集。utf-32采用4个字节存贮unicode字符集。</p>
<p><em>utf-8</em><br/><br/>
utf-16、utf-32分别是采用固定的2个字节和4个字节存储,比较浪费空间。有没有一种能够根据字符大小可变的存储方式呢?utf-8就是这个编码方式,UTF-8用1~4个字节来表示字符。例如,原来的ASCII在utf8中继续采用1个字节, 而汉字则采用2个或3个字节。这样根据实际情况来采用可变长度编码大大节省了空间。</p>
<p><em>Little endian和Big endian</em><br/><br/>
一个字符可能占用多个字节, 在计算机中可以是'ABCD'也可以是'CDAB', 到底是采取什么顺序呢?实际上两者都有可能,并分别有不同的名字。如果存储为 AB CD,则称为Big Endian;如果存储为 CD AB,则称为Little Endian。因此,utf-16又有utf-16le, utf-16be。</p>
<p><em>Mysql中的编码</em><br/><br/>
查看MySQL中的字符编码:</p>
<pre><code>show variables like 'character%';
</code></pre>
<p>得到如下结果:</p>
<pre><code>character_set_client utf8
character_set_connection utf8
character_set_database utf8
character_set_filesystem binary
character_set_results utf8
character_set_server utf8
character_set_system utf8
character_sets_dir /usr/local/Cellar/mysql/5.6.20/share/mysql/charsets/
</code></pre>
<p>其中,<br/><br/>
character_set_client: 为客户端编码方式, 也就是客户端连接向服务器发送请求,请求字符的编码方式;<br/><br/>
character_set_connection: 为建立连接使用的编码;<br/><br/>
character_set_database: 数据库的默认编码;<br/><br/>
character_set_results: 结果集的编码, 服务发送给客户端采用的编码方式;<br/><br/>
character_set_server: 数据库服务器的默认编码; </p>
<p>导致我们查询结果乱码的主要是:set character_set_client,set character_set_connection,set character_set_results。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Javascript新接口]]></title>
<link href="./14913797913804.html"/>
<updated>2017-04-05T16:09:51+08:00</updated>
<id>./14913797913804.html</id>
<content type="html"><![CDATA[
<p>随着Html5的到来,javascript也得到极大的发展,产生了很多新API,给web应用带来很大的便利。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">requestAnimationFrame()</h3>
<p>这个API是给我们来创建动画用,在html5之前我们创建动画基本是用setInterval()来循环执行。</p>
<pre><code>(function(){
function updateAnimations(){
doAnimation1();
doAnimation2(); //其他动画
}
setInterval(updateAnimations, 100);
})();
</code></pre>
<p>这个设置动画最主要的问题是,显示器本身也需要刷新,设置时间间隔导致动画不平滑。</p>
<p>requestAnimationFrame()只是告诉浏览器需要执行动画,至于多少时间执行由浏览器自己决定和优化。</p>
<pre><code>function updateProgress(){
var div = document.getElementById("status");
div.style.width = (parseInt(div.style.width, 10) + 5) + "%";
if (div.style.left != "100%"){
mozRequestAnimationFrame(updateProgress);
} }
mozRequestAnimationFrame(updateProgress);
</code></pre>
<p>moz前缀大家应该明白的吧,还有webkitRequestAnimationFrame与msRequestAnimationFrame。</p>
<h3 id="toc_1">Page Visibility API</h3>
<p>页面可见性api, 能够好的帮助我们了解用户是与当前页面互交。也就是说,如果当前页面别最小化,或者被其他程序遮挡住,那么我们可以将该页面的一些动画效果后后台服务可以暂停。这样大大节省开销。</p>
<p>Page Visibility API由3个部分组成:<br/><br/>
1.document.hidden:表示页面是否隐藏的布尔值。页面隐藏包括页面在后台标签页中或者浏览<br/>
器最小化。<br/><br/>
2.document.visibilityState, 表示下列 4 个可能状态的值:(1)页面在后台标签页中或浏览器最小化;(2)页面在前台标签页中;(3)实际的页面已经隐藏,但用户可以看到页面的预览(就像在 Windows 7 中,用户把鼠标移动到<br/>
任务栏的图标上,就可以显示浏览器中当前页面的预览);(4)页面在屏幕外执行预渲染处理<br/><br/>
3.visibilitychange 事件</p>
<pre><code>if (document.hidden || document.msHidden || document.webKitHidden){ //页面隐藏了
} else { //页面未隐藏
}
</code></pre>
<h3 id="toc_2">Geolocation API</h3>
<p>地理位置的api, 也就是浏览器能获得用户的地理位置经纬度。这个在很多见的到。是由navigator.geolocation对象来实现。</p>
<h3 id="toc_3">File API</h3>
<p>File API让web中也能访问计算机中的文件成为可能而不是简单使用<input type="file">字段。</p>
<p>每个 File 对象都有下列只读属性。<br/><br/>
1. name:本地文件系统中的文件名。<br/><br/>
2. size:文件的字节大小。<br/><br/>
3. type:字符串,文件的 MIME 类型。<br/><br/>
4. lastModifiedDate:字符串,文件上一次被修改的时间 </p>
<pre><code>var filesList = document.getElementById("files-list");
EventUtil.addHandler(filesList, "change", function(event){
var files = EventUtil.getTarget(event).files,
i = 0,
len = files.length;
while (i < len){
console.log(files[i].name + " (" + files[i].type + ", " + files[i].size +" bytes) ");
i++; }
});
</code></pre>
<h3 id="toc_4">Web 计时</h3>
<p>主要是用来检查页面的性能,Web 计时机制的核心是 window.performance 对象。方法众多, 如:<br/><br/>
1. redirectCount:页面加载前的重定向次数。<br/><br/>
2. navigationStart:开始导航到当前页面的时间。 </p>
<h3 id="toc_5">Web Workers</h3>
<p>这个绝对是神器之一,js可以像其他语言一样,讲一些耗时间的操作使用线程、后台进程等放在后台进行。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Javascript中类,名字空间和类的继承的实现]]></title>
<link href="./14914439620917.html"/>
<updated>2017-04-06T09:59:22+08:00</updated>
<id>./14914439620917.html</id>
<content type="html"><![CDATA[
<p>最近在做一个微信项目,由于微信加载页面很慢,所以像jquery这些成熟的js库显得是个庞然大物。没办只能自己动手实现一些基础的东西,<br/>
首先,需要实现最基础javascript的类定义和类的继承,其次是名字空间。这几个是方便我们管理和组织代码最基础的,当然不是必须的,你也可以以最少代码方式将js写在你需要的地方;作为一个完整的项目我不建议这做。来看看我的具体实现吧。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">名字空间</h3>
<p>Javascript中没有namespace概念,稍微面向对象一点,所有的对象跑在顶级作用域下是个很大的麻烦。所以首先要解决这个问题,实现的方式以一个空对象作为空间名字,如: BH.file.image.Upload等。我们在Upload空间下定义自己的类。</p>
<p>具体实现:</p>
<pre><code>省略代码段...
namespace: function (nstr) {
var fns = nstr.split('.'), pns = BH;
if (fns[0] == 'BH') {
fns.shift();
}
for (var i = 0; i <= fns.length - 1; i++) {
pns[fns[i]] = pns[fns[i]] || {};
pns = pns[fns[i]];
}
return pns;
}
省略代码段...
</code></pre>
<p>方法很简单,一次遍历以'.'分割的空间名,然后设置为空对象即可,当然一定要讲起始空间保存这个是关键。最后返回最后一个空间作为当前对象。</p>
<p>使用方法:<br/><br/>
BH.namespace('BH.file.image.Upload');<br/><br/>
BH.file.image.Upload // 为空对象{}</p>
<h3 id="toc_1">类定义</h3>
<p>严格的讲javascript是没有类这个概念的,一切都是对象。我们为了面向对象方便,运用各种设计模式实现与其他语言中等同的类。这些实现方式不少于5种,比如:工厂模式,构造函数模式,原型模式等等,各有利弊。我构造函数和原型组合的方式。</p>
<p>实现如下:</p>
<pre><code> defines: function (nstr, prototype) {
var nstr = nstr.split('.'),
fn = nstr.pop(),
ns = BH.namespace(nstr.join('.'));
ns[fn] = prototype.constructor || function () {}; //设置构造函数为constructor,或者空函数
ns[fn].prototype = prototype; //设置prototype
prototype.constructor = ns[fn]; //设置prototype的constructor属性指向当前函数而不是Object
return ns[fn];
}
</code></pre>
<p>使用方法:</p>
<pre><code>BH.defines('BH.file.image.Upload', {
constructor: function() {}, //定义构造函数
A: function() {},
attrB: 'attr'
});
</code></pre>
<h3 id="toc_2">类继承</h3>
<p>和类定义一样,javascript中也是用设计模式实现等同其他语言的继承方式。实现方式很多,我才用目前认为是最好的一种方式--寄生组合式继承。这个也是YUI中实现继承的方式。</p>
<p>实现如下:</p>
<pre><code>extend: function (sub, parent, options) {
var emptyClass = function () {};
emptyClass.prototype = parent.prototype;
sub.prototype = new emptyClass();
sub.prototype.constructor = sub;
sub.superclass = superc.prototype;
if (options) {
for (var i in options) {
subc.prototype[i]=options[i];
}
}
return sub;
}
</code></pre>
<p>采用一个空函数做为构造函数来置空父类的构造函数,同时继承父类的prototype,这样做的目的为了避免引用数据类共享带来的问题。然后用options覆盖父类属性和方法,如果需要的话。</p>
<p>使用方法:<br/><br/>
BH.defines('BH.a.B');<br/><br/>
BH.extend(BH.a.B, BH.a.C { name: 'B'});</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[记一枚不错的Gem:wechat-rails]]></title>
<link href="./14914440114235.html"/>
<updated>2017-04-06T10:00:11+08:00</updated>
<id>./14914440114235.html</id>
<content type="html"><![CDATA[
<p>很少因为某个gem写博客觉得只是某个工具,最近做微信发下一枚不错的gem, 不得不记一笔。</p>
<p>wechat-rails是一个微信开发者api接口的gem包,可以在rails和命令行中使用。它的主要优点有这么几个:</p>
<ol>
<li>提供命令行调用方式,大大方便了调试</li>
<li>DSL的事件处理方式,让开发者更关注具体业务逻辑</li>
<li>最重要的作者对ruby的使用很熟练,gem设计很简洁明了</li>
</ol>
<p>安装和使用自己去看他的readme不再这里重复了,我们来看看使用的几个要点。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">配置文件</h3>
<p>命令行和rails的配置不一样,命令行需要在自己的home目录下面建立一个~/.wechat.yml文件,access_token是一个当前用户具有读写权限的文件目录,注意指定到具体的文件,用于存放获取的access_token。</p>
<pre><code> appid: "my_appid"
secret: "my_secret"
access_token: "/var/tmp/wechat_access_token"
</code></pre>
<p>rails配置是config/wechat.yml, 类似database.yml需要为每个环境分别配置。</p>
<pre><code>default: &default
appid: "app_id"
secret: "app_secret"
token: "app_token"
access_token: "/var/tmp/wechat_access_token"
production:
appid: <%= ENV['WECHAT_APPID'] %>
secret: <%= ENV['WECHAT_APP_SECRET'] %>
token: <%= ENV['WECHAT_TOKEN'] %>
access_token: <%= ENV['WECHAT_ACCESS_TOKEN'] %>
staging:
<<: *default
development:
<<: *default
test:
<<: *default
</code></pre>
<h3 id="toc_1">rails中使用</h3>
<p>如果controller需要使用微信api, 可以直接在controller中声明。</p>
<pre><code>class WechatsController < ApplicationController
wechat_responder #将weichat-rails include进来
on :text do |request, content|
request.reply.text "echo: #{content}" #Just echo
end
on :text, with:"help" do |request, help|
request.reply.text "help content" #回复帮助信息
end
on :fallback, respond: "fallback message"
end
</code></pre>
<p>上面的代码,wechat_responder用于声明当前controller接受微信回调,one :text 代码块用于声明处理微信不同类型的回调消息,但是当两声类型明相同是只调用第一声明的代码块。fallback是默认处理方式。</p>
<h3 id="toc_2">rails是如何调用api接口的</h3>
<p>上面代码只是涉及到如何响应微信的回调请求,如果你想使用其他高级接口,比如:菜单修改,用户消息查询。怎么办呢?看看下面代码:</p>
<pre><code>if defined? ActionController::Base
class ActionController::Base
def self.wechat_responder opts={}
self.send(:include, Wechat::Responder)
if (opts.empty?)
self.wechat = Wechat.api
self.token = Wechat.config.token
else
self.wechat = Wechat::Api.new(opts[:appid], opts[:secret], opts[:access_token])
self.token = opts[:token]
end
end
end
end
</code></pre>
<p>看到没有self.wechat = Wechat.api这个就是微信api接口实例,在当前controller中使用wechat就可以。如,获得关注者列表:</p>
<pre><code>wechat.users
</code></pre>
<h3 id="toc_3">wechat-rails是如何缓存access_token?</h3>
<p>wechat-rails使用文件来缓存access_token, 也就是wechat.yml中配置的文件路径。wechat-rails会每次先读取这个文件的内容,当出现访问异常时,说明access_token过期了,就需要重新请求微信然后将新的access_token写入该文件。</p>
<p>这里有个问题,当我们在服务器集群上就不大好办了,除非你将access_token缓存文件置于共享目录。这样访问效率就低了。这里我的做法是使用memcache作为缓存,需要略作改进:</p>
<pre><code>Wechat.class_eval do
# 使用数据库存储微信appid, secret和token信息,同时支付多个微信号。
# 因此,之前使用wechat.yml方式不再被支持
def self.api
raise 'we use database store token information, please use \'set_weixin_api :app_name\' inestad !'
end
end
Wechat::AccessToken.class_eval do
def cache_key
"weixin/#{appid}"
end
# 使用Rails缓存来存储token, 覆盖原本的access_token使用文件存储方式
def token
@token_data = Rails.cache.read(cache_key) || refresh
return valid_token(@token_data)
end
def refresh
data = client.get("token", params:{grant_type: "client_credential", appid: appid, secret: secret})
Rails.cache.write cache_key, data, expires_in: data["expires_in"]
return @token_data = data
end
end
</code></pre>
<p>将上面的代码至于config/initializers下面,就可以了。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Swift中的闭包]]></title>
<link href="./14914440431935.html"/>
<updated>2017-04-06T10:00:43+08:00</updated>
<id>./14914440431935.html</id>
<content type="html"><![CDATA[
<p>闭包的概念来自函数编程,很多语言都支持。Swift对闭包的定义可能是最明确易懂的(与js和ruby比较,哈哈),来看看官方定义。</p>
<blockquote>
<p>闭包是自包含的函数代码块,可以在代码中被传递和使用。<br/>
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。</p>
</blockquote>
<p>非常明确的指出闭包的实质,一、闭包是可以被传递的代码块,二、闭包可以访问所处上下文(context)中的变量和常量。这里请记住一个词上下文(context), 对于闭包理解十分重要。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">简述一下什么是下上下文环境</h3>
<p>context这个词在编程语言中是一个比较标准的专业术语,每种语言的文法必须要明确定义的。简单说,当我们函数调用时都会有个执行环境,这个执行环境主要是绑定相关的变量,对象等等。换句话说执行环境是伴随这当前的函数生命周期的一些对象和变量,当函数生命周期结束部分对象和变量随之消失。而闭包则可以在函数生命周期以外访问这些资源。</p>
<h3 id="toc_1">Swift中闭包形式</h3>
<p>1 全局函数是一个有名字但不会捕获任何值的闭包<br/><br/>
2 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包<br/><br/>
3 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包 </p>
<p><em>闭包表达式语法</em> </p>
<pre><code>{ (parameters) -> returnType in
statements
}
</code></pre>
<p>用一对大括({})号包含,指定参数和返回值。</p>
<p><em>来自官的举例</em> </p>
<p>对数组排序<br/><br/>
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] </p>
<p>1、标准的使用,闭包函数</p>
<pre><code>func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = sort(names, backwards)
</code></pre>
<p>2、使用闭包表达式</p>
<pre><code>reversed = sort(names, { (s1: String, s2: String) -> Bool in
return s1 > s2
})
</code></pre>
<p>3、自动推断类型参数类型和返回值</p>
<pre><code>reversed = sort(names, { s1, s2 in return s1 > s2 } ) //参数类型和返回类型省略
</code></pre>
<p>4、单表达式闭包隐式返回</p>
<pre><code>reversed = sort(names, { s1, s2 in s1 > s2 } ) //省略return
</code></pre>
<p>5、参数名称缩写</p>
<pre><code>reversed = sort(names, { $0 > $1 } ) //通过$0,$1,$2来顺序调用闭包的参数
</code></pre>
<p>6、运算符函数<br/>
Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。因此可以更简洁的写为</p>
<pre><code>reversed = sort(names, >)
</code></pre>
<p>这个有点复杂了,需要进一步了解运算符函数相关内容了。</p>
<p><em>尾随闭包</em><br/><br/>
尾随闭包是另外一种闭包的调用方式,当你将闭包作为最后一个函数传递时,可以将其放在函数参数列表以外。还是以sort为例:</p>
<p>正常使用</p>
<pre><code>var reversed = sort(names, backwards)
reversed = sort(names, { $0 > $1 } )
</code></pre>
<p>尾随闭包,闭包体位于函数调用后面</p>
<pre><code>reversed = sort(names) { $0 > $1 }
</code></pre>
<h3 id="toc_2">比较swift, ruby和javascript中的闭包</h3>
<p>我们看几个不同语言中的例子来看看什么是闭包。</p>
<p>Javascript中闭包主要是通过函数传递或者嵌套定义来实现</p>
<pre><code>function a() {
var counter = 1;
renturn function b() {
return counter ++;
}
}
c = a();
c() // counter为2, 一般情况执行完a()之后,counter就会被回收,但是这里因为闭包b将它带出了作用域
</code></pre>
<p>Ruby不支持嵌套定义函数,闭包是通过Proc来实现</p>
<pre><code>def a
counter = 1
return Proc.new { counter += 1 }
end
c = a
c.call # counter为2
</code></pre>
<p>ios中闭包</p>
<pre><code>
func a() -> () -> Int {
var counter = 1;
func b() -> Int {
return ++counter
}
return b
}
var c = a()
c() //counter为2
</code></pre>
<p>通过从上面例子我们可以看出,1. 要形成闭包首先得支持代码块传递,2. 闭包的行为是能够将变量带出在当前执行上下文环境以外,也就是本身作用域之外还能继续访问。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[rails的中的MIME类型]]></title>
<link href="./14914440715103.html"/>
<updated>2017-04-06T10:01:11+08:00</updated>
<id>./14914440715103.html</id>
<content type="html"><![CDATA[
<p>Rails开发中经常使用不同的请求格式来处理不同的响应,最常见的是同一个action对html/text和json格式的响应不同的数据。 那么, Rails中有哪些响应格式已经是怎么处理这些请求格式呢?本文详细讲讲rails中的处理方式。</p>
<span id="more"></span><!-- more -->
<h3 id="toc_0">什么是MIME?</h3>